Page 1 of 4
Serial over USB problem
Posted: Mon Dec 10, 2012 7:53 pm
by alexblack
I can not get USB to work properly.
I used last trunk 2.5.1 and STM32F103 board.
The problem is that for some time it is functioning properly, but after a number of transactions the device stops responding. After USB cable reinsertion the process starts again. I noticed that this happens when transferring big packets of data (512 bytes or more). The feeling that the MCU does not have time to respond and the computer loses it. I tried to increase enpoints max packet sizes in descriptors (not sure I did it right) to 256 bytes and it begins work better but I still have problems.
As a base, I used the USB_CDC example from testhal folder. All descriptors are the same.
The thread looks as:
Code: Select all
static WORKING_AREA(waThreadUSB, 2048);
static msg_t ThreadUSB(void *arg)
{
(void) arg;
for (;;)
{
chThdSleepMilliseconds(MS2ST(1000));
// Wait USB ready
while (SDU1.config->usbp->state != USB_ACTIVE)
{
chThdSleepMilliseconds(MS2ST(1000));
}
chprintf(dbg_port, "USB cable plugged.\n\r");
// Process commands
while (SDU1.config->usbp->state == USB_ACTIVE)
{
int size = USB_GET_PACKET(COMM_RX_BUFFER, sizeof(COMM_RX_BUFFER));
if (size > 0)
{
size = COMM_PROCESS_COMMAND(COMM_RX_BUFFER, COMM_RX_BUFFER, sizeof(COMM_RX_BUFFER));
if (size > 0)
{
// Send result
sdWrite(&SDU1, COMM_RX_BUFFER, size);
}
}
}
chprintf(dbg_port, "USB cable unplugged.\n\r");
}
}
I debugged the code and found that packets received from USB, processed OK and sdWrite running but on the PC side receive nothing. I look at the raw data from Port monitor and can''t understand what happens.
0.00029761 stm_loader.exe IRP_MJ_WRITE USBSER000 SUCCESS Length 5: 0C 02 00 00 48
0.00000021 stm_loader.exe IRP_MJ_WRITE USBSER000 SUCCESS Length 0:
0.00000208 stm_loader.exe IOCTL_SERIAL_GET_COMMSTATUS USBSER000 SUCCESS
0.00000210 stm_loader.exe IOCTL_SERIAL_PURGE USBSER000 SUCCESS Purge: TXABORT RXABORT TXCLEAR RXCLEAR
0.00000061 stm_loader.exe IOCTL_SERIAL_PURGE USBSER000 SUCCESS Purge: TXABORT TXCLEAR
0.00000519 stm_loader.exe IOCTL_SERIAL_SET_WAIT_MASK USBSER000 SUCCESS Mask:
0.00000075 stm_loader.exe IOCTL_SERIAL_PURGE USBSER000 SUCCESS Purge: RXABORT RXCLEAR
0.00000053 stm_loader.exe IRP_MJ_CLEANUP USBSER000 SUCCESS
0.00291877 stm_loader.exe IRP_MJ_CLOSE USBSER000 SUCCESS
When I using UART cable and the same soft on PC all works fine.
Re: Serial over USB problem
Posted: Mon Dec 10, 2012 8:45 pm
by Giovanni
The driver should NAK incoming data if the program does not consume them fast enough, so that should not be the case.
That code does not tell me much, all actual calls to the USB driver are hidden. Are you running with debug options enabled?
Giovanni
Re: Serial over USB problem
Posted: Tue Dec 11, 2012 9:37 am
by alexblack
Giovanni wrote:The driver should NAK incoming data if the program does not consume them fast enough, so that should not be the case.
That code does not tell me much, all actual calls to the USB driver are hidden. Are you running with debug options enabled?
Giovanni
I tried both variants: with full debug on and all debug options off. No error was reported.
All code is standard - which code do you need, i can give it?
I wrote that PC emulated serial port not receive data when sdWrite executed after some successful writes.
Maybe I must write directly to endpoint, because need to transfer big packets? If so how can I do this?
Maybe this is the problem of the serial driver on the computer? I used last from ST and Windows XP.
Now I will write small test program to try to find where the problem... maybe it already exists?
Re: Serial over USB problem
Posted: Tue Dec 11, 2012 10:17 am
by Giovanni
Hi,
I have not enough elements to make an hypothesis. You should not have any need to write directly to the HW, the driver API should be sufficient.
Try remove the serial port handling and just consuming the data the host sends to the device, verify if the transfer continues to stall.
Giovanni
Re: Serial over USB problem
Posted: Tue Dec 11, 2012 12:02 pm
by alexblack
I installed USB Analyzer program (USBlyzer) and see strange things:
After device plugged all works fine. I start my program to communicate with device and it start read data.
Communication was successful but USB sniffer still receive packets 0 byte length and doing it forever every 1 ms. The report strings follow:
Code: Select all
URB 0069 12:43:51.734 39.442891s Bulk or Interrupt Transfer 4096 bytes buffer in 01:01:81 88852490h USBPDO-6 usbhub 892278F8h
URB 0070-0069 12:43:51.734 39.443884s 993 us Bulk or Interrupt Transfer 0 bytes data in 01:01:81 88852490h USBPDO-6 usbhub 892278F8h Success
URB 0071 12:43:51.734 39.443888s Bulk or Interrupt Transfer 4096 bytes buffer in 01:01:81 88852490h USBPDO-6 usbhub 892278F8h
URB 0072-0071 12:43:51.734 39.444881s 994 us Bulk or Interrupt Transfer 0 bytes data in 01:01:81 88852490h USBPDO-6 usbhub 892278F8h Success
Since I have no experience in USB maybe it is normal but with FTDI chip there are no such things.
I can give full report from USBlyzer in more readable form if need.
I can't catch the problem in sniffer because after some time it report that its buffer overflow and stop capture.
Re: Serial over USB problem
Posted: Tue Dec 11, 2012 2:05 pm
by Giovanni
The zero packet is part of the Bulk endpoints protocol, it should be normal. Note that is the host sending those since the transfer is host->device.
Giovanni
Re: Serial over USB problem
Posted: Tue Dec 11, 2012 7:14 pm
by alexblack
I wrote sample USB program and found that the USB works unstable if transfer big amount of data from host to device:
Code: Select all
static WORKING_AREA(waThreadUSB, 2048);
static msg_t ThreadUSB(void *arg)
{
(void) arg;
int size;
static char BUFFER[512];
for (;;)
{
// Wait USB ready
while (SDU1.config->usbp->state != USB_ACTIVE)
{
chThdSleepMilliseconds(MS2ST(1000));
}
DEBUG_TRACE("USB cable plugged.\n\r");
size = sdReadTimeout(&SDU1, BUFFER, 64, MS2ST(10));
if (size != 0)
{
DEBUG_TRACE("read %d bytes\r", size);
sdWrite(&SDU1, COMM_RX_BUFFER, size);
}
}
DEBUG_TRACE("\n\r");
DEBUG_TRACE("USB cable unplugged.\n\r");
}
}
I wrote simple test program for PC on DELPHI 7 (I can give executable if need):
Code: Select all
program usb_test;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows, Registry, Classes;
// Searching serial devices
Procedure SearchHardware;
Var
I : Integer;
reg : TRegistry;
st : TStrings;
Port : String;
Begin
Writeln('Available Serial devices:');
// Using reestry
reg := TRegistry.Create;
Try
reg.RootKey := HKEY_LOCAL_MACHINE;
reg.OpenKey('hardware\devicemap\serialcomm',false);
st := TStringList.Create;
Try
reg.GetValueNames(st);
For I := 0 to st.Count -1 Do
Begin
Port := reg.ReadString(st.Strings[i]);
Writeln(st.Strings[i],' ', Port);
End;
Finally
st.Free;
End;
Finally
reg.CloseKey;
reg.free;
End;
Writeln;
End;
Var
WrBuffer,
RdBuffer : Array of Byte;
Count, Speed : Integer;
n, amount : Integer;
h : Thandle;
DeviceName, S : String;
r : Cardinal;
Timeouts : TCommTimeouts;
Begin
Writeln('USB SERIAL TEST Program V.1.00 (C) 2012 ALEX BLACK');
If ParamCount<2 Then
Begin
Writeln('Usage: usb_test <com_port> <packet size>');
SearchHardware;
Exit;
End;
// Check COM port name
S := ParamStr(1);
If (length(S)<4) or (AnsiUpperCase(Copy(S, 1, 3))<>'COM') Then
Begin
Writeln('Error: invalid com_port name (must be as COM1, COM3 or COM10)');
Exit;
End;
Delete(S, 1, 3);
Try
n := StrToInt(S);
If (n<=0) or (n>255) Then Abort;
Except
Writeln('Error: invalid com_port number');
Exit;
End;
DeviceName := 'COM'+IntToStr(n);
If n>=10 Then
Begin
Devicename := '\\.\'+DeviceName;
End;
// Setup buffers
Try
n := StrToInt(ParamStr(2));
If (n<=0) or (n>65536) Then Abort;
Except
Writeln('Error: invalid buffer size!');
Exit;
End;
SetLength(WrBuffer, n);
SetLength(RdBuffer, n);
Writeln('Open COM port...');
h := CreateFile(PChar(DeviceName), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
If h = INVALID_HANDLE_VALUE then
Begin
If GetLastError = ERROR_FILE_NOT_FOUND Then
Begin
Writeln('Error: invalid COM port');
End Else
Begin
Writeln('Error: port open error');
End;
Exit;
End;
Writeln('OK');
// Setup timeouts for read and write operations
GetCommTimeouts(h, Timeouts);
Timeouts.ReadIntervalTimeout := 0;
Timeouts.ReadTotalTimeoutMultiplier := 0;
Timeouts.ReadTotalTimeoutConstant := 1000;
Timeouts.WriteTotalTimeoutConstant := 1000;
SetCommTimeouts(h, Timeouts);
Count := 1;
amount := 0;
Repeat
Write(#13'COUNT ', Count, ' write ');
WriteFile(h, WrBuffer[0], n, r, nil);
If (n<>r) Then
Begin
Writeln;
Write('error ', getLastError);
Break;
End Else
Begin
Write(r, ' bytes');
End;
Write(' : reading ');
ReadFile(h, RdBuffer[0], n, r, nil);
Inc(amount, r);
Write(r,' bytes, amount = ', amount, ' ');
Inc(Count);
Until False;
CloseHandle(h);
End.
This test program writes to serial device specified amount of data and read it back. If I specified packet size 64 bytes all works long time but if greater than after some packets the device stopped to receive data and program return error. If USB cable replugged than device start to work again.
Can You check this?
Re: Serial over USB problem
Posted: Tue Dec 11, 2012 7:25 pm
by Giovanni
Hi,
I have D7, I used to program a lot with Delphi, great tool.
I will give it a try, there were other reports of problems with that USB driver too, not sure if that could be related to this problem.
viewtopic.php?f=2&t=790I should have access to an USB analyzer by Friday or early next week.
Giovanni
Re: Serial over USB problem
Posted: Tue Dec 11, 2012 8:10 pm
by alexblack
It seems some synchronization or low speed problem because when I turned off all debug options and turn on full speed optimization of compiler the test works much longer time. For example 60000 cycles with 512 packet size against max 1000 cycles before.
Code: Select all
G:\NEW_WORK\USB_TEST>usb_test COM18 512
USB SERIAL TEST Program V.1.00 (C) 2012 ALEX BLACK
Open COM port...
OK
COUNT 60333 write 512 bytes : reading 512 bytes, amount = 30889984
error 0
And another thing I noticed is that the problem with the USB stops working test USB_THREAD, ie there is no return from this function:
Code: Select all
size = sdReadTimeout(&SDU1, COMM_RX_BUFFER, 64, MS2ST(10));
But it must return with timeout 10 ms!
viewtopic.php?f=2&t=790
Yes, I've read it - it seems there is another case.
Re: Serial over USB problem
Posted: Tue Dec 11, 2012 9:27 pm
by Giovanni
Just a note "sd" functions are specific of the serial driver, they do work with the "sdu" driver but are not meant for that. you should use chnReadTimeout() instead.
The difference? sdReadTimeout() assumes there is a queue to read from, chnReadTimeout() calls an abstract method, there is no necessarily a queue involved. It works just because it happens that a queue is used in the sdu driver too.
However I don't think this is the cause of the problem.
About the timeout, what is the state of the system when it hangs? crashed or just some thread hung and others working?
Giovanni