调试
调试应用程序有以下两种方式。
使用log机制跟踪代码的执行和数据。
使用ARM Keil MDK或J-Link Commander和SWD进行调试,增加/删除断点以及访问/追踪memory等。
Log机制
Debug Analyzer是用来通过打印log的方式来追踪应用程序的执行情况,以及抓取BT的数据并进一步通过第三方BT分析工具来分析。详情请参考 《Debug Analyzer User Guide》 。
P0_3默认作为Log UART的输出引脚(也可以将Log功能重新配置到其它引脚),经UART-to-USB连接到PC,在PC端COM口接收Log数据。
Debug Analyzer
使用步骤如下。
打开
DebugAnalyzer.exe
,点击 即可。

Debug Analyzer主页面
Settings 界面中,Serial Port 选择LOG对应的COM口。
- App Trace File 选择对应的
App.trace
。注:App.trace
在APP程序编译后和App.bin
生成在同一个目录位置。

Debug Analyzer设置页面
Debug Analyzer提供了一些高级功能。
Save Raw File:(建议勾选)保存Log到
xxx.bin
文件,此文件可提供给Realtek做进一步分析。Log Filter:过滤显示,弹出新窗口,只显示满足过滤条件的Log。
Keyword Search:在Log打印窗口高亮显示关键字。
Clear Trace:清空显示框中的Log。
备注
Debug Analyzer会自动保存Log文件,并按照端口号和生成时间命名,如 COM5_2015-06-12_18- 05-00.log
,保存位置在DebugAnalyzer安装路径 DebugAnalyzer\DataFile
中。
Log打印基本接口
硬件有特定的GDMA通道来打印Log,log接口声明如下。
DBG_BUFFER(T_LOG_TYPE type, T_LOG_SUBTYPE sub_type,..T_MODULE_ID module,uint8_t level, char* fmt, uint8_t param_num,...).
参数 type 固定是 TYPE_BEE4, sub_type 固定是 SUBTYPE_FORMAT。只要关心参数 module 和 level。T_MODULE_ID类型中有预定义好几种module,这些module用于将log分类别。Debug Analyzer能够识别这些module,在每条打印的log前自动加到module名称。
还有一个概念是日志级别,表示log要打印的级别,定义了以下4种类别。
日志级别 |
使用场景 |
---|---|
LEVEL_ERROR |
致命错误,程序无法继续运行(Log标识:!!!) |
LEVEL_WARN |
异常情况发生,程序可以继续运行(Log标识:!!*) |
LEVEL_INFO |
重要信息(Log标识:!**) |
LEVEL_TRACE |
详细调试信息(Log标识:无) |
DBG_BUFFER()接口灵活、功能丰富,但不方便使用。为此,RTL87x2G SDK在trace.h中提供了一些易读性更强的APIs来包装此接口。
Log打印封装接口
APIs通用语法如下。
{MODULE}_PRINT_{LEVEL}_{PARAMNUM}(...)
参数释义:
MODULE: trace.h中定义——APP/GAP/USB/FLASH…
LEVEL: 四种level——ERROR/WARN/INFO/TRACE
PARAMNUM: 0到8——代表log打印参数的个数
例如,想要打印一条含2个参数的log。
APP_PRINT_WARN2("Test app: ID = %d, data = 0x%x", id, data);
Debug Analyzer显示如下这条Log。
0049410-13#17:06:45.994 087 02145 [APP] !!*Test app: ID = 3, data = 0xF0
备注
不要超过8个参数(如果使用DBG_BUFFER()接口,最多允许20个参数)。
尽量把所有参数放到一条打印语句中。
辅助打印接口
DBG_BUFFER()接口只能打印诸如(d,i,u,o,x)的整型、字符(c)和指针类型(p),当要打印string,binary array或者BT地址时,需用到以下辅助打印接口。
- TRACE_STRING(char* data)直接打印字符串,转换符%s。
- TRACE_BINARY(uint16_t length, uint8_t* data)以16进制格式打印二进制数据,转换符%b。
- TRACE_BDADDR(char* bd_addr)以BT地址格式打印二进制字符串,转换字符%s。例如:
Hex Array: 0xaa 0xbb 0xcc 0xdd 0xee 0xff –> Literal String: FF::EE::DD::CC::BB::AA
备注
TRACE_STRING:字符串的长度最大为240字节。
TRACE_BINARY:二进制数据最大为240字节。
TRACE_BDADDR:单条Log最多可打印4个BT地址。
Log打印示例
下面的例子展示了log APIs的一般用法,以及在Debug Analyzer上对应的输出。
uint32_t n = 77777;
uint8_t m = 0x5A;
uint8_t bd1[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
uint8_t bd2[6] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
char* c1[10] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
char* c2[8] = {'a', 'b', 'C', 'd', 'E', 'F', 'g', 'H'};
char* s1 = "Hello world!";
char* s2 = "Log Test";
ADC_PRINT_TRACE1("ADC value is %d", n);
UART_PRINT_INFO3("Serial data: 0x%x, c1[%b], s1[%s]",..m, TRACE_BINARY(10, c1), TRACE_STRING(s1));
GAP_PRINT_WARN6("n[%d], m[%c] bd1[%s], bd2[%s], c2[%b], s2[%s]", n, m,..TRACE_BDADDR(bd1), TRACE_BDADDR(bd2),TRACE_BINARY(8, c2), TRACE_STRING(s2));
APP_PRINT_ERROR0("APP ERROR OCCURRED...");
Debug Analyzer上对应的输出结果。
00252 10-25#17:12:02.021 132 10241 [ADC] ADC value is 77777
00253 10-25#17:12:02.021 133 10241 [UART] !**Serial data:..0x5a, c1[31-32-33-34-35-36-37-38-39-30], s1[Hello world!]
00254 10-25#17:12:02.022 134 10241 [GAP] !!*n[77777], m[Z] bd1[55::44::33::22::11::00],bd2[FF::EE::DD::CC::BB::AA],c2[61-62-43-64-45-46-67-48], s2[Log Test]
00255 10-25#17:12:02.022 135 10241 [APP] !!!APP ERROR OCCURRED...
Log控制接口
有时候需要控制某些log的打开和关闭。一种方式是通过设定MPTool中的Config File,将Config File烧录到RTL87x2G。如果需要频繁改变log打印level,这种方式就不够灵活了,因为每次重烧Config File也不方便,所以SDK中提供了3个APIs来控制特定module的特定level,分别为:
log_module_trace_init()
log_module_trace_set()
log_module_bitmap_trace_set_update()
这里通过一些场景来帮助用户理解如何在应用程序中使用log控制的APIs。假设log打印功能已经打开,并且Config File中将所有log trace mask置成1,意味着所有module的所有level的log都会打印出来。
- 场景1
关闭APP module的所有trace和info级别的log
int main(void) { log_module_trace_set_update (MODULE_APP, LEVEL_INFO, false); log_module_trace_set_update(MODULE_APP, LEVEL_TRACE, false); ... }
- 场景2
只打开PROFILE module的log
int main(void) { uint64_t mask[LEVEL_NUM]; memset(mask, 0, sizeof(mask)); log_module_trace_init(mask); log_module_trace_set_update(MODULE_PROFILE, LEVEL_ERROR, true); log_module_trace_set_update(MODULE_PROFILE, LEVEL_WARN, true); log_module_trace_set_update(MODULE_PROFILE, LEVEL_INFO, true); log_module_trace_set_update(MODULE_PROFILE, LEVEL_TRACE, true); ... }
- 场景3
关闭PROFILE/PROTOCOL/GAP/APP module的trace级别log
int main(void) { log_module_bitmap_trace_set(MODULE_BIT_PROFILE | MODULE_BIT_PROTOCOL | MODULE_BIT_GAP | MODULE_BIT_APP, LEVEL_TRACE, false); ... }
- 场景4
关闭除了APP module以外的所有trace和info级别的log,包括关闭BT Snoop log
int main(void) { for (uint8_t i = 0; i < MODULE_NUM; i++) { log_module_trace_set_update((T_MODULE_ID)i, LEVEL_TRACE, false); log_module_trace_set_update((T_MODULE_ID)i, LEVEL_INFO, false); } log_module_trace_set_update(MODULE_APP, LEVEL_INFO, true); log_module_trace_set_update(MODULE_APP, LEVEL_TRACE, true); log_module_trace_set_update(MODULE_SNOOP, LEVEL_ERROR, false); ... }
DBG_DIRECT
通过调用基于DBG_BUFFER接口的函数打印log对系统性能的影响比较小,但是打印实时性不高,因为通过这些APIs打印的log会被缓存到buffer中,在系统空闲的时候发送给Log UART。
DBG_DIRECT用来打印实时log。这个API打印log对系统的影响比较大,因为会直接发送数据给Log UART,在Log打印完之前系统不能继续执行,所以 强烈建议只在以下一些特定的情况下使用该API。
在系统重启前
实时性要求高的场景
打印Log的示例代码
DBG_DIRECT("ROM version: %s %s", __DATE__, __TIME__);
Debug Analyzer上对应的输出结果
00002 12-22#19:19:32.573 004 00000 ROM version: Dec 22 2017 14:54:04
SWD调试
如 RTL87x2G调试接口 所示,RTL87x2G实现了3个基本的调试接口:run control,breakpoint和memory access。

RTL87x2G调试接口
备注
RTL87x2G支持SWD,不支持JTAG。
ARM Keil MDK SWD调试
首先正确安装和配置ARM Keil MDK和SWD debugger。RTL87x2G支持的主要调试特性如UI上展示。
Running control按钮:Running/Reset/Step
Breakpoints按钮:Add/Delete/Conditional
调试功能窗口
Core registers window:监视/修改MCU寄存器值
Disassembly window:显示程序执行的汇编代码,或者与源代码混合显示
Source code window:查看C代码,支持断点以及变量的实时显示
Variable watch window:查看加入监视的变量值
Memory window:显示/修改待查的内存,支持直接的地址输入和可变的地址输入
Call stack and local variable window:显示当前的调用栈,以及local变量(即stack上的变量)
备注
有时候可能会遇到image无法成功下载到flash上,或者即使与J-link成功连接,但依旧找不到SWD,这时可做如下检查:
更改debug clock到一个较小的值(例如从2MHz降到1MHz),或者换用更短的SWD调试线。
IC可能已经进入了DLPS模式,reset IC,这样系统会保持处于active状态5秒钟。
应用程序中是否关闭了SWD feature。
J-Link Commander SWD调试
在使用J-Link Commander之前,先添加Device信息,配置Flash算法。这样可以通过J-Link Commander直接烧录bin、data到Flash。
在J-Link安装目录(
JLink.exe
所在目录)创建文件夹:Devices\Realtek\RTL87x2G
。从SDK中(
sdk\tool\flash
目录下)找到RTL87x2G_FLASH.FLM
、RTL876x_LOG_TRACE.FLM
文件,拷贝到Devices\Realtek\RTL87x2G
。打开J-Link安装目录下的
JLinkDevices.xml
文件,添加Device下载算法信息。
<Device>
<ChipInfo Vendor="Realtek" Name="RTL87x2G" Core="JLINK_CORE_CORTEX_M33" WorkRAMAddr="0x00130000" WorkRAMSize="0x8000"/>
<FlashBankInfo Name="QSPI Flash" BaseAddr="0x04000000" MaxSize="0x01000000" Loader="Devices/Realtek/RTL87X2G/RTL87x2G_FLASH.FLM" LoaderType="FLASH_ALGO_TYPE_CMSIS" AlwaysPresent="1" />
<FlashBankInfo Name="QSPI Flash" BaseAddr="0x08000000" MaxSize="0x10400000" Loader="Devices/Realtek/RTL87X2G/RTL876x_LOG_TRACE.FLM" LoaderType="FLASH_ALGO_TYPE_CMSIS" AlwaysPresent="1" />
</Device>
打开J-Link Commander命令窗口,依次输入 connect、RTL87X2G 和 s,看到如下命令 Cortex-M33 identified. 即说明连接成功。

J-Link Commander SWD调试1

J-Link Commander SWD调试2
成功连接上SWD之后,进而可以通过J-link Commander中支持的命令调试,例如常用的命令:
指令 |
说明 |
---|---|
h |
halt cpu |
r |
reset cpu |
g |
go |
s |
单步运行 |
setbp |
设置断点 |
mem32 |
读取指定地址的数据 |
w4 |
向指定地址写入数据 |
erase |
擦除Flash |
loadbin |
烧录bin文件到Flash |
savebin |
将Flash上的数据保存成bin文件 |
? |
直接输入“?”可以获取全部支持的命令 |

J-Link Commander SWD调试3