固件

原文来源:【https://hackrf.readthedocs.io/en/latest/index.html】机器翻译加人工修改,不正之处,请指正!

更新固件

HackRF 设备附带 SPI 闪存上的固件。只需 USB 数据线和主机即可更新固件。

这些说明允许您升级固件以利用新功能或错误修复。

如果您在本机操作系统上执行此过程有任何困难,您可以 使用 Pentoo 或 GNU Radio Live DVD来执行更新。

更新 SPI 闪存固件

要更新正在运行的 HackRF One 上的固件,请使用 hackrf_spiflash 程序:

hackrf_spiflash -w hackrf_one_usb.bin

您可以在最新发布包的 firmware-bin 目录中找到固件二进制文件 (hackrf_one_usb.bin),或者您可以从源代码编译您自己的。对于 Jawbreaker,使用 hackrf_jawbreaker_usb.bin。如果您从源代码编译,该文件将被称为 hackrf_usb.bin。

hackrf_spiflash 程序是 hackrf-tools 的一部分。

将固件映像写入 SPI 闪存时,请务必选择文件名以“.bin”结尾的固件。

将固件写入 SPI 闪存后,您可能需要通过按下 RESET 按钮或拔下并重新插入来重置 HackRF 设备。

如果您收到提到 HACKRF_ERROR_NOT_FOUND 的错误,请查看常见问题解答。这通常是可以快速解决的权限问题。

更新 CPLD

较旧版本的 HackRF 固件(2021.03.1 之前的版本)需要额外的步骤才能将比特流编程到 CPLD 中。

要更新 CPLD 映像,首先将 SPI 闪存固件、libhackrf 和 hackrf-tools 更新为您正在安装的版本。然后:

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

几秒钟后,三个 LED 应该开始闪烁。这表明 CPLD 已成功编程。通过按下 RESET 按钮或拔下并重新插入来重置 HackRF 设备。

仅在必要时:DFU 启动

DFU 引导模式通常仅在固件无法正常工作或从未安装时才需要。

HackRF 上的 LPC4330 微控制器能够从多个不同的代码源启动。默认情况下,HackRF 从 SPI 闪存 (SPIFI) 启动。它还可以在 DFU (USB) 启动模式下启动 HackRF。在 DFU 启动模式下,HackRF 将通过 USB 进行枚举,等待使用 DFU(设备固件更新)标准通过 USB 传送代码,然后从 RAM 中执行该代码。SPIFI 在 DFU 模式下通常不被使用和改变。

要在 DFU 模式下启动 HackRF One,请在开机时按住 DFU 按钮或按下并释放 RESET 按钮。3V3 LED 亮起后松开 DFU 按钮。1V8 LED 应保持关闭状态。此时 HackRF One 已准备好通过 USB 接收固件。

要在 DFU 模式下启动 Jawbreaker,请在首次供电时短接其中一个“BOOT”接头连接器上的两个引脚。必须短接的引脚是 Jawbreaker 上接头 P32 的引脚 1 和 2。大多数 Jawbreaker 上的接头 P32 标记为“P2_8”,但在原型装置上可能标记为“2”。引脚 1 标有“VCC”。引脚 2 是中心引脚。DFU 启动后,您应该看到 VCCLED 亮起,并注意 1V8LED 不亮。此时 Jawbreaker 已准备好通过 USB 接收固件。

您应该只使用文件名以“.dfu”结尾的固件映像而不是以“.bin”结尾的固件。

仅在必要时:恢复 SPI 闪存固件

如果安装在 SPI flash 中的固件已经损坏,或者如果您是第一次编写自制的 HackRF,您将无法立即使用上述过程中列出的 hackrf_spiflash 程序。请改为执行以下步骤:

  1. 按照 DFU 引导说明以 DFU 引导模式启动 HackRF。
  2. 键入以将固件从发布包加载到 RAM 中。如果您有 Jawbreaker,请改用 hackrf_jawbreaker_usb.dfu。或者,使用将固件加载到 RAM 中并启动它。dfu-util --device 1fc9:000c --alt 0 --download hackrf_one_usb.dfumake -e BOARD=HACKRF_ONE RUN_FROM=RAM program
  3. 按照上面的 SPI 闪存固件更新程序将“.bin”固件映像写入 SPI 闪存。

获取DFU-Util

在全新安装操作系统时,您可能需要获取一份 DFU-Util。对于大多数 Linux 发行版,它应该作为一个包提供,例如在 Debian/Ubuntu 上

sudo apt-get install dfu-util

如果您使用的平台没有 dfu-util 包,可以在 dfu-util source forge 构建页面上找到构建说明。

cd ~
sudo apt-get build-dep dfu-util
sudo apt-get install libusb-1.0-0-dev
git clone git://git.code.sf.net/p/dfu-util/dfu-util
cd dfu-util
./autogen.sh
./configure
make
sudo make install

现在您将在系统上安装当前版本的 DFU Util。

固件开发环境设置

固件构建说明包含在 firmware/README 下的存储库中:

https://github.com/mossmann/hackrf/blob/master/firmware/README

LPC43xx调试

存在用于 LPC43xx 的各种调试器选项。

Black Magic Probe

https://github.com/blacksphere/blackmagic

将 gdb 与 Black Magic Probe 结合使用的示例:

arm-none-eabi-gdb -n blinky.elf
target extended-remote /dev/ttyACM0
monitor swdp_scan
attach 1
set {int}0x40043100 = 0x10000000
load
cont

如果您使用 jtag_scan 而不是 swdp_scan,则可以连接到 M0 而不是 M4,但是我上次尝试使用 M0 时,Black Magic Probe 有一些错误。

LPC-Link

(包含在 LPCXpresso 板中)

TitanMKD 取得了一些成功。请参阅 hackrf/doc/LPCXPresso_Flash_Debug_Tutorial.pdf 或 .odt 中的教程(PDF 和 OpenOffice 文档)文档链接 [ https://github.com/mossmann/hackrf/tree/master/doc )

ST-LINK/V2

硬件配置

从 STM32F4-Discovery 板开始。从 CN3 上拆下跳线。将目标的 SWD 接口连接到 CN2“SWD”连接器。

软件配置

我正在使用 libusb-1.0.9。

安装 OpenOCD-0.6.0 开发版

# Cloned at hash a21affa42906f55311ec047782a427fcbcb98994
git clone git://openocd.git.sourceforge.net/gitroot/openocd/openocd
cd openocd
./bootstrap
./configure --enable-stlink --enable-buspirate --enable-jlink --enable-maintainer-mode
make
sudo make install

OpenOCD 配置文件

openocd配置文件

#debug_level 3
source [find interface/stlink-v2.cfg]
source ./lpc4350.cfg

lpc4350.cfg

set _CHIPNAME lpc4350
set _M0_CPUTAPID 0x4ba00477
set _M4_SWDTAPID 0x2ba01477
set _M0_TAPID 0x0BA01477
set _TRANSPORT stlink_swd

transport select $_TRANSPORT

stlink newtap $_CHIPNAME m4 -expected-id $_M4_SWDTAPID
stlink newtap $_CHIPNAME m0 -expected-id $_M0_TAPID

target create $_CHIPNAME.m4 stm32_stlink -chain-position $_CHIPNAME.m4
#target create $_CHIPNAME.m0 stm32_stlink -chain-position $_CHIPNAME.m0

target.xml,来自 OpenOCD 邮件列表线程,用于修复 GDB 和更新的 OpenOCD 构建之间的通信问题。

<?xml version="1.0"?>
<!DOCTYPE target SYSTEM "gdb-target.dtd">
<target>
  <feature name="org.gnu.gdb.arm.core">
    <reg name="r0" bitsize="32" type="uint32"/>
    <reg name="r1" bitsize="32" type="uint32"/>
    <reg name="r2" bitsize="32" type="uint32"/>
    <reg name="r3" bitsize="32" type="uint32"/>
    <reg name="r4" bitsize="32" type="uint32"/>
    <reg name="r5" bitsize="32" type="uint32"/>
    <reg name="r6" bitsize="32" type="uint32"/>
    <reg name="r7" bitsize="32" type="uint32"/>
    <reg name="r8" bitsize="32" type="uint32"/>
    <reg name="r9" bitsize="32" type="uint32"/>
    <reg name="r10" bitsize="32" type="uint32"/>
    <reg name="r11" bitsize="32" type="uint32"/>
    <reg name="r12" bitsize="32" type="uint32"/>
    <reg name="sp" bitsize="32" type="data_ptr"/>
    <reg name="lr" bitsize="32"/>
    <reg name="pc" bitsize="32" type="code_ptr"/>
    <reg name="cpsr" bitsize="32" regnum="25"/>
  </feature>
  <feature name="org.gnu.gdb.arm.fpa">
    <reg name="f0" bitsize="96" type="arm_fpa_ext" regnum="16"/>
    <reg name="f1" bitsize="96" type="arm_fpa_ext"/>
    <reg name="f2" bitsize="96" type="arm_fpa_ext"/>
    <reg name="f3" bitsize="96" type="arm_fpa_ext"/>
    <reg name="f4" bitsize="96" type="arm_fpa_ext"/>
    <reg name="f5" bitsize="96" type="arm_fpa_ext"/>
    <reg name="f6" bitsize="96" type="arm_fpa_ext"/>
    <reg name="f7" bitsize="96" type="arm_fpa_ext"/>
    <reg name="fps" bitsize="32"/>
  </feature>
</target>

运行 ARM GDB

很快,我将这些东西转储到 .gdbinit 文件中。

arm-none-eabi-gdb -n
target extended-remote localhost:3333
set tdesc filename target.xml
monitor reset init
monitor mww 0x40043100 0x10000000
monitor mdw 0x40043100   # Verify 0x0 shadow register is set properly.
file lpc4350-test.axf    # This is an ELF file.
load                     # Place image into RAM.
monitor reset init
break main               # Set a breakpoint.
continue                 # Run to breakpoint.
continue                 # To continue from the breakpoint.
step                     # Step-execute the next source line.
stepi                    # Step-execute the next processor instruction.
info reg                 # Show processor registers.

针对不熟悉 GDB 的更多 GDB 技巧:

# Write the variable "buffer" (an array) to file "buffer.u8".
dump binary value buffer.u8 buffer

# Display the first 32 values in buffer whenever you halt
# execution.
display/32xh buffer

# Print the contents of a range of registers (in this case the
# CGU peripheral, starting at 0x40050014, for 46 words):
x/46 0x40050014

还有更多,用于调试 ARM Cortex-M4 硬故障:

# Assuming you have a hard-fault handler wired in:
display/8xw args

# Examine fault-related registers:

# Configurable Fault Status Register (CFSR) contains:
# CFSR[15:8]: BusFault Status Register (BFSR)
#   "Shows the status of bus errors resulting from instruction
#   prefetches and data accesses."
#   BFSR[7]: BFARVALID: BFSR contents valid.
#   BFSR[5]: LSPERR: fault during FP lazy state preservation.
#   BFSR[4]: STKERR: derived bus fault on exception entry.
#   BFSR[3]: UNSTKERR: derived bus fault on exception return.
#   BFSR[2]: IMPRECISERR: imprecise data access error.
#   BFSR[1]: PRECISERR: precise data access error, faulting
#            address in BFAR.
#   BFSR[0]: IBUSERR: bus fault on instruction prefetch. Occurs
#            only if instruction is issued.
display/xw 0xE000ED28

# BusFault Address Register (BFAR)
# "Shows the address associated with a precise data access fault."
# "This is the location addressed by an attempted data access that
# was faulted. The BFSR shows the reason for the fault and whether
# BFAR_ADDRESS is valid..."
# "For unaligned access faults, the value returned is the address
# requested by the instruction. This might not be the address that
# faulted."
display/xw 0xE000ED38

LPC43xx SGPIO 配置

LPC43xx SGPIO 外设用于在 USB 和 ADC/DAC 芯片 (MAX5864) 之间传输采样数据。SGPIO 是具有一组 32 位移位寄存器的外设。这些移位寄存器可以配置为充当不同宽度的并行接口。对于 HackRF,我们将 SGPIO 配置为一次传输八位。SGPIO 接口也可以接受外部时钟,我们用它来同步传输与采样时钟。

在当前的 HackRF 设计中,有一个 CPLD 管理 MAX5864 和 SGPIO 接口之间的接口。有四个 SGPIO 信号控制 SGPIO 数据传输:

  • 时钟:确定何时传输 SGPIO 数据总线上的值。
  • Direction:确定是将 MAX5864 DA (ADC) 数据驱动到 SGPIO 线上,还是 SGPIO 线驱动数据总线为 MAX5864 DD (DAC) 信号提供数据。
  • 数据有效:表示 SGPIO 数据总线上的样本是有效数据。
  • Transfer Enable:允许 SGPIO 与 I/Q 数据流同步。MAX5864 在每个采样周期产生/消耗两个值(正交/复值)——一个 I 值和一个 Q 值。这两个值在 SGPIO 线上复用。该信号暂停数据有效,直到应该传输 I 值。

经常问的问题

为什么不使用GPDMA而是通过SGPIO传输采样数据呢?

如果可以,那就太好了,因为这会释放大量的处理器时间。不幸的是,LPC43xx 中的 GPDMA 方案似乎不支持使用 SGPIO 外设进行外设到内存和内存到外设的传输。

您可能会观察到 SGPIO 外设可以使用切片移位寄存器中的任意位模式从 SGPIO14 和 SGPIO15 生成请求。切片中的模式决定了请求间隔。这是一个好的开始。但是,您如何指定在每次请求时读取/写入哪些 SGPIO 影子寄存器,以及这些寄存器以何种顺序随内存传输?事实证明你做不到。事实上,如果您的源或目标是“外设”,SGPIO 请求似乎根本不会引起任何传输。相反,SGPIO 请求旨在执行与 SGPIO 同步的内存到内存传输。但是,就从 SGPIO 影子寄存器获取数据或从中获取数据而言,您只能靠自己了。我相信这就是为什么用户手册中的 SGPIO 相机示例描述了一个 SGPIO 中断执行 SGPIO 影子寄存器传输,

也许如果我们只传输一个 SGPIO 影子寄存器,使用内存到内存?那么我们就不用担心SGPIO寄存器的顺序,或者哪些需要转移了。事实证明,当您切换到内存到内存传输时,您将失去外设请求生成。因此 GPDMA 将尽可能快地传输——比 SGPIO 产生/消耗的字快得多。

我真的很想在这一切上犯错,但我的所有测试都表明没有比使用 SGPIO 中断传输样本更好的使用 GPDMA 的可行解决方案。如果您想要一些示例 GPDMA 代码来进行试验,请联系 Jared(在 Discord 或 IRC 的#hackrf 上分享)。

发表回复 0

Your email address will not be published. Required fields are marked *