STM32的ITM跟蹤調試功能介紹及實現(一)KEIL篇

原文鏈接:https://www.jianshu.com/p/0255097f594e

ITM,(英文:Instrumentation Trace Macrocell,指令跟蹤宏單元),是一種針對MCU進行跟蹤調試的新方法,與打斷點(Breakpoint)不同,ITM方法不需要暫停程序運行,可以在程序全速運行的過程中實時輸出變量的數值以便觀察,即Trace功能。對於有一定產品開發經驗的工程師而言,會馬上意識到ITM的獨到用處:調試跟“通訊”有關的代碼將非常有用,後文將介紹一個調試USB設備應用代碼的實例。文章分爲下面幾個部分:

1、ITM的硬件環境

2、ITM的軟件環境與代碼實現方式

3、ITM在KEIL MDK上的實現

4、ITM在IAR EWARM上的實現

5、ITM在ST-LINK V2客戶端上的實現

6、ITM調試與 printf 輸出

7、ITM應用實例:USB設備(模擬一個鼠標)代碼調試

其中1、2、3在本文中介紹,4、5、6、7分別在後續文章中介紹。

 

1、ITM的硬件環境

ITM可以理解爲一個可以提供調試數據結果的MCU內部的東東,他首先是一個硬件存在,在Cortex-M3,M4,M7上都支持(很遺憾,性價比很高的M0,M0+是不支持的),在代碼調試過程中,他與ST-LINK(或其他debugger設備)結合,可以實時查看MCU中變量的數值(其實ITM功能很強大,能顯示時間戳、記錄中斷的進出等,本文不詳述了),既然是實時的,就免不了有額外的硬件開銷,使用ST-LINK打斷點調試時,“信號”通路上只需要兩根線:SWDIO和SWCLK,一個是雙向的數據,一個是時鐘信號。ITM則不同,除了這兩根線,還需要額外的一個叫做SWO的信號線來傳輸Trace數據。也就是說,目標板MCU上會有一個pin跟ST-LINK的某一個pin連接,以ST官方的開發板NUCLEO-F411RE爲例,其電路原理圖如下,其中PB3用作了調試輸出管腳SWO:

 

圖一

再來看板載ST-LINK的電路部分:

 

圖二

可見,MCU的PB3最終是跟ST-LINK上的PA10管腳相連接的(也就是說,市面上買到的ST-LINK,如果沒有提供SWO管腳,是無法做ITM跟蹤調試的,這個本人沒有實測過,哪位網友如果知道是否能用ITM,請留言告知,謝謝),這樣就具備了ITM調試的硬件基礎。

 

2、ITM的軟件環境與代碼實現方式

有了正確的硬件連接作爲調試基礎,下面還要做兩件事情:添加代碼利用ITM輸出我們想看的變量,同時配置主機上的IDE(KEIL,IAR,ST-LINK)來“接收”這個變量的數值。本文先不講printf怎樣通過“重定向”來實現,而是先實現一個最簡單的單個字符的輸出與接收,目的是驗證整個調試的硬件環境和軟件環境是否配置正確。

以 NUCLEO-F411RE 板子爲例,使用STM32CUBEMX生成一個最簡單的應用,能閃燈即可(小燈LD2的管腳是PA5),先讓板子能正常跑起來。然後在main()中只需增加一個HAL函數調用:

          ITM_SendChar('A');

這句話的意思是,通過ITM機制向調試器送出一個字符‘A’。

 

3、ITM在KEIL MDK上的實現

下面來配置KEIL工程選項來正確接收這個字符‘A’。所有配置都在KEIL工程Options -- Debug 選項卡中操作:

 

圖三

點擊上圖中的 Settings ,在彈出的窗口中選擇 Trace 選項卡:

 

圖四

這裏的配置非常重要,首先要將 Trace Enable 打勾,否則上圖中大部分選項都是灰色的;然後要正確設置 Core Clock 的數值,這個就是你的目標板上MCU的實際運行頻率,單位是MHz。這個頻率數值必須輸入正確,否則後面就看不到ITM的輸出了。最後檢查一下 ITM Stimulus Ports 中的“端口”0是否是打勾的。默認情況下,貌似所有Port都是打勾的,這也沒問題的。至於 Privilege ,是否勾選不重要,不影響結果。這裏所謂的Ports,是說ITM中有32個“端口”來輸出變量數值,我們只使用了0#端口,所以把0#端口打上勾就行了。至於Privilege,相當於把8個端口編成一組,由Privilege來控制這一組端口是否使能,在MCU的代碼中需要檢查Privilege是否正確配置了(HAL函數中已經爲我們配置好了),KEIL中不要管他,打不打勾都可以。

然後就是編譯、下載、調試了。爲了看到ITM的輸出,還需要在KEIL中打開相應的觀察窗口:

 

圖五

啓動調試、並全速運行,在 Debug (printf)Viewer 窗口中將顯示我們之前寫的  ITM_SendChar('A'); 語句輸出的字符A。

 

圖六

也許有細心的寶寶問了:上面的代碼中沒有指定ITM的端口0呀,爲什麼是在端口0輸出的字符A呢?

ITM_SendChar()函數在 core_cm4.h 中定義:

__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch)

{

  if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) &&      /* ITM enabled */

      ((ITM->TER & 1UL) != 0UL)  )    /* ITM Port #0 enabled */

  {

    while (ITM->PORT[0U].u32 == 0UL)

    {

      __NOP();

    }

    ITM->PORT[0U].u8 = (uint8_t)ch;

  }

  return (ch);

}

嗯,HAL中明確了只使用PORT[0]。

 

小結:

ITM相對於傳統的斷點調試有許多增強的性能,但需要調試器支持SWO。

爲了正確使用ITM功能,需要正確配置IDE軟件環境。

ITM的關鍵代碼是HAL函數 ITM_SendChar()。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章