This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TAS1020B and 64-byte Endpoint 0 max packet size

The TAS1020B eval kit code v1.8 uses a default Endpoint 0 maximum packet size of 8 bytes. My application needs a 64-byte packet to support a big Feature report.  So, to that end,  I've set the bMaxPacketSize0 field in the device descriptor to 64 by changing the #define of DEV_MAX_EP0_PKT in devDesc.h. This has the effect of setting the USBENGINE_EP0_SIZE macro (actually UsbRequest.ep0MaxPacket) to 64 too.

But then things get really confusing. Looking at the original eval kit code, we see a bunch of #defines in devmap.h. (Aside: the comments at the top of this file think it's Mmap.h.)  A comment at the top of this file says, "The Ep0 temporary save buffer size is defined by the application. This buffer is not the same as the IN/OUT EP0 pipe buffers." Then there are two #defines: 

// the size of EP0 temporary save buffers:

#define DEV_USB_INEP0_SIZE 0x08

#define DEV_USB_OUTEP0_SIZE 0x08

So what exactly are the "EP0 temporary save buffers?"

Then there's another #define:

#define USB_EP0_XFERDATA_SIZE 0x10

and which is of course the same size as the two temporary save buffers. Why? This is used to (as far as I can tell) locate the start of endpoint 0 transfer data in the xdata-space RAM. Then the two "temporary save buffers" plus the transfer buffer are used to locate the USB_APP_ADDR_START address, which is where one of the FIFOs for the streaming audio data starts.

Now since I only need to Set this large feature report, and not Get it, my assumption is that the OUT endpoint buffer needs to be 64 bytes but the IN buffer can be 8. Is this correct? And why is the USB_EP0_XFERDATA_SIZE set to 16 above, and must I set it to 64 to accommodate my 64-byte EP0 max packet size?

This stuff is rather baffling ... any advice is appreciated.

 

 

  • Andy,

    When looking at the sample TAS1020B application, it may be helpful to keep in mind that the ROM application does run on every TAS1020B boot, and some of the stuff there in the ROM directory is needed for a complete ROM application.  If the ROM application doesn't find an application EEPROM, it needs to setup xdata so that it can respond to control requests.  If an application is found in the EEPROM, the application is free to setup things differently, but if the EEPROM application wants to use the application framework (or parts thereof) from the ROM, it will be limited as to flexibility.

    For example, if your application invokes
      devRomFunction(ROM_ENG_USB_INIT);
    then the ROM's engUsbInit() will be invoked, so IEP0 and OEP0 will be setup as per the ROM's engUsbInit().  That routine will set OEPBSIZ0 = IEPBSIZ0 = UsbRequest.ep0MaxPacket >> 3, so in theory your app could overwrite UsbRequest.ep0MaxPacket with 64 before invoking devRomFunction(ROM_ENG_USB_INIT), and the setup would be done correctly, though that would result in both IN0 and OUT0 buffers being large (the USB 1.1 spec doesn't explicitly say that bMaxPacketSize0 pertains to both in and out, but the code here makes that assumption).

    As an alternative, suppose you leave the sizes of IEP0 and OEP0 at 8 bytes, but increase the size of USB_EP0_XFERDATA to 64 bytes.  The host will chunkify the outgoing data into 8-byte chunks, which engSaveRxFifo() will concatenate into USB_EP0_XFERDATA.  usbProtocolHandler() won't be invoked until the byte count provided in the Setup Data has arrived, and there the data will be, sitting in USB_EP0_XFERDATA, all nicely reformed. 

    Granted, this approach involves more USB overhead than making OEP0 bigger, but:
    - one would _still_ need to make USB_EP0_XFERDATA larger, since the incoming packet is copied there by the the ROM code so the engine can be ready for the next transfer
    - the USB overhead is probably not material in the overall scheme of things.

    Regards,

    Frank

  • Hi, Frank,

    Thanks for the thoughtful reply.

    So assume that I have an application EEPROM. (This whole exercise is about using HID to support firmware update, instead of using DFU, simply because implementing a DFU host driver is a non-starter for a bunch of Real Good Reasons.)

    I do call devRomFunction(ROM_ENG_USB_INIT)on the assumption that I have to. Immediately before calling that function, I set the USBENGINE_EP0_SIZE to the DEV_MAX_EP0_PKT, which in the eval code is 8.

    I spent some quality time with the USB spec, and my understanding is that I'm free to do an HID SetFeature() with a report larger than the endpoint 0 max packet size, as the transaction will be broken up into several packets. And that's what you indicate above. The reason for choosing to use the 64-byte Endpoint 0 max packet size was to make my life easier in dealing with a 35-byte payload (Report ID, two bytes for EPROM destination address, and 32 bytes of firmware image data) as I didn't understand how the engine in the ROM would deal with the oversize packet.

    Therefore, I can set the Endpoint 0 Max Packet size in the device descriptor to 8, which means some amount of USB overhead doing multiple transactions to get the large report to the device. This, as you say, isn't a concern. I'll have smaller (8 bytes each) endpoint buffers (thus saving memory); these buffer sizes are determined by #define-ing DEV_USB_INEP0_SIZE 0x08 and DEV_USB_OUTEP0_SIZE 0x08 in devmap.h. USBENGINE_EP0_SIZE must also be set to 8. Then I will set the USB_EP0_XFERDATA to 64 (or whatever multiple-of-8 will be most memory-efficient, which would be 40 in my case), then when I get the report in the DEV_HIDSETREPORT handler it will be complete because the USB engine won't actually call DevFunctionEntryParser() until the entire 35-byte payload has been collected into USB_EP0_XFERDATA[].

     

    So I think this answers my question ... I'll implement all of this and report back.

  • Andy,

    > ... implementing a DFU host driver is a non-starter ...

    If you are targeting Windows hosts, have you looked at WinUSB for this?  It can be used to perform control transactions, though cannot be used to initiate a USB bus reset. 

    I'd be interested in hearing your Reasons.

    >  I'll implement all of this and report back.

    Please do!

    Regards,

    Frank

  • Frank Minich said:

    Andy,

    > ... implementing a DFU host driver is a non-starter ...

    If you are targeting Windows hosts, have you looked at WinUSB for this?  I've used it in the past for something else, but have the impression that it allows an app to perform control transactions (though not positive).  I'd be interested in hearing your Reasons.

    It needs to support OS X as well.

    (BTW: on OS X, all of the various Audio Control Features, such as gain, volume, etc are well-supported. On Windows, it's still a clusterfsck. The programmer with whom I'm working is pulling his hair out. We decided to bypass all of it and provide access to input gain through an HID Feature Report. Sheesh.)

    -a

  • Hi, Frank,

    I am back on this.

    I ran into a serious problem increasing USB_EP0_XFERDATA_SIZE from 16 (the default in the FDK code) to 40, while leaving the endpoint packet size at 8 each.

    Yes, the micro did as you described; multiple packets were necessary to fill the USB_EP0_XFERDATA buffer before the handler was called, and this allowed me to do the firmware-update thing. The HID interface also uses single-byte Feature reports for gain and other controls. Report ID 1 is the other controls, Report ID 2 is channel 1 input gain, report ID 3 is channel 2 input gain, etc. (The reason for using HID Feature reports to set gain is because Windows, hatefully, does not easily allow you to use the Audio Control features to actually control input gain in a reasonable way! Unlike OS X, which of course, just works. But I digress ...)

    Under stress testing with audio going, if I sent repeated control-change SetFeature() reports (obviously not a real user case) I noticed that my hardware stopped responding. The audio might still be going, but the gain change messages were being dropped on the floor. And, at some point, the audio would stop, too. My bus analyzer told me that some of the OUT transactions on the control endpoint, related to the gain changes, were being stalled. Nothing in my user code would do that, so I surmised that the packets were getting bolloxed in the micro, and the parser in the ROM would give up and assert the stall.

    But why would this happen? I reverted back to the original 16-byte USB_EP0_XFERDATA_SIZE, and the problem went away.

    So my guess is that the weapons-grade bullshit #defines in Devmap.h and Mmap.h and wherever else were doing the wrong thing, and either the streaming endpoint buffer was overlapping the endpoint 0 buffer, or one of the buffers ended up in an illegal location, or something else, I don't know.

    <rant>

    And I know you didn't write the firmware in the FDK, and it will never be updated, but it's an unmitigated disaster. It's full of header files referencing other header files in a circular manner, comments that are meaningless or wrong, and more. Like in Mmap.h, referring to a #define of ROM_TEMP_PDATAGROUPSIZE: "This value is known only at compiled time. If the size is more than 0x40, we have to update this value." Of course it's #defined to be 0x28, and there's absolutely no explanation of what this value is used for, or why it would be changed from the default!

    Another ball of confusion is in Mmap.h as well. There are two #defines related to endpoint 0:

    // Temprary storage for transaction either IN or OUT. The size is supposed to be
    // be defined by the application. This buffer is intended to be used for passing
    // values by the Usb engine/Usb higher protocol handlers and applications
    #define USB_EP0_XFERDATA_ADDR (OUTPACK_ADDR + OUTPACK_RSIZE)
    #define USB_EP0_XFERDATA      stc_sfr_array(USB_EP0_XFERDATA_ADDR)
    and of course in Devmap.h we have:
    // the size of EP0 temporary save buffer
    #define DEV_USB_INEP0_SIZE 0x08
    #define DEV_USB_OUTEP0_SIZE 0x08

    // This is the buffer that endpoint data ends up in or is removed from.
    #define USB_EP0_XFERDATA_SIZE 16
    #define USB_DEV_EP0_XFERDATA  stc_sfr_array(INPACK_ADDR + USB_EP0_XFERDATA_SIZE)
    #define USB_APP_ADDR_START    (INPACK_ADDR + DEV_USB_INEP0_SIZE + DEV_USB_OUTEP0_SIZE + USB_EP0_XFERDATA_SIZE)

    Why two similar, but different, #defines? It's so clever that the only person who could reasonably understand it is the guy who came up with this spaghetti. The code is a hack and should not have been released to customers, and it certainly wouldn't pass a code review.

    </rant>

    So the obvious solution would be to not allow anyone to do firmware updates when the audio engine is active, so the FWU process can use as much of the XDATA RAM as it might need, but that requires convincing the operating system to not use the audio interface ...

  • Andy,

    It's very unlikely that _anything_ in the ROM directory will ever be changed, even if there is a revision to the FDK, because that represents the project as it was when the ROM image was created.  There may be some cleanup in other directories;  if so, I will try to address these and other problems.

    According to the Universal Serial Bus Device Class Specification for Device Firmware Upgrade, Version 1.0 of May 13, 1999, downloading is only supported in a mode wherein DFU is the only public interface (see Section 2).  So, audio should not be active during this timeframe.

    As to the SetFeature reports being dropped - would you have a USB trace that shows a sequence?  Another user had problems with the TAS1020B failing to return STALL on error - is that possibly this scenario?

    Regards,

    Frank

  • Frank Minich said:

    Andy,

    It's very unlikely that _anything_ in the ROM directory will ever be changed, even if there is a revision to the FDK, because that represents the project as it was when the ROM image was created.  There may be some cleanup in other directories;  if so, I will try to address these and other problems.

    Cleanup is definitely necessary. There are too many circular and/or conflicting definitions and such.

    According to the Universal Serial Bus Device Class Specification for Device Firmware Upgrade, Version 1.0 of May 13, 1999, downloading is only supported in a mode wherein DFU is the only public interface (see Section 2).  So, audio should not be active during this timeframe.

    Understood, but I am not using the DFU class for a bunch of reasons. Now, if only there was a way to actually ensure that the audio interfaces weren't active when writing new firmware. Actually, there is: re-enumerate as a different device which has no audio interfaces.

    But if you think of this process as simply "writing some data to an EEPROM in the device," since the EEPROM is only read at boot time, there's no particular reason why this won't work. (To get the device to recognize the new firmware, the user has to unplug and replug the device, which isn't really all that tragic.)

    As to the SetFeature reports being dropped - would you have a USB trace that shows a sequence?  Another user had problems with the TAS1020B failing to return STALL on error - is that possibly this scenario?

    Actually, I'm seeing STALLs on bus traces -- but I don't know what's causing the errors, because the packets going down are, at least according to bus traces, correct.

    After a lot more investigation -- and I swear I'd give up something of value for a JTAG debugger, and I'll never use a micro that doesn't have this support ever again -- my guess is that due to confused #defines, my Endpoint 0 buffer is overlapping one of the audio endpoint buffers. I use SetFeature reports for gain control, and since the user is reasonably expected to change input gain while the audio is running, obviously I need to have the HID interface not get clobbered by the audio interface.

    I suspect the overlap because odd things will happen after sending the gain control features ... the device will sometimes set the gain to an incorrect value, or it'll trip up something else. In an extreme case, the audio engine itself gets hung up.

    In the DevFunctionEntryParser() function, I parse that the command is DEV_HIDSETREPORT, and further parse the Report ID. Since the reports are single bytes, I copy the contents of USB_EP0_XFERDATA[1] (byte [0] is the report ID) to the appropriate member variable in the device record, and set a bit flag that says, "This thing changed." Back in the main loop, I look for that bit flag and if it's set, then do the Right Thing (after clearing the bit). 

    When I see the bus STALLs, I assume that the ROM code can't grok the packet and it never gets to DevFunctionEntryParser() for further handling. Hard to tell without in-circuit debug.

    Anyways, the reason for the above rant is that since the endpoint buffer locations as set using OEPBBAXx and IEPBBAXx register assignments are derived using the intertwined REALLY FRICKIN' CLEVER #defines, and some things are #defined in the ROM\Mmap.h which is assumed to be immutable so it's all really confusing. I think what's going on is that if I change the default endpoint 0 buffer size/location (set in Devmap.h) and I don't manage to update it in Mmap.h (again, WTF does this mean:

    // This value is known only at compiled time

    // If the size is more than 0x40, we have to

    // update this value

    #define ROM_TEMP_PDATAGROUP_SIZE   0x28

    ??) then things get screwed up.

    I'm about to parse the #defines by hand to see exactly what's happening. But the circular references and the utter lack of useful code documentation make this really difficult because I am never quite sure what the code actually uses!