#include "retarget.h" #include #include #include "cmsis_os.h" #include "usbd_cdc_if.h" /* * 说明: * 1. 这里默认使用 FreeRTOS 的 CMSIS-RTOS2 接口 * 2. printf 最终会走到 _write() * 3. _write() 内部调用 CDC_Transmit_FS() 发送到 USB 虚拟串口 * 4. 为避免多个任务同时 printf 打花,这里提供互斥锁 */ static osMutexId_t s_retarget_mutex = NULL; static uint8_t s_inited = 0U; /* 互斥锁属性 */ static const osMutexAttr_t s_retarget_mutex_attr = { .name = "retargetMutex" }; void Retarget_Init(void) { if (s_inited != 0U) { return; } /* 只有在内核启动后创建互斥量才有意义 */ if (osKernelGetState() == osKernelRunning) { s_retarget_mutex = osMutexNew(&s_retarget_mutex_attr); } s_inited = 1U; } void Retarget_Lock(void) { if ((s_retarget_mutex != NULL) && (osKernelGetState() == osKernelRunning)) { (void)osMutexAcquire(s_retarget_mutex, osWaitForever); } } void Retarget_Unlock(void) { if ((s_retarget_mutex != NULL) && (osKernelGetState() == osKernelRunning)) { (void)osMutexRelease(s_retarget_mutex); } } /* * GNU 工具链 printf 重定向 * 注意: * - 不要在中断里调用 printf * - USB CDC 忙时最多等待 20ms * - 等待期间 osDelay(1) 让出 CPU */ int _write(int file, char *ptr, int len) { uint32_t start_tick; uint8_t result; (void)file; if ((ptr == NULL) || (len <= 0)) { return 0; } start_tick = HAL_GetTick(); while (1) { result = CDC_Transmit_FS((uint8_t *)ptr, (uint16_t)len); if (result == USBD_OK) { return len; } /* USB 还没准备好或者正忙,最多等 20ms */ if ((HAL_GetTick() - start_tick) > 20U) { return 0; } /* 在 FreeRTOS 下主动让出 CPU */ if (osKernelGetState() == osKernelRunning) { osDelay(1); } } }