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, '\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 */
}

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
To download the code, click DOWNLOAD button and view the Ad. The project will download after the Ad is finished.

21 Comments. Leave new

  • 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.

    Reply
  • 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?

    Reply
    • 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.

      Reply
  • 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?

    Reply
  • 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….

    Reply
    • 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.

      Reply
  • 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

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

    Reply
    • 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

      Reply
  • RyanSIlvers
    May 16, 2022 4:49 PM

    This tutorial in Stdlibrary instead please

    Reply
  • 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)

    Reply
  • Nguyễn Tuấn Anh
    May 11, 2021 9:52 PM

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

    Reply
  • 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

    Reply
  • stm32f4 ws2812b with cubeide.

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

    Reply
  • it’s great 😍

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

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

keyboard_arrow_up

Adblocker detected! Please consider reading this notice.

We've detected that you are using AdBlock Plus or some other adblocking software which is preventing the page from fully loading.

We don't have any banner, Flash, animation, obnoxious sound, or popup ad. We do not implement these annoying types of ads!

We need money to operate the site, and almost all of it comes from our online advertising.

Please add controllerstech.com to your ad blocking whitelist or disable your adblocking software.

×