I'm trying to integrate the Micrium OS-III USB stack into my product using a custom USB driver abstraction later. The USB class is mass-storage if it matters but the problem is more fundamental. The problem is as follows, after the enumeration and exchange of the descriptors, the USB stack opens EP1 IN and OUT for bulk transfers.
OUT transfers are done in 3 stages:
1) Configure the EasyDMA for the transfer by initialising the PTR and MAXCNT registers and writing to the SIZE register:
/* Configure the EasyDMA: */ lcx_usbd(LCX_USBD_0)->EPOUT[addr].PTR.PTR = (uint32_t) p_buf; lcx_usbd(LCX_USBD_0)->EPOUT[addr].MAXCNT.MAXCNT = 0U; /* Mark the transfer to be serviced by the EasyDMA: */ lcx_usbd(LCX_USBD_0)->SIZE.EPOUT[addr].SIZE = 0U;
2) Wait for the EPDATA event (handled in the ISR) and check EPDATASTATUS for the corresponding bit for the endpoint, Set the MAXCNT register to SIZE.EPOUT and trigger the corresponding STARTEPOUT task:
lcx_usbd(LCX_USBD_0)->EPOUT[addr].MAXCNT.MAXCNT = lcx_usbd(LCX_USBD_0)->SIZE.EPOUT[addr].SIZE; lcx_usbd_trigger_task(LCX_USBD_0, LCX_USBD_TASKS_STARTEPOUT_0 + addr);
3) Wait for the EPOUTEND event to mark the end of the transfer (or prepare for the next transfer).
I've put trace messages in each of these stages to monitor the events. The first few transactions happen as expected (the following messages are received from the trace console). In "O" or "I" indicate whether it's an IN or OUT transfer, the number following that indicated the endpoint number.
O1_INIT O1_START O1_END I1_INIT I1_START I1_END O1_INIT O1_START O1_END I1_INIT I1_START I1_END O1_START O1_END O1_INIT
As you can see, during the last transaction, state 2 is already triggered (EPDATA event generated) before we set SIZE.EPOUT[addr].SIZE to 0 to indicate to the DMA engine that the buffer is ready to receive data. According to the reference manual: "Once the EasyDMA is prepared and enabled, by writing the EPOUT[n] registers and triggering the STARTEPOUT[n] task, the incoming data will be transferred to Data RAM. Until that transfer is finished, the hardware will automatically NAK any other incoming OUT+DATA packets. Only when the EasyDMA transfer is done (signalled by the ENDEPOUT[n] event), or as soon as any values are written by the software in register SIZE.EPOUT[n], the endpoint n will accept incoming OUT+DATA again." The last sentence seem to suggest that when the previous transaction is finished (signalled by the ENDEPOUT event) the USBD peripheral will start to ACK further OUT transactions (generate EPDATA event) even before the software has had the chance to configure the buffer pointer etc. This looks like what is happening in my case. The problem is, how can I tell the USBD peripheral to NACK all further transactions until I've configured the pointers and the USB stack is ready to receive more data?