This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

USB Composite VCOM Speed

Dear all,
Thanks a lot for every consecutive help i get from this forum and a special thanks to Tsuneo.

I downloaded VCOM example program from keil but that doesn't fits to my requirement.

The code doesn't work if I transmit the data as soon as i receive the IN interrupt.

I want to transmit 64bytes in 1 ms. i tried changing the usbdesc.c but it doesn't transmits the data at this rate and makes the PC to go hang.

My minimum requirement is to tranmsit 30KBytes/sec.

I highly appreciate your help.

Parents
  • "I want to transmit 64bytes in 1 ms."

    Put ZLP (Zero-Length Packet) to the bulk IN EP, as the next packet just after the 64 bytes.

    64 bytes is a critical number for the bulk IN EP on Full speed, because it matches just to the wMaxPacketSize of the EP. While the firmware puts 64 bytes, the transfer continues. The host controller on the PC holds the packets and it doesn't hand the packets to the device driver, until it sees a short packet (including ZLP). Then, your host app hangs, dried up by no input.

    To put a ZLP to the IN EP, USB_WriteEP( the_EP, NULL, 0 );

    Tsuneo

Reply
  • "I want to transmit 64bytes in 1 ms."

    Put ZLP (Zero-Length Packet) to the bulk IN EP, as the next packet just after the 64 bytes.

    64 bytes is a critical number for the bulk IN EP on Full speed, because it matches just to the wMaxPacketSize of the EP. While the firmware puts 64 bytes, the transfer continues. The host controller on the PC holds the packets and it doesn't hand the packets to the device driver, until it sees a short packet (including ZLP). Then, your host app hangs, dried up by no input.

    To put a ZLP to the IN EP, USB_WriteEP( the_EP, NULL, 0 );

    Tsuneo

Children
  • I've seen this kind of question related to "transfer" many times.
    The understanding of "transfer" and its termination is the first hurdle in USB study.

    1) Transfer

    "Transfer" is the greatest unit of communication sequence on USB.
    USB carries transfer splitting into packets(*) on the bus. The wMaxPacketSize field of the endpoint descriptor determines the size of division unit.

    Host app handles transfer directly, and firmware does in the split shape, a sequence of packets.

    For example, suppose that a host app sends 200 bytes of data. It is sent by single WriteFile (or equivalent call) to the device driver. The device driver and the host controller splits it into packets, according to the wMaxPacketSize of the endpoint. When wMaxPacketSize = 64, the firmware sees this sequence of packets.

    64 + 64 + 64 + 8

    In the opposite direction, also, the reverse process is done; the firmware sends a sequence of packets, they are combined together into a single block, and handed to the host app as a single transfer.

    In this way, any size of transfer is carried over USB, even if it grows up to MBytes.


    2) Termination of transfer

    USB spec defines the end of bulk and interrupt transfer as follows,

    a) Has transferred exactly the amount of data expected
    b) Transfers a packet with a payload size less than wMaxPacketSize or transfers a zero-length packet
    
    5.8.3 Bulk Transfer Packet Size Constraints (usb_20.pdf p53)
    5.7.3 Interrupt Transfer Packet Size Constraints (usb_20.pdf p49)
    

    a) Expected transfer size
    The host side always knows the expected transfer size, because any transfer is initiated by the host, regardless of the transfer direction, IN or OUT.

    For example, these parameters of ReadFile and WriteFile mean the expected transfer size.
    ReadFile( ..., nNumberOfBytesToRead, ...)
    WriteFile(..., nNumberOfBytesToWrite, ...)

    On the other hand, the firmware doesn't know the expected size,
    unless the host sends it to the firmware beforehand,
    OR, it is documented explicitly as the protocol design.

    b) Short packet
    Short packets means a packet shorter than wMaxPacketSize, including ZLP.
    As above example shows, each packet on a transfer has wMaxPacketSize of data, until the last one. A short packet appears at the end of transfer.

    When the transfer size is just the multiple of wMaxPacketSize, ZLP is appended to the transfer to stop the transfer in halfway, before the transfer size reaches to the expected size.

    For example, the host app requests 200 bytes transfer,
    nNumberOfBytesToRead = 200;
    ReadFile( ..., nNumberOfBytesToRead, ...);

    And the firmware returns 128 bytes (wMaxPacketSize = 64),
    64 + 64 + 0(ZLP)

    ZLP is appended because the firmware cuts off the transfer.

    However, the host app requests just 128 bytes here, no ZLP is required, because it matches to the expected size.

    nNumberOfBytesToRead = 128;
    ReadFile( ..., nNumberOfBytesToRead, ...);
    64 + 64 (no ZLP)

    Please note, ZLP is seen just for IN transfers, not for OUT transfers, because host always sends just the expected size of OUT transfers. No way to stop it without error.


    3) The CDC device driver

    A generic device driver is supposed in above examples.
    However, the CDC device driver issues bulk IN transfer by itself. ReadFile doesn't directly link to the USB transfer any more. ReadFile just reads the data on the RX buffer on the device driver.

    The expected size for the bulk IN transfer is not clear (maybe it depends on Windows version), MS haven't documented anywhere. But It seems greater than 4 Kbytes.
    Then, always put ZLP, whenever the transfer size is just the multiple of 64 bytes on the firmware.


    This is the full story of transfer and ZLP.
    Complicated?
    That is why it is called as the first hurdle of USB :-)

    (*)For simplicity, I dare to use the term "packet" incorrectly in USB sense here. More precisely, it is called as the payload of the DATA packet on an IN/OUT transaction.

    Tsuneo

  • Hi Tsuneo,
    Thanks for the reply and that very useful information. I am getting a weird problem. Now i have made the max packet size as 32 and IN token time as 8 ms. I am using two VCOM ports.

    Have made few changes in the code.

    void USB_EndPoint2 (DWORD event) {
      switch (event) {
        case USB_EVT_IN:
            USB_WriteEP(0x82, A_TxData0_U8R, 32);
    
    

    In usbDesc.c i have changed the time to 8 ms, USB_MAX_PACKET0 as 34,
    WBVAL(0x20),/* wMaxPacketSize */.

    My firmware always transfers an array A_TxData0_U8R of size 32 byte.

    Even with this simple code the PC comes to hang.
    I am not able to troubleshoot it.

    It would be even fine if I can transfer 32Bytes in 1 ms from 1 VCOM port.

    Another interesting thing is if I set a flag in the void USB_EndPoint2 (DWORD event) function, check that in main(), and transfer the data after 4 ms, it works. But according to my design constrains i cannot go with this implementation.

    Please guide me how i can overcome this problem. If you can give some coding help also, it would be very great.

    Thanks!
    Kamal

  • Hi Tsuneo,
    Thanks for the reply and that very useful information. I am getting a weird problem. Now i have made the max packet size as 32 and IN token time as 8 ms. I am using two VCOM ports.

    Have made few changes in the code.

    void USB_EndPoint2 (DWORD event) {
      switch (event) {
        case USB_EVT_IN:
            USB_WriteEP(0x82, A_TxData0_U8R, 32);
    
    

    In usbDesc.c i have changed the time to 8 ms, USB_MAX_PACKET0 as 34,
    WBVAL(0x20),/* wMaxPacketSize */.

    My firmware always transfers an array A_TxData0_U8R of size 32 byte.

    Even with this simple code the PC comes to hang.
    I am not able to troubleshoot it.

    It would be even fine if I can transfer 32Bytes in 1 ms from 1 VCOM port.

    Another interesting thing is if I set a flag in the void USB_EndPoint2 (DWORD event) function, check that in main(), and transfer the data after 4 ms, it works. But according to my design constrains i cannot go with this implementation.

    Please guide me how i can overcome this problem. If you can give some coding help also, it would be very great.

    Thanks!
    Kamal

  • Are you working on KEIL MCB23xx USBCDC example?

    If you send just 32 bytes, you don't need to change any descriptors.
    The default wMaxPacketSize (= 64) is good for your requirement.
    32 bytes transfer is less than 64. Then, the single packet terminate the transfer well.

    You've modified the USB EP Interrupt Service Routine (ISR), USB_EndPoint2().
    But it is a wrong place to modify.
    As VCOM_GetChar() (vcomdemo.c) does, call USB_WriteEP() directly in the routine in which the data is generated.

    For IN EP, the EP interrupt is evoked just when the EP buffer becomes empty. The interrupt is not evoked until you put some data to the EP buffer, outside of the ISR. Therefore, USB_EndPoint2() is never called for the IN EP.

    It is similar to UART TX.
    UART TX interrupt is evoked when the UART TX buffer becomes empty. The interrupt is not evoked until you put a byte to the UART TX buffer. Then, you need a kick-off routine to fill the first byte, even if UART TX is handled using interrupt.

    Tsuneo

  • Hi,

    I am using VCOM example for MCB2140 board provided by Nxp. I am calling USB_Write() first in configuration function and then in EP interrupt functions. I have made no changes in ISR routine. just have made the time to 8 ms and MaxPacket size to 32. it doesn't work even if i make the packet size to 64 or even 16.

    The PC comes to hang... not able to troubleshoot at all.

    Kamal

  • "I downloaded VCOM example program from keil"
    "I am using VCOM example for MCB2140 board provided by Nxp."

    Are you talking about this NXP example?

    "AN10420: USB Virtual COM Port on LPC214x"
    www.standardics.nxp.com/.../an10420.pdf

    "Sample Code for AN10420 USB Virtual COM Port on LPC214x"
    www.standardics.nxp.com/.../code.lpc214x.usb.zip

    Tsuneo

  • Yes, Its exactly the same.
    I have commented the other USB_WriteEP() functions and in main have just kept a while(1); And the USB_WriteEP is getting called by UAB_EndPoint2();

    Kamal

  • Hi Tsuneo,

    I again reviewed the code and couldn't trace out the bug. I am using the PC side driver provided in the same sandbox.

    I hope you have that VCOM example with you. I have a buffer of 64Bytes with some const datas lets say "aaaa.............1234"; I have to transfer it at every 1ms or 2ms. Can you suggest me what code to comment and what to be added where? I have nothing to do with UART in that code. Board just sends the data. Receiption is event triggered from same VCOM.

    Thanks
    Kamal

  • For the NXP VCOM example also, the principle is the same.

    You don't need to modify any descriptor.

    In the main loop, disable DeviceData2Host( 0 ) call.
    Then, you can use the IN EP2 freely.

    demo.c
    int main (void) {
      ...
      while (1)           /* Loop forever */
      {
    #if USB_VCOM
        if ( /*Data2Host0 ||*/ Data2Host1 ) {
    //     DeviceData2Host( 0 );
           DeviceData2Host( 1 );
        }
        ...
    #endif
      }
    

    Next, enable SOF interrupt as 1ms timer.

    usbcfg.h
    #define USB_SOF_EVENT       1
    

    In the SOF handler, send 64 bytes data on your buffer to the IN EP2. Also, send ZLP at the first IN EP2 interrupt.

    vcomuser.c
    
    /*
     *  USB Start of frame Event Callback
     *    Parameter:       frame: 11-bit Frame Number
     */
    
    #if USB_SOF_EVENT
    void USB_SOF_Event (DWORD frame) {
      if ( Data2Host0 ) {
        if ( your_data_is_ready ) {
          //
          // fill your buffer with 64 bytes data here
          //
          USB_WriteEP( USB_ENDPOINT_IN(2), your_buffer_ptr, 64 );  // send 64 bytes data
          Data2Host0 = 0;
        }
      }
      frame;
    }
    #endif
    ...
    ...
    /*
     *  USB Endpoint 2 Event Callback
     *    Parameter:       event
     */
    
    void USB_EndPoint2 (DWORD event) {
      switch (event) {
        case USB_EVT_IN:
          if ( ! Data2Host0 ) {
              USB_WriteEP( USB_ENDPOINT_IN(2), NULL, 0 );        // send ZLP
              Data2Host0 = 1;
          }
          break;
        case USB_EVT_OUT:
          DeviceData2UART( 0 );
          break;
      }
      event;
    }
    

    This code is supposed to send the data in every 1ms.
    Using the parameter "frame" of USB_SOF_Event(), you can select arbitrary interval in 1ms step.

    That's all.

    Tsuneo

  • Hi Tsuneo,
    Thanks for your great help.
    Well, even by doing that the PC comes to hang.

    i tried it this way now.

    void USB_SOF_Event (DWORD frame)
    {
            static int count = 0;
            if(count>=8)
            {
                    USB_WriteEP( 0x82, &UART2USBBuf0[0], 64 );
                    count = 0;
            }
            else
            count++;
    

    By this 64 bytes are transmitted in 8 ms.

    Well, this is max i can get i think. I don't doubt my firmware now. I think the PC side USB driver for VCOM is not able to handle the data and goes to hang. I tried toggling a pin and monitored it in CRO, the pin gets toggled during USB_WriteEP().

    I am now going with 64bytes/8msec. But,now I have another set of problem. My PC shows VCOM8 and VCOM9.
    I have to receive data too. When i try writting something from VCOM8, the PC gets hang again.

    This is what i am doing:

    void USB_EndPoint2 (DWORD event) {
    
            BYTE array[64];
      switch (event) {
        case USB_EVT_IN:
              Data2Host0 = 1;
    //      if ( ! Data2Host0 )
    //      {
    //          USB_WriteEP( 0x82, NULL, 0 );        // send ZLP
    //          Data2Host0 = 1;
    //      }
    
    
          break;
            case USB_EVT_OUT:
                    IODIR1 |= 1<<16;
                    IOPIN1 ^= 1<<16;
                    USB_ReadEP(0x02, array);
    //        DeviceData2UART( 0 );
              break;
      }
      event;
    }
    
    I don't know what could be the reason
    
    
    

  • "Well, even by doing that the PC comes to hang."
    "I think the PC side USB driver for VCOM is not able to handle the data and goes to hang."

    Test your firmware with a terminal app.

    RealTerm
    realterm.sourceforge.net/

    DockLight
    http://www.docklight.de/

    etc.
    wiki.oliverbetz.de/.../TerminalPrograms

    If your host app is coded in VB, and it uses OnComm with RThreshold, you may need to send extra ZLP from the device side. This problem of IOCTL_SERIAL_WAIT_ON_MASK was seen on usbser.sys on this topic in USB-IF.

    "USB CDC USBSER.SYS Buffering delay?"
    www.usb.org/.../viewtopic.php

    It is also applied to the NXP device driver. In the first place, the source code for the serial driver on the WinDDK has the problem on IOCTL_SERIAL_WAIT_ON_MASK handling. Then, any example driver which follows WinDDK has the same problem.

    Anyway, the ZLP just after the 64 bytes IN transfer is required, regardless of this problem.

    Tsuneo

  • Hi Tsuneo,

    Thats a great help.

    Right now i am using windows Hyper Terminal program.

    It would be of great help if you can also guide me for OUT messges.

  • Hi Tsuneo,

    I took the code from www.standardics.nxp.com/.../code.lpc214x.usb.zip and to my surprize, the raw code itself is not working for reception.

    I made that NO_UART_CABLE to 1. and when i open the the COM(X) and type anything there, PC comes to hang. I tried this with many PCs, same thing happens.

    I don't think there is any problem in the code. Can you download usb.zip from the same location and just make a run i you too are getting the same problem?

    I want to add one more thing. I am not using MCB2140 board but it is my custom design similar to MCB2140 and there are no problems with the board.

    i will highly appreciate your help

  • Hi all,

    Things started working now. All problem was because of a corrupted usbser.sys.

    I downloaded the hotfix freshly from microsoft and everything started working fine.

    Thanks a lot to all of you specially Tsuneo.

    Regard!
    Kamal

  • "All problem was because of a corrupted usbser.sys."

    ???
    The NXP example (AN10420) has a vendor specific interfaces, and it works with the custom device driver attached to the zip file.

    Windows usbser.sys works with a CDC-ACM device.
    Did you modify the NXP example to a CDC implementation?

    Anyway, MS starts to distribute Win XP SP3 over Windows Update.
    forums.microsoft.com/.../ShowPost.aspx

    It has newer versions (usbser.sys: 5.1.2600.5508, usbccgp.sys: 5.1.2600.5512) than the hotfix.

    This version of usbser.sys and usbccgp.sys allow composite device of CDC using IAD (Interface Association Descriptor), successfully. I'm testing it now. Maybe, a composite device with multiple CDC will also work on this version, which has been proved on Vista SP1.

    Tsuneo