1、引言
STM32N6 是 ST 第一款帶 NPU 的基于 Cortex-M55 內(nèi)核的 MCU,在 STM32N6 開(kāi)發(fā)過(guò)程中,有些開(kāi)發(fā)者希望通過(guò)打印信息的方式進(jìn)行軟件調(diào)試。為了盡量減少 IO 占用,客戶在使用 STM32CubeIDE 時(shí)希望使用 SWV/ITM 進(jìn)行 printf 內(nèi)容輸出??蛻魢L試了STM32CubeIDE 用戶手冊(cè)中 printf 重定向的方法,但沒(méi)有成功。本文將介紹失敗原因及如何實(shí)現(xiàn) printf IO 重定向到 SWV/ITM。
2、Printf IO 重定向 SWV/ITM
Printf 重定向一般有三種,使用 UART/USART,使用 SWV/ITM 或者使用 SEGGER 的RTT 功能。
我們這里討論的是 STM32CubeIDE 下使用 SWV/ITM,首先必須將 syscalls.c 包含在工程里。printf()會(huì)調(diào)用_write()函數(shù),該函數(shù)在 syscalls.c 中有實(shí)現(xiàn)。__io_putchar()會(huì)由_write()調(diào)用,至于如何修改依賴于硬件與庫(kù),手冊(cè) UM2609 中有詳細(xì)描述,這里就不再贅述。對(duì)于 STM32N6,使用 STM32CubeIDE,具體實(shí)現(xiàn)請(qǐng)見(jiàn)下面的逐步描述。
2.1. __io_putchar 修改
將 printf()重定向 SWV/ITM,我們這里需要修改__io_putchar,代碼如下。
int __io_putchar(int ch)
{
ITM_SendChar(ch);
return(ch);
}
2.2. 使能 Trace Clock 和 Debug Clock
使能 Trace Clock 和 Debug Clock 需要通過(guò)設(shè)置 DBGMCU 寄存器實(shí)現(xiàn),代碼如下:
DBGMCU->CR |=0x00300000;
ITM->TER |= 0x1;
ITM->TCR |= 0x00001;
2.3. SWO GPIO 設(shè)置
以 STM32N6-DK 板為例,使用芯片型號(hào)為 STM32N657X0H3 (VFBGA264), 查詢數(shù)
據(jù)手冊(cè) DB4396,表 15. STM32N657xx pin description 中有詳細(xì)描述,PB5 管腳可以
復(fù)用為 TRACESWO(AF0_TRACE)。另外需要特別注意,GPIO B 掛在總線 AHB4,
RCC 模塊中 AHB4ENR 負(fù)責(zé) AHB4 Run 或 Sleep 模式的設(shè)置,需要對(duì)該寄存器進(jìn)行設(shè)置
以使能 GPIO B。參考代碼如下:
//SWO is used PB5 pin on STM32N6.
__HAL_RCC_GPIOB_CLK_ENABLE();
gpio_init.Mode = GPIO_MODE_AF_PP;
gpio_init.Pull = GPIO_PULLUP;
gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
gpio_init.Pin = GPIO_PIN_5;
gpio_init.Alternate = GPIO_AF0_TRACE;
HAL_GPIO_Init(GPIOB, &gpio_init);
上述 3 個(gè)步驟需要修改代碼,代碼綜合起來(lái)的示例如下(main.c):
// ################ main.c ####################
int __io_putchar(int ch)
{
ITM_SendChar(ch);
return(ch);
}
int main(void)
{
/* USER CODE BEGIN 1 */
GPIO_InitTypeDef gpio_init;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
HAL_Init();
/* USER CODE BEGIN Init */
DBGMCU->CR |=0x00300000;
ITM->TER |= 0x1;
ITM->TCR |= 0x00001;
//SWO is used PB5 pin on STM32N6.
__HAL_RCC_GPIOB_CLK_ENABLE();
gpio_init.Mode = GPIO_MODE_AF_PP;
gpio_init.Pull = GPIO_PULLUP;
gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
gpio_init.Pin = GPIO_PIN_5;
gpio_init.Alternate = GPIO_AF0_TRACE;
HAL_GPIO_Init(GPIOB, &gpio_init);
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
… …
/* Infinite loop */
while (1)
{
… …
}