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.

MSP430F5529 USB CDC Stack issues

Other Parts Discussed in Thread: MSP430F5529

We're designing a board with the 5529 and a USB interface. 

We downloaded the CDC+HID API Stacks from the 5529 product page (slac285.zip) and copied the USB_CDC_API, USB_HID_API and USB_Common code from one of the examples into our project.  While debugging, I see that there are actually differences between the USB code modules in the different Example directories.  (see USB_Common/usb_eventHandling.c)  Particularly disturbing is the comment in USBCDC_Example6/USBCDC_Constructs.c suggesting that receiveDataInBuffer() is not supported.  Of these 6 examples, which one is "the right stuff?"  Is there a newer version than 1.12 (20-Jul-2009)?

The document "Starting a USB Design Using MSP430 MCUs" describes the USB module as a "full speed USB device (12 Mbps)," but it also qualifies device classes in Table 1, saying that CDC is "Fast (hundreds of KB/sec)"  Right now we're only getting about 27 KB/sec, which seems kind of slow.  Should we expect more?

We think we've run into a couple of bugs.  Has anyone else experienced these issues?

1.  Bulk data transfer through CDC intermittently causes a reset, until we configured the code to only send 64 bytes at a time.

2.  It appears that we have to activate/deactivate the USCI in USB_handleVbusOnEvent() and USB_handleVbusOffEvent() to get correct behavior when plugging/unplugging the USB cable.

Thanks,

Bob Techentin

  • Bob,

    The newer stack version is 1.18. It has addressed some issues similar to the ones you have quoted.

    Also we are seeing much better performance numbers.

    Can you contact Keith who owns these examples and can update the F5529 page for the latest releases?

    Thanks,

    Prathap.

  • The API stacks on the web are an early version, posted for pre-release sampling of the F552x.  Now with the F552x approaching release-to-production in January, we’ll be releasing the updated version Prathap mentioned.  The goal is to have all examples ported to that version before Christmas.  In this version, the projects will use the recently-released versions of IAR/CCS that include F552x support, rather than the earlier pre-release versions that required a patch. 

    It wasn’t intended there be differences in the constructs files from example to example… that’ll be fixed in the next rev.  The comment you see in Example 6 relates to a bug that was found in the call USBCDC_bytesInUSBBuffer() in v1.12, and that call is used by receiveDataInBuffer(). 

    Regarding speed, USB’s stated 12Mbps is only a theoretical max that doesn’t even include bus overhead, let alone other factors.  There are many system-wide factors (host, bus, device) that can affect bandwidth, especially for bulk transfers.  But 27KB/sec does indeed sound slow...  A big factor to consider is at the application level – i.e., what is the application doing between chunks of sent or received data.  Was this one of our examples or a custom application?  If you want to exclude application handling from the equation (for downstream), simply to test the pipe’s bandwidth, write an app that calls “USBCDC_rejectData()” every time you get a handleDataReceived() event.  Rejecting is the fastest thing you can do with the data. 

    Regarding your issues 1 and 2… #1 sounds maybe like a particular issue that was fixed, as Prathap said.  It has to do with how Windows interprets the end of a stream of data.  #2 hasn’t been observed that I'm aware of.  The only thing I can think of relates to interrupt priority – USCI is higher.  If for some reason your USCI disables interrupts for long periods – including having long ISRs – it could delay the host responding to any USB interrupt, including the ones you mentioned.  Long ISRs are generally discouraged in any context, not just USB, for this reason.  Could this be the case? 

    Regards,

    Keith

  • Thanks for the insights, Keith.

    I tried measuring the speed of your 1.12 Examples 5 & 6 (both sending bulk data from the device to the host), and the best I can get is about 63 KByte/sec, which is just 1/20th of the peak (12 Mbps).  Has anybody benchmarked this higher?  I've tried hypterterminal and custom serial applications on Windows and Linux, all with about the same results.

    (I'm going to look in to the interrupt thing.  Just haven't go there yet.)

    Bob

  • Bob,

    Try increasing the MCLK speed to the max -- this is another factor.  (Be sure to use the config constant in descriptors.h  -- I believe it's USB_MCLK_FREQ.)  I would try it on a different PC also.

    I assume you're doing this with nothing else attached to the PC?  Be aware that PCs often have 'internal' USB devices, and it's possible they may share the same host controller, thus sharing bandwidth.  Your Windows device manager can shed light on this.  (However, it would have to be a real bandwidth hog to be causing this, like a HDD moving a lot of data.)

    I would expect that the intermittent resets you mentioned earlier are probably affecting the bandwidth sa well -- to be fixed in the upcoming rev.

    Regards, Keith

  • Keith,

    I tried increasing USB_MCLK_FREQ from 8 to 16 million, but it had no effect.  My PC has four USB controllers, and I have tried several of them, all with the same results.  But I am beginning to suspect that the bottleneck is the Windows XP desktop.

    I have now have an Ellisys USB protocol analyzer, and I can look at the packets and transactions going between the device and the PC.  It turns out that the difference between the demo/example application (620 Kbits/sec) and my app (270 Kbits/sec) was handshaking for 1KByte data blocks.  In both cases, the MSP430 can blast data to the host in 63 byte packets at about 1000 per second.  And in both cases, the protocol analyzer shows that the MSP430 responds with data in about 4 microseconds.  The delay appears to be in the Windows device driver.  Here is the timing on two data transactions (3 packets each)

    Packet Type Direction Time (us)
    IN Packet (3 bytes) --> host to device 0
    DATA0 Packet (63 bytes) <-- device to host 3
    ACK Packet (1 byte) --> host to device 49
    IN Packet (3 bytes) --> host to device 996
    DATA1 Packet (63 bytes) <-- device to host 999
    ACK Packet (1 byte) --> host to device 1023

    Does anybody know of a Windows or Linux USB virtual COM port driver that doesn't lollygag quite so much between transactions?  Would a custom device driver be required?  Or is there some sort of asynchronous mode to be supported at both ends?

    Thanks,

    Bob

     

     

  • Hi.

    Just in relation to the newer version of the library mentioned earlier - I gather the plan is for them to be publicaly available after Christmas. Are they available (as beta) now, and more importantly, how is the MSD class library coming along?

    Thanks - Scott :)

  • I have downloaded the CDC+HID API Stacks v1.19 from the MSP430F5529 product page and tried the demos.  I still only get about 63 KByte/sec throughput.  And the USB analyzer still shows one transaction per (millisecond) frame.

    I also tried a couple of different driver options on the PC side, and found that the Jungo driver development kit ("windriver") gives me much higher throughput with the same firmware on the MPS430.  A full custom driver would probably give similar results.

     

  • I kind of hate to answer my own question, but ...

    The whole slow-speed (60 kbps) issue appears to be the fault of the Windows XP serial port driver.  I haven't figured out how to tell it to request more than one 63 byte packet per millisecond frame.  So there you go.  It is just slow.

    In the mean time, we licensed the Windows USB driver development package from http://www.jungo.com/, wrote a user-space device driver, and managed to achieve up to 3800 kbps, which is about a third of the theoretical maximum.    I can live with that.

     

  • Hi Bob,

    I came to the same conclusion on my end. Based on what I'd read in USB books, I expected to get a throughput of around 19 * 64 bytes per frame, when I'm getting the same 1/20th that you are using the virtual com ports.

    Thanks for the tip about jungo. I'll look into that.

    darkwzrd

  • Hi Bob,

    While playing around with the USB Stack today, I decided to look more into this issue with the Virtual Serial Port. I found a page on Jan Axelson's website that talks about USB Virtual Com Ports (http://www.lvr.com/usb_virtual_com_port.htm). It had this to say...

     

    For full-speed devices, set wMaxPacketSize in the bulk endpoint descriptors to 64 to enable transferring the most data possible in each USB transaction. With a UHCI host controller, if a full-speed bulk endpoint’s wMaxPacketSize is less than 64, the host controller schedules no more than one transaction per millisecond for the endpoint. (Full-speed host controllers comply with either the OHCI or the UHCI standard. Many PC motherboards contain UHCI controllers.) High-speed bulk endpoints must set wMaxPacketSize = 512.

     

    How about that! For a UHCI host, if the max packet size is 63 bytes, it only does ONE PACKET PER FRAME!

     

    So I went and tried the fix. Go into UsbCdc.c, and change EP_MAX_PACKET_SIZE_CDC  to 0x40. Note the comment that the author wrote. Well talk about that next.

     

    //workaround for CDC windows driver: it doesn't give data to Application if was sent 64 byte

    #define EP_MAX_PACKET_SIZE_CDC      0x40

    With the fix, it seems to go about 4 times faster than before (I did some measurements with a stopwatch, but I haven't looked at any packets in detail). Anyways, its something to look into.
    I did a bit more searching around about what the author was talking about and I found this (http://www.keil.com/forum/docs/thread13504.asp)....

    bulk IN EP
    Here, NAK flow control is applied, too. Just when we have data to send, the data is put to the bulk IN EP. When no data is written to the IN EP, no more EP interrupt is generated. Then, we have to poll the number of data on the TX buffer periodically out side of the EP ISR, too. SOF interrupt is often used for this purpose.

    When the last transaction is just 64 bytes, host controller waits for next short packets forever. Until receiving a shot packet, host controller doesn't pass the data to the input buffer on the PC device driver. In this case, Zero-Length Packet (ZLP) should be put to IN EP, to speed up the response of host. This ZLP is also added in SOF ISR.

    The version above is the "easy to understand" version, however, if you want a more definitive source see (www.usb.org/developers/devclass_docs/usbcdc11.pdf) page 24. 
    So basically you have a choice between sending a lot of data FAST (sending 64 bytes per packet) and having the Windows Driver sit on it, OR
    having the PC be really responsive and be really slow (sending 63 bytes or less per packet).
    My application tends not to care about data until it is all there, so I just sent a zero length packet when I had no more data. You could just as easily up the responsiveness of the PC by mixing in some sub-64 byte packets in the byte stream though.
    I am no longer working with the vanilla USB CDC stack (mine is very much changed from the original), so I cannot recommend an exact fix and test it. However if you want to send a zero length packet, I recommend that you do it here:
    //this function is used only by USB interrupt
    BOOL CdcToHostFromBuffer()
    {
        BYTE byte_count, nTmp2;
        BYTE * pEP1;
        BYTE * pEP2;
        BYTE * pCT1;
        BYTE * pCT2;
        BYTE bWakeUp = FALSE; //TRUE for wake up after interrupt
        static BYTE bZeroPacketSent; // = FALSE;
        if (CdcWriteCtrl.nCdcBytesToSendLeft == 0)           // do we have somtething to send?
        {
            if (!bZeroPacketSent)               // zero packet was not yet sent
            {
                bZeroPacketSent = TRUE;
                SEND ZERO PACKET HERE!
                CdcWriteCtrl.nCdcBytesToSend = 0;   // nothing to send
                //call event callback function
                if (wUsbEventMask & kUSB_sendCompletedEvent)
                {
                    bWakeUp = USBCDC_handleSendCompleted(1);
                }
            } // if (!bSentZeroPacket)
            return bWakeUp;
        }
    Hope this helps!
    darkwzrd

  • Ah Hah!

    Thanks for finding that, Darkwzrd.  I think I understand the issue now.

    I tried your fix - re-hacking the EP_MAX_PACKET_SIZE_CDC back to 64 bytes.  Since we are already using the Jungo driver on the PC side, I only saw a very modest performance improvement.

    It isn't clear to me what "SEND ZERO PACKET HERE!" means.  Can I just insert a call to USBCDC_sendData() inside this function called by the USB interrupt?  Does it have to be protected with pre-send or post-polling, as the API user documentation suggests?

    And finally, is this more sophisticated fix going to be integrated into the USB CDC stack and released?

    Thanks,

    Bob


  • Basically what "SEND ZERO PACKET HERE" means is you have to is write a zero to the current X/Y buffer count register. This will clear the NAK bit and set the size of the packet to zero bytes, informing the host that there is no more data.

     

    Please note that if you have the max set at 64, and you don't find a way to purge the buffer for your last transmission (any packet less than 64 bytes; zero or otherwise), the PC App won't have received ALL of it's data. You have to make sure to purge it if you set the max to 64.

     

    As for the pre-send/post-polling, I assume you are referring to table 30 on page 49 of the API document? If so, then yes, you still have to follow the appropriate rules noted in the document to use the constructs listed in USBCDC_constructs.c. I don't THINK you have to do anything else to get it to work. I rewrote the entire stack from the ground up, so I don't use their mechanisms anymore. Their stack is excellent for someone to get USB up and running quickly without much knowledge of USB or their stack, but its not exactly very good to put in a commercial embedded product. Using their stack as a working example was a huge help though, so kudos to them. I definitely couldn't have done it on my own.

     

    As for a "fix" in the next stack release, I don't think so. You see, my bet is that the author had a very specific reason to code it the way he did. That reason was compatibility with hyperterminal. The user types in a command on hyperterminal, which the target echoes back to the PC. In this case, a human is in control of the PC output (based on keyboard strokes). In order to have this system work correctly, the user needs to have immediate feedback from hyperterminal that the key they entered was the correct key. Thus, the max packet size was set at 63 bytes to guarantee that the windows driver always flushed its input buffer so hyperterminal could print to the screen. Really, the change to EP_MAX_PACKET_SIZE_CDC is not so much of a "fix" as it is a different system configuration.

     

    Perhaps they will create another example project that uses a 64 byte max, but that would require matching PC code to go with it. This might be too much to ask for some toy example code. However, I definitely think that TI should add some documentation to their API about this so that users are aware of it.

     

    Also, if you think I've answered your question, please feel free to verify my post as the answer. That way other people looking for the solution will know that one exists. I nominated your post a while back which stated (paraphrased) "TI's USB CDC Stack is just slow. There is no solution. Use Jungo." as a joke (the joke being the solution is there's no solution), and someone actually verified it! Ha!

  • darkwzrd said:
    I nominated your post a while back which stated (paraphrased) "TI's USB CDC Stack is just slow. There is no solution. Use Jungo." as a joke (the joke being the solution is there's no solution), and someone actually verified it! Ha!

    Even more of a joke is that the one verifying it was , a TI employee :)

  • Hey Jens,

    Since you put it out there I have to clarify that I was referring to the comment " The whole slow-speed (60 kbps) issue appears to be the fault of the Windows XP serial port driver" as the verified answer.

    Also, I don't/can't check back to see if these posts get edited.

    So if someone changed it to 'nothing works on my device' it would still show up as an answer verified by me!

    Regards,

    Priya

     

     

    chk

  • Priya Thanigai said:
    Since you put it out there I have to clarify that I was referring to the comment " The whole slow-speed (60 kbps) issue appears to be the fault of the Windows XP serial port driver" as the verified answer.

    Well Actually it wasn't I who did put it out. I just added the (already visible) information who did the verify and the (in all of your posts visible) information that you're an TI employee. I hope you didn't take it for more than it was (or anybody else).

    Anyway, verifying this (still correct) answer wasn't the point. The point was that it was meant as a joke and turned out to be an answer worth of verification by you. :)

    Priya Thanigai said:
    Also, I don't/can't check back to see if these posts get edited.


    Indeed, there's an 'last edited at...' hint missing in the forum interface when a post has been edited. Considering that it is already really slow, it should be able to add such an information without making it even slower.

    Priya Thanigai said:
    So if someone changed it to 'nothing works on my device' it would still show up as an answer verified by me!


    In case of an edit, the 'verified' state should be automatically reverted to 'suggested'.

    btw, I know that you edited your post at least once, since I got the original one per mail. But unless you tell me how much you get for it, I won't answer the (removed) question. :))

    You do a good job here.

  • Jens-Michael Gross said:
    In case of an edit, the 'verified' state should be automatically reverted to 'suggested'.

    Aah good catch. Actually the post changes to an 'in-between' state between suggested and verified.

    Jens-Michael Gross said:
    btw, I know that you edited your post at least once, since I got the original one per mail

     yes, there are some words better left unsaid ;)

    Jens-Michael Gross said:
    You do a good job here.

    Thanks.  Coming from you (one of the most prolific contributors in the MSP430 forum) that means something:)

    Btw, I enjoy your quotes the most ; esp 'I want shoes. What size shoes do I buy?!'

    Regards,

    Priya

**Attention** This is a public forum