2017-01-31 05:32 PM
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 #usb2017-02-06 04:53 PM
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.
2017-02-23 01:25 PM
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!