-
Notifications
You must be signed in to change notification settings - Fork 338
Description
It's been a while since I wanted to dive into LUFA code to understand how USB controllers work on 32u4 so I've finally got enough time to understand the code, which is really well written. I mean coming from Arduino USB code and Atmel's own demo code, I can see with the docs that come with LUFA you can actually understand what it's doing.
I'm writing my own USB device stack because of a special use case of 32u4. So my goal is to understand how it works. Been hacking the arduino USB code for some years but the way it's written is just a mess.
References I have:
- 32u4 full spec sheet with 2 chapters on USB controller. I also compared with at90USB1286, seems very similar albeit at90 is OTG capable.
- LUFA code
- Arduino USBCore.cpp etc.
Tools:
- Beagle USB protocol analyzer
- My own USB Host shield based protocol injector so it would do any requests I want.
I found some inconsistencies between the code I read and the spec sheet I read. I am hoping the LUFA folks will help me get over the difficulties because strictly following the spec sheets got my project derailed LOL
Confusions (two exactly):
- The process of set_address. In LUFA, it is inside DeviceStandardReq.c, the function USB_Device_SetAddress() does the following (my summary):
- Read new address
- Call USB_Device_SetDeviceAddress(), which simultaneously sets ADDEN and the address. Isn't this NOT ALLOWED in spec sheet?
- Call Endpoint_ClearSETUP () to clear RXSTPI
- Call Endpoint_ClearStatusStage(), which does status stage depending on request direction determined by USB_ControlRequest global struct
- Call USB_Device_EnableDeviceAddress() to set ADDEN bit
- Set USBDeviceState to Device_STATE_Addressed if the address isn't 0 else to DEVICE_STATE_Default
| static void USB_Device_SetAddress(void) |
Except for the last bullet point, everything else was hardware related. According to 32u4 spec sheet, one shall NOT set ADDEN and address at the same time but LUFA did it anyway. I've seen atmel and arduino code do the same. So isn't this bad idea? The status stage (ZLP IN) should carry default address of 0 instead of new address.
- A related confusion was inside Endpoint_ClearStatusStage(), which is in Endpoint_AVR8.c.
The last step of status stage is either release ZLP IN or receive and clear ZLP OUT. This function does this depending on the direction of the request. BUT, the Endpoint_ClearIN() and Endpoint_ClearOUT() both clear FIFOCON besides TXINI/RXOUTI. The spec sheet of 32u4 specifically says not to mess with FIFOCON for control endpoints. So why messing with it?
| void Endpoint_ClearStatusStage(void) |
Related inline declarations:
| static inline void Endpoint_ClearIN(void) |
Unless you define CONTROL_ONLY_DEVICE, which is considered "rare" in LUFA beginner's guide, you're clearing both FIFOCON and respective interrupt flag.