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.
"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
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.
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.
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
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();
View all questions in Keil forum