libhackrf: Firmware flashing & debugging

libhackrf HackRF SDR platform library

Loading...
Searching...
No Matches
Data Structures | Functions
Firmware flashing & debugging

Firmware flashing and directly accessing hardware components. More...

## Data Structures
struct | hackrf_m0_state
| State of the SGPIO loop running on the M0 core. More...
struct | hackrf_selftest
| Self-test results. More...

## Functions
int | hackrf_get_m0_state (hackrf_device *device, hackrf_m0_state *value)
| Get the state of the M0 code on the LPC43xx MCU.
int | hackrf_read_selftest (hackrf_device *device, hackrf_selftest *value)
| Get the results of the device self-test.
int | hackrf_test_rtc_osc (hackrf_device *device, bool *pass)
| Test the RTC oscillator on the device.
int | hackrf_read_adc (hackrf_device *device, uint8_t adc_channel, uint16_t *value)
| Read a value from an ADC channel.
int | hackrf_max2837_read (hackrf_device *device, uint8_t register_number, uint16_t *value)
| Directly read the registers of the MAX2837 transceiver IC.
int | hackrf_max2831_read (hackrf_device *device, uint8_t register_number, uint16_t *value)
| Directly read the registers of the MAX2831 transceiver IC.
int | hackrf_max2837_write (hackrf_device *device, uint8_t register_number, uint16_t value)
| Directly write the registers of the MAX2837 transceiver IC.
int | hackrf_max2831_write (hackrf_device *device, uint8_t register_number, uint16_t value)
| Directly write the registers of the MAX2831 transceiver IC.
int | hackrf_si5351c_read (hackrf_device *device, uint16_t register_number, uint16_t *value)
| Directly read the registers of the Si5351C clock generator IC.
int | hackrf_si5351c_write (hackrf_device *device, uint16_t register_number, uint16_t value)
| Directly write the registers of the Si5351 clock generator IC.
int | hackrf_rffc5071_read (hackrf_device *device, uint8_t register_number, uint16_t *value)
| Directly read the registers of the RFFC5071/5072 mixer-synthesizer IC.
int | hackrf_rffc5071_write (hackrf_device *device, uint8_t register_number, uint16_t value)
| Directly write the registers of the RFFC5071/5072 mixer-synthesizer IC.
int | hackrf_fpga_read_register (hackrf_device *device, uint8_t register_number, uint8_t *value)
| Directly read the registers of the current gateware through the FPGA SPI interface (HackRF Pro)
int | hackrf_fpga_write_register (hackrf_device *device, uint8_t register_number, uint8_t value)
| Directly write the registers of the current gateware through the FPGA SPI interface (HackRF Pro)
int | hackrf_spiflash_erase (hackrf_device *device)
| Erase firmware image on the SPI flash.
int | hackrf_spiflash_write (hackrf_device *device, const uint32_t address, const uint16_t length, unsigned char *const data)
| Write firmware image on the SPI flash.
int | hackrf_spiflash_read (hackrf_device *device, const uint32_t address, const uint16_t length, unsigned char *data)
| Read firmware image on the SPI flash.
int | hackrf_spiflash_status (hackrf_device *device, uint8_t *data)
| Read the status registers of the W25Q80BV SPI flash chip.
int | hackrf_spiflash_clear_status (hackrf_device *device)
| Clear the status registers of the W25Q80BV SPI flash chip.
int | hackrf_cpld_write (hackrf_device *device, unsigned char *const data, const unsigned int total_length)
| Write configuration bitstream into the XC2C64A-7VQ100C CPLD.

## Detailed Description

# Firmware flashing

IMPORTANT You should try to use the existing flashing utilities (`hackrf_spiflash`) to flash new firmware to the device! Incorrect usage of the SPIFLASH functions (especially hackrf_spiflash_erase an hackrf_spiflash_write) can brick the device, and DFU mode will be needed to unbrick it!

Firmware flashing can be achieved via writing to the SPI flash holding the firmware of the ARM microcontroller. This can be achieved by the `hackrf_spiflash_*` functions.

The Spartan II CPLD inside the HackRF One devices could also be reconfigured in the past, but in newer firmwares, the ARM MCU automatically reconfigures it on startup with a bitstream baked into the firmware image, thus the function hackrf_cpld_write has no effect, and CPLD flashing can only be done by building a custom firmware (or the automatic loading can be disabled this way as well). The function hackrf_cpld_write and the util `hackrf_cpldjtag` are deprecated and only kept for backward compatibility with older firmware versions.

# Debugging

The functions in this section can be used to directly read/write internal registers of the chips inside a HackRF One unit. See the page Hardware Components for more details on them.

Here's a brief introduction on the various chips in the HackRF One unit:

## MAX2837 2.3 to 2.7 GHz transceiver

This transceiver chip is the RF modulator/demodulator of the HackRF One. This chip sends/receives analog I/Q samples to/from the MAX5864 ADC/DAC chip.

Its registers are accessible through the functions hackrf_max2837_read and hackrf_max2837_write

## MAX5864 ADC/DAC

This chip converts received analog I/Q samples to digital and transmitted I/Q samples to analog. It connects to the main ARM MCU through the CPLD. No configuration is needed for it, only the sample rate can be set via the clock generator IC.

## Si5351C Clock generator

This chip supplies clock signals to all of the other chips. It can synthesize a wide range of frequencies from its clock inputs (internal or external). It uses a fixed 800-MHz internal clock (synthesized via a PLL).

Its registers are accessible through the functions hackrf_si5351c_read and hackrf_si5351c_write

## RFFC5072 Synthesizer/mixer

This mixer mixes the RF signal with an internally synthesized local oscillator signal and thus results in the sum and difference frequencies. Combined with the LPF or HPF filters and the frequency setting in the MAX2837 IC it can be used to tune to any frequency in the 0-6000MHz range.

Its registers are accessible through the functions hackrf_rffc5071_read and hackrf_rffc5071_write

## LPC4320 ARM MCU

This is the main processor of the unit. It's a multi-core ARM processor. It's configured to boot from a W25Q80B SPI flash, but can also be booted from DFU in order to unbrick a bricked unit. It communicated with the host PC via USB.

Some operation details are available via the function hackrf_get_m0_state

## W25Q80B SPI flash

This chip holds the firmware for the LPC4320 ARM MCU.

It's accessible through the functions hackrf_spiflash_read, hackrf_spiflash_write, hackrf_spiflash_erase, hackrf_spiflash_status and hackrf_spiflash_clear_status

## XC2C64A CPLD

This CPLD sits between the MAX5864 ADC/DAC and the main MCU, and mainly performs data format conversion and some synchronisation.

Its bitstream is auto-loaded on reset by the ARM MCU (from the firmware image), but in older versions, it was possible to reconfigure it via hackrf_cpld_write, and the (since temporarily removed) `hackrf_cpld_checksum` function could verify the firmware in the configuration flash (again, overwritten on startup, so irrelevant).

See issue 608, issue 1140 and issue 1141 for some more details on this!

## Function Documentation

## ◆ hackrf_cpld_write()

int hackrf_cpld_write | ( | hackrf_device * | device,
|  | unsigned char *const | data,
|  | const unsigned int | total_length
| ) |  |
| extern

Parameters

  device | device to configure
  data | CPLD bitstream data
  total_length | length of the bitstream to write

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_fpga_read_register()

int hackrf_fpga_read_register | ( | hackrf_device * | device,
|  | uint8_t | register_number,
|  | uint8_t * | value
| ) |  |
| extern

Intended for debugging purposes only!

Parameters

  [in] | device | device to query
  [in] | register_number | register number to read
  [out] | value | value of the specified register

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_fpga_write_register()

int hackrf_fpga_write_register | ( | hackrf_device * | device,
|  | uint8_t | register_number,
|  | uint8_t | value
| ) |  |
| extern

Intended for debugging purposes only!

Parameters

  [in] | device | device to write
  [in] | register_number | register number to write
  [out] | value | value to write in the specified register

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_get_m0_state()

int hackrf_get_m0_state | ( | hackrf_device * | device,
|  | hackrf_m0_state * | value
| ) |  |
| extern

Requires USB API version 0x0106 or above!

Parameters

  [in] | device | device to query
  [out] | value | MCU code state

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_max2831_read()

int hackrf_max2831_read | ( | hackrf_device * | device,
|  | uint8_t | register_number,
|  | uint16_t * | value
| ) |  |
| extern

Intended for debugging purposes only!

Parameters

  [in] | device | device to query
  [in] | register_number | register number to read
  [out] | value | value of the specified register

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_max2831_write()

int hackrf_max2831_write | ( | hackrf_device * | device,
|  | uint8_t | register_number,
|  | uint16_t | value
| ) |  |
| extern

Intended for debugging purposes only!

Parameters

  device | device to write
  register_number | register number to write
  value | value to write in the specified register

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_max2837_read()

int hackrf_max2837_read | ( | hackrf_device * | device,
|  | uint8_t | register_number,
|  | uint16_t * | value
| ) |  |
| extern

Intended for debugging purposes only!

Parameters

  [in] | device | device to query
  [in] | register_number | register number to read
  [out] | value | value of the specified register

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_max2837_write()

int hackrf_max2837_write | ( | hackrf_device * | device,
|  | uint8_t | register_number,
|  | uint16_t | value
| ) |  |
| extern

Intended for debugging purposes only!

Parameters

  device | device to write
  register_number | register number to write
  value | value to write in the specified register

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_read_adc()

int hackrf_read_adc | ( | hackrf_device * | device,
|  | uint8_t | adc_channel,
|  | uint16_t * | value
| ) |  |
| extern

Parameters

  [in] | device | device to query
  [in] | adc_channel | ADC channel, e.g. 0 for ADC0_0. Add 0x80 to use an alternate pin.
  [out] | value | Value read from ADC.

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_read_selftest()

int hackrf_read_selftest | ( | hackrf_device * | device,
|  | hackrf_selftest * | value
| ) |  |
| extern

Parameters

  [in] | device | device to query
  [out] | self-test | results

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_rffc5071_read()

int hackrf_rffc5071_read | ( | hackrf_device * | device,
|  | uint8_t | register_number,
|  | uint16_t * | value
| ) |  |
| extern

Intended for debugging purposes only!

Parameters

  [in] | device | device to query
  [in] | register_number | register number to read
  [out] | value | value of the specified register

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_rffc5071_write()

int hackrf_rffc5071_write | ( | hackrf_device * | device,
|  | uint8_t | register_number,
|  | uint16_t | value
| ) |  |
| extern

Intended for debugging purposes only!

Parameters

  [in] | device | device to write
  [in] | register_number | register number to write
  [out] | value | value to write in the specified register

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_si5351c_read()

int hackrf_si5351c_read | ( | hackrf_device * | device,
|  | uint16_t | register_number,
|  | uint16_t * | value
| ) |  |
| extern

Intended for debugging purposes only!

Parameters

  [in] | device | device to query
  [in] | register_number | register number to read
  [out] | value | value of the specified register

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_si5351c_write()

int hackrf_si5351c_write | ( | hackrf_device * | device,
|  | uint16_t | register_number,
|  | uint16_t | value
| ) |  |
| extern

Intended for debugging purposes only!

Parameters

  [in] | device | device to write
  [in] | register_number | register number to write
  [out] | value | value to write in the specified register

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_spiflash_clear_status()

int hackrf_spiflash_clear_status | ( | hackrf_device * | device | ) |
| extern

See the datasheet for details of the status registers.

Requires USB API version 0x0103 or above!

Parameters

  device | device to clear

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_spiflash_erase()

int hackrf_spiflash_erase | ( | hackrf_device * | device | ) |
| extern

Should be followed by writing a new image, or the HackRF will be soft-bricked (still rescuable in DFU mode)

Parameters

  device | device to erase

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_spiflash_read()

int hackrf_spiflash_read | ( | hackrf_device * | device,
|  | const uint32_t | address,
|  | const uint16_t | length,
|  | unsigned char * | data
| ) |  |
| extern

Should only be used for firmware verification.

Parameters

  device | device to read from
  address | address to read from. Firmware should start at 0
  length | length of data to read. Must be at most 256.
  data | pointer to buffer

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_spiflash_status()

int hackrf_spiflash_status | ( | hackrf_device * | device,
|  | uint8_t * | data
| ) |  |
| extern

See the datasheet for details of the status registers. The two registers are read in order.

Requires USB API version 0x0103 or above!

Parameters

  [in] | device | device to query
  [out] | data | char[2] array of the status registers

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_spiflash_write()

int hackrf_spiflash_write | ( | hackrf_device * | device,
|  | const uint32_t | address,
|  | const uint16_t | length,
|  | unsigned char *const | data
| ) |  |
| extern

Should only be used for firmware updating. Can brick the device, but it's still rescuable in DFU mode.

Parameters

  device | device to write on
  address | address to write to. Should start at 0
  length | length of data to write. Must be at most 256.
  data | data to write

Returns
  HACKRF_SUCCESS on success or hackrf_error variant

## ◆ hackrf_test_rtc_osc()

int hackrf_test_rtc_osc | ( | hackrf_device * | device,
|  | bool * | pass
| ) |  |
| extern

Parameters

  [in] | device | device to query
  [out] | pass | RTC oscillator test result

Returns
  HACKRF_SUCCESS on success or hackrf_error variant