cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 USB Library NAKs OUT packets from host

Elijah Brown
Associate II
Posted on February 01, 2017 at 02:32

I have the STMicro USB library configured as a full speed CDC device.  This is running on a STM32F405OG chip.  Everything works as expected but (very) occasionally it gets into a state where the device NAKs every OUT packet sent by the host, and this continues forever (see attached screenshot of the USB trace).  I haven't been able to figure out exactly what triggers this but it seems to happen when there is a lot of USB traffic going through the device.  Has anyone seen this before or have any ideas what is happening? 

#usb-cdc #stm32 #usb
2 REPLIES 2
Elijah Brown
Associate II
Posted on February 07, 2017 at 01:53

The issue has to do with the HAL_LOCK logic implemented in the HAL layer of the STMicro USB CDC driver.  When CDC_Receive_FS() calls USBD_CDC_ReceivePacket() to prepare the endpoint for the next transfer, it occasionally fails silently if the background task happened to have called CDC_Transmit_FS(), 'locking' the resource just when the interrupt fired.  CDC_Receive_FS() is called in the interrupt context by the STMicro driver so I don't see how this ever correctly worked.  And because the drivers are making calls to HAL_Delay() inside the 'locked' sections, it's not possible to just replace the HAL_LOCK calls with a proper critical section (turning off interrupts) due to the way HAL_Delay() is implemented... has anyone actually made this work in a robust way?  Very disappointed in the quality of STMicro's libraries. 

Posted on February 23, 2017 at 21:25

Hi Elijah,

I ran into the same problem where USBD_CDC_ReceivePacket() fails when the USB is still locked by USBD_CDC_TransmitPacket() at the time the OUT EP1 interrupt is received.

To fix this, I disable interrupts, call USBD_CDC_TransmitPacket() and then reenable interrupts as shown in

RED

in the code below. It should work if CDC_Transmit_FS() is called from the main loop, not an interrupt.

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)

{

  uint8_t result = USBD_OK;

  /* USER CODE BEGIN 7 */

  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;

  if (hcdc->TxState != 0){

    return USBD_BUSY;

  }

  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);

 

__disable_irq();    // added!

  result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);

 

__enable_irq();     // added!

  /* USER CODE END 7 */

  return result;

}

Hope this help!