You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32 USB CDC的CDC_Receive_FS回调调用机制及并发保护咨询

STM32 USB CDC_Receive_FS Callback: Invocation Mechanism & Concurrency Safety

Great question—let’s break this down clearly for your STM32 Virtual Com Port project.

1. CDC_Receive_FS Invocation Mechanism

The CDC_Receive_FS callback is called directly from the USB interrupt service routine (ISR) context. Here’s the behind-the-scenes flow:

  • When your USB host sends data to the STM32, the USB hardware triggers an interrupt.
  • The USB ISR (usually USBD_IRQHandler in CubeMX-generated code) processes the incoming packet and passes the data to the CDC class driver.
  • The CDC driver then invokes CDC_Receive_FS to hand off the received data to your application code.

Keep in mind: since this runs at interrupt priority, you must keep the callback’s execution time as short as possible. Avoid blocking operations, long loops, or heavy computations here—they’ll delay handling other critical interrupts.

2. Concurrency Protection When Copying to a Main Queue

Yes, you absolutely need concurrency protection when moving data from the callback’s buffer to a queue accessed by your main code. Here’s why:

  • CDC_Receive_FS runs in interrupt context, while your main code runs in thread context (or the main loop, in bare-metal setups). These two contexts can access the queue at the same time, leading to data races—like the main loop reading the queue while the interrupt writes to it, causing corrupted data or lost bytes.

Implementation Examples:

Bare-metal setup (no RTOS):

Use critical sections to temporarily disable interrupts during the data copy:

uint8_t main_queue[QUEUE_SIZE];
volatile uint32_t queue_write_ptr = 0;

int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
    // Disable global interrupts to protect queue access
    __disable_irq();
    
    // Copy data to main queue (adjust logic to match your queue design)
    for(uint32_t i=0; i<*Len; i++)
    {
        if(queue_write_ptr < QUEUE_SIZE)
        {
            main_queue[queue_write_ptr++] = Buf[i];
        }
        // Add queue overflow handling if needed
    }
    
    // Re-enable interrupts
    __enable_irq();

    // Acknowledge the transfer to receive more data
    USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
    USBD_CDC_ReceivePacket(&hUsbDeviceFS);
    return (USBD_OK);
}

RTOS setup (e.g., FreeRTOS):

Use RTOS-provided thread-safe queue functions designed for interrupt contexts. For FreeRTOS, use xQueueSendFromISR instead of the regular xQueueSend:

QueueHandle_t main_data_queue;

int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    // Send data to the queue from interrupt context
    for(uint32_t i=0; i<*Len; i++)
    {
        xQueueSendFromISR(main_data_queue, &Buf[i], &xHigherPriorityTaskWoken);
    }
    
    // Trigger a context switch if a higher-priority task was woken
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);

    USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
    USBD_CDC_ReceivePacket(&hUsbDeviceFS);
    return (USBD_OK);
}

This ensures safe, race-free access to the queue regardless of which context is interacting with it.

内容的提问来源于stack exchange,提问作者John Gaby

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:17:41