reading from serial port way too slow (C++)
Please support our C++ advertiser: Programming Forums
Thread Solved
![]() |
•
•
Posts: 19
Reputation:
Solved Threads: 0
Hey,
I'm having a problem reading from a device attached to my serial port.
I have a big application which uses a thread to read from the serial device and writes the data to a log file. The device is set to transmit data at 500Hz, which means that my thread receives data of 14 bytes every 2 miliseconds.
The baud rate is set to 115200 and actually everything is working pretty fine accept it takes too long.
I'm using a polling method, meaning I check if there are enough bytes in the buffer and I read them. After the device stops transmitting I read from the buffer until it's empty and the thread ends.
The problem with this is that I'm constantly polling the buffer which results in 100% CPU usage. Since we're talking about a thread which is a part of a much bigger application this CPU business is out of the question.
Thus, I'm forced to use the Sleep() function. And here the problem begins:
Minutes are not the timing I had in mind when I wrote this thread. I tried to change the thread priority but it didn't work. I also tried to use event driven programming but it's too slow for my thread.
I could really use your help, any suggestion would be welcomed.
Thank You,
Gadi
I'm having a problem reading from a device attached to my serial port.
I have a big application which uses a thread to read from the serial device and writes the data to a log file. The device is set to transmit data at 500Hz, which means that my thread receives data of 14 bytes every 2 miliseconds.
The baud rate is set to 115200 and actually everything is working pretty fine accept it takes too long.
I'm using a polling method, meaning I check if there are enough bytes in the buffer and I read them. After the device stops transmitting I read from the buffer until it's empty and the thread ends.
The problem with this is that I'm constantly polling the buffer which results in 100% CPU usage. Since we're talking about a thread which is a part of a much bigger application this CPU business is out of the question.
Thus, I'm forced to use the Sleep() function. And here the problem begins:
- without Sleep: After the device stops transmitting the thread empties the buffer almost immediately and the thread ends in a matter of seconds.
- with Sleep: After the device stops transmitting the thread takes from 5 minutes to 35 minutes to empty the buffer (depends on the transmission duration).
Minutes are not the timing I had in mind when I wrote this thread. I tried to change the thread priority but it didn't work. I also tried to use event driven programming but it's too slow for my thread.
I could really use your help, any suggestion would be welcomed.
Thank You,
Gadi
Last edited by GadiK : Dec 3rd, 2008 at 1:02 pm.
•
•
Posts: 19
Reputation:
Solved Threads: 0
Hi,
I didn't try on another computer yet.
The Sleep() function is set to 1 milisecond. It is the minimum, so I tested to see if a "longer" sleep would help me - it didn't, it took longer.
Here's the thread:
(I'm using a SerialCom object that somebody else wrote. The function ReadString() uses ReadFile() and returns FALSE if operation didn't succeed. Also, I used AfxBeginThread() to start this thread)
I didn't try on another computer yet.
The Sleep() function is set to 1 milisecond. It is the minimum, so I tested to see if a "longer" sleep would help me - it didn't, it took longer.
Here's the thread:
(I'm using a SerialCom object that somebody else wrote. The function ReadString() uses ReadFile() and returns FALSE if operation didn't succeed. Also, I used AfxBeginThread() to start this thread)
unsigned int CRmi_demoDlg::GetADISData(void *Sender)
{
CRmi_demoDlg* pSender = NULL;
pSender = (CRmi_demoDlg *)Sender;
char filename[60];
int rd_iter, i;
GetSystemTime(&st);
//------------------------Files--------------------
//open the serial device com port
pSender->ADISDevice.Open("COM8");
//setting buffer size for serial device to avoid buffer overrun
if (!SetupComm(pSender->ADISDevice.hCom,0x00F00000,64))
myprintf("\nCouldn't set device buffer size!");
GetCommProperties(pSender->ADISDevice.hCom,&commProp);
//myprintf prints to a console which logs the threads activities
myprintf("\nADIS buffer size: %d bytes",(int) commProp.dwCurrentRxQueue);
//setup the serial port
pSender->ADISDevice.Setup(115200,8,0,1);
//if port isn't open;
if (pSender->ADISDevice.hCom == INVALID_HANDLE_VALUE) {
pSender->ADISDevice.Close();
AfxMessageBox((CString)"Couldn't get device handle");
return 0;
}
sprintf_s(filename,60,"test%d_ADIS_%d.%d.%d_%d. %d.%d.txt",test_num,st.wDay,st.wMonth,st.wYear,st.wHour+3,st.wMinute,st.wSecond);
// open the log file
ofstream logfile(filename);
if ( !logfile.is_open() ) {
AfxMessageBox((CString) "Couldn't open LOG file!");
return 0;
}
CreateADISFileHeader(logfile);
//------------------------Sampling--------------------
//clear com before working with it
pSender->ADISDevice.clearCom();
if(pSender && pSender->initialized )
{
char finger_byte[14]="0";
short finger_word, index;
short short_lowbyte=0;
short short_highbyte=0;
short flags = 0;
short data_error; //keeps tabs of bit errors
bool r_sent = false;
pSender->ADISDevice.WriteString("r",1); //send "reset" command
pSender->ADISDevice.WriteString("s",1); //send "start" command
while ( pSender->ADISDevice.getNumBytesInQue() < 1 ) {}; //wait for data to come into the buffer
myprintf("\nReceiving Data");
//stop running if no more data in buffer or GUI closed
while( pSender->initialized && (!r_sent || pSender->ADISDevice.getNumBytesInQue() > 0) )
{
if ( !pSender->is_sample )
{
//if stop button pressed tell the ADIS to stop sending data
if ( !pSender->ADISDevice.WriteString("r",1) ) myprintf("\nCouldn't write to ADIS");
if (!r_sent) myprintf("\nStop button pressed");
r_sent = true; //r_sent flags that the device was told to stop sending data
}
GetSystemTime(&st);
//first two bytes of every iteration are 0x55
if ( pSender->ADISDevice.getNumBytesInQue() >= 2 )
{
pSender->ADISDevice.ReadString(finger_byte, 2);
}
else if (!r_sent) continue; //loop only if ADIS stil working
if ( (finger_byte[0] != finger_byte[1]) || (finger_byte[0] != 0x55) )
{
AfxMessageBox((CString)"Out of sync!");
logfile.close();
logfile2.close();
pSender->ADISDevice.Close();
AfxEndThread(0);
return 0;
}
//reading iteration = 15 times, each time 14 bytes
for (rd_iter=0; rd_iter < 15 ; rd_iter++)
{
data_error = 0;
logfile << setw(5) << setfill(' ') << st.wHour+3 << ", "
<< setw(7) << setfill(' ') << st.wMinute << ", "
<< setw(7) << setfill(' ') << st.wSecond << ", "
<< setw(7) << setfill(' ') << st.wMilliseconds << ", ";
// wait untill there is enough information in the buffer unless ADIS stopped
while ( pSender->ADISDevice.getNumBytesInQue() < 14 && !r_sent) {} [
Sleep(1);
if ( !pSender->ADISDevice.ReadString(finger_byte, 7*2) )
{
//if no more data in buffer end loop and make sound
myprintf("\nCouldn't read from ADIS");
MessageBeep(MB_ICONASTERISK);
Sleep(500);
MessageBeep(MB_ICONASTERISK);
Sleep(500);
MessageBeep(MB_ICONASTERISK);
Sleep(500);
break;
}
//processing the received 14 bytes
//and writing them to the log file
for (i=0; i < 7*2 ; i++)
{
short_highbyte=(( short)finger_byte[i]) & 0x00FF;
short_lowbyte=(( short)finger_byte[++i]) & 0x00FF;
finger_word=0;
finger_word=short_highbyte*256+short_lowbyte;
if (i == 1) //first word is always index
{
finger_word = ( short) finger_word/64; //shift right 6 times
finger_word = finger_word & 0x000F;
index = finger_word;
}
else
{
flags = 0xC000 & finger_word;
//contracting 2 msb which are NewData
//and ErrorAlarm the other 14 bits are data
finger_word <<= 2;
finger_word >>= 2; //with bit extraction because its signed short
// put '1' at the bit corresponding to processed data
//for example: XAccl error is at bit number 5
// ZGyro error is at bit number 0
data_error = data_error << 2;
flags = flags >>14; //without bit extraction because its unsigned
short
data_error |= flags;
}
logfile << setw(10) << setfill(' ') << finger_word << ", ";
}
logfile << setw(10) << setfill(' ') << data_error << endl;
}
}
}
myprintf("\nNo more data in buffer");
pSender->ADISDevice.WriteString("r",1); //send "reset" command
while (pSender->ADISDevice.getNumBytesInQue() > 0) pSender->ADISDevice.clearCom();
pSender->ADISDevice.Close();
if( logfile.is_open() )logfile.close();
AfxEndThread(0);
return 0;
}
/*----------------------------End of GetADISData---------------------------------------------*/ Last edited by GadiK : Dec 4th, 2008 at 3:55 am.
•
•
Posts: 19
Reputation:
Solved Threads: 0
Another development:
If I set the following conditions I am able to run the entire application with 62% CPU usage (where without the above thread the main application uses 52%):
SetPriorityClass(HIGH_PRIORITY_CLASS);
SetThreadPriority(THREAD_PRIORITY_HIGH);
And I set the Sleep() argument to be 0.01 - meaning I call it like this: Sleep(0.01).
If I don't set the priorities and only use the Sleep(0.01) it doesn't work. If I only set the priorities but use Sleep(1) it doesn't work.
I don't know how it is possible that the Sleep() function receives a float argument since it should get DWORD arguments, but it does.
I get a warning that I am sending a float instead of DWORD so I gather that a casting from float to DWORD occurs, however I tried to use Sleep(0) and it gave me 90% CPU usage.
This is still not the solution I am seeking. Since the high priorities may affect the performance of the rest of the application, and since the purpose of the application is to control a small vehicle, I wouldn't want my small thread to cause an accident.
P.S. I've changed the thread creation to CreateThread() instead of AfxBeginThread() so that I could get a HANDLE on the thread.
If I set the following conditions I am able to run the entire application with 62% CPU usage (where without the above thread the main application uses 52%):
SetPriorityClass(HIGH_PRIORITY_CLASS);
SetThreadPriority(THREAD_PRIORITY_HIGH);
And I set the Sleep() argument to be 0.01 - meaning I call it like this: Sleep(0.01).
If I don't set the priorities and only use the Sleep(0.01) it doesn't work. If I only set the priorities but use Sleep(1) it doesn't work.
I don't know how it is possible that the Sleep() function receives a float argument since it should get DWORD arguments, but it does.
I get a warning that I am sending a float instead of DWORD so I gather that a casting from float to DWORD occurs, however I tried to use Sleep(0) and it gave me 90% CPU usage.
This is still not the solution I am seeking. Since the high priorities may affect the performance of the rest of the application, and since the purpose of the application is to control a small vehicle, I wouldn't want my small thread to cause an accident.
P.S. I've changed the thread creation to CreateThread() instead of AfxBeginThread() so that I could get a HANDLE on the thread.
Another approach to consider.
http://msdn.microsoft.com/en-us/libr...83(VS.85).aspx
http://msdn.microsoft.com/en-us/libr...83(VS.85).aspx
If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
UK Voter? Please send a message to Incapability Brown and the rest of Zanu-Labour
Up to 8Mb PlusNet broadband from only £5.99 a month!
UK Voter? Please send a message to Incapability Brown and the rest of Zanu-Labour
Up to 8Mb PlusNet broadband from only £5.99 a month!
•
•
Posts: 19
Reputation:
Solved Threads: 0
Thanks.
I'll try it on Monday, report to you then
•
•
Posts: 19
Reputation:
Solved Threads: 0
okay, just wanted to let you know that I've worked things out.
Your tips were helpful so thank you very much.
I'll explain what I did so that others with a similar problem would try it.
Instead of trying to capture every data package that is sent, I waited 'till there were 5 packages and then read all of them into my working buffer (which was basically an array of chars with the appropriate size). After I rewrote my thread to work like this, the CPU usage dropped down to almost none.
I tried using my thread reading a single package at a time, and it worked great!
So, again, thanks everyone
And have a good and happy new year.
Your tips were helpful so thank you very much.
I'll explain what I did so that others with a similar problem would try it.
Instead of trying to capture every data package that is sent, I waited 'till there were 5 packages and then read all of them into my working buffer (which was basically an array of chars with the appropriate size). After I rewrote my thread to work like this, the CPU usage dropped down to almost none.
I tried using my thread reading a single package at a time, and it worked great!
So, again, thanks everyone
And have a good and happy new year.
![]() |
Similar Threads
Other Threads in the C++ Forum
- reading data using serial port (Visual Basic 4 / 5 / 6)
- SpeedUp Your Window XP Never Than Before (Windows tips 'n' tweaks)
- memory management in wndows 2000 (Windows NT / 2000 / XP / 2003)
- need suggestion on this project (Visual Basic 4 / 5 / 6)
Other Threads in the C++ Forum
- Previous Thread: Set the include path
- Next Thread: Help with saving/loading system.
•
•
•
•
Views: 970 | Replies: 6 | Currently Viewing: 1 (0 members and 1 guests)






Linear Mode