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

Some questions about LPCUSB with LPC2378

(Sorry for my limited English ability.)

I have been assigned to develop an USB based I/O board (software portion). The requirement of this I/O board has never been discussed and never been defined, and the hardware has not been made. So I am working on the LPC23xx evaluation boards. What I have been told is that, this USB based I/O board is made to work with a X86 platform running Linux.

I read some Tsuneo's (Tsuneo Chinzei) articles, and eventually decided to choose the LPCUSB for my LPC2378 evaluation board. The major reasons are: 1. Tsuneo said that it is the best open source project for LPC23xx. 2. Its Linux driver is ready. (The standard one in the Linux kernel.)

I built a Cygwin/YAGARTO GNU ARM toolchain environment to perform some simple tests for LPCUSB. And found that, the main_serial.c works. Then, I migrated the LPCUSB to the KEIL environment, and the main_serial.c still works. But during the migrations and the tests, I found that, or I guessed that, the LPCUSB USB stack is good; however, its examples are only for demonstrating purpose, so they are not well tested.

The major problem for me currently is that, the
[static void USBFrameHandler(U16 wFrame)]
function does not work properly, because the [fBulkInBusy] variable has never been reset to FALSE. Actually, the real circumstance is: If I send one byte from the X86 desktop to the LPC2378 board, the LPC2378 can send one byte back to the X86 desktop. If I do not send one byte from the X86 desktop to the LPC2378 board, then the LPC2378 board can not send anything to the X86 desktop. I am not so sure that, it is a bug that I have to fix, or it is not a bug, I just need to implement some more USB functions to complete the mechanism.

I don't actually know that, how it works originally. Is that the host sends data with a BulkOut, and this BulkOut invokes a BulkIn? Or the LPC2378 board sends data to the host when it is polled every milisecond by the host? What is the correct way to send data from the LPC2378 board to the host?

Is there any USB-CDC tutorial for a novice? Or could someone please kindly provide some advices?

Parents
  • > So there is NO "Bulk IN transactions" nor "Interrupt IN transactions"; they are the same "IN transactions". Am I right?

    Yah, you are right.
    Bulk and interrupt transfer apply the same IN and OUT transaction format. So, just seeing transaction on the line, we cannot distinguish them each other, bulk or interrupt. But the endpoint is assigned to bulk or interrupt on the endpoint descriptor. Therefore, we call them as bulk IN or interrupt OUT transaction.

    The USB SIEs on NXP LPC family MCU classify each endpoint into interrupt/bulk/isoc (and default control) transfer type. Actually, these bulk and interrupt endpoints can be exchanged, because there is no difference on the handling of bulk and interrupt transaction of the device side. NXP calls double buffered endpoints as bulk, single buffer ones as interrupt.

    Host controller processes interrupt transfer differently from bulk. For interrupt transfer, it reserves bandwidth (chance to occur the transfer) on enumeration. When a request for interrupt transfer comes from device driver, host controller schedules it in the periodical time table. Isoc transfer is also assigned to similar (or same) periodical time table. Control transfer is guaranteed for a fixed amount of bandwidth. For bulk transfers, the rest bandwidth is available.



    >> CDC device driver polls bulk IN endpoint (Polling IN transactions) repeatedly.

    > Then a "raw IN EP" (not a "bulk IN EP", right?) responses to the host with DATA0/DATA1 Packet.

    The firmware don't always to respond to each IN transaction.
    Just when the firmware has data to send, it puts the data to the IN EP.
    If there is no data on the IN EP, the device SIE returns NAK (Not ready) to the IN transaction.

    USB don't have any mean to notify from device to host (at least until USB 3.0).
    Therefore, host polls device using IN transaction, repeatedly.
    This is called polling IN transaction, an orthodox method for device drivers, like HID, CDC, Printer, CCID, etc.



    > Since it is a "raw IN EP", why it is called BULK_IN_EP? and why the function is called BulkIn? why the function is called after the DATA Packet had been sent? why not called before the DATA Packet had been sent? I mean that, what is the real role of this function?

    The same reason as above, the endpoint is assigned to bulk type.

    Tsuneo

Reply
  • > So there is NO "Bulk IN transactions" nor "Interrupt IN transactions"; they are the same "IN transactions". Am I right?

    Yah, you are right.
    Bulk and interrupt transfer apply the same IN and OUT transaction format. So, just seeing transaction on the line, we cannot distinguish them each other, bulk or interrupt. But the endpoint is assigned to bulk or interrupt on the endpoint descriptor. Therefore, we call them as bulk IN or interrupt OUT transaction.

    The USB SIEs on NXP LPC family MCU classify each endpoint into interrupt/bulk/isoc (and default control) transfer type. Actually, these bulk and interrupt endpoints can be exchanged, because there is no difference on the handling of bulk and interrupt transaction of the device side. NXP calls double buffered endpoints as bulk, single buffer ones as interrupt.

    Host controller processes interrupt transfer differently from bulk. For interrupt transfer, it reserves bandwidth (chance to occur the transfer) on enumeration. When a request for interrupt transfer comes from device driver, host controller schedules it in the periodical time table. Isoc transfer is also assigned to similar (or same) periodical time table. Control transfer is guaranteed for a fixed amount of bandwidth. For bulk transfers, the rest bandwidth is available.



    >> CDC device driver polls bulk IN endpoint (Polling IN transactions) repeatedly.

    > Then a "raw IN EP" (not a "bulk IN EP", right?) responses to the host with DATA0/DATA1 Packet.

    The firmware don't always to respond to each IN transaction.
    Just when the firmware has data to send, it puts the data to the IN EP.
    If there is no data on the IN EP, the device SIE returns NAK (Not ready) to the IN transaction.

    USB don't have any mean to notify from device to host (at least until USB 3.0).
    Therefore, host polls device using IN transaction, repeatedly.
    This is called polling IN transaction, an orthodox method for device drivers, like HID, CDC, Printer, CCID, etc.



    > Since it is a "raw IN EP", why it is called BULK_IN_EP? and why the function is called BulkIn? why the function is called after the DATA Packet had been sent? why not called before the DATA Packet had been sent? I mean that, what is the real role of this function?

    The same reason as above, the endpoint is assigned to bulk type.

    Tsuneo

Children
  • Ah, I didn't answer to the last question,

    > why the function is called after the DATA Packet had been sent? why not called before the DATA Packet had been sent? I mean that, what is the real role of this function?

    More precisely, the endpoint interrupt is generated when the device receives ACK from host on the IN transaction, not on the DATA0/1 packet.

    Return to the meaning of your question,
    The FIFO implementation allows more than full-size (64 bytes) "packet" transfer (*1). VCOM_putchar() fills just one byte to the txfifo buffer. But, as usual putchar() does, VCOM_putchar() is expected to be called repeatedly, to pass strings. In this way, txfifo may hold greater data, before USBFrameHandler() starts a transfer. For greater size transfer than wMaxPacketSize (64 bytes) of the endpoint, it should be split into full-sized packets.

    USBFrameHandler() starts the transfer by putting the first "packet".
    BulkIn() (SendNextBulkIn()) puts the second and latter "packets", when the last transaction finishes.

    (*1) this "packet" is not strictly USB term, but we often use "packet" in this way. Sometimes, confusing.

    Tsuneo

  • -> As Tamir says, that would not necessarily be any different in a big company!

    I had worked for a big global firm, where I met some real professionals, and co-worked with them. That was the only good thing. Oh, the pay was good too.

    Before that, or after that, I haven't had any opportunity to co-work with real professionals.

  • To me, the biggest difference between small and large companies lays in the scope of your work (this may not always be true, of course). When you end up in a big company, you are not likely to be allowed to write something from scratch, really from scratch - using existing components will be required even if they suck (perfectly logical of course - time is money). One of the products firmware framework (plus some application) I am now working on was written almost entirely by me to my liking - from total scratch (except RL-ARM components of course). So, you need to know almost everything. However, when I worked for one of these large companies I begged to do more and get to know more, but my team leader would not allow me, because I had my responsibilities. that sucked, and was the main reason I left.

  • Hi Tsuneo,

    With your exposition and help, I think/guess I have gotten enough information for my stage-1.

    I will re-read all the stuff I read before, trying to get a better understanding of the LPCUSB's CDC example.

    Then, in my stage-2, I will try to slightly re-write the main_serial.c etc.

    Many thanks.

  • I am just being told that the USB based I/O board should be capable to handle the data transmission every millisecond. The X86 Linux Application polls the USB based I/O board every millisecond, then the USB I/O board must respond right away.

    I don't think this is a rational requirement. I think/guess that, the USB host controller chip on the X86 platform polls the USB device every millisecond, but such a polling is unintentional. I just checked and confirmed that, for Ubuntu 9.10 Desktop Linux, the CONFIG_HZ is 250 (tick = 4ms).

    I don't know how to write a Linux testing application to poll the USB based I/O board every millisecond. And I don't know how to explain this to them.

  • > I am just being told that the USB based I/O board should be capable to handle the data transmission every millisecond.

    This assumption is almost ture, but not 100%.
    You may see around 2 ms interval occasionally. Then, you need buffering so as not to drop the data.
    Also, the transfer size becomes greater, this assumption breaks. A packet-full size (64 bytes) is a good amount.

    To run 1 ms interval using a generic device driver like libusb, you have to put multiple asynchronous calls in advance, without waiting completion of any call.
    When a call finishes, put another call, to keep the request queue populate.

    Tsuneo

  • ==> \LPCUSB\target\examples\main_serial.c

    /**
            Local function to handle incoming bulk data
    
            @param [in] bEP
            @param [in] bEPStatus
     */
    static void BulkOut(U8 bEP, U8 bEPStatus)
    {
            int i, iLen;
    
            if (fifo_free(&rxfifo) < MAX_PACKET_SIZE) {
                    // may not fit into fifo
                    return;    // Here!!!
            }
    
            // get data from USB into intermediate buffer
            iLen = USBHwEPRead(bEP, abBulkBuf, sizeof(abBulkBuf));
            for (i = 0; i < iLen; i++) {
                    // put into FIFO
                    if (!fifo_put(&rxfifo, abBulkBuf[i])) {
                            // overflow... :(
                            ASSERT(FALSE);
                            break;
                    }
            }
    }
    

    If there is no space in the rxfifo (rxdata), the ISR function BulkOut() returns.

    In such a case, the EP_SLOW bit in USBDevIntClr Register had been set (cleared) by the major ISR function USBHwISR() already. But the bEP is still full with data, so the host application will not be able to write any data into this bEP (OUT-NAK), so the ISR function BulkOut() will not be triggered once again.

    The data in the bEP will never be processed. It is a dead-end.