HackRF One · Volume 3

HackRF One Volume 3 — The Digital Subsystem (LPC4320, CPLD, SGPIO, Clocking)

How an 8-bit sample physically gets from the MAX5864 to a USB endpoint

Contents

SectionTopic
1About this Volume
2The LPC4320
· 2.1The boot story
3The CPLD — Xilinx CoolRunner-II XC2C64A
4The SGPIO Peripheral
5Clocking
· 5.1The external CLKIN port
· 5.2Why this matters for absolute frequency
6The USB Stack
7GPIO Allocation
8Memory Map
9Interrupt Architecture
10The CPLD Recovery Path
11Differences in the HackRF Pro
12Cheatsheet Updates from this Volume
13Resources

1. About this Volume

Volume 2 covered the analogue chain. This volume covers what happens after the MAX5864 — the digital subsystem that moves 8-bit I/Q samples between the ADC/DAC and a USB endpoint at 20 MS/s, plus the clocking that synchronises the whole device.

Three chips do the digital work:

  1. The NXP LPC4320FBD144 — a dual-core ARM Cortex-M4F + Cortex-M0 microcontroller. It runs the firmware, drives USB, and orchestrates everything else.
  2. The Xilinx CoolRunner-II XC2C64A — a 64-macrocell CPLD that implements the parallel-to-serial sample-shifting glue between the MAX5864 and the LPC4320’s SGPIO peripheral.
  3. The SiLabs Si5351C (Si5351A on r9) — a clock generator that derives every clock in the device from the 25 MHz crystal reference.

The digital subsystem differs in three places between revisions: r9 changed the Si5351C → Si5351A and added clock-distribution components; r10 reverted that. Otherwise the digital subsystem has been stable since r1.

2. The LPC4320

The LPC4320FBD144^[NXP product page: https://www.nxp.com/products/microcontrollers-and-processors/arm-processors/lpc-arm-cortex-m-mcus/lpc-dual-core-cortex-m0-m4f/lpc4300:MC_1403790133078. User manual: http://www.nxp.com/documents/user_manual/UM10503.pdf. Datasheet: http://www.nxp.com/documents/data_sheet/LPC4350_30_20_10.pdf.] is the brain. Key specs:

ParameterLPC4320FBD144
Cortex-M4F core204 MHz, single-precision FPU, DSP extensions
Cortex-M0 core204 MHz, asymmetric, runs in parallel
Internal SRAM200 KB (split across multiple banks)
External flashNone on-die; uses W25Q80BV SPIFI (8 Mbit)
USB 2.0 HS PHYOn-die, with on-die regulator
SGPIO peripheral16-bit, multi-mode parallel/serial shifter
GPIO pins144 in TQFP package (~80 usable)
PackageLQFP144 (20×20 mm)

The LPC43xx family is unusual in being asymmetric multi-core — the M4F and the M0 share memory and bus fabric but run independent firmware images. On the HackRF, the M4F runs almost everything; the M0 is used by stock GSG firmware as a streaming co-processor that babysits the SGPIO peripheral while the M4F handles USB, SPI register writes to MAX2837/RFFC5072/Si5351C, and command handling.

The split is what makes 20 MS/s sustainable on a single-USB-endpoint design — the M4F could not both service USB and shovel samples through SGPIO at line rate; the M0 takes the sample-shovelling job.

2.1 The boot story

On power-up:

  1. The LPC4320 boots from internal ROM into a first-stage bootloader at the address selected by strapping pins. The HackRF straps boot from SPIFI (the W25Q80BV).
  2. ROM reads the SPIFI flash header; if a valid image is present, jumps to it.
  3. The HackRF firmware initialises clocks (via Si5351C SPI commands), brings up USB, configures GPIO direction registers, programs the CPLD bitstream if not already loaded, and lights up the front-panel LEDs.
  4. M0 firmware is started by the M4F as part of its init.

If the SPIFI flash is corrupt, the ROM falls back to DFU mode — enumerates as USB VID:PID 1d50:6088 and accepts a firmware image via the standard USB DFU protocol. This is the recovery path for “bricked” units; Vol 4 §3 walks the workflow.

3. The CPLD — Xilinx CoolRunner-II XC2C64A

The MAX5864’s parallel ADC/DAC interface is not directly compatible with the LPC4320’s SGPIO peripheral. The CPLD bridges the two:

  • On the MAX5864 side: 8 data lines per direction (8-bit samples I or Q), a clock, and direction control.
  • On the LPC4320 SGPIO side: a multi-bit shift register clocked from the same source, but with a different timing relationship.

The CPLD’s bitstream — a few KB of .xsvf data — implements a small state machine that reformats the parallel ADC bytes into the SGPIO’s expected serial-with-frame format. The bitstream lives in the firmware repo at firmware/cpld/sgpio_if/default.xsvf and is reflashed via:

hackrf_cpldjtag -x firmware/cpld/sgpio_if/default.xsvf

After a successful flash, three LEDs on the board blink in a known pattern as the CPLD restarts. This step is not required for routine firmware updates — hackrf_spiflash updates the LPC4320 firmware only. The CPLD bitstream changes very rarely (handful of times in the project’s history).

The XC2C64A is a 64-macrocell device — small, cheap (~$3 in qty), and EEPROM-backed (retains its configuration across power cycles). Xilinx discontinued the CoolRunner-II family in 2022 but parts remain available and AMD/Xilinx promised long-term support in the discontinuation notice^[The CoolRunner-II discontinuation notice (XCN22020) is at https://www.amd.com/en/support/documentation-archive.html — search for “CoolRunner”. Long-term support runs through 2032 per Xilinx’s commitment.].

The HackRF Pro replaces the CPLD with a Lattice iCE40 UltraPlus FPGA (UP5K), which has roughly 5,000 LUTs vs the CoolRunner-II’s effective ~64 macrocells. The 80× capacity headroom is what enables the Pro’s planned digital-correction and extended-precision modes (Vol 4 §10).

4. The SGPIO Peripheral

The LPC4320’s SGPIO (Serial GPIO) peripheral is the single most important block on the chip from the HackRF’s perspective. SGPIO provides 16 32-bit shift registers that can be daisy-chained, gated by an external clock, and run independently of the CPU — essentially a small built-in DMA engine for parallel-to-serial conversion^[The SGPIO chapter in NXP’s UM10503 user manual covers this in detail: http://www.nxp.com/documents/user_manual/UM10503.pdf — Chapter 22.].

On the HackRF, SGPIO is configured to:

  • Accept 8-bit parallel samples from the CPLD on a sample clock.
  • Shift them into a 32-bit register that fills 4 samples deep.
  • DMA the filled register to a system memory buffer.
  • Generate an interrupt to the M0 when buffers are full or empty.

The M0 firmware is essentially a ring-buffer manager — it cycles through ~8 ring buffers in SRAM, marking them ready as SGPIO fills them, while the M4F copies them to USB endpoints. With 20 MS/s × 2 channels × 8 bits = 320 Mbit/s = 40 MB/s of sample data, this pipeline runs near the limit of what USB 2.0 high-speed (480 Mbit/s nominal, ~280 Mbit/s practical) can sustain. The HackRF firmware is tuned tight here — minor changes to ring-buffer sizes or interrupt service times can cause sample drops, which is why the firmware is conservative about feature additions to the streaming path.

GSG’s LPC43XX_SGPIO_Configuration.html in the docs^[https://hackrf.readthedocs.io/en/latest/LPC43XX_SGPIO_Configuration.html] is the authoritative reference for the SGPIO register settings used by the HackRF.

5. Clocking

There is one reference oscillator in the entire device: a 25 MHz quartz crystal (Y1 in the schematic) driving the Si5351C’s primary input.

The Si5351C^[https://www.silabs.com/timing/clocks/general-purpose-i2c-programmable-clocks/device.si5351c — the C-variant has 8 outputs and an additional CMOS input for clock disciplining; A-variant has 3 outputs and is used on r9 with extra board-level distribution to feed the same clock count.] is a clock-generator IC that takes one input frequency and produces up to 8 independently-programmable output frequencies via a fractional-N PLL + multi-synthesiser architecture. Programming is over I²C from the LPC4320.

The HackRF uses the Si5351C to generate:

OutputFrequencyDestination
CLK0Programmable (sample clock)MAX5864 ADC/DAC clock
CLK1ProgrammableRFFC5072 reference
CLK212 MHzLPC4320 main clock (multiplied internally to 204 MHz)
CLK3ProgrammableMAX2837 reference
CLK4–7ReservedSpare; available for future use

The MAX5864’s sample clock is set by the firmware as a function of the user’s requested sample rate — at 20 MS/s, CLK0 runs at 20 MHz; at lower rates, CLK0 runs at the matching rate.

5.1 The external CLKIN port

The HackRF One has a CLKIN port on the front panel — a U.FL or SMA (depending on rev) connector for an external 10 MHz reference. When activated by hackrf_clock --set-input-source external, the Si5351C is reprogrammed to lock its internal PLL to the external 10 MHz instead of the on-board 25 MHz crystal.

This is how you give a HackRF One absolute-frequency stability — feed it from a GPSDO, a rubidium reference, or a lab signal generator. The Si5351C’s PLL bandwidth is ~10 kHz, so the external reference’s phase noise inside that bandwidth dominates; outside, the Si5351C’s noise floor takes over.

For two-HackRF synchronised work (TDOA, direction finding, IQ-coherent dual-receive), the canonical setup is:

[GPSDO 10 MHz] ── splitter ─┬─► HackRF #1 CLKIN

                            └─► HackRF #2 CLKIN

Vol 5 §7 walks the hackrf_clock CLI in detail.

5.2 Why this matters for absolute frequency

A 25 MHz crystal at room temperature has a tolerance of ±20 ppm over its operating range. At 2.4 GHz tuning, ±20 ppm is ±48 kHz of frequency uncertainty — enormous for narrowband digital modes (FT8 at ±2 Hz, WSPR at ±1 Hz, even FM voice at ±5 kHz). Drift over a 30-minute warm-up is typically half this — but it’s still ±24 kHz on a cold device.

Solutions in increasing order of cost:

  1. Warm-up + manual offset — let the device sit powered for 30 minutes, measure the offset against a known reference, set --ppm-offset in receiver software. Acceptable for casual work above 100 MHz.
  2. External GPSDO into CLKIN — $80–250 part. Brings stability to <1 ppb. Vol 5 §7 covers wiring and software setup.
  3. Buy the HackRF Pro — built-in TCXO replaces the crystal. Sub-ppm without external hardware.

6. The USB Stack

USB 2.0 high-speed (480 Mbit/s nominal) is the host interface. The LPC4320’s on-die USB PHY drives a single USB endpoint pair: bulk IN (samples to host) and bulk OUT (samples from host) on the streaming path, plus control endpoints for the command surface.

The vendor-specific HackRF USB protocol is documented in hackrf-tools/host/hackrf-tools/src/hackrf.h of the host repo and consists of about 60 vendor commands^[https://github.com/greatscottgadgets/hackrf/blob/main/host/libhackrf/src/hackrf.h]:

Command classExamples
IdentificationBOARD_ID_READ, VERSION_STRING_READ, SERIAL_READ
Sample rateSET_SAMPLE_RATE
FrequencySET_FREQUENCY, SET_FREQUENCY_EXPLICIT
GainSET_LNA_GAIN, SET_VGA_GAIN, SET_TXVGA_GAIN
TX/RX modeSET_TRANSCEIVER_MODE
StreamingSTART_RX, START_TX, STOP
Bias-TSET_ANTENNA_ENABLE
ClockGET_CLKIN_STATUS, SET_CLKOUT_ENABLE
SweepINIT_SWEEP
FirmwareSPIFLASH_READ, SPIFLASH_WRITE, RESET

libhackrf wraps these into a friendly C API; libhackrf is what hackrf_transfer, hackrf_sweep, and every host application uses (Vol 5).

USB enumeration as device VID:PID 1d50:6089 in normal mode, 1d50:6088 in DFU mode. The vendor ID 1d50 is “OpenMoko, Inc.” and is shared with several open-hardware projects.

7. GPIO Allocation

Of the 144 LPC4320 pins, the HackRF uses approximately:

GroupPinsPurpose
SGPIO 0–7 (sample data)8Parallel sample data to/from CPLD
SGPIO clock/sync4Sample clock + frame strobe + control
SPI to MAX28374Register writes; MAX2837 doesn’t use SPI for data
SPI to RFFC50724LO programming
I²C to Si5351C2Clock generator config
RF switch control2–4SP4T path select (decoded vs encoded — depends on switch part)
Bias-T enable2Per-direction enable (RX, TX)
LEDs3USB / RX / TX activity
User button1DFU mode entry
Reserved expansion header32The PortaPack uses many of these
Hardware revision strap pins (r6+)3Self-reported revision
USB4DP, DM, VBUS, GND

The expansion header (P22 on the schematic) is what the PortaPack mates to. Vol 9 §3 covers the pinout in full.

8. Memory Map

The LPC4320’s address space:

RangeRegion
0x00000000 – 0x000FFFFFInternal Boot ROM (factory programmed, read-only)
0x10000000 – 0x10007FFFLocal SRAM bank 0 (32 KB) — M4F-favoured
0x10080000 – 0x1009FFFFLocal SRAM bank 1 (40 KB)
0x14000000 – 0x14FFFFFFSPIFI external flash window (W25Q80BV mapped here)
0x20000000 – 0x20007FFFAHB SRAM bank 0 (32 KB) — typically M0-favoured
0x20008000 – 0x2000BFFFAHB SRAM bank 1 (16 KB) — sample ring buffers
0x40000000 – 0x4FFFFFFFPeripheral registers (USB, SGPIO, SPI, I²C, GPIO, etc.)

The sample ring buffers live in AHB SRAM — accessible by both cores and by the SGPIO DMA engine without contention with the M4F’s instruction fetches.

9. Interrupt Architecture

The streaming path runs in interrupt context. The hot path:

  1. SGPIO DMA fills a ring-buffer slot.
  2. SGPIO interrupt fires → M0 ISR marks the slot ready.
  3. M4F’s USB ISR fires when USB endpoint is ready for more data.
  4. USB ISR reads the next ready slot from M0’s ring, DMAs it to USB, marks the slot free.
  5. SGPIO sees the free slot, fills it, repeat.

This pipeline runs at 40 MB/s without dropping samples on a clean USB chain. The conditions that cause drops:

  • Host buffering issues — laptop with slow USB host controller, or competing USB devices on the same root hub. Solution: dedicated USB chain.
  • CPU load on the host — the host application can’t drain the USB pipe fast enough. Solution: drop sample rate, or run the capture on a more powerful machine.
  • Power dips — the HackRF draws ~500 mA on USB 2.0 (full spec), and a marginal cable or hub causes voltage sag that triggers unexpected resets.

hackrf_transfer reports drops in its end-of-run summary; if the count is > 0, the data has gaps.

10. The CPLD Recovery Path

Occasionally — usually after a botched firmware development experiment, never in routine use — the CPLD bitstream becomes corrupt. Symptoms: hackrf_info works (LPC4320 firmware is fine) but no samples flow.

Recovery:

# 1. Confirm the LPC firmware is alive
$ hackrf_info
# Should show device + firmware version. If this fails, see Vol 4 §3
# (DFU recovery — different problem).

# 2. Reflash the CPLD bitstream (default-known-good)
$ git clone https://github.com/greatscottgadgets/hackrf
$ cd hackrf
$ hackrf_cpldjtag -x firmware/cpld/sgpio_if/default.xsvf

# 3. Wait for the LEDs to blink (3-5 seconds), then reset
$ hackrf_transfer -r /dev/null -f 100000000 -s 2000000 -n 1000000
# Should succeed without "samples not received" errors

This procedure is in hackrf_cpldjtag.c of the host tools and on the GSG troubleshooting page^[https://hackrf.readthedocs.io/en/latest/troubleshooting.html].

11. Differences in the HackRF Pro

The HackRF Pro’s digital subsystem replaces:

  • CPLDiCE40 UltraPlus FPGA (UP5K) — 5280 LUTs, BRAM blocks, DSP slices. Open-source toolchain via Yosys + nextpnr-ice40.
  • FlashW25Q32 (32 Mbit, 4× the One). Holds a larger firmware image and FPGA bitstream.
  • MCU → still LPC4320 (planned upgrade in a future revision).

The FPGA capacity headroom enables features the CPLD couldn’t fit:

  • Digital pre-distortion of the TX path (compensates for mixer non-linearity).
  • Extended-precision sample modes (12-bit equivalent via oversampling + decimation).
  • Built-in test signal generator at the FPGA fabric level.
  • Future modes that the firmware team has not yet announced.

The Pro’s iCE40 is JTAG-flashed by the firmware on every boot — there is no separate hackrf_cpldjtag step for the Pro. The bitstream lives in the firmware image and is loaded into the FPGA by the LPC4320 over a dedicated SPI link at startup.

12. Cheatsheet Updates from this Volume

For Vol 12:

  • LPC4320 dual-core: M4F + M0; M0 babysits SGPIO
  • USB streaming: 40 MB/s sustained, 20 MS/s × 2 channels × 8-bit
  • Si5351C: I²C-programmable, 8 outputs, locked to 25 MHz crystal or external 10 MHz CLKIN
  • CPLD recovery: hackrf_cpldjtag -x firmware/cpld/sgpio_if/default.xsvf
  • DFU mode entry: hold DFU button while plugging USB → enumerates as 1d50:6088
  • Memory map: AHB SRAM 0x20000000–0x2000BFFF for ring buffers
  • HackRF Pro: iCE40 UP5K FPGA replaces CPLD; 4× more flash

13. Resources

ResourceURL
LPC43xx user manual (UM10503)http://www.nxp.com/documents/user_manual/UM10503.pdf
LPC43xx datasheethttp://www.nxp.com/documents/data_sheet/LPC4350_30_20_10.pdf
SGPIO configuration (GSG docs)https://hackrf.readthedocs.io/en/latest/LPC43XX_SGPIO_Configuration.html
LPC43xx debugging (GSG docs)https://hackrf.readthedocs.io/en/latest/LPC43XX_Debugging.html
Si5351 datasheethttp://www.silabs.com/Support%20Documents/TechnicalDocs/Si5351.pdf
Si5351 AN619 register maphttp://www.silabs.com/Support%20Documents/TechnicalDocs/AN619.pdf
Xilinx CoolRunner-II XC2C64Ahttps://docs.amd.com/v/u/en-US/ds090
iCE40 UltraPlus (HackRF Pro)https://www.latticesemi.com/en/Products/FPGAandCPLD/iCE40UltraPlus
External clock interface (GSG docs)https://hackrf.readthedocs.io/en/latest/external_clock_interface.html
Synchronisation checklist (GSG docs)https://hackrf.readthedocs.io/en/latest/synchronization_checklist.html
HackRF host C API headerhttps://github.com/greatscottgadgets/hackrf/blob/main/host/libhackrf/src/hackrf.h