1. 硬件接口
SF32FB55X采用SWD作為調(diào)試接口。用戶可以通過配置,來切換選擇HCPU或者LCPU。
系統(tǒng)上電默認(rèn)選擇HCPU,如果想要調(diào)試LCPU,可以調(diào)用SDK的工具tools/segger/jlink_lcpu_a0.bat,將SWD切換到LCPU。
同樣,如果目前SWD連接LCPU,可以調(diào)用SDK的工具tools/segger/jlink_hcpu_a0.bat,將SWD切換到HCPU。
- Note
- 由于SWD使用PB IO,當(dāng)使用SWD進(jìn)行調(diào)試時,需確保LPSYS處于active或者light sleep狀態(tài),無論當(dāng)前SWD連接至HCPU還是LCPU
- Jlink發(fā)送reset命令不會改變SWD當(dāng)前連接的CPU
- LPSYS從Standby喚醒后, SWD會切換回默認(rèn)的HCPU
LCPU日志接口
系統(tǒng)ROM在初始化的時候,使用屬于LCPU的UART3作為console接口,波特率為1000000bps,用來打印日志或者輸入命令。建議這個接口保留給LCPU作為日志接口。
HCPU日志接口
HCPU的日志接口可以選擇UART1/2或者SWD,如果需要選擇屬于LCPU的UART3/4/5,則需要確保使用時,LCPU屬于喚醒狀態(tài)。
2. 調(diào)試方法
這里主要講一下常見的Assert或者HardFault的分析方法,以及死機(jī)解決辦法,這里調(diào)試器都是使用的Jlink。
設(shè)置斷點(diǎn)
當(dāng)Jlink連接到HCPU/LCPU的時候,通常系統(tǒng)已經(jīng)初始化完成,如果需要調(diào)試初始化,例如冷啟動或者standby睡眠喚醒, 需要將系統(tǒng)停留在盡早的地方。
建議用戶可以修改系統(tǒng)初始化程序,
- HCPU
drivers/cmsis/sf32lb55x/Templates/arm/startup_bf0_hcpu.S
- LCPU
drivers/cmsis/sf32lb55x/Templates/arm/startup_bf0_lcpu.S
在Reset_Handler中的第一條指令去掉注釋 ';', 變?yōu)?
B .
這樣CPU啟動,就會停留在第一條指令,當(dāng)Jlink連接成功后,可以改變PC寄存器 (+2), 設(shè)置所需斷點(diǎn),從而調(diào)試初始化過程。
同樣的方法也可以在其他的地方使用,使系統(tǒng)停留在某個事件發(fā)生的時刻,在所懷疑有問題的地方,如果是C文件,加入
_asm("B .");
可以使系統(tǒng)停留在這個指令,這個時候,再連接Jlink, 可以改變PC寄存器 (+2), 繼續(xù)調(diào)試。
- Note
- 不能使用while(1); 否則系統(tǒng)會優(yōu)化,將while(1)之后的語句都無效了。
Assert/HardFault 錯誤分析
當(dāng)錯誤發(fā)生的時候,如果開發(fā)板有連接SWD到Jlink工具,可以使用tools\crash_dump_analyser\script\save_ram_a0.bat保存RAM,EPIC寄存器和PSRAM的內(nèi)容到當(dāng)前路徑,有助于分析死機(jī)的原因
- Note
- 需要將jlink的路徑加入Windows環(huán)境變量PATH, 如 C:\Program Files (x86)\SEGGER\JLink_v672b,以后可以通過Jlink加載RAM回復(fù)死機(jī)現(xiàn)場。
通過日志分析
默認(rèn)SDK會在Assert時通過日志接口輸出斷點(diǎn)行,以及最后的CPU寄存器,根據(jù)內(nèi)容分析即可。注意,如果日志接口是異步輸出,可能出現(xiàn)沒有輸出完整的情況。
Assertion failed at function:app_exit, line number:704 ,(app_node->next != &running_app_list)
===================
Thread Info
===================
thread pri status sp stack size max used left tick error
-------- --- ------- ---------- ---------- ------ ---------- ---
app_watc 25 ready 0x00000100 0x00002800 26% 0x00000008 000
tshell 20 suspend 0x000000f4 0x00001000 13% 0x00000008 000
ble_app 15 suspend 0x000001b4 0x00000400 54% 0x00000007 000
mbox_th 10 suspend 0x00000110 0x00001000 51% 0x00000006 000
ds_proc 12 suspend 0x0000011c 0x00000800 24% 0x00000005 000
ds_mb 11 suspend 0x00000148 0x00000400 32% 0x0000000a 000
touch_th 10 suspend 0x000000ec 0x00000200 59% 0x00000006 000
test 15 suspend 0x0000011c 0x00000400 27% 0x0000000a 000
alarmsvc 8 suspend 0x00000074 0x00000200 22% 0x00000001 000
ulog_asy 30 ready 0x000000ec 0x00000400 36% 0x0000000b 000
tidle 31 ready 0x00000064 0x00000200 19% 0x00000008 000
timer 4 suspend 0x000000e0 0x00000400 23% 0x00000003 000
main 10 suspend 0x000000ec 0x00000800 31% 0x0000000c 000
===================
Mailbox Info
===================
mailbox entry size suspend thread
-------- ---- ---- --------------
g_bf0_si 0000 0016 0
ble_app 0000 0008 1:ble_app
===================
MessageQueue Info
===================
msgqueue entry suspend thread
-------- ---- --------------
uisrv 0000 0
mq_guiap 0000 0
data_mb_ 0000 1:ds_mb
dserv 0000 1:ds_proc
test 0000 1:test
===================
Mutex Info
===================
mutex owner hold suspend thread
-------- -------- ---- --------------
dserv (NULL) 0000 0
tmalck (NULL) 0000 0
alarmsvc (NULL) 0000 0
alm_mgr (NULL) 0000 0
ulog loc (NULL) 0000 0
i2c_bus_ (NULL) 0000 0
i2c_bus_ (NULL) 0000 0
i2c_bus_ (NULL) 0000 0
i2c_bus_ (NULL) 0000 0
spi1 (NULL) 0000 0
===================
Semaphore Info
===================
semaphore v suspend thread
-------- --- --------------
app_tran 000 0
lv_data 001 0
lv_lcd 001 0
lv_epic 001 0
drv_lcd 000 0
fb_sem 000 0
lvlargef 001 0
lvlarge 001 0
btn 001 0
shrx 000 1:tshell
g_sifli_ 000 0
tma525b 000 1:touch_th
aw_tim 000 0
cons_be 000 0
ulog 150 0
heap 001 0
===================
Memory Info
===================
total memory: 260784 used memory : 69096 maximum allocated memory: 96768
===================
MemoryHeap Info
===================
memheap pool size max used size available size
-------- ---------- ------------- --------------
lvlargef 309172 301588 309124
lvlarge 2473392 2201700 2473344
=====================
sp: 0x2006ec08
psr: 0x60000000
r00: 0x00000000
r01: 0x00000000
r02: 0x200bc8f8
r03: 0x0000002a
r12: 0x10069305
lr: 0x100642e9
pc: 0x10020bfa
=====================
fatal error on thread: app_watc?
通過Ozone查看死機(jī)現(xiàn)場
如果日志打印沒法分析出死機(jī)問題,則可以通過Ozone 這個Segger提供的調(diào)試工具分析。它在死機(jī)時比Keil更容易通過Jlink Attach到芯片(Keil的配置很容易使芯片重啟,從而破壞死機(jī)現(xiàn)場).
Ozone 在板子沒有死機(jī)的情況下,也可以通過以下方法Attach上去,并單步調(diào)試,類似Keil的功能。但是它的棧解析好像不如Keil的好。
- 新建一個工程,選擇適當(dāng)?shù)腄evice驅(qū)動(ButterFlier 是SF32LB6XX), CPU型號(ButterFlier 是CM33), 以及外設(shè)SVD文件(用于看外設(shè)寄存器內(nèi)容,僅供Sifli內(nèi)部使用,用戶可以忽略,設(shè)為空)
- 下一步選擇Jlink的連接方式,SWD接口
- 選擇燒錄程序的ELF文件,讀取符號信息
- 工程建立完畢,然后將Ozone 通過Jlink Attach到死機(jī)的板子并且Halt住板子
- 然后就可以通過菜單里面的功能,單步調(diào)試、變量查看、棧解析等操作,跟Keil類似。
3. 日志接口
通過UART口作為日志輸出
UART口的pinmux配置此處不做贅述,詳見 UART
如果使用的是RT-Thread RTOS, 則配置好UART的pinmux后,可以通過如下menuconfig的配置,選擇不同的uart device
另外,SDK 采用ULOG作為通用的日志輸出接口,詳見 日志
通過Jlink作為日志輸出
如果管腳不夠用,則可以通過Jlink的RTT功能作為console口,配置步驟如下(SDK自帶的RT-Thread RTOS已經(jīng)集成了Segger RTT功能):
- 通過menuconfig,打開Segger RTT功能(它將自動注冊一個名為segger的rt-device)
- 將RT-Thread的默認(rèn)console口指定到segger這個rt-device上
- 通過Ozone連接到板子,如果已經(jīng)指定了ELF文件Ozone將自動尋找RTT_Ctrlb,否則需要自己指定
4. 使用總線監(jiān)視器
總線監(jiān)視器可以監(jiān)視總線上面的訪問,當(dāng)條件滿足的時候,產(chǎn)生中斷回掉,這個可以在調(diào)試中檢測某塊內(nèi)存,或者外圍設(shè)備的訪問。
使能總線監(jiān)視器
可以通過如下menuconfig的配置,使能總線控制器功能
使用總線監(jiān)視器
在代碼中,可以添加如下代碼,實(shí)現(xiàn)特定的功能:
void busmon_cbk()
{
rt_kprintf("Busmon captured\n");
}
...
dbg_busmon_reg_callback(busmon_cbk);
dbg_busmon_read(0x20080000,1);
dbg_busmon_reg_callback(busmon_cbk);
dbg_busmon_write(0x20080004,3);
dbg_busmon_reg_callback(busmon_cbk);
dbg_busmon_write(0x20080008,2);