0%

配置树莓派成为一个 JTAG adapter

OpenOCD 支持通过树莓派的 GPIO 作为一个 JTAG 调试器。

配置树莓派成为一个 JTAG adapter

http://blog.sina.com.cn/s/blog_7cedb56d0102v141.html

在树莓派上编译 openocd:

  1. 下载 openocd 源码

    基于提交: 1756f393e45c2a23dd29ff8bc85d188b547624f9

    1
    $ git clone git://repo.or.cz/openocd.git
  2. 按照 README 安装依赖库

    1
    $ sudo apt-get install libtool pkg-config autoconf automake texinfo
  3. 编译

    1
    2
    3
    4
    5
    6
    $ cd openocd
    $ git checkout 1756f393e45c2a23dd29ff8bc85d188b547624f9
    $ ./bootstrap
    $ ./configure --enable-bcm2835gpio
    $ make
    $ sudo make install
  4. 测试

    按 BCM 编码,SWCLK 是 11 脚(排针23),SWDIO 是 25 脚(排针22),连接到 STM32F410 的 SWD 脚上

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    $ cd tcl
    $ sudo openocd -f interface/raspberrypi2-native.cfg -c "transport select swd" -f target/stm32f4x.cfg -c init -c "dump_image ram.bin 0x8000000 0x10000"
    Open On-Chip Debugger 0.10.0+dev-00364-g1756f393 (2018-03-28-14:26)
    Licensed under GNU GPL v2
    For bug reports, read
    http://openocd.org/doc/doxygen/bugs.html
    BCM2835 GPIO config: tck = 11, tms = 25, tdi = 10, tdo = 9
    BCM2835 GPIO nums: swclk = 11, swdio = 25
    swd
    adapter speed: 20000 kHz
    adapter_nsrst_delay: 100
    none separate
    cortex_m reset_config sysresetreq
    Info : BCM2835 GPIO JTAG/SWD bitbang driver
    Info : JTAG and SWD modes enabled
    Info : clock speed 4061 kHz
    Info : SWD DPIDR 0x2ba01477
    Info : stm32f4x.cpu: hardware has 6 breakpoints, 4 watchpoints
    Info : Listening on port 3333 for gdb connections
    dumped 65536 bytes in 0.123247s (519.282 KiB/s)
    Info : Listening on port 6666 for tcl connections
    Info : Listening on port 4444 for telnet connections

    速度达到可怕的 519 KiB/s,J-Link 是 103KiB/s,是 J-Link 的 5 倍多!!!

    image-20201208213734757

    为什么会比 J-Link 要快?

    JTAG 通信速度由 GPIO 和 CPU 速度共同决定,J-Link v9 使用的是 STM32F205,GPIO 速度 60MHz,树莓派3B 的 BCM2837 的 GPIO 速度应该也是这个量级,并且从 log 可以看出,事实上树莓派的 JTAG clock speed 最大是 4MHz,而 J-Link 是 10MHz,这说明了影响 JTAG 速度的主要是 CPU 速度。STM32F205 最大 150 DMIPS,而树莓派是 11040 DMIPS,完全不是一个量级的,这就导致了树莓派虽然 JTAG 频率低,但是超快的协议处理速度还是让其通信速度碾压了 J-Link

    修改 JTAG 引脚

    在 raspberrypi2-native.cfg 内用 bcm2835gpio_swd_nums 来设置 SWD 使用的 GPIO,注意是 BCM 编码

    bit-bang

    什么是SPI的bitbang / bit bang / bit-bang / bitbanging

    在了解了基本的SPI之后,在Linux内核源码里面,发现关于SPI来说,有个叫做bitbang的东西,所以有点迷惑,想搞清楚bitbang是啥意思。

    找了点资料,大概看明白了:

    首先,对于多数情况来说,我们所用的SPI,都是有对应的SPI的控制器的,其负责和外部SPI设备进行通信,负责两者通信时候的信号之间的同步,保证信号的timing都符合SPI协议,保证可以正常进行SPI通信。

    但是有些时候,没有此对应的硬件上的SPI控制器,而还想要和SPI设备通信,那么就只能用GPIO端口去模拟对应的SPI接口的对应的pin:片选CS,数据输入Data In,数据输出Data Out,始终Clock,去模拟SPI协议,和对应spi设备进行通信。所以,此时你对每个端口的操作,作为编程者,你自己要去负责信号的同步,保证timing符合协议规定,才能正常进行SPI通信。

    这样的SPI的bit-bang,优点是不需要SPI的控制器了,但是缺点很明显,除了要用户自己负责同步,timing等事情之外,相对来说,即使本身SPI设备支持以很高的频率运行,可以实现很好的性能,但是以bit-bang的方式去使用的话,实际性能往往很差。

    最后,可以用一句话来解释,什么是SPI的bitbang/bit-bang:

    Use software to control serial communication at general-purpose I/O pins

    通过GPIO引脚,用软件来模拟串行通信(SPI/I2C 。。。)。

树莓派作 JTAG 的 OpenOCD 权限问题

pi 用户提示open: Permission denied

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ openocd -s rtl8710_openocd/ -f rtl8710_openocd/interface/raspberrypi2-native.cfg -f rtl8710_openocd/rtl8710/rtl8710.cfg
Open On-Chip Debugger 0.10.0+dev-00364-g1756f393 (2018-03-30-05:45)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
BCM2835 GPIO config: tck = 11, tms = 25, tdi = 10, tdo = 9
BCM2835 GPIO nums: swclk = 11, swdio = 25
swd
Warn : Transport "swd" was already selected
adapter speed: 10000 kHz
adapter_nsrst_delay: 100
none separate
cortex_m reset_config vectreset
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : BCM2835 GPIO JTAG/SWD bitbang driver
Info : JTAG and SWD modes enabled
open: Permission denied

打开 -d 查看 debug log:

1
2
3
Info : 261 78 bcm2835gpio.c:438 bcm2835gpio_init(): JTAG and SWD modes enabled
open: Permission denied
Debug: 262 79 command.c:642 run_command(): Command failed with error code -100

到源代码内查看,原来是写 /dev/mem 的权限问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (bcm2835gpio_jtag_mode_possible()) {
if (bcm2835gpio_swd_mode_possible())
LOG_INFO("JTAG and SWD modes enabled");
else
LOG_INFO("JTAG only mode enabled (specify swclk and swdio gpio to add SWD mode)");
} else if (bcm2835gpio_swd_mode_possible()) {
LOG_INFO("SWD only mode enabled (specify tck, tms, tdi and tdo gpios to add JTAG mode)");
} else {
LOG_ERROR("Require tck, tms, tdi and tdo gpios for JTAG mode and/or swclk and swdio gpio for SWD mode");
return ERROR_JTAG_INIT_FAILED;
}

dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
if (dev_mem_fd < 0) {
perror("open");
return ERROR_JTAG_INIT_FAILED;
}

/dev/mem 是 CPU 的内存

1
2
ls -l /dev/mem
crw-r----- 1 root kmem 1, 1 Apr 3 03:39 /dev/mem

把 /dev/mem 换成 /dev/gpiomem,更安全,并且不需要 root 权限

树莓派上多个 openocd(不同 io)并行运行时的问题

比如,使用 2,3 脚作为一组 SWD,使用 4,5 脚作为另一组 SWD,那么两组 SWD 同时跑起来时就会互相影响,导致同时只有一组能用,但是,2,3 脚的 SWD 和 10,11 脚的 SWD 就不会冲突。

原因是:SWDIO 是双向通信口,所以 openocd 要在通信时频繁地切换其方向(输入/输出),配置方向的寄存器是 10 个 io 共用一个寄存器(参考 BCM2835-ARM-Peripherals.pdf),总共有 0 -9 或者 10- 19 或者 20-27 三个寄存器。openocd 内配置某个 io 方向是对寄存器内位或/与来实现的,也就是(读出 - 与/或 - 写回),所以在不同进程内会有临界区风险发生。如:

1
#define INP_GPIO(g) do { *(pio_base+((g)/10)) &= ~(7<<(((g)%10)*3)); } while (0)

即使是不属于同一个 io 方向配置寄存器,如 2,3 和 11,12,在频繁的启动 - 退出 openocd 时也会互相影响,原因是 bcm2835gpio.c 内有个 bug:bcm2835gpio.c 内使用 -1 来表示无效/不用的 io,但是它只对 trst 和 srst 作有效性判断,若使用 SWD 模式,那么 tdo, tdi 和 tck 也是不用的,此时代码内仍会去操作这些 io,就可能会写到其他 io,因为 -1%10 是 -1, -1 << m 是不确定的。

ondemand 模式下 CPU 频率变化导致的 SWCLK 变化问题

树莓派默认是 ondemand 模式,此模式下 CPU 会动态调整频率。由于 openocd 内是 bitbang 模拟协议,靠 while 循环来延时,所以 SWCLK 频率随之变化,导致了 SWD 连接不稳定。

修改为 powersave 模式,锁定 CPU 使用最低的 600MHz 频率就好了。

坚持原创技术分享,您的支持将鼓励我继续创作!