/** ****************************************************************************** * @file retarget.c * @brief Printf 重定向实现(支持 Ozone SWO/ITM 调试) * @note 提供多种 printf 输出方式 ****************************************************************************** */ #include "stm32f4xx.h" #include /* 配置选择:根据需求选择一种方式 */ #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