Send and Receive data to PC without UART (STM32 USB COM)

This tutorial will cover yet another feature of the USB in STM32 and Today we will see how can we communicate to the computer without using the UART. I will show you how can we use the STM32 USB to send and receive data from the computer, just like we did using the UART.

To do so, I will use the STM32F103C8 controller in the USB DEVICE mode, and the Communication Device class (Virtual Com Port). The setup for the same is shown below

CubeMX Setup

First of all I am selecting the USB in DEVICE only MODE, as shown above

In the USB DEVICE, select the class as Communication Device Class (Virtual Port Com) and leave everything to default

Finally the clock is set to maximum here. As you can see above, the USB clock is automatically adjusted to 48 MHz



HOW TO SEND DATA

The functions required to send or receive data are located in USB_DEVICE -> App -> usbd_cdc_if.c file.

The function CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) can be used to transmit the data to the PC via the USB. The parameters are the Buf (Buffer to send) and the Len (length of the data)

#include "main.h"
#include "usb_device.h"

#include "usbd_cdc_if.h"
#include "string.h"

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t *data = "Hello World from USB CDC\n";
/* USER CODE END 0 */

int main(void)
{
  HAL_Init();
  
  SystemClock_Config();

  MX_GPIO_Init();
  MX_USB_DEVICE_Init();

  while (1)
  {
	  CDC_Transmit_FS(data, strlen(data));
	  HAL_Delay (1000);
  }
}

As you can see above, I am transmitting the data every 1 second.

When we run the code, the DEVICE gets detected in the computer as shown below

I have opened the COM 5 on the Hercules, and the data is being printed every second



HOW TO RECEIVE DATA

The function CDC_Transmit_FS is globally available, and hence I was able to use it in the main file. On the other hand, the function CDC_Receive_FS is a static function defined in USB_DEVICE -> App -> usbd_cdc_if.c file, and hence can not be used outside that file.

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
  /* USER CODE BEGIN 6 */
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  return (USBD_OK);
  /* USER CODE END 6 */
}

In order to make use of it, I am going to define a buffer in the main.c file as shown below

uint8_t buffer[64];

Next, I am going to externally define the same in the usbd_cdc_if.c file so that i can use the buffer in the receive function

/* USER CODE BEGIN PRIVATE_TYPES */
extern uint8_t buffer[64];
/* USER CODE END PRIVATE_TYPES */

and finally modify the CDC_Receive_FS function as shown below

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
  /* USER CODE BEGIN 6 */
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  
  memset (buffer, '
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
  /* USER CODE BEGIN 6 */
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  
  memset (buffer, '\0', 64);  // clear the buffer
  uint8_t len = (uint8_t)*Len;
  memcpy(buffer, Buf, len);  // copy the data to the buffer
  memset(Buf, '\0', len);   // clear the Buf also
  
  return (USBD_OK);
  /* USER CODE END 6 */
}
', 64); // clear the buffer
uint8_t len = (uint8_t)*Len; memcpy(buffer, Buf, len); // copy the data to the buffer memset(Buf, '
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
  /* USER CODE BEGIN 6 */
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);
  
  memset (buffer, '\0', 64);  // clear the buffer
  uint8_t len = (uint8_t)*Len;
  memcpy(buffer, Buf, len);  // copy the data to the buffer
  memset(Buf, '\0', len);   // clear the Buf also
  
  return (USBD_OK);
  /* USER CODE END 6 */
}
', len); // clear the Buf also
return (USBD_OK); /* USER CODE END 6 */ }

In the above code,

  • clear the buffer first to remove any data from previous reception
  • Find the actual length of the received data
  • copy the data from the received Buf into our buffer
  • clear the Buf too ( I have realized that this saves the old data, if not cleared)


RESULT

The result of the above code is shown below

The controller was keep transmitting “Hello World from USB CDC”. When i sent the data (“123456789”) to the controller, it gets stored in the buffer.


The same happened here too. This time I transmitted a different data and it gets stored in the buffer.

We can later process this data in any means we want since it can be accessed from the main.c file itself

Check out the Video Below




Info

You can help with the development by DONATING Below.
To download the project, click the DOWNLOAD button.

Subscribe
Notify of

24 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
Ali
3 months ago

Hello Sir, hope you are doing well, i followed the steps from tutorial but the device is not showing up in com port of PC, i have tried different codes like led blink and all which works fine but the CDC doesn’t work , the code gets uploaded successfully , but no com port show on device manager . pls help.

Log output file: C:\Users\NW\AppData\Local\Temp\STM32CubeProgrammer_a05264.log
ST-LINK SN : 211405003212364D434B4E00
ST-LINK FW : V2J45S7
Board : —
Voltage : 3.19V
SWD freq : 4000 KHz
Connect mode: Under Reset
Reset mode : Hardware reset
Device ID : 0x410
Revision ID : Rev X
Device name : STM32F101/F102/F103 Medium-density
Flash size : 64 KBytes
Device type : MCU
Device CPU : Cortex-M3
BL Version : —

Opening and parsing file: ST-LINK_GDB_server_a05264.srec

Memory Programming …
File : ST-LINK_GDB_server_a05264.srec
Size : 29.15 KB
Address : 0x08000000

Erasing memory corresponding to segment 0:
Erasing internal memory sectors [0 29]
Download in Progress:

File download complete
Time elapsed during download operation: 00:00:01.887

Verifying …

Download verified successfully

Shutting down…
Exit.

saeed
6 months ago

Hi,
Thanks for the tenurial you have made.
please make and share another one for USB BULK TRANSFER application if it is viable for you.
many thanks

Mohammad
8 months ago

Thank you so much 🙏

mjh
1 year ago

I’m using a blue pill with stm32f103c8t6 using STlink-V2 when I flash the file to the blue pill the stlink disconnected and not able to debug and see the data I sent to the board.
How did you connect your blue pill board and stlink.
Very good tutorial.

Mehrdad
1 year ago

Hi, how should I receive unknown length of data from usb com port?I know that such operation in uart could be done using Idle line detector. but how about usb cdc receive?

Andy
1 year ago

after I press the reset button, data is no longer received by Hercules. I had to reconnect the USB to get it working again. Is there a way to prevent that?

neeraj
1 year ago

i am using STM32F413zh nucleo when i connect the micro-USB cable to PC there is nothing as appearance in device manager????
i connect D+ and D- in p12 and p11.
in device manage only st-link cable was showing.
what i do please help….

Karim
2 years ago

Salut, j’utilise un STM32H735G-DK. J’ai suivi votre tuto, et vu que les désignations de fonction diffèrent (STM32F & STM32H) j’ai du modifier le “F” de CDC_Transmit_FS par “H” ce qui m’a donné CDC_Transmit_HS. Malgré toutes mes tentatives, mon pc ne détecte pas le port vituel de mon MCU. Svp j’ai besoin d’aide . . . vous pouvez me contacter à mon adresse m.a.i.l: karimnana520 @gmail.com ou sur mon whatsapp actuel: +237 658747103

babak
2 years ago

I’m using stm32f429zit6 but my board is not detected by hercule. what am i do?

RyanSIlvers
2 years ago

This tutorial in Stdlibrary instead please

12val12
3 years ago

How recieve packet from PC

B0=254; // sync
B1 //number of variable
B2//Low byte
B3// byte
B4// byte
B5=//High Byte
Var[B1]=B2+B3<<8+B4<<16+B5<<32
If the stream fails, then in the incoming stream we look for synchrobyte 254 (skip bytes until we have received 254)

Nguyễn Tuấn Anh
3 years ago

how can i transmit a HEX value instead of char?
Thanks!

rajkumar
4 years ago

Hai, how can we send/transmit the adc value through the usb cdc virtual comfort, I am new to stm32 ,if anyone known please help me

ahmed
4 years ago

stm32f4 ws2812b with cubeide.

Tan Sang
4 years ago

That great! You can make video with NRF24L01, please!

reza
4 years ago

it’s great 😍

Last edited 4 years ago by reza
Peter
Reply to  reza
4 years ago

The USB_CDC_ReceivePacket is the acknowledge of receiving. It should be called after copy the data.