使用 openocd 和 gdb 在 STM32L4 芯片上使用半主机获取额外字节
Getting extra bytes with semihosting on STM32L4 chip with openocd and gdb
我尝试使用 openocd
版本 0.10.0+dev-00512-gfd044600
和 gdb-multiarch
的 SWO 引脚获得一些调试输出。
我用 ARMToolchain_8-2018-q4
和标记 --specs=nosys.specs --specs=nano.specs --specs=rdimon.specs
编译了固件,将函数调用 initialise_monitor_handles();
放在 main()
中。我的 .gdbinit
看起来像这样:
target extended-remote localhost:3333
monitor reset halt
monitor arm semihosting enable
monitor tpiu config internal ../bin/swo.log
load
break main
我在 _putchar()
函数中安装了对 ITM_SendChar()
的调用,如下所示:
void _putchar(char c) { ITM_SendChar(c) };
芯片为STM32L432KC,openocd命令为:
openocd -f board/stm32l4discovery.cfg
当我打印 "Test\r\n" 字符串时,我在 swo.log
文件中得到了一些额外的字符(来自 xxd -b swo.log
的输出):
000032e8: 00000001 01010100 00000001 01100101 00000001 01110011 .T.e.s
000032ee: 00000001 01110100 00000001 00001101 00000001 00001010 .t....
字符串 "Test\r\n" 在那里,但有一些额外的垃圾。我怎样才能摆脱它?
我现在的解决方法是使用以下方法剪切不可打印的字符:
tail -f ../bin/swo.log | tr -cd '-6'
ITM 通道可以处理 8、16 和 32 位数据。
ITM_SendChar()
使用 8 位(1 字节)流,因此每隔一个字节就有 1
作为后续数据部分的长度。
对于 swo.log
解码,可以使用来自 this post.
的 perl 脚本
澄清一下,"semihosting" 和 "SWO" 是完全不同的概念。您描述的内容没有使用半主机,因此您可以跳过 --specs=rdimon.specs
、initialise_monitor_handles();
和 monitor arm semihosting enable
,因为它们与您的问题无关。
Semihosting 是一种让宿主系统执行某些系统调用的方法,方法是让目标在内存中填充一些数据结构,然后执行断点。这会触发调试主机 (OpenOCD),后者将从目标内存中读取参数,模拟系统调用,将结果写回内存,最后恢复目标。这可以用作 stdout
通道,但也可以用于更多(stdin
、完整的文件系统仿真等)。缺点是目标在系统调用期间停止,因此该方法非常具有侵入性。
另一方面,SWO 是一个轻量级跟踪通道,除其他外,它可以通过 ITM 块的 32 个通道中的任何一个输出任意数据。这可以用作 non-intrusive stdout
频道。其他类型的数据也可以通过 SWO 输出汇集;时间戳、PC-sampling、变量访问的 DWT 跟踪、性能计数器等等。这种多路复用需要围绕每种数据类型建立框架,这就是您在 SWO log-file 中看到的额外字节。数据流可以通过 Swodec.
等实用程序进行解码
我尝试使用 openocd
版本 0.10.0+dev-00512-gfd044600
和 gdb-multiarch
的 SWO 引脚获得一些调试输出。
我用 ARMToolchain_8-2018-q4
和标记 --specs=nosys.specs --specs=nano.specs --specs=rdimon.specs
编译了固件,将函数调用 initialise_monitor_handles();
放在 main()
中。我的 .gdbinit
看起来像这样:
target extended-remote localhost:3333
monitor reset halt
monitor arm semihosting enable
monitor tpiu config internal ../bin/swo.log
load
break main
我在 _putchar()
函数中安装了对 ITM_SendChar()
的调用,如下所示:
void _putchar(char c) { ITM_SendChar(c) };
芯片为STM32L432KC,openocd命令为:
openocd -f board/stm32l4discovery.cfg
当我打印 "Test\r\n" 字符串时,我在 swo.log
文件中得到了一些额外的字符(来自 xxd -b swo.log
的输出):
000032e8: 00000001 01010100 00000001 01100101 00000001 01110011 .T.e.s
000032ee: 00000001 01110100 00000001 00001101 00000001 00001010 .t....
字符串 "Test\r\n" 在那里,但有一些额外的垃圾。我怎样才能摆脱它?
我现在的解决方法是使用以下方法剪切不可打印的字符:
tail -f ../bin/swo.log | tr -cd '-6'
ITM 通道可以处理 8、16 和 32 位数据。
ITM_SendChar()
使用 8 位(1 字节)流,因此每隔一个字节就有 1
作为后续数据部分的长度。
对于 swo.log
解码,可以使用来自 this post.
澄清一下,"semihosting" 和 "SWO" 是完全不同的概念。您描述的内容没有使用半主机,因此您可以跳过 --specs=rdimon.specs
、initialise_monitor_handles();
和 monitor arm semihosting enable
,因为它们与您的问题无关。
Semihosting 是一种让宿主系统执行某些系统调用的方法,方法是让目标在内存中填充一些数据结构,然后执行断点。这会触发调试主机 (OpenOCD),后者将从目标内存中读取参数,模拟系统调用,将结果写回内存,最后恢复目标。这可以用作 stdout
通道,但也可以用于更多(stdin
、完整的文件系统仿真等)。缺点是目标在系统调用期间停止,因此该方法非常具有侵入性。
另一方面,SWO 是一个轻量级跟踪通道,除其他外,它可以通过 ITM 块的 32 个通道中的任何一个输出任意数据。这可以用作 non-intrusive stdout
频道。其他类型的数据也可以通过 SWO 输出汇集;时间戳、PC-sampling、变量访问的 DWT 跟踪、性能计数器等等。这种多路复用需要围绕每种数据类型建立框架,这就是您在 SWO log-file 中看到的额外字节。数据流可以通过 Swodec.