Hi, All.
I tested last trunk, but my problem remains.
I wrote new test code and found that the problem occurs only with data transmission in both directions (my protocol is half duplex: send command, read answer). If transmit data all time in one direction, then everything works as it should. Also, if I insert a pause ~10 ms between write and read functions and no error occurs but it kill performance.
I also want to say that the error occurs only on write data to USB_SERIAL (chnWrite function) and it is caused by the fact that the flag 'SDU1.config->usbp->transmitting' always remains in state 2. If it is reset to zero, the program continues to run and driver works. Since I could not understand why this happens, I just set the flag to zero and it helps - but this is not correct.
This is test code of main loop:
Code: Select all
// main loop
for (;;)
{
int size = 0; // transfer count
int rd; // read count
int wr; // write count
RTCTime start_time, end_time;
// Wait for USB active
while (SDU1.config->usbp->state != USB_ACTIVE)
{
PAUSE(1000);
}
DEBUG_TRACE("USB cable plugged.\n\r");
// Enable to read from USB
#define USB_READ_ENABLE
// Enable to write to USB
#define USB_WRITE_ENABLE
while (SDU1.config->usbp->state == USB_ACTIVE)
{
// Read from USB max 512 bytes
#ifdef USB_READ_ENABLE
rd = chnReadTimeout(&SDU1, &COMM_RX_BUFFER[0], 512, MS2ST(10));
#else
rd = 512;
#endif
if (rd != 0)
{
// Read OK
if (size == 0)
{
// Start timer
rtcGetTime(&RTCD1, &start_time);
}
// accumulate size
#ifdef USB_READ_ENABLE
size += rd;
#endif
// Print debug info
DEBUG_LINE("\rread %d bytes, tx_stat = %d, rx_stat = %d ", rd, SDU1.config->usbp->transmitting, SDU1.config->usbp->receiving);
#ifdef USB_WRITE_ENABLE
wr = chnWriteTimeout(&SDU1, &COMM_RX_BUFFER[0], rd, MS2ST(100));
#else
wr = rd;
#endif
if (wr != rd)
{
// error writing data
DEBUG_LINE("\n\rWrite error\n\r");
// dancing with a tambourine
chSysLock();
SDU1.config->usbp->transmitting = 0;
SDU1.config->usbp->receiving = 0;
chOQResetI(&SDU1.oqueue);
chSysUnlock();
PAUSE(10);
} else
{
// accumulate size
#ifdef USB_WRITE_ENABLE
size += wr;
#endif
// Print statistics
rtcGetTime(&RTCD1, &end_time);
int time = end_time.tv_sec - start_time.tv_sec;
if (time) DEBUG_LINE("write %d bytes, amount %d Kb, R+W speed = %d Kb/sec ", wr, size/1024, size/1024/time);
}
} else
{
// nothing to read
}
}
DEBUG_TRACE("\n\r");
DEBUG_TRACE("USB cable unplugged.\n\r");
}
This is test program for PC in Pascal/Delphi for Windows:
Code: Select all
program usb_test;
{$APPTYPE CONSOLE}
uses
JWAWindows, SysUtils, 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;
amount, n : Integer;
wrN, rdN : Integer;
h : Thandle;
DeviceName, S : String;
r : Cardinal;
Timeouts : TCommTimeouts;
Begin
Writeln;
Writeln('USB SERIAL TEST Program V.1.00 (C) 2012 ALEX BLACK');
If ParamCount<3 Then
Begin
Writeln('Usage: usb_test <com_port> <write size> <read size>');
Writeln(' com_port - COM Port Name');
Writeln(' write_size - amount of data to write (0 - do not write)');
Writeln(' read_size - amount of data to read (0 - do not read');
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;
System.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
wrN := StrToInt(ParamStr(2));
If (wrN<0) or (wrN>65536) Then Abort;
Except
Writeln('Error: invalid write buffer size!');
Exit;
End;
Try
rdN := StrToInt(ParamStr(3));
If (rdN<0) or (rdN>65536) Then Abort;
Except
Writeln('Error: invalid read buffer size!');
Exit;
End;
SetLength(WrBuffer, wrN);
SetLength(RdBuffer, rdN);
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.WriteTotalTimeoutMultiplier := 0;
Timeouts.WriteTotalTimeoutConstant := 1000;
SetCommTimeouts(h, Timeouts);
PurgeComm(h, PURGE_TXCLEAR or PURGE_RXCLEAR);
Count := 1;
amount := 0;
Repeat
Write(#13'COUNT ', Count, ' write ');
r := 0;
If wrN>0 Then
Begin
WriteFile(h, @WrBuffer[0], wrN, @r, nil);
If (GetLastError<>0) Then
Begin
Writeln;
Writeln('ERROR write');
Break;
End;
If (wrN<>r) Then
Begin
//Writeln;
Write('error ', getLastError);
PurgeComm(h, PURGE_RXCLEAR);
//Sleep(3000);
End;
End;
Inc(amount, r);
Write(r, ' bytes');
Write(' : reading ');
r := 0;
If rdN>0 Then
Begin
ReadFile(h, @RdBuffer[0], rdN, @r, nil);
If (GetLastError<>0) Then
Begin
Writeln;
Writeln('ERROR read');
Break;
End;
If (rdN <> r) Then
Begin
//Writeln;
Write('error ', getLastError);
PurgeComm(h, PURGE_TXCLEAR);
//Sleep(3000);
End;
End;
Write(r,' bytes, amount = ', amount div (1024*1024), ' MB ');
Inc(Count);
Inc(amount, r);
Until False;
CloseHandle(h);
End.
Debug Output:
Code: Select all
MAIN: > CPU is STM32F103, XTAL = 72MHz
MAIN: > Compiled Feb 26 2013 20:14:18
MAIN: > ChibiOS Version: 2.5.2
MAIN: > USB cable plugged.
read 512 bytes, tx_stat = 2, rx_stat = 2 write 512 bytes, amount 551 Kb, R+W speed = 183 Kb/sec
Write error
read 512 bytes, tx_stat = 2, rx_stat = 2 write 512 bytes, amount 720 Kb, R+W speed = 144 Kb/sec
Write error
read 512 bytes, tx_stat = 2, rx_stat = 2 write 512 bytes, amount 4454 Kb, R+W speed = 171 Kb/sec
Write error
read 512 bytes, tx_stat = 2, rx_stat = 2 write 512 bytes, amount 4699 Kb, R+W speed = 167 Kb/sec
Write error
read 512 bytes, tx_stat = 2, rx_stat = 2 write 512 bytes, amount 5511 Kb, R+W speed = 162 Kb/sec
Write error
read 512 bytes, tx_stat = 2, rx_stat = 2 write 512 bytes, amount 5766 Kb, R+W speed = 160 Kb/sec
Write error
read 256 bytes, tx_stat = 0, rx_stat = 2 write 256 bytes, amount 6002 Kb, R+W speed = 153 Kb/sec