Windows COM Port Question

Question about the low-er level operation of serial ports

Page 1 of 1

3 Replies - 4447 Views - Last Post: 21 March 2009 - 10:26 AM Rate Topic: -----

#1 Robotics Guy  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 6
  • Joined: 20-March 09

Windows COM Port Question

Post icon  Posted 20 March 2009 - 04:45 PM

Good evening,

My code is rather long and convoluted at the moment (I am working on cleaning it up), and I don't think my question will require it being posted, but once I get it straightened out I'll be happy to post it. Just saying this since there are GIANT letters in this text box saying "You Must Show Us Your Code." :P

I'm communicating with an external device using a serial (COM) port on the Windows Vista operating system, in the C++ language. By creating and using a handle to a file (the COM port), I am successfully reading and writing to the communications port. So my question is NOT how to communicate with an external device.

The question arises from a problem with my program. I've used the wxWidgets toolkit to build a GUI for my program, and because the toolkit allows for the easy implementation of multiple threads, I decided to put the serial port code inside a separate thread then that where my main program resides, and to simply run the thread continuously, polling the COM port continuously. My problem was, for a certain amount of time after opening the program, the user is not connected to the serial port, and thus the code inside the thread was not executed (I had it inside an if statement, to only run if the user had connected to the serial port). And so, with the help of the users on the toolkit's forum, I learned of "Busy Waiting." Apparently if the while loop is empty (which is was, since the if statement was passed over), this "Busy Waiting" occurs and takes nearly 100% of the CPU! How terrible! What mystified me was that when the serial port code was executed, the CPU usage was minimal. This seemed absurd, until someone suggested that perhaps the serial port code on Windows had some sort of sleep statement built into it.

And so, after searching Google, I found this forum B)

As previously mentioned, my code is at the moment, a mess. But this document is where the inspiration for my code came from, and I'm sure is much clearer to read then mine:

http://www.robbayer..../serial-win.pdf

Could anyone provide me with some insight, as to how executing the serial port code keeps the "Busy Waiting" from occurring?

Appreciate the advice!

This post has been edited by Robotics Guy: 20 March 2009 - 04:49 PM


Is This A Good Question/Topic? 0
  • +

Replies To: Windows COM Port Question

#2 matthew180  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 51
  • View blog
  • Posts: 202
  • Joined: 07-January 09

Re: Windows COM Port Question

Posted 20 March 2009 - 05:49 PM

I would have to see your code for the thread reading the serial port, but if you have something like in the document you posted:

if(!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL)){
//error occurred. Report to user.
}



Then the call to ReadFile is a system call and will block until there is data to read. When you are blocking in a system call the kernel knows you are waiting for it to send you data, and thus it knows you do not need a time slice to execute until that function is ready to return.

Thus, while you are blocked in a system call like that, your usage should be zero. However, if you are in a loop polling for an event, then you are *very busy*. It is best to block rather than poll. Also, in your main application thread you should use a condition variable (instead of polling) to signal your serial port thread that it is time to connect and read / write data.

So your serial port thread initializes itself and blocks on the condition variable immediately, then when it is time to connect your main thread signals the serial port thread which then unblocks, connects the serial port, and starts reading / writing.

Matthew
Was This Post Helpful? 1
  • +
  • -

#3 Robotics Guy  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 6
  • Joined: 20-March 09

Re: Windows COM Port Question

Posted 21 March 2009 - 09:15 AM

That makes perfect sense, thank you.

I'm using a baud rate of 9600 8 N 1. Which means a bit arrives at the serial port every 1/9600 seconds, or every 104 microseconds.

So, my code in the while loop must only run every 104 microseconds, and the system "blocks" the rest of the time. The low CPU usage now makes sense.

Thanks again!
Was This Post Helpful? 0
  • +
  • -

#4 matthew180  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 51
  • View blog
  • Posts: 202
  • Joined: 07-January 09

Re: Windows COM Port Question

Posted 21 March 2009 - 10:26 AM

FYI: The baud rate and symbol rate are not always the same, but in this case they do correlate (as do most of the buad rates used in old modems). Check out the wikipedia page on baud rate for more info.

Also, your code is going to block for more than 104us. The serial port hardware will be receiving the bits and assemble them into bytes. The serial port also has a hardware buffer (of at least 16 bytes, maybe more) which the *kernel* will be reading when the serial port generates a hardware interrupt that data has arrived. You have supplied a buffer and size to the kernel in your ReadFile call, so your code will not unblock until your buffer has been filled.

Assuming at least a 16 byte hardware buffer in the serial port, if the kernel unblocked your code once every 16 bytes, that would be about every 13.332ms.

Check out the wikipedia page on multitasking which explains in better detail why blocking is better than polling.

"At any specific time, processes can be grouped into two categories: those that are waiting for input or output (called "I/O bound"), and those that are fully utilizing the CPU ("CPU bound"). In primitive systems, the software would often "poll", or "busywait" while waiting for requested input (such as disk, keyboard or network input). During this time, the system was not performing useful work. With the advent of interrupts and preemptive multitasking, I/O bound processes could be "blocked", or put on hold, pending the arrival of the necessary data, allowing other processes to utilize the CPU. As the arrival of the requested data would generate an interrupt, blocked processes could be guaranteed a timely return to execution."

Matthew
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1