2016-02-23 09:02 PM
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 implementedCDC_Receive_FS
, and in main(), it constants call the functionCDC_Receive_FS
to read data.UserRxBufferFS
is the buffer created by cubemx. In main(), I get the received data via the arrayBuf
. I do receive the input from PC, but the problem is everytime I call the functionCDC_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 arrayBuf
, 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 */
}
2016-02-24 10:43 AM
any suggestions, please.
2016-02-25 12:09 AM
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.2016-02-25 07:55 AM
2016-02-25 11:59 PM
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 */
}
2016-02-26 08:48 PM
qwer, that is right,
CDC_Receive_FS
is a callback function. In the functionCDC_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 functionVCP_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;
}
2019-01-04 03:02 AM
@rwmao Interesting
But would it be possible to detail CDC_Init_FS(void) which set buffers?
(UserTxBufferFS & s_RxBuffers.UserRxBufferFS)
2019-01-04 05:35 AM
Post from about 3 years ago, forum migrating also damaged some posts.
2019-01-04 07:48 AM
Forum closed!
2019-01-04 07:49 AM
Ah ! Zut !