32u4 USB setup packet handing question

1 post / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm writing my own ISR to handle USB setup requests. Trying to handle set_address request, which is a host-2-device request with on OUT stage.

 

So I spelled out the steps outlined in the doc, which I quote:

 

The USB device address is set up according to the USB protocol:
• the USB device, after power-up, responds at address 0
• the host sends a SETUP command (SET_ADDRESS(addr)),
• the firmware handles this request, and records that address in UADD, but keep ADDEN
cleared,
• the USB device firmware sends an IN command of 0 bytes (IN 0 Zero Length Packet), (I think this is because we need to complete the status stage in the old address so it must be done before ADDEN is set).
• then, the firmware can enable the USB device address by setting ADDEN. The only accepted
address by the controller is the one stored in UADD.
ADDEN and UADD shall not be written at the same time.
UADD contains the default address 00h after a power-up or USB reset.

So as the code below indicates, I store the address in UADD, keeping ADDEN at 0.

I then wait for a TXINI to know there is a blank TXIN.

I then release the TXIN by clearing the bit.

After that I set ADDEN.

This procedure causes no TXIN to be received by host. I'm watching the traffic on a beagle USB protocol analyzer.

 

				//if (setup.wLength) WaitForRXOUTI();	// Wait for the first packet of OUT data if there is any.
				switch (setup.bRequest)
				{
					case SET_ADDRESS:	// H2D ctrl xfer no OUT data
					UDADDR = setup.wValueL;	// Record address
					WaitForTXINI();			// Wait for an available IN bank to send ZLF IN in status stage
					ClearTXINI();			// Clear TXINI to send ZLP IN for the status stage.
					UDADDR |= (1<<ADDEN);	// Enable new address

					break;

					default:
					// Error, unsupported standard request.
					stalled=1;
					break;
				}
				if (!stalled)
				{
					if (setup.bRequest!=SET_ADDRESS)	// SET_ADDRESS has its own sequence that 32u4 is expected to follow.
					{
						WaitForTXINI();	// Wait for an available IN bank to send ZLF IN in status stage
						ClearTXINI();	// Clear TXINI to send ZLP IN for the status stage.
					}
				}
				else Stall();

All of the inline calls are trivial. WaitForXXX will run a while loop until the respective bit is set. ClearXXX will clear the respective bit.

So the set_address command times out, with no ZLP IN, which is surprising. But, if I add an additional ClearTXINI at the beginning of the set_address case, it works. I have separately working get_descriptor so I can repeatedly ask for descriptors after set_address and that works.

 

					ClearTXINI();	// Arduino handler has this one and another one at the end but why?

This line solves the problem. I really don't know why this would work. It's in the Arduino version not LUFA. I'm not interested in reading LUFA at the moment. Did that a while ago it looks great and is the best USB code for atmel written by the most qualified expert on this matter. But as good as it looks, it's un-simple and has to handle a zoo of different chips. I just need to confirm an average developer only trying to figure out 32u4 has a chance to understand by doing it.

 

So if someone knows why a clear TXINI must be done before handling a ctrl xfer OUT and the another after handling, please respond. Again, not interested in pointer to LUFA. I'm sure it works for 99% of people but I'm only interested in simple code to help me understand both USB and 32u4.

 

Attached is a diagram. As you can see, the TXINI stays high because I think there is a blank TXIN for use, and you only clear it at the status stage, once, not twice once at beginning and once at the status stage.

 

I'd like to assume that the get_descriptor request before set_address was successful and didn't leave any junk because the sequence looks correct on protocol analyzer. I added the set_configuration case later, without the ClearTXINI() to start the case with and it works. This seems to be an issue only affecting set_address so it MUST be my understanding issue.

Attachment(s): 

30+ yr in programming, 20+ years in experimental physics, 10+ yr in embedded system development
Experience across many industries