Skip to main content
rwmao
Senior
February 24, 2016
Question

Read data from PC to STM32 via USB CDC

  • February 24, 2016
  • 16 replies
  • 19776 views
Posted on February 24, 2016 at 06:02

I am working on a project. One of the part is exchanging data between PC and MCU(STM32F4) via the USB CDC.

Sending data from STM32 to PC is very easy, but there is difficulty receiving data from PC. In the file usbd_cdc_if.c, I implemented

CDC_Receive_FS

, and in main(), it constants call the function

CDC_Receive_FS

to read data.

UserRxBufferFS

is the buffer created by cubemx. In main(), I get the received data via the array

Buf

. I do receive the input from PC, but the problem is everytime I call the function

CDC_Receive_FS

I get the same data until new data were received. This is not the supposed logic I want. I want to keep the buffer empty until new data were received. Or receive nothing if no new data were received. Therefore I try to clear the buffer once the data were copied to array

Buf

, but if I do this, Ialways receive a empty string in main(). What to do?

int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) 
{ 
/* USER CODE BEGIN 6 */
uint8_t status=USBD_CDC_ReceivePacket(hUsbDevice_0); 
if
(status==USBD_OK) 
{ 
if
(UserRxBufferFS[0]!=
'\0'
) 
//there are data received 
{ 
memcpy(Buf,UserRxBufferFS,APP_RX_DATA_SIZE); 
// memset(UserRxBufferFS,1,APP_RX_DATA_SIZE); 
// UserRxBufferFS[0]='\0'; 
} 
} 
return
status; 
/* USER CODE END 6 */
}

    This topic has been closed for replies.

    16 replies

    rwmao
    rwmaoAuthor
    Senior
    February 24, 2016
    Posted on February 24, 2016 at 19:43

    any suggestions, please.

    qwer.asdf
    Senior
    February 25, 2016
    Posted on February 25, 2016 at 09:09

    You must use callback functions to know when the data was received.

    Look at this example in your STM32Cube repository where a bridge is implemented between STM32's UART and the PC using the CDC (the readme.txt file there describes everything):

    STM32Cube_FW_F4_V1.11.0\Projects\STM324xG_EVAL\Applications\USB_Device\CDC_Standalone

    The interesting file is usbd_cdc_interface.c.
    rwmao
    rwmaoAuthor
    Senior
    February 25, 2016
    Posted on February 25, 2016 at 16:55

    I use cubemx to generate the code, in which the mode of USB is device only, class for fs is CDC.

    I didn't see any place to set the callback. I read the example you mentioned, but i couldn't find place to set the callback in my project files.

    qwer.asdf
    Senior
    February 26, 2016
    Posted on February 26, 2016 at 08:59

    I'm not using HAL so I may be wrong, but I'll try to help.

    If I understand correctly the CDC_Receive_FS is the callback function, you shouldn't call it, it is being called when data was received through USB OUT endpoint and is ready for you to take it. When it is called, you must take (use, copy, whatever) the Len bytes from the Buf and tell the CDC layer that you are ready to receive the next packet by calling the USBD_CDC_ReceivePacket function. I don't really know but maybe you are required to call the USBD_CDC_ReceivePacket just once in the beginning to initiate the transfer (the next call will be from the callback function).

    static
    int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)
    {
    /* USER CODE BEGIN 6 */
    // here, use the data of Len length in the Buf
    //...
    //...
    // Set the RX buffer if necessary...
    USBD_CDC_SetRxBuffer(hUsbDevice_0, &Buf[0]);
    // Tell that you are ready to receive the next packet
    USBD_CDC_ReceivePacket(hUsbDevice_0);
    return
    (USBD_OK);
    /* USER CODE END 6 */
    }

    rwmao
    rwmaoAuthor
    Senior
    February 27, 2016
    Posted on February 27, 2016 at 05:48

    qwer, that is right,

    CDC_Receive_FS

    is a callback function. In the function

    CDC_Receive_FS, where data were received, code was included to save info into a user buffer and set a data ready flag.

    Then we define another function

    VCP_retrieveInputData

    , in which it checks if the data have been received. It returns 0 if no data were received. We frequently call this function in main() to get the data. Problem is solved. Also I implemented a queue to save multiple incoming strings, therefore I wouldn't lose received data. Each time it receives a new string, it save to the buffer and move the index forward by 1.

    #define MaxCommandsInBuffer 10 //max 10 commands can be received and saved without overwriting. Each command has a max size of APP_RX_DATA_SIZE 
    static
    struct
    {
    int
    pos_receive, pos_process; 
    //pos_receive is the current position in buffer to save incoming data. pos_process is the index of data in buffer which has been processed. 
    //if pos_receive=pos_process, it means all data were processed, waiting for new data coming
    unsigned 
    char
    IsCommandDataReceived; 
    //anynumber >0 means data were received. 0 means no data is available 
    uint8_t UserRxBufferFS[MaxCommandsInBuffer][APP_RX_DATA_SIZE];
    //it could save <MaxCommandsInBuffer> number of commands
    uint8_t CommandsLens[MaxCommandsInBuffer]; 
    //save the len of each command
    } s_RxBuffers;
    int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)
    {
    
    /* USER CODE BEGIN 6 */ // CDC_Receive_FS is a callback function. When data were received, the system calls this function. The received data can be accessed via Buf,and *Len
    s_RxBuffers.IsCommandDataReceived=1; 
    //indicates data were received
    s_RxBuffers.CommandsLens[s_RxBuffers.pos_receive]=*Len; 
    //only set the length, data was directly saved to buffer
    s_RxBuffers.pos_receive++;
    //move to next position to receive data 
    if
    (s_RxBuffers.pos_receive>=MaxCommandsInBuffer) 
    //reach the last buffer, need to rewind to 0
    {
    s_RxBuffers.pos_receive=0;
    } 
    //prepare to receive the next data
    USBD_CDC_SetRxBuffer(hUsbDevice_0, s_RxBuffers.UserRxBufferFS[s_RxBuffers.pos_receive]);
    //Set the buffer to receive incoming data
    USBD_CDC_ReceivePacket(hUsbDevice_0);// Tell that you are ready to receive the next packet, otherwise you wouldn't be able to receive next data
    return
    USBD_OK;
    /* USER CODE END 6 */
    }

    Define in the same file as that of CDC_Receive_FS

    /**
    * @brief VCP_retrieveInputData, defined by user
    * Call this function frequently to check if data is received.
    * 
    * 
    * 
    * @param Buf: Buffer of data to be received
    * @param Len: Number of data received (in bytes)
    * @retval 0 means no data was received.
    */
    int8_t VCP_retrieveInputData(uint8_t* Buf, uint32_t *Len)
    {
    if
    (s_RxBuffers.IsCommandDataReceived==0)
    return
    0; 
    //no data received
    int
    index=s_RxBuffers.pos_process;
    *Len=s_RxBuffers.CommandsLens[index]; 
    //return the length 
    memcpy(Buf,s_RxBuffers.UserRxBufferFS[index],*Len); 
    Buf[*Len]=
    '\0'
    ; 
    //testing only. make sure there is ending char in the returned command string
    //check if all data were processed.
    s_RxBuffers.pos_process++;
    if
    (s_RxBuffers.pos_process>=MaxCommandsInBuffer) 
    //reach the last buffer, need to rewind to 0
    {
    s_RxBuffers.pos_process=0;
    }
    if
    (s_RxBuffers.pos_process==s_RxBuffers.pos_receive)s_RxBuffers.IsCommandDataReceived=0; 
    //check if all data were processed
    return
    1;
    }

    In main() frequently call above defined

    VCP_retrieveInputData

    while
    (1)
    {
    // DO something else here
    if
    (VCP_retrieveInputData(hexbuffer,&pos32)!=0)
    {
    // you could do data processing here.
    //by demo, i just send it back to PC
    sprintf(textbuf,
    ''i=%d,data=%s
    ''
    ,i_temp0,hexbuffer);
    //export it to char buffer first. 
    SendTextMsgToUSB(textbuf); 
    //send the text to PC via cdc 
    hexbuffer[0]=
    '\0'
    ;
    }
    TM_DelayMillis(10);
    //it is better to delay a little bit time, 0.1ms up to a few ms
    i_temp0++;
    }

    /**
    * @brief VCP_retrieveInputData, defined by user
    * Call this function frequently to check if data is received.
    *
    *
    *
    * @param Buf: Buffer of data to be received
    * @param Len: Number of data received (in bytes)
    * @retval 0 means no data was received.
    */
    int8_t VCP_retrieveInputData(uint8_t* Buf, uint32_t *Len)
    {
    if

    (s_RxBuffers.IsCommandDataReceived==0)

    return

    0;

    //no data received

    int

    index=s_RxBuffers.pos_process;
    *Len=s_RxBuffers.CommandsLens[index];

    //return the length

    memcpy(Buf,s_RxBuffers.UserRxBufferFS[index],*Len);
    Buf[*Len]=

    '\0'

    ;

    //testing only. make sure there is ending char in the returned command string

    //check if all data were processed.
    s_RxBuffers.pos_process++;
    if

    (s_RxBuffers.pos_process>=MaxCommandsInBuffer)

    //reach the last buffer, need to rewind to 0

    {
    s_RxBuffers.pos_process=0;
    }
    if

    (s_RxBuffers.pos_process==s_RxBuffers.pos_receive)s_RxBuffers.IsCommandDataReceived=0;

    //check if all data were processed

    return

    1;
    }
    
    

    cnhx27
    Associate III
    January 4, 2019

    @rwmao Interesting

    But would it be possible to detail CDC_Init_FS(void) which set buffers?

    (UserTxBufferFS & s_RxBuffers.UserRxBufferFS)

    Tesla DeLorean
    Guru
    January 4, 2019

    Post from about 3 years ago, forum migrating also damaged some posts.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    cnhx27
    Associate III
    January 4, 2019

    Ah ! Zut !

    cnhx27
    Associate III
    January 4, 2019

    Forum closed!

    rwmao
    rwmaoAuthor
    Senior
    January 4, 2019
    Hello
    It has been long time ago.
    Please go to my bit hub I make it public.
    https://bitbucket.org/rwmao/cdc_onstm32f411rc/src/master/
    There is readme file and detailed source file.
    Thanks


    Dr. RongWei Mao
    2019-01-04

    On 2019-01-04 at 03:02, ST Community wrote:

    @rwmao Interesting But would it be possible to detail CDC_Init_FS(void) which set buffers? (UserTxBufferFS & s_RxBuffers.UserRxBufferFS)






    cnhx27 (Community Member)
    @rwmao Interesting
    But would it be possible to detail CDC_Init_FS(void) which set buffers?
    (UserTxBufferFS & s_RxBuffers.UserRxBufferFS)

    View/Answer View/Answer
    or reply to this email




    Replying to



    rwmao (Community Member) to ST Community (STMicroelectronics): asked a question.
    Edited by STCommunity Wednesday, October 10, 2018 11:01 AM
    Read data from PC to STM32 via USB CDC
    Posted on February 24, 2016 at 06:02
    I am working on a project. One of the part is exchanging data between PC and MCU(STM32F4) via the USB CDC.
    Sending data from STM32 to PC is very easy, but there is difficulty receiving data from PC. In the file usbd_cdc_if.c, I implemented
    CDC_Receive_FS
    , and in main(), it constants call the function
    CDC_Receive_FS
    to read data.
    UserRxBufferFS
    is the buffer created by cubemx. In main(), I get the received data via the array
    Buf
    . I do receive the input from PC, but the problem is everytime I call the function
    CDC_Receive_FS
    I get the same data until new data were received. This is not the supposed logic I want. I want to keep the buffer empty until new data were received. Or receive nothing if no new data were received. Therefore I try to clear the buffer once the data were copied to array
    Buf
    , but if I do this, Ialways receive a empty string in main(). What to do?
    int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)
    {
    /* USER CODE BEGIN 6 */
    uint8_t status=USBD_CDC_ReceivePacket(hUsbDevice_0);
    if
    (status==USBD_OK)
    {
    if
    (UserRxBufferFS[0]!=
    '\0'
    )
    //there are data received
    {
    memcpy(Buf,UserRxBufferFS,APP_RX_DATA_SIZE);
    // memset(UserRxBufferFS,1,APP_RX_DATA_SIZE);
    // UserRxBufferFS[0]='\0';
    }
    }
    return
    status;
    /* USER CODE END 6 */
    }







    cnhx27 (Community Member)
    @rwmao Interesting
    But would it be possible to detail CDC_Init_FS(void) which set buffers?
    (UserTxBufferFS & s_RxBuffers.UserRxBufferFS)
    Friday, January 4, 2019 5:02 AM






    You're receiving emails when someone "Comments on my posts."

    To change or turn off ST Community email, log in as rwmao@uci.edu.st.

    Are notifications about this post getting annoying? Reply to this email with the word " mute ".

    STMicroelectronics N.V.
    cnhx27
    Associate III
    January 4, 2019

    @rwmao​  Thank you very much.

    Smalik
    Associate III
    May 18, 2020

    Which Software you are using to monitor the Receive and transmit data from USB. Do you have any suggestions for the USB data Loggers ?