Hi there,
I'm trying to get my AT91SAM7 based USB device enumerated and this seems to be really painful...
In the following lines I'll try to make a clear explaination of what my code actually does, step-by-step, later I will introduce some useful debug messages I managed to get from my device.
To keep it clear I will ommit all the initialization code since that seems to be ok (I thought so by reading the later debug messages from the device, should you want to see the init code I'll post it).
On receiving a setup packet (AT91C_UDP_RXSETUP is SET), the code actually:
- Read the endpoint's FIFO (8 bytes)
Code:
unsigned int i;
for(i=0; i < SETUP_PACKET_SZ; i++)
last_request[i] = AT91C_BASE_UDP->UDP_FDR[0];
- Fix data direction for the eventual data stage
Code:
if ((last_request[BM_REQUEST_TYPE] >> 7) & 1)
{
AT91C_BASE_UDP->UDP_FDR[0] |= AT91C_UDP_DIR;
while(!(AT91C_BASE_UDP->UDP_FDR[0] & AT91C_UDP_DIR));
}
else
{
AT91C_BASE_UDP->UDP_FDR[0] &= ~AT91C_UDP_DIR;
while(AT91C_BASE_UDP->UDP_FDR[0] & AT91C_UDP_DIR);
}
- Clear the RX Setup Flag in the EP's CSR:
Code:
AT91C_BASE_UDP->UDP_CSR[0] &= ~AT91C_UDP_RXSETUP;
while(AT91C_BASE_UDP->UDP_CSR[0] & AT91C_UDP_RXSETUP);
- Parse the setup packet
Code:
I'm ommitting this part of code since it's quite long, but it should be working fine, see later debug messages
- Whether the request has a data IN stage, prepare data to be sent in the FIFO buffer and let UDP know data is ready to be sent:
Code:
unsigned int i =0;
while( i < EP0_MAX_SIZE )
{
AT91C_BASE_UDP->UDP_FDR[0] = my_buffer[my_buffer_iterator];
my_buffer_iterator++;
i++;
}
AT91C_BASE_UDP->UDP_CSR[0] |= AT91C_UDP_TXPKTRDY;
while( !(AT91C_BASE_UDP->UDP_CSR[0] & AT91C_UDP_TXPKTRDY) );
- Exit from interrupt
On completing an IN transaction (AT91C_UDP_TXCOMP is SET), the code actually:
- Whether there is any other payload of data to send, prepare it in the FIFO buffer and let UDP know it is ready to be sent:
Code:
unsigned int i =0;
while( i < EP0_MAX_SIZE )
{
AT91C_BASE_UDP->UDP_FDR[0] = my_buffer[my_buffer_iterator];
my_buffer_iterator++;
i++;
}
AT91C_BASE_UDP->UDP_CSR[0] |= AT91C_UDP_TXPKTRDY;
while( !(AT91C_BASE_UDP->UDP_CSR[0] & AT91C_UDP_TXPKTRDY) );
- Clear the TXCOMP flag in EP's CSR:
Code:
AT91C_BASE_UDP->UDP_CSR[0] &= ~AT91C_UDP_TXCOMP;
while( AT91C_BASE_UDP->UDP_CSR[0] & AT91C_UDP_TXCOMP );
- Exit from interrupt
With this said, I've managed to put around some debug messages in the code, and here it is the output:
Code:
Device has been attached.
Resume request event occurred.
Start of frame event occurred.
Wakeup request event occurred.
Resume request event occurred.
Bus reset event occurred.
Resume request event occurred.
Bus reset event occurred.
EP0 Int. CSR Entry value: 0x00088804 .
Setup request received. B1=0x01000680 B2=0x00400000
Processing a GET_DESCRIPTOR request, setup stage
Processing a GET_DESCRIPTOR request, preparing IN data
EP0 Int. CSR Exit value: 0x00008001 .
Start of frame event occurred.
EP0 Int. CSR Entry value: 0x00008001 .
Processing a GET_DESCRIPTOR request, preparing IN data
EP0 Int. CSR Exit value: 0x00008010 .
Start of frame event occurred.
Bus reset event occurred.
EP0 Int. CSR Entry value: 0x00088804 .
Setup request received. B1=0x01000680 B2=0x00400000
Processing a GET_DESCRIPTOR request, setup stage
Processing a GET_DESCRIPTOR request, preparing IN data
EP0 Int. CSR Exit value: 0x00008001 .
Start of frame event occurred.
EP0 Int. CSR Entry value: 0x00008001 .
Processing a GET_DESCRIPTOR request, preparing IN data
EP0 Int. CSR Exit value: 0x00008010 .
Bus reset event occurred.
EP0 Int. CSR Entry value: 0x00088804 .
Setup request received. B1=0x01000680 B2=0x00400000
Processing a GET_DESCRIPTOR request, setup stage
Processing a GET_DESCRIPTOR request, preparing IN data
EP0 Int. CSR Exit value: 0x00008001 .
Start of frame event occurred.
EP0 Int. CSR Entry value: 0x00008001 .
Processing a GET_DESCRIPTOR request, preparing IN data
EP0 Int. CSR Exit value: 0x00008010 .
Start of frame event occurred.
The intersting part is the second one, the others are just the same (windows seems to be retrying the enumeration).
After receiving a setup request (GET_DESCRIPTOR), the device loads the first payload of data (first 8 bytes of the device descriptor) and quit from EP0 interrupt handling. The loading of the FIFO should be just fine, I introduced other debug messages to verify it and it looks OK (the bytes being pushed are the ones from my device descriptor):
Code:
Pushing 0x12 into FIFO buffer.
Pushing 0x01 into FIFO buffer.
Pushing 0x10 into FIFO buffer.
Pushing 0x01 into FIFO buffer.
Pushing 0x00 into FIFO buffer.
Pushing 0x00 into FIFO buffer.
Pushing 0x00 into FIFO buffer.
Pushing 0x08 into FIFO buffer.
The device is then interrupted another time by UDB because of partial transfer completion (AT91C_UDP_TXCOMP is SET), at this point it loads the second payload of data into the FIFO buffer and let UDP know it is ready to be sent.
As you can see from debug messages there are no other TXCOMP interrupts, so that data is actually not being requested by the host. This is fine since windows should start the status stage just after receiving the first packet of the device descriptor. The problem is that EP0 doesn't cause any further interrupts at all, maybe because the host doesn't actually send the 0-lenght data packet to begin status stage, or maybe because my device doesn't catch it, I don't know! After that windows resets the device and retries 2 more times.
At this point I really don't know what to think, maybe I'm missing something small in the whole thing, any suggestion would be really appriciated.