I have coded an LPC54608 application which includes a composite USB HS device (dual CDC) running on FreeRTOS, based upon the code provided in the SDK example (lpcxpresso54608_dev_composite_cdc_vcom_cdc_vcom_freertos), from SDK version 2.5.0. The code appears to work correctly most of the time, but when I carried out a more extensive testing I have found that the data in vcomInstance->currRecvBuf occasionally gets corrupted.
The USB_DeviceCdcVcomCallback() and the USB_DeviceCdcVcomTask() are called as expected, so the SDK code ‘appears’ to the working, but the data in the buffer is not always what I have sent. To confirm that the data is being sent correctly I added a CRC to my applications packet handling layer which confirms that I am indeed receiving USB data packets which occasionally contain invalid data.
I know the USB standard includes a CRC check at a lower layer for all data transfers, so only valid packets should be accepted by the USB peripheral device. Therefore, I can only presume that this data corruption is happening while the data is being passed from the USB controller up the SDK USB stack.
As I have mentioned this corruption only happens occasionally, less than 1% of data packets are affected, but absolutely no data corruption is allowed for my application. Due to the infrequent nature of the problem I have not been able to correlate the occurrence of the data corruption with any other USB events.
Just wondering if anyone else has seen this problem or can help me to resolve the root cause?
I think this is related to the next errata:
3.22 USB.15: USB high-speed device in endpoint TX data corruption
Please check the next link, under the errata section you will find a document that list some errors in the MCU and the workaround for it:
I hope this helps you.
Unfortunately not, I have been through the Errata document several times and cannot see anything which explains the problem.
In the case of the particular errata you referenced (3.22 USB.15: USB high-speed device in endpoint TX data corruption)
a) I am not seeing corruption of the first byte alone, and the corrupted byte value is not set to zero.
My protocol includes a typical header, count, and payload; the header bytes are generally fine, the count is sometimes corrupted, and sometimes it is the payload.
b) The corruption is happening on the RX (OUT) device side not the TX(IN) (unless the errata document has changed the USB IN/OUT naming convention around)
c) My test consists of repeated sending of 512 bytes long data packets to the LPC device without any response so that rules out the conditions listed in the errata.
Also, for that errata I previously requested further info on how one can send a NAK between RX and TX because from the API provided by the USB SDK it doesn't seem to me that the workaround is possible!
But thanks for your suggestion,
The byte sending occurs in FREERTOS task context while the USB currRecvBuf is filled in ISR context per 125uS in USB high speed.
If data copy and USB_DeviceCdcAcmSend is not done on time, data is corrupted.
One method can be done to confirm the fact
1. set GPIOA at entrance of USB_DeviceCdcVcomTask and clear it after data is sent.
2. toggle GPIOB in USB_DeviceCdcVcomCallback
Check the GPIOA and GPIOB sequence, there should be no GPIOB toggling when GPIO is high.
Has this issue been solved in the latest SDK or is it still an issue that requires a fix?
Thank you for your suggestion, but I'm still not entirely clear as to what the problem root-cause is.
Are you saying that the data from the currRecvBuf needs to be copied before the next send event?
If so then I can easily modify my code to achieve this, at present I simply signal an RTOS task to process this when ready.
Or, are you suggesting that the occurrence of a USB interrupt (calling USB_DeviceCdcVcomCallback) while USB_DeviceCdcAcmSend() is being called causes the corruption of the currRecvBuf?
As regards toggling the GPIO as you suggest, my understanding is that the send function USB_DeviceCdcAcmSend() simply queues the data for sending by the USB peripheral so the pin GPIOA would have to be set before sending and cleared in USB_DeviceCdcVcomCallback(). Is that what you are suggesting?
If so, then surely GPIOB toggling while GPIOA is high would simply be a function of the positioning of the two lines in USB_DeviceCdcVcomCallback().
By the way, I think the SDK example code contains a possible bug.
In USB_DeviceCdcVcomCallback() the handler for sending complete event includes code to reset the buffer for the next receive event (as shown in the code fragment below), why should the receiver be reset after a send event?
if ((epCbParam->length != 0) && (!(epCbParam->length % vcomInstance->bulkInEndpointMaxPacketSize)))
/* If the last packet is the size of endpoint, then send also zero-ended packet,
** meaning that we want to inform the host that we do not have any additional
** data, so it can flush the output.
error = USB_DeviceCdcAcmSend(handle, vcomInstance->bulkInEndpoint, NULL, 0);
else if ((1 == vcomInstance->attach) && (1 == vcomInstance->startTransactions))
if ((epCbParam->buffer != NULL) || ((epCbParam->buffer == NULL) && (epCbParam->length == 0)))
/* User: add your own code for send complete event */
/* Schedule buffer for next receive event */
error = USB_DeviceCdcAcmRecv(handle, vcomInstance->bulkOutEndpoint, vcomInstance->currRecvBuf, vcomInstance->bulkOutEndpointMaxPacketSize);
I have removed this from my own code and have seen no obvious side effects.
The USB stack manages low level NAK/ACK. Why isn't this work around implemented in the USB stack ?
I don't see how it could even be implemented to begin with because the code (whether it is application or USB stack itself) can not foresee when an RX (OUT) is about to come in because it could be happening on the hardware side before the ISR gets notified/invoked while the application/USB stack is about to prime a TX(IN).
Doesn't this compromise the use of LPC546xx for USB use ? This is a major flaw.