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'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
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();
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.
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.
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.
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.
Even i was thinking this..
I tested the example in many PCs which doesn't have usbser.sys file at all. I was getting problem in all those PCs. In one XP PC usbser.sys was there but it didn't worked with that too. I thought of using windows cdc driver and for that i downloaded usbser.sys. I made it work with cdc driver too. Just for fun again i tried flashing the nxp code and this time it started working... Now it is working fine in the machines where usbser.sys is installed. I don't know the link between nxp vendor specific driver and usbser.sys but it worked.
Don't know how....