99 lines
1.9 KiB
C
99 lines
1.9 KiB
C
#include "retarget.h"
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
#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);
|
|
}
|
|
}
|
|
} |