cancel
Showing results for 
Search instead for 
Did you mean: 

USB CDC on F103C8T6 detected by PC but not working in any way - pClassData is always a null pointer

sq8l
Associate

Hello.

The device is correctly detected by the PC as a COM port and I can open the connection with some terminal. Although I can't send anything through it in any way.

I've tried using CDC_Transmit_FS (from usbd_cdc_if.c) after waiting some time for the USB to initalize, but it returns USBD_BUSY every time. The problem is at these lines:

USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
  if (hcdc->TxState != 0){
    return USBD_BUSY;
  }

It seems that pClassData is always a null pointer, so TxState contains some garbage.

According to my investigation, in function USBD_CDC_Init() (usbd_cdc.c) there is some malloc, which should assign an address to pClassData:

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

But the problem is that USBD_CDC_Init() is NEVER called (checked with a breakpoint). Chaning this line to statically assign some dummy address to pClassData also has no effect. In the result I can't send anything and there is no reaction when I send something from the PC.

I'm using STM32CubeMX for this. The problem is present also in plain, fresh generated code.

Does anyone have any idea?

Thanks in advance

2 REPLIES 2
TDK
Guru

Custom board? Does it work with existing CubeMX examples?

You've spotted exactly what's happening. USBD_CDC_Init should get called at some point during enumeration. Until then, pClassData is NULL and you need to avoid calling CDC_Transmit_FS.

You could use USBPcap to see what's happening on the line.

If you feel a post has answered your question, please click "Accept as Solution".
sq8l
Associate

Thank you for the response. The board I'm using is Blue Pill.

In the meantime, I found the solution. It seems that the main problem is the D+ pull-up resistor, which is physically connected to Vcc on a PCB.

After first MCU power-up, the USB initializes, the PC sees the resistor, enumerates the device and USBD_CDC_Init() is called. At this point everything works fine. But when I keep the whole device powered (so D+ is still pulled up) and "soft" reset the MCU (using reset button for example), the USB peripheral reinitializes, but the PC doesn't enumerate the device again, because D+ has been constantly pulled up since the very first power-up. This results in USBD_CDC_Init() not being called at all.

Hope I'm right, as this conclusion is based only on my intuition and some small debugging.

The easiest solution is just to replug the USB cable, but the way to do it more automatic is to remove the original pull-up resistor and use some GPIO pin with similar resistor to disable the pull-up for a short period during boot and then to enable it. This forces the PC to reenumarate the MCU.

The other way to achieve that, without any hardware modifications, is to set D+ (PA12 on F103C8T6) as an output, short it to ground for a short while and deinitialize the output, everything just before USB initialization. This also looks like a device reconnection and forces enumeration. I have just tested it and works fine. Not very elegant, but according to USB spec every USB transceiver should handle any shorts to ground for at least 24h.