cancel
Showing results for 
Search instead for 
Did you mean: 

Read data from PC to STM32 via USB CDC

rwmao
Senior
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 */
}

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

any suggestions, please.

qwer.asdf
Senior
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
Senior
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
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
Senior
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

@rwmao Interesting

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

(UserTxBufferFS & s_RxBuffers.UserRxBufferFS)

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

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

Forum closed!

Ah ! Zut !