Showing results for 
Search instead for 
Did you mean: 

USB CDC Receive for the STM32F103C8 using CubeMX?

Nathan Conrad
Associate II
Posted on September 06, 2017 at 02:55

How should I implement USB CDC Receive for the STM32F103C8 using CubeMX? I could not find any examples.

I have a partially working implementation of a USB CDC for this IC, but I have a few occasional issues with missed data.

First, I don't understand the


  1. Do I process/copy the buffer on line 5 or line 10?
  2. Why does it need to


    ? It shouldn't change, should it? Isn't it always stored into


    ?Or is this function passing a pointer to some other buffer internal to the USB driver, and


    is never used?
  3. What does


    do? Since it does LL stuff, why wouldn't it be called by the function that calls


  4. My understanding is that the max packet length for full-speed USB is 512 bytes. Do I need to change


    to be 512?
  5. Are there still concerns with read/write locking? (See

  6. Is there a way to cancel the previous USB transmit, or append data to its buffer?

static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)
 /**** Do I process the buffer here? ****/
 /* Can the next line be removed, unless the RX buffer needs to change? */
 USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]); /*<-- Change buffer for next RX? */
 /**** Or do I process it here? ****/
 return (USBD_OK);
 /* USER CODE END 6 */ 

I'm currently detecting if the USB CDC is connected by seeing if the previous transmission succeeded in a timely fashion. I'm using FreeRTOS. Is this proper, or is there a better way? Since I don't know how to cancel the previous transmit, I don't want to overwrite the buffer while it may still be transmitting.

static void usbTx(char *msg) {
 static TickType_t lastXmit = 0;
 /* If still transmitting, and it has been more than 200 ms, give up */
 while(CDC_Busy() && (xTaskGetTickCount()-lastXmit < (200/portTICK_PERIOD_MS ))) {
 // Last transmission failed, so lets skip this one.
 size_t len = strlen(msg);
 uint8_t result = CDC_Transmit_FS((uint8_t*)msg,len);
 if(result == USBD_OK)
 lastXmit = xTaskGetTickCount();

#freertos-stm32cube #stm32f103 #cdc #usb
Nathan Conrad
Associate II
Posted on September 10, 2017 at 05:32

(I'm replying to my own post, though I'd still appreciate answers to the questions I posed.)

I found that I had a memory-management bug in my code while transmitting. The issue was that after calling the transmit function, the TX buffer may not change until the transmission is complete. I've not done thorough testing, but my CDC implementation seems to be reliable now.

To solve my bug, I added a memcpy(...) to the TX function:

// Use 65, just to be safe. I dislike buffer overruns.
#define APP_TX_DATA_SIZE 65
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
 uint8_t result = USBD_OK;
if(hUsbDeviceFS.dev_state != USBD_STATE_CONFIGURED)
return USBD_FAIL;
USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
if (hcdc->TxState != 0){
return USBD_BUSY;
// I've read that lengths of 64 can confuse Windows, as it interprets it as a reset.
configASSERT(Len > 0 && Len < 63);
memcpy(UserTxBufferFS, Buf, Len);
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, Len);
result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
 /* USER CODE END 7 */ 
 return result;

Vitor Pereira
Associate II
Posted on November 14, 2017 at 12:39

Hi, I'm sorry that I don't have any answers for you your questions, but I have a question myself. How are we supposed to use the CDC_Receive_FS function if it's satic on main.c or any other file? Same thing to the other static functions in the 'usbd_cdc_if.c' file.


Vítor Pereira

Posted on November 29, 2017 at 13:45

Replying to myself, hoping to be usefull for someone else: CDC_Receive_FS/HS is a callback function. When data is received on USB port, this function is called. You have to implement what you wnat to do with data received in this function. Data received will be in Buf pointer.