Paul:
Thanks for the response. I very much appreciate your willingness to look at the code, but all I actually asked is whether anyone had observed slow data transfer over USB, using the usb-serial adapter, as opposed to a standard serial port. The exact same code is used in both instances, with very different results.
Following is the code for the PC side, simplified about as much as possible. It does in principle do overlapped read/write IO and I haven’t yet turned that off, because it works so well on a standard serial port. Since it transmits only, nothing is required on the uP side. I use CODE::BLOCKS as the development platform and the executable runs on Win98, WinXP and Win7.
I certainly don’t expect anyone to debug this, but if something jumps out, fantastic!
Best regards, Jim
//
// serial com port transmit & receive
//
#include <conio.h>
#include <stdio.h>
#include <time.h>
#include <windows.h>
#include <string.h>
#include <math.h>
HANDLE SerialInit(char*, int);
char SerialGetc(HANDLE*);
void SerialPutc(HANDLE*, unsigned char);
void MySleep(int mSec);
// variables used with the com port
BOOL bPortReady;
DCB dcb;
COMMTIMEOUTS CommTimeouts;
BOOL bWriteRC;
BOOL bReadRC;
DWORD iBytesWritten;
DWORD dwRead;
HANDLE SerPrt = INVALID_HANDLE_VALUE;
OVERLAPPED osReader = {0};
DWORD dwEvtMask;
BOOL fWaitingOnRead = FALSE;
#define READ_BUF_SIZE 16
char InBuf[READ_BUF_SIZE];
typedef unsigned int uint;
//
int main(int argc, char *argv[])
{
int i, tmp, cnt = 0;
// COMx definition
int port = 5; //must be set to suit
unsigned int n = 0;
unsigned int timeCnt = 0;
unsigned int x;
char SerialPortStr[] = "\\\\.\\COM0";
int baudrate = 38400; //115200; 9600; 38400; 57600;
SerialPortStr[7] = port + '0';
printf("Using COM%c: at %d baud\n", port + '0', baudrate);
SerPrt = SerialInit(SerialPortStr, baudrate);
if (SerPrt == INVALID_HANDLE_VALUE) {
printf("Unable to Open COM%c:\n", port + '0');
return FALSE;
}
printf("Test character transmit speed \n");
//send characters as quickly as possible
n = 0;
timeCnt = GetTickCount();
// infinite loop for testing
while(1) {
for (i='a'; i<'a'+20; i++) {
SerialPutc(&SerPrt, i); n++;
// MySleep(0);
// about every second, output character count
if ( (tmp = (x = GetTickCount()) - timeCnt) >= 1000) {
printf("char cnt: %d ticks: %d\n", n, tmp);
timeCnt = x; n=0;
}
}
SerialPutc(&SerPrt,0x0D); SerialPutc(&SerPrt,0x0A); n+=2;
// MySleep(0);
}
return 0;
}
HANDLE SerialInit(char *ComPortName, int BaudRate)
{
HANDLE hCom;
hCom = CreateFileA(ComPortName,
GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
NULL, // no security
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, // overlapped I/O
NULL); // null template
if (hCom == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
char lpMsg[512];
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsg, 0, NULL);
return hCom;
}
bPortReady = SetupComm(hCom, 16, 128); // set buffer sizes
bPortReady = GetCommState(hCom, &dcb);
dcb.BaudRate = BaudRate;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY; // EVENPARITY;
dcb.StopBits = ONESTOPBIT;
dcb.fAbortOnError = TRUE;
// set XON/XOFF
dcb.fOutX = FALSE; // XON/XOFF off for transmit
dcb.fInX = FALSE; // XON/XOFF off for receive
// set RTSCTS
dcb.fOutxCtsFlow = FALSE; // turn on CTS flow control
dcb.fRtsControl = RTS_CONTROL_DISABLE; //
// set DSRDTR
dcb.fOutxDsrFlow = FALSE; // turn on DSR flow control
dcb.fDtrControl = DTR_CONTROL_DISABLE; // DTR_CONTROL_HANDSHAKE;
bPortReady = SetCommState(hCom, &dcb);
// Communication timeouts are optional
bPortReady = GetCommTimeouts (hCom, &CommTimeouts);
CommTimeouts.ReadIntervalTimeout = 2500;
CommTimeouts.ReadTotalTimeoutConstant = 2500;
CommTimeouts.ReadTotalTimeoutMultiplier = 1000;
CommTimeouts.WriteTotalTimeoutConstant = 2500;
CommTimeouts.WriteTotalTimeoutMultiplier = 1000;
bPortReady = SetCommTimeouts (hCom, &CommTimeouts);
// Create Read event
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (NULL == osReader.hEvent) {
printf("SerialInit: failure to create reader hEvent.\n");
}
return hCom;
}
void SerialStartRead(void)
{
int i;
unsigned long err;
if (!fWaitingOnRead) {
// Issue Read Operation
if (!ReadFile(SerPrt, InBuf, READ_BUF_SIZE, &dwRead, &osReader)) {
err = GetLastError();
if ((ERROR_IO_PENDING != err) && (ERROR_IO_INCOMPLETE != err)) {
printf("SerialStartRead: ReadFile failed error: 0x%lx ", err);
ClearCommError(SerPrt, &err, NULL);
printf("detail: 0x%lx\n", err);
} else {
fWaitingOnRead = TRUE;
}
} else {
//ReadFile finished
for (i = 0; i < (int)dwRead; i++) printf("%2x ", InBuf[i]);
fWaitingOnRead = FALSE;
}
fflush(stdout);
}
}
void SerialCheckRead(void)
{
DWORD dwRes;
int i;
unsigned long err;
if (fWaitingOnRead) {
dwRes = WaitForSingleObject(osReader.hEvent, 0); // don't wait
switch (dwRes) {
case WAIT_OBJECT_0: // Read Completed
if (!GetOverlappedResult(SerPrt, &osReader, &dwRead, FALSE)) {
err = GetLastError();
if ((ERROR_IO_PENDING != err) && (ERROR_IO_INCOMPLETE != err)) {
printf("SerialCheckRead: GetOverlappedResult failed error: 0x%lx ", err);
ClearCommError(SerPrt, &err, NULL);
printf("detail: 0x%lx\n", err);
} else {
// Still waiting
}
break;
}
// success, dump characters to window for testing
for (i = 0; i < (int)dwRead; i++) {
printf("%2x ", InBuf[i]);
}
fflush(stdout);
fWaitingOnRead = FALSE; // ready for another operation
break;
case WAIT_TIMEOUT:
// still waiting
break;
default:
// error
printf("SerialCheckRead: communication error: 0x%lx\n", dwRes);
}
}
}
void MySleep(int mSec)
{
while (mSec > 10) {
SerialStartRead();
SerialCheckRead();
Sleep(10);
mSec -= 10;
}
SerialStartRead();
SerialCheckRead();
Sleep(mSec);
}
void SerialPutc(HANDLE *hCom, unsigned char txchar)
{
BOOL bWriteRC;
static DWORD iBytesWritten;
OVERLAPPED osWrite = {0};
DWORD dwRes;
// Create an event object for write operation
osWrite.hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // not signaled
NULL // no name
);
if (NULL == osWrite.hEvent) {
printf("Error: unable to create Write Operation Event\n");
return;
}
bWriteRC = WriteFile(*hCom, &txchar, 1, &iBytesWritten,&osWrite);
if (!bWriteRC) {
// Check if Write is pending.
if (ERROR_IO_PENDING != GetLastError()) {
printf("SerialPutc: unexpected return 0x%lx from WriteFile()\n", GetLastError());
return;
}
dwRes = WaitForSingleObject(osWrite.hEvent, INFINITE);
switch (dwRes) {
case WAIT_OBJECT_0:
if (0 == GetOverlappedResult(*hCom, &osWrite, &iBytesWritten, TRUE)) {
printf("GetOverlappedResult failed with error 0x%lx.\n", GetLastError());
} else {
// success
}
break;
default:
printf("WaitForSingleObject failed with error 0x%lx.\n", dwRes);
break;
}
} else {
// WriteFile() returned TRUE
DWORD err = GetLastError(); //returns 995, Operation Aborted
}
CloseHandle(osWrite.hEvent);
// transmit speed does not depend on the following calls:
SerialStartRead();
SerialCheckRead();
}