1. 程式人生 > >基於ARM Cortex-M和Eclipse的SWO單總線輸出

基於ARM Cortex-M和Eclipse的SWO單總線輸出

nds register [0 額外 ast 最重要的 代碼 情況 得到

最近在MCU on Eclipse網站上看到Erich Styger所寫的一篇有關通過SWD的跟蹤接口SWO獲取ARM Cortex-M相關信息的文章,文章結構明晰,講解透徹,本人深受啟發,特意將其翻譯過來供各位同仁參考。當然限於個人水平,有不當之處懇請指正。原文網址:https://mcuoneclipse.com/2016/10/17/tutorial-using-single-wire-output-swo-with-arm-cortex-m-and-eclipse/

作為一個標準過程,我將一些控制臺功能添加到我的嵌入式應用程序中。這樣我就有了一個命令行接口,可以檢查和修改目標系統。ARM Cortex-M的一個有趣的硬件特性是單線輸出(SWO) ,它允許通過一根線路將數據(例如字符串)發送到32個不同的激勵端口。

技術分享

ARM調試器接頭上的SWO引腳

調試跟蹤輸出?SWO

我使用普通的UART/SCI作為標準的文本和命令行與目標板的接口。然而,在許多板上,UART被應用程序使用。

有一個Semihosting(半托管),但是速度非常慢,而且取決於調試器和工具鏈/庫,加上需要消耗FLASH和RAM,所以我不建議在任何情況下使用Semihosting。

【註】Semihosting是針對ARM目標機的一種機制,它能夠根據應用程序代碼的輸入/輸出請求,與運行有調試功能的主機通訊。這種技術允許主機為通常沒有輸入和輸出功能的目標硬件提供主機資源。

也有一個USB CDC,但這需要一個USB接口,一個USB棧和一個具有USB功能的微控制器。不適用於所有情況。

還有一個Segger RTT,它很小,速度快,最好的是不需要任何特殊的引腳。但只能工作於Segger的調試探測器。

ARM SWO

但還有另一件事:ARM SWO跟蹤端口是由ARM為Cortexm-M定義的。從技術上講,SWO是一個單一的跟蹤引腳,它被用來以從CPU核心時鐘中提取一個特定的時鐘頻率發送數據包。您可以將SWO看作是一種使用特殊格式發送數據包的UART TX引腳。可以使用多達32種包類型(或激勵)。發送什麽樣的數據取決於應用程序,並且只需要很少的CPU處理或代碼。

常見SWO用法是:

  • 按字符串發送調試信息
  • 記錄中斷的進入與退出
  • 記錄函數的進入與退出
  • 周期性的PC值采樣
  • 事件提示
  • 變量或內存單元修改超時

最常見的用法之一就是第一種:使用SWO以UART樣式打印來自目標的調試消息。並且這也正是我再這篇文章中將要表達的。還有另一種編碼(曼徹斯特編碼),這裏不做介紹。

ARM CoreSight

SWO是ARM CoreSight調試功能塊的一部分,而ARM CoreSight則通常是Cortex-M3,M4,M7的一部分:

技術分享

CoreSight功能塊(來自:http://www.arm.com/files/pdf/AT_-_Advanced_Debug_of_Cortex-M_Systems.pdf)

如上圖所示,通過SWO(或SWV)ITM和DWT跟蹤消息可以發送。對於指令跟蹤需要4個額外的跟蹤引腳

SWO引腳

使用SWO的前提條件是這個引腳可以在調試頭中使用。這是我的TWR-K64F120M板的情況:

技術分享

trace swo引腳(來自:TWR-K64F120M原理圖)

如上圖所示,SWO跟蹤引腳是與JTAG TDO引腳共享的。所以這就意味著SWO不能在JTAG中使用,而只能在SWD中使用。

所以仔細檢查你板子的原理圖確定他是否支持SWO。例如FRDM-K64F(是TWR-K64F120M上一個版本),它的SWO是沒有被引到調試頭的:

技術分享

FRDM-K64F上沒有SWO

調試探針與SWO

為了能夠使用SWO,我需要一個能夠讀取SWO引腳的調試探測器。例如,Freescale/NXP OpenSDA在Freedom和Tower模塊板載調試接口硬件就不支持SWO。

然而,外部的Segger J-Link卻支持SWO引腳。下面我有一個J-Link EDU連接到TWR-K64F120M板的調試和跟蹤端口:

技術分享

j-link edu連接到跟蹤端口

通過SWO引腳發送調試信息的源碼

為了通過SWO寫調試消息到主機,需要一小段代碼。在Github上有一個可用的完整代碼的例子項目:

https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/TWR-K64F120M/TWR-K64F120M_Demo/Sources

外部工具(比如Segger RTT查看器)可以在硬件中設置SWO。我的建議是從應用程序初始化它。因為SWO跟蹤輸出時鐘是從CPU時鐘派生而來的,所以初始化函數需要這個時鐘加上SWO端口號來初始化。下面是我用來初始化SWO輸出的代碼,默認為64k波特率:

/*!

* \brief Initialize the SWO trace port for debug message printing

* \param portBits Port bit mask to be configured

* \param cpuCoreFreqHz CPU core clock frequency in Hz

*/

void SWO_Init(uint32_t portBits, uint32_t cpuCoreFreqHz) {

uint32_t SWOSpeed = 64000; /* default 64k baud rate */

uint32_t SWOPrescaler = (cpuCoreFreqHz / SWOSpeed) - 1; /* SWOSpeed in Hz, note that cpuCoreFreqHz is expected to be match the CPU core clock */

CoreDebug->DEMCR = CoreDebug_DEMCR_TRCENA_Msk; /* enable trace in core debug */

*((volatile unsigned *)(ITM_BASE + 0x400F0)) = 0x00000002; /* "Selected PIN Protocol Register": Select which protocol to use for trace output (2: SWO NRZ, 1: SWO Manchester encoding) */

*((volatile unsigned *)(ITM_BASE + 0x40010)) = SWOPrescaler; /* "Async Clock Prescaler Register". Scale the baud rate of the asynchronous output */

*((volatile unsigned *)(ITM_BASE + 0x00FB0)) = 0xC5ACCE55; /* ITM Lock Access Register, C5ACCE55 enables more write access to Control Register 0xE00 :: 0xFFC */

ITM->TCR = ITM_TCR_TraceBusID_Msk | ITM_TCR_SWOENA_Msk | ITM_TCR_SYNCENA_Msk | ITM_TCR_ITMENA_Msk; /* ITM Trace Control Register */

ITM->TPR = ITM_TPR_PRIVMASK_Msk; /* ITM Trace Privilege Register */

ITM->TER = portBits; /* ITM Trace Enable Register. Enabled tracing on stimulus ports. One bit per stimulus port. */

*((volatile unsigned *)(ITM_BASE + 0x01000)) = 0x400003FE; /* DWT_CTRL */

*((volatile unsigned *)(ITM_BASE + 0x40304)) = 0x00000100; /* Formatter and Flush Control Register */

}

在我的主應用程序中,我像這樣初始化它(對於一個有24MHz核心時鐘的系統):

#define CPU_CORE_FREQUENCY_HZ 120000000 /* CPU core frequency in Hz */

SWO_Init(0x1, CPU_CORE_FREQUENCY_HZ);

在SWO_PrintChar()函數中完成打印:

/*!

* \brief Sends a character over the SWO channel

* \param c Character to be sent

* \param portNo SWO channel number, value in the range of 0 to 31

*/

void SWO_PrintChar(char c, uint8_t portNo) {

volatile int timeout;

/* Check if Trace Control Register (ITM->TCR at 0xE0000E80) is set */

if ((ITM->TCR&ITM_TCR_ITMENA_Msk) == 0) { /* check Trace Control Register if ITM trace is enabled*/

return; /* not enabled? */

}

/* Check if the requested channel stimulus port (ITM->TER at 0xE0000E00) is enabled */

if ((ITM->TER & (1ul<<portNo))==0) { /* check Trace Enable Register if requested port is enabled */

return; /* requested port not enabled? */

}

timeout = 5000; /* arbitrary timeout value */

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

/* Wait until STIMx is ready, then send data */

timeout--;

if (timeout==0) {

return; /* not able to send */

}

}

ITM->PORT[0].u16 = 0x08 | (c<<8);

}

上面的代碼使用了一個非常簡單的超時機制:重要的一點是,如果SWO沒有啟用或者SWO端口沒有準備好,那麽應用程序就會被阻塞。

為了更方便地打印字符串,我使用以下函數:

/*!

* \brief Sends a string over SWO to the host

* \param s String to send

* \param portNumber Port number, 0-31, use 0 for normal debug strings

*/

void SWO_PrintString(const char *s, uint8_t portNumber) {

while (*s!=‘\0‘) {

SWO_PrintChar(*s++, portNumber);

}

}

要通過SWO發送一個“hello”,它就像這樣簡單:

SWO_PrintString("hello world with SWO\r\n", 0);

第一個參數是要發送的字符串,第二個是SWO跟蹤通道號。

GNU ARM Eclipse查看器

要接收主機上的SWO跟蹤輸出,GNU ARM Eclipse插件內置了Segger J-Link探測器的SWO支持。

SWO僅支持SWD(單線調試)模式,不支持JTAG模式。所以確保SWD被選為調試協議:

技術分享

SWD調試

在GNU ARM Eclipse調試配置中,啟用SWO並指定CPU頻率和SWO頻率(請參見http://gnuarmeclipse.github.io/debug/jlink/上的有關頻率的文檔)。我必須提供CPU頻率(在我的情況下為120 MHz),並且可以將SWO頻率設置為0,以便J-Link自動確定速度)。在端口掩碼中指定使用的端口(作為位掩碼),因此0x1用於使用端口0:

技術分享

SWO的設置

這樣,在目標板上運行應用程序就會在Eclipse控制臺視圖中顯示輸出:

技術分享

Eclipse控制臺視圖

Segger SWO Viewer

Segger有一個特殊的SWO Viewer(命令行和GUI版本)。

在GUI版本中,我指定使用的設備,它可以感測跟蹤時鐘:

技術分享

segger gui swo viewer

在查看器中,我可以打開/關閉端口,並查看收到的數據:

技術分享

segger j-link swo viewer

Telnet: Putty

但是,沒有需要查看SWO數據的花哨的查看器或Eclipse。Segger默認使用端口2332:

技術分享

SEGGER SWO端口

我可以配置任何telnet客戶端(例如PuTTY)在端口2332上打開會話:

技術分享

putty telnet會話設置

我在PuTTY中得到的輸出:

技術分享

SWO在PuTTY中的輸出

綜述

ARM SWO跟蹤引腳允許向主機發送跟蹤消息。一個常見的用法是向主機發送調試或其他消息。SWO只需要一個引腳,僅適用於SWD(而不是JTAG),並且在目標上需要很少的代碼和資源。不幸的是,許多電路板沒有將SWO跟蹤引腳路由到調試頭,因此如果您正在進行自己的設計,則至少應考慮將SWO路由到調試頭。

雖然SWO跟蹤輸出很大,但是限於高端Cortex-M,我沒有在Cortex-M0(+)中找到它,它只是輸出,需要一個支持它的調試探針/接口。至少與Eclipse和GNU ARM Eclipse插件結合Segger J-Link探針SWO輸出對我來說非常棒。

另一方面,Segger RTT的功能更加多樣化,也非常快。它適用於所有ARM Cortex,最重要的是不需要額外的引腳。然而,它在目標系統上需要更多的開銷和RAM資源。此外,它允許發送和接收數據。所以對於串行調試消息打印,Segger RTT對我來說聽起來更好的解決方案。

接下來就是快樂SWO中了!

相關鏈接

  • SWO on Kinetis:https://community.nxp.com/thread/318058
  • SWO與GNU ARM Eclipse插件:http : //gnuarmeclipse.github.io/debug/jlink/
  • Segger SWO Viewer:https : //www.segger.com/j-link-swo-viewer.html
  • GNU ARM Eclipse插件:http : //gnuarmeclipse.github.io/debug/
  • Eclipse RxTx插件,用於解析SWO數據:http : //forum.segger.com/index.php? page=Thread&threadID=1010
  • ARM CoreSight概述:http : //www.arm.com/files/pdf/AT_-_Advanced_Debug_of_Cortex-M_Systems.pdf
  • GitHub上的示例代碼:https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/KDS/TWR-K64F120M/TWR-K64F120M_Demo/Sources

歡迎關註:

技術分享

基於ARM Cortex-M和Eclipse的SWO單總線輸出