|
Hi Paul,
I have new information about the USB problem. I found that with our implementation the problem lies in the SET_CSR macro. When this macro is called from both a foreground and background context then there is an issue that the original creator of the USB driver overlooked. To solve this I converted the macro into a dedicated C function for the TXPKTRDY bit and use this function whenever the TXPKTRDY bit needs to be set. Below is the code. The large comment in this functions describes the issue and the workaround.
void SET_CSR_TXPKTRDY(unsigned char endpoint) { volatile unsigned int reg; DWORD TimeOutCount; /* Wait until TXPKTRDY bit is 0. */ TimeOutCount = USB_TIME_OUT_COUNT_START_VALUE; do { reg = AT91C_BASE_UDP->UDP_CSR[endpoint]; TimeOutCount--; } while (((reg & AT91C_UDP_TXPKTRDY)== AT91C_UDP_TXPKTRDY) && TimeOutCount); reg |= REG_NO_EFFECT_1_ALL; reg |= AT91C_UDP_TXPKTRDY; AT91C_BASE_UDP->UDP_CSR[endpoint] = reg; // See datasheet paragraph 34.6.10: Due to synchronization between MCK and UDPCK, the software application must wait for the end of the write // operation before executing another write by polling the bits which must be set/cleared. // Note that we cannot read the CSR here until the TXPKTRDY bit that we forced to 1 are is read back as 1. // The reason for this is that an interrupt may occur in the meanwhile which may take some time to handle. If during this interrupt the USB // finishes handling the FIFO and clears TXPKTRDY again, we may never see it rise when control is returned to here after the interrupt!!! // In practice we have seen the original Atmel driver hang on this. // So we remove the while-loop for the TXPKTRDY bit. // However, to fulfill the requirement of synchronization between MCK and UDPCK we just do a dummy read of CSR here. reg = AT91C_BASE_UDP->UDP_CSR[endpoint]; }
Some additional hints: - Include time out counters in all while-loops of the driver. So no infinite looping if bit clear/bit set is missed. - Special case is EPEDS bit for control endpoint. To our experience this bit sometimes is set but not read back as 1. See description of this bit in paragraph 34.6.10 of datasheet for explanation why this may occur. In our implementation we also made a workaround for this.
With all these improvements and workaround the USB driver has become really stable now. (AT91SAM7XC512)
|