cancel
Showing results for 
Search instead for 
Did you mean: 

USB CDC Bug in CubeMX firmware

richard239955
Associate II
Posted on April 11, 2014 at 10:07

Hey everybody,

in order to initialize a working Virtual Com Port with CubeMX on the STM32F4 Discovery, I had to change

   pdev->pClassData = USBD_malloc(sizeof (USBD_CDC_HandleTypeDef));

to

   pdev->pClassData = (void *) USBD_malloc(sizeof (USBD_CDC_HandleTypeDef));

Without the type cast pClassData would always be null, which will make the parent function (USBD_CDC_Init in usbd_cdc.c) return before initializing the interface.

Btw I used firmware 1.1.0.

EDIT: Sorry, that was too fast. This line was actually not the root cause, it was the following line in USB_CDC.h

   &sharpdefine CDC_DATA_HS_MAX_PACKET_SIZE        512

Changing that value to 256 made it work for me now. In case anyone is interested, here's a small code example for a vcp mirror. Add this code to CDC_Receive in usb_cdc_if.c

    static uint8_t buff_RX[256];

    static uint8_t buff_TX[256];

    

    int i = 0;

    

    for (i = 0; i < *Len; i++)

        buff_TX[i] = buff_RX[i];

    

    USBD_CDC_SetTxBuffer(&hUsbDeviceFS, &buff_TX[0], *Len);

    USBD_CDC_TransmitPacket(&hUsbDeviceFS);

    

    USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &buff_RX[0]);

    USBD_CDC_ReceivePacket(&hUsbDeviceFS);

Also you will have to add

    extern USBD_HandleTypeDef hUsbDeviceFS;

to this file.

 

#usb #cdc #cdc #cdc #cdc_receive_fs #full-echo #usb-cdc #vcp #vcp
49 REPLIES 49
giuseppe239955_st
Associate II
Posted on March 26, 2015 at 10:04

Thank you again for your answer!

In facts, I have no problems in echoing a few characters, up to 63. When I attempt to send a large quantity, some packets are lost.

Perhaps I should use USB FS instead than HS, but on this particular Discovery board this is not possible.

In any case, I am not really worried about this behavior, because echoing chars was just an exercise... it was useful to learn a bit of HAL.

B Zikhali
Associate III
Posted on March 26, 2015 at 16:02

Hi,

I am having the same problem that others have reported, USBD_CDC_Init() is never called, hence CDC_Init_FS() is never called as well. hUsbDevice.pClass is never malloc'ed (see screenshot) and any subsequent calls to USBD_CDC_SetTxBuffer will set off a HardFault Handler.

I have applied the fixes described in this and other forums but am still getting the same problem. CDC_Receive_FS() works and I can use it to run a simple echo function, which surprises me because I can see in the debugger that pClassData is not initialized. What am I missing?

In my *.ld script

/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x00400; 
/* required amount of heap */
_Min_Stack_Size = 0x000400; 
/* required amount of stack */

In my usb_device.c generated by STM32CubeMx

/* USB Device Core handle declaration */
USBD_HandleTypeDef hUsbDeviceFS;
/* init function */
void
MX_USB_DEVICE_Init(
void
)
{
/* Init Device Library,Add Supported Class and Start the library*/
USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS);
USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC);
USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS);
USBD_Start(&hUsbDeviceFS);
}

In my usbd_cdc.h, I have fixed the bug as described by previous posters

#define CDC_DATA_HS_MAX_PACKET_SIZE 256 /* Endpoint IN & OUT Packet size */

As well as applied the fix to the bug in USBD_CDC_TransmitPacket(), which set flag after transmit had begun.

uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)
{ 
USBD_CDC_HandleTypeDef *hcdc = pdev->pClassData;
if
(pdev->pClassData != NULL)
{
if
(hcdc->TxState == 0)
{
/* Tx Transfer in progress */
hcdc->TxState = 1;
/* Transmit next packet */
USBD_LL_Transmit(pdev,
CDC_IN_EP,
hcdc->TxBuffer,
hcdc->TxLength);
return
USBD_OK;

I have a static malloc (which is never used in any case since UBSD_CDC_Init() is never called

/**
* @brief static single allocation.
* @param size: size of allocated memory
* @retval None
*/
void
*USBD_static_malloc(uint32_t size)
{
static
uint32_t mem[
sizeof
(USBD_CDC_HandleTypeDef)];
return
mem;
}

My device is being recognised by both Windows and Linux as a Virtual Com Port, with all descriptors in order. I just cannot call USBD_CDC_SetTxBuffer() (as described in the User Manual) to send data from the MCU to the PC.

My device is a STM32F302K8, using code generated by STM32CubeMX version 4.6.0 and my IDE is Atollic True Studio.

________________

Attachments :

PClassData_NULL.png : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006HzOY&d=%2Fa%2F0X0000000bLA%2FrF1il7ghIYcbcK4fTRBA7mtJ.kohUYr0qFlnxJ9rh0o&asPdf=false
petr239955
Associate III
Posted on March 26, 2015 at 16:59

My device is a STM32F302K8, using code generated by STM32CubeMX version 4.6.0 and my IDE is Atollic True Studio.

Hi Zikhali,

what version of STM32CubeF3

you are using

?

B Zikhali
Associate III
Posted on March 26, 2015 at 17:25

Hi Petr, 

I am using version 1.1.1 of STM32CubeF3

petr239955
Associate III
Posted on March 27, 2015 at 13:02

Hi Zikhali,

I have no development board with STM32F3 family, but

I

tried

to generate

your project.

I compared

the files

for

USB

from

STM32CubeF3

and

STM32CubeF0

. Middleware USB files from

STM32CubeF3

are older and

some changes

were made. F

iles

for

STM32F0

and

STM32F3

are identical

, so try

to replace

all your

files

newer

from

STM32F0

(see. attachment).

The USB

CD

C

works

well

for me

with

STM32F0

family.

I just had

problems identifying the

initialization

before the

transmitting

(

u8_usb_initialized).

I use

STM32CubeMX

4.7.0

and

STM32CubeF0

1.2.1

.

I have

to test

available

yet

STM32F1

,

STM32F2

and

STM32F4

boards

.

________________

Attachments :

Middlewares.zip : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006HzGi&d=%2Fa%2F0X0000000bL9%2FxAm7yEMBf5g_Z8y14wbJTQhs_c7TbkRpi06PvFTczqU&asPdf=false
B Zikhali
Associate III
Posted on March 30, 2015 at 16:39

Thank you Petr!!! You were right, my code was trying to send data before the port had been opened. 

I realised during the weekend that I would never be able to see the initialization of u8_cdc_initialized whilst the MCU was connected to the debugger, which is why I had initially said your solution was not working for me. The solution I found was to disconnect and reconnect the MCU and read the output from the terminal, and I can see my data being sent from the MCU after a slight pause where the port is being opened. 

Do you have the link to the forum you read this on? It sounds more informative than ST's own documentation which actually told me to call USBD_CDC_Init() [Page 52 Part 7.5.6 of User manual UM1734] which cost me three days of debugging! Thank you so much for your help. Let me now try and create a protocol for my application. Thank you again, and to all the posters who pointed our the bugs in the libraries, thank you.

petr239955
Associate III
Posted on March 30, 2015 at 23:06

Do you have the link to the forum you read this on?

 

I am pleased that I have been able to help you

.

I

found the main

information

here

http://visualgdb.com/tutorials/arm/stm32/usb/

.

I hope

that

these experiences

the CubeMX

team

added to

the next

version of

HAL

libraries

.

B Zikhali
Associate III
Posted on April 09, 2015 at 16:34

Sorry to pollute the thread but I thought it best to post here. I have managed to get the µC working and sending data to my PC which acts as a host. I am now however confronted with a new problem and two days of debugging later, I have no idea how to surmount it.

Whenmy µC is sending data via USB, it NEEDS an application on the other side of the USB to consume the data apparently. When connected to my PC, and a program displaying the data is active (Realterm, Python script etc...) it will function indefinitely. If for any reason the program on PC closes, or is never opened, the µC will function for half a minute then freeze. Here is the code for my transmission, I have tried to get the µC to test if there is activity on the bus before sending data but that apparently doesn't work. Using LEDS I I think the µC freezes on one of the while conditions surrounding USBD_CDC_TransmitPacket() and USBD_CDC_SetTxBuffer() below:

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len){
uint8_t result = USBD_OK;
volatile
uint8_t bDeviceState = (
volatile
uint8_t) hUsbDevice_0->dev_state
// If no activity on the bus for past 3 seconds fail
if
(bDeviceState == USBD_STATE_SUSPENDED)
return
USBD_FAIL;
// wait for previous transfer to complete 
USBD_CDC_HandleTypeDef *pCDC = (USBD_CDC_HandleTypeDef * hUsbDevice_0->pClassData;
while
(pCDC->TxState) { }
USBD_CDC_SetTxBuffer(hUsbDevice_0, Buf, Len);
result = USBD_CDC_TransmitPacket(hUsbDevice_0);
// wait until transfer is done
while
(pCDC->TxState) { } 
return
result;
}

This is a simplified version of the send function, a more complex recursive function (based on the tutorial on visualgdb.com) which takes into account cases where the data to send is larger than the packet size shows the same behaviour, in either case I'm not too worried because my application for the time being is sending data byte by byte. (Stupid I know but I am still at the testing stage). Why is my µC behaving like this and any ideas for methods of debugging since I cannot use the normal debugger in True Studio (if I run the code under debug, the USB fails to initalize and my code hangs in the initialization active wait).

In unrelated weirdness, when connected to a Windows PC, the µC runs normally. When I connect it to Linux, it runs at about half normal speed (judging from the speed of my flashing LEDS). Any ideas why this weird behaviour? Sorry for the many questions but I am new to USB programming and the STm32 environment and ST software is not the best documented in the world #understatement
markb
Associate II
Posted on April 09, 2015 at 18:16

Here's how I do it. I have implemented _write() so I can simply use printf(), etc. to send output to my laptop (running Linux, of course) and then I can just use ''screen /dev/ttyACM0'' to interact with my program on the MCU.
 int _write(int fd, void *buf, size_t count) {
static int failed;
if(fd == 1) {
if(hUsbDeviceFS.dev_state != USBD_STATE_CONFIGURED)
return 0;
if(failed) {
if(CDC_Transmit_FS(buf, count) == USBD_OK) {
failed = 0;
return count;
}
return 0;
}
uint32_t timeout = HAL_GetTick() + 500; // 0.5 second timeout
while(HAL_GetTick() < timeout) {
if(hUsbDeviceFS.dev_state != USBD_STATE_CONFIGURED)
return 0;
int result = CDC_Transmit_FS(buf, count);
if(result == USBD_OK)
return count;
if(result != USBD_BUSY)
return -1;
// save some power!
__WFI();
}
failed = 1;
return 0;
}
return -1;
}

markb
Associate II
Posted on April 09, 2015 at 18:19

Sorry, I forgot this in the last post.
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;
}