I have been using a USB CDC device driver successfully for a few years but recently had an instance where the emumeration once took some time to take place. This provoked an investigation which culminated in a stress-test being devised which sends the SET_LINE_CODING (used to configure the serial settings like Baud rate) repeatedly at a high rate.
The uses a SETUP token (class request OUT 0x20) and is a bit special because most other class SETUP tokens are not accompanied by data.
The result was that at some point during the test (maybe it took 1000 repetitions - sometimes more but also often less) the endpoint 0 operation would make a mistake (other endpoints still operate) and the USB host interface would stop and timeout (30s typical) before continuing normally again until the error maybe re-occurs at some point later in the stress test.
The first thing found was that the SETUP tokens are usually received in the EVEN frame buffer. When the problem occurs the frame however is received in the ODD frame buffer. The USD device is acknowledging the data and the host is then expecting a zero data termination. This is never sent back because the DATA1 frame neither causes an interrupt to be generated (the Kinetis SW is still expecting the data to be received) nor can be found in the receive frame buffer.
After various attempts to work out why the USB device was acknowledging the data but the data content not actually being received by the Kinetis SW driver layer a solution was identified:
Originally the code (for SETUP tokens) did:
- determine which frame buffer the reception is in (ODD or EVEN)
- ensure that the alternative frame buffer is free to receive (set OWN flag)
- allow SIE to continue token processing [CTL &= ~TXSUSPEND_TOKENBUSY;]
- handle the reception frame content
- clear the interrupt status
The 'solution' to the problem was to remove the [CTL &= ~TXSUSPEND_TOKENBUSY;] to after the reception frame content processing.
Now I never really understood the TXSUSPEND_TOKENBUSY bit but, if I remember correctly, its position was taken from a Freescale example (Coldfire at the time). I am wondering whether someone can explain the behaviour seen in relation to this bit??