112 lines
2.7 KiB
C
112 lines
2.7 KiB
C
/**
|
||
******************************************************************************
|
||
* @file retarget.c
|
||
* @brief Printf 重定向实现(支持 Ozone SWO/ITM 调试)
|
||
* @note 提供多种 printf 输出方式
|
||
******************************************************************************
|
||
*/
|
||
|
||
#include "stm32f4xx.h"
|
||
#include <stdio.h>
|
||
|
||
/* 配置选择:根据需求选择一种方式 */
|
||
#define USE_ITM_SWO 1 // 使用 ITM/SWO (Ozone Terminal 查看)
|
||
#define USE_UART 0 // 使用 UART 串口
|
||
#define USE_SEMIHOSTING 0 // 使用半主机模式
|
||
|
||
/* ========== 方案1: ITM/SWO 输出(Ozone 原生支持)========== */
|
||
#if USE_ITM_SWO
|
||
|
||
/**
|
||
* @brief 初始化 ITM(必须在 main 开始时调用)
|
||
* @note 在 main() 函数的 USER CODE BEGIN 2 中调用此函数
|
||
*/
|
||
void ITM_Init(void)
|
||
{
|
||
// 1. 启用 TRCENA (Trace Enable)
|
||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||
|
||
// 2. 解锁 ITM 访问
|
||
ITM->LAR = 0xC5ACCE55;
|
||
|
||
// 3. 启用 ITM
|
||
ITM->TCR = ITM_TCR_ITMENA_Msk;
|
||
|
||
// 4. 启用 ITM 端口0(用于 printf)
|
||
ITM->TER = 0x01;
|
||
|
||
// 5. 设置 ITM 的 Trace Privilege
|
||
ITM->TPR = 0x00;
|
||
}
|
||
|
||
/**
|
||
* @brief 通过 ITM 端口0 发送字符
|
||
* @note Ozone 中需要配置:Tools -> Terminal -> Enable SWO
|
||
*/
|
||
int __io_putchar(int ch)
|
||
{
|
||
// 直接发送,不检查(因为已经初始化过了)
|
||
while (ITM->PORT[0].u32 == 0UL)
|
||
{
|
||
__NOP(); // 等待端口就绪
|
||
}
|
||
ITM->PORT[0].u8 = (uint8_t)ch;
|
||
|
||
return ch;
|
||
}
|
||
|
||
#endif // USE_ITM_SWO
|
||
|
||
|
||
/* ========== 方案2: UART 串口输出 ========== */
|
||
#if USE_UART
|
||
|
||
#include "usart.h" // 根据你的项目调整头文件
|
||
|
||
/**
|
||
* @brief 通过 UART 发送字符
|
||
* @note 需要先在 CubeMX 中配置好 UART
|
||
*/
|
||
int __io_putchar(int ch)
|
||
{
|
||
// 假设使用 UART1,根据实际情况修改
|
||
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
|
||
return ch;
|
||
}
|
||
|
||
#endif // USE_UART
|
||
|
||
|
||
/* ========== 方案3: 半主机模式(Semihosting)========== */
|
||
#if USE_SEMIHOSTING
|
||
|
||
/**
|
||
* @brief 半主机模式输出
|
||
* @note 需要在链接选项中添加 --specs=rdimon.specs
|
||
* 并在 main 函数前调用 initialise_monitor_handles();
|
||
*/
|
||
// 半主机模式使用系统默认实现,无需额外代码
|
||
// 但需要在 main() 中调用:
|
||
// extern void initialise_monitor_handles(void);
|
||
// initialise_monitor_handles();
|
||
|
||
#endif // USE_SEMIHOSTING
|
||
|
||
|
||
/* ========== getchar 实现(可选)========== */
|
||
#if USE_ITM_SWO || USE_UART
|
||
|
||
int __io_getchar(void)
|
||
{
|
||
// 简单实现:返回 EOF
|
||
return EOF;
|
||
|
||
/* 如果需要从 UART 读取,可以这样实现:
|
||
uint8_t ch;
|
||
HAL_UART_Receive(&huart1, &ch, 1, HAL_MAX_DELAY);
|
||
return ch;
|
||
*/
|
||
}
|
||
|
||
#endif
|