cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L476 USB CDC VCOM PC cannnot send large amount data to device

jiangpen
Associate II
Posted on March 14, 2016 at 08:11

Hi all,

I configure the STM32L476 as USB CDC device. It works by PC sends bytes like 256 length to embedded, and embedded side sends big data to PC is OK. However, when the PC send data like 2048 or 512 bytes a time, then the embedded side cannoot receive all of them. I caculate the received len, it always less than what is send if lager than 512 bytes. I split the data to send several times does not help. In the main loop, I call USBD_CDC_ReceivePacket to continue to receive data, and below function is call in the usb receive, and I log the len of total recieve. If I send data like below in C#, the receive len is less than 5 But if I send 256, then the receive len is Ok. serialPort1.Write(arr, 0, 512); Anyone has an idea about that? void data_handler(uint8_t* Buf, uint32_t *Len) { memcpy(datareadbuf, Buf, *Len); readlen=*Len; datairq+=*Len; datacoming=1; }

/**
******************************************************************************
* @file : usbd_cdc_if.c
* @brief :
******************************************************************************
* COPYRIGHT(c) 2015 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include ''usbd_cdc_if.h''
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_CDC 
* @brief usbd core module
* @{
*/ 
/** @defgroup USBD_CDC_Private_TypesDefinitions
* @{
*/ 
/* USER CODE BEGIN 0 */ 
/* USER CODE END 0 */ 
/**
* @}
*/ 
/** @defgroup USBD_CDC_Private_Defines
* @{
*/ 
/* USER CODE BEGIN 1 */
/* Define size for the receive and transmit buffer over CDC */
/* It's up to user to redefine and/or remove those define */
#define APP_RX_DATA_SIZE 2048
#define APP_TX_DATA_SIZE 2048
/* USER CODE END 1 */ 
/**
* @}
*/ 
/** @defgroup USBD_CDC_Private_Macros
* @{
*/ 
/* USER CODE BEGIN 2 */ 
/* USER CODE END 2 */
/**
* @}
*/ 
/** @defgroup USBD_CDC_Private_Variables
* @{
*/
/* Create buffer for reception and transmission */
/* It's up to user to redefine and/or remove those define */
/* Received Data over USB are stored in this buffer */
uint8_t UserRxBufferFS[APP_RX_DATA_SIZE];
/* Send Data over USB CDC are stored in this buffer */
uint8_t UserTxBufferFS[APP_TX_DATA_SIZE];
/* USB handler declaration */
/* Handle for USB Full Speed IP */
USBD_HandleTypeDef *hUsbDevice_0;
extern USBD_HandleTypeDef hUsbDeviceFS;
/**
* @}
*/ 
/** @defgroup USBD_CDC_Private_FunctionPrototypes
* @{
*/
static int8_t CDC_Init_FS (void);
static int8_t CDC_DeInit_FS (void);
static int8_t CDC_Control_FS (uint8_t cmd, uint8_t* pbuf, uint16_t length);
static int8_t CDC_Receive_FS (uint8_t* pbuf, uint32_t *Len);
USBD_CDC_ItfTypeDef USBD_Interface_fops_FS = 
{
CDC_Init_FS,
CDC_DeInit_FS,
CDC_Control_FS, 
CDC_Receive_FS
};
/* Private functions ---------------------------------------------------------*/
/**
* @brief CDC_Init_FS
* Initializes the CDC media low layer over the FS USB IP
* @param None
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
*/
static int8_t CDC_Init_FS(void)
{
hUsbDevice_0 = &hUsbDeviceFS;
/* USER CODE BEGIN 3 */ 
/* Set Application Buffers */
USBD_CDC_SetTxBuffer(hUsbDevice_0, UserTxBufferFS, 0);
USBD_CDC_SetRxBuffer(hUsbDevice_0, UserRxBufferFS);
return (USBD_OK);
/* USER CODE END 3 */ 
}
void receive_data()
{
USBD_CDC_ReceivePacket(hUsbDevice_0);
}
/**
* @brief CDC_DeInit_FS
* DeInitializes the CDC media low layer
* @param None
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
*/
static int8_t CDC_DeInit_FS(void)
{
/* USER CODE BEGIN 4 */ 
return (USBD_OK);
/* USER CODE END 4 */ 
}
/**
* @brief CDC_Control_FS
* Manage the CDC class requests
* @param cmd: Command code 
* @param pbuf: Buffer containing command data (request parameters)
* @param length: Number of data to be sent (in bytes)
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
*/
USBD_CDC_LineCodingTypeDef linecoding =
{
115200, /* baud rate*/
0x00, /* stop bits-1*/
0x00, /* parity - none*/
0x08 /* nb. of bits 8*/
};
static int8_t CDC_Control_FS (uint8_t cmd, uint8_t* pbuf, uint16_t length)
{ 
/* USER CODE BEGIN 5 */
switch (cmd)
{
case CDC_SEND_ENCAPSULATED_COMMAND:
break;
case CDC_GET_ENCAPSULATED_RESPONSE:
break;
case CDC_SET_COMM_FEATURE:
break;
case CDC_GET_COMM_FEATURE:
break;
case CDC_CLEAR_COMM_FEATURE:
break;
/*******************************************************************************/
/* Line Coding Structure */
/*-----------------------------------------------------------------------------*/
/* Offset | Field | Size | Value | Description */
/* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
/* 4 | bCharFormat | 1 | Number | Stop bits */
/* 0 - 1 Stop bit */
/* 1 - 1.5 Stop bits */
/* 2 - 2 Stop bits */
/* 5 | bParityType | 1 | Number | Parity */
/* 0 - None */
/* 1 - Odd */ 
/* 2 - Even */
/* 3 - Mark */
/* 4 - Space */
/* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
/*******************************************************************************/
case CDC_SET_LINE_CODING: 
linecoding.bitrate = (uint32_t)(pbuf[0] | (pbuf[1] << 
8
) |\
(pbuf[2] << 16) | (pbuf[3] << 24));
linecoding.format
= 
pbuf
[4];
linecoding.paritytype
= 
pbuf
[5];
linecoding.datatype
= 
pbuf
[6];
break;
case CDC_GET_LINE_CODING: 
pbuf[0] = (uint8_t)(linecoding.bitrate);
pbuf[1] = (uint8_t)(linecoding.bitrate >> 8);
pbuf[2] = (uint8_t)(linecoding.bitrate >> 16);
pbuf[3] = (uint8_t)(linecoding.bitrate >> 24);
pbuf[4] = linecoding.format;
pbuf[5] = linecoding.paritytype;
pbuf[6] = linecoding.datatype; 
break;
case CDC_SET_CONTROL_LINE_STATE:
break;
case CDC_SEND_BREAK:
break; 
default:
break;
}
return (USBD_OK);
/* USER CODE END 5 */
}
/**
* @brief CDC_Receive_FS
* Data received over USB OUT endpoint are sent over CDC interface 
* through this function.
* 
* @note
* This function will block any OUT packet reception on USB endpoint 
* untill exiting this function. If you exit this function before transfer
* is complete on CDC interface (ie. using DMA controller) it will result 
* in receiving more data while previous ones are still not sent.
* 
* @param Buf: Buffer of data to be received
* @param Len: Number of data received (in bytes)
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
*/
static int8_t usb_inited=0;
int8_t get_usb_status()
{
return usb_inited;
}
static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
usb_inited=1;
data_handler(Buf, Len);
return (USBD_OK);
/* USER CODE END 6 */ 
}
/**
* @brief CDC_Transmit_FS
* Data send over USB IN endpoint are sent over CDC interface 
* through this function. 
* @note
* 
* 
* @param Buf: Buffer of data to be send
* @param Len: Number of data to be send (in bytes)
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY
*/
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
uint8_t result = USBD_OK;
/* USER CODE BEGIN 7 */ 
USBD_CDC_SetTxBuffer(hUsbDevice_0, Buf, Len); 
result = USBD_CDC_TransmitPacket(hUsbDevice_0);
/* USER CODE END 7 */ 
return result;
}
/**
* @}
*/ 
/**
* @}
*/ 
/**
* @}
*/ 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

#cdc #usb-vcp-cdc
5 REPLIES 5
jiangpen
Associate II
Posted on March 14, 2016 at 12:23

I solved the problem myself, the

 USBD_CDC_ReceivePacket needs to be called in the callback function.Previously I called it from main loop.

However, it comes to another problem. How do I implement the flow control? I don't want PC floods my system by sending too much data a time. I thought I can use the USBD_CDC_ReceivePacket to performe the flow control by not calling it in some time, but it appears it will lost data if I don't call that in time.

Any idea to have some flow control, to have PC to send only when I sends some ACK?

 thanks a lot.

Here is the code to solve the problem:

static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)

{

  /* USER CODE BEGIN 6 */

    usb_inited=1;

    data_handler(Buf, Len);

    USBD_CDC_ReceivePacket(hUsbDevice_0);

  return (USBD_OK);

  /* USER CODE END 6 */

}

connectjagadeep
Associate II
Posted on March 15, 2016 at 12:52

Hi,

    I too faced similar problem. But I had Host program under my control. I made a small serial port terminal using Python and controlled data transmission upon receiving ACK token from the device.

Jagadeep. 

Posted on December 06, 2016 at 15:42

Any updates on how to achieve flow control with this library?

Geoffrey1
Associate III
Posted on December 07, 2016 at 04:09

As noted, until USBD_CDC_ReceivePacket is called, then no further data will be accepted from the host. Flow control is implemented by using a queue where the USB interrupt enqueues and the user code dequeues:

// executed by interrupt handler
volatile int rxKick = 0;
int8_t vcom_Receive_FS (uint8_t* Buf, uint32_t *Len)
{
 Enqueue(&rxQ, Buf, *Len)
 // release receive buffer only if there's enough space
 // otherwise set rxKick flag so our dequeue can restart
 // reception
 if (USB_FS_MAX_PACKET_SIZE >= QueueSpace(&rxQ)) {
 rxKick = 1;
 } else {
 USBD_CDC_ReceivePacket(hUsbDevice_0);
 }
 return (USBD_OK);
}
// executed by main code to pull things out of the queue
uint32_t vcom_read(uint8_t *pBuf, uint32_t buf_len) 
{
 uint32_t cnt = Dequeue(&rxQ, pBuf, buf_len);
 // release receive buffer 
 if (rxKick && (USB_FS_MAX_PACKET_SIZE <= QueueSpace(&rxQ))) {
 rxKick = 0;
 USBD_CDC_ReceivePacket(hUsbDevice_0);
 }
 return cnt;
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Posted on December 08, 2016 at 17:51

Well I 'm on other things but this overflow flow-control is going to come up for me too So I ask the same question here as in the other thread. Doesn't the example USB stack NACK incoming data from USB if the FIFO is FULL?

(IE - flowcontrol) ???