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
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.
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
Thank you so much 🙏
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.
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?
The function int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) already receives the data of unknown length. Here Len is the pointer to the number of data byte received.
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?
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….
1. Why are you even doing this on the nucleo board ? You can simply send the data to the PC via the STlink using the UART2.
2. Nucleo STM32F413zh has one user USB at the bottom. Use it.
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
USB HS Does not supports virtual Communication. You have to use FS only
I’m using stm32f429zit6 but my board is not detected by hercule. what am i do?
if you are using the nucleo or discovery boards, make sure you connect to the USER USB, not the ST-Link
Also check if the cable supports the data transfer or not
This tutorial in Stdlibrary instead please
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)
how can i transmit a HEX value instead of char?
Thanks!
just send it simply. What’s the issue?
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
try sending the address to the value.
If can’t, then convert it to string and send
https://www.digikey.com/en/maker/projects/getting-started-with-stm32-working-with-adc-and-dma/f5009db3a3ed4370acaf545a3370c30c
stm32f4 ws2812b with cubeide.
That great! You can make video with NRF24L01, please!
it’s great 😍
The USB_CDC_ReceivePacket is the acknowledge of receiving. It should be called after copy the data.