Serial C And The Raspberry Pi
Written by Harry Fairhead   
Monday, 29 August 2016
Article Index
Serial C And The Raspberry Pi
Linux Presents A Problem
Setting up
Send and Recieve
Polling for data

Utility Functions

There are some useful utility functions you need to know about:

  • tcdrain(filedescriptor);

waits until all of the data that has been written has been sent. The Linux UART driver will accept large amounts of data and send it for you while your program gets on with something else and this is true even in blocking mode. If you need to wait before sending any more data  or reading a response this is the way to do it. 

  • tcflush(filedescriptior,action)

discards data written to the object referred to by fd but not transmitted, or data received but not read, depending on the value of action:

TCIFLUSH flushes data received but not read
TCOFLUSH flushes data written but not transmitted
TCIOFLUSH flushes all data waiting to be processed

  • tcsendbreak(filedescriptor,duration)

transmits a continuous stream of zero-valued bits for a specific duration. A break is an "out of band" transmission needed to signal special conditions like a hard reset to some devices. It doesn't correspond to any transmitted character because it is out of specification for the number of bits, stop bit and parity specified - the line is simply held low for a given time. If duration is zero, it transmits zero-valued bits for at least 0.25 seconds, and not more that 0.5 seconds. If duration is not zero, it sends zero-valued bits for some implementation-defined length of time.

Sending Data

We have already used the write function without really discussing it, but sending data isn't the difficult part of using serial - receiving data is. 

You can use the standard file descriptor writing function to send data:

  • write(fd,buffer,len)

writes len bytes of buffer to the file specified by the file descriptor. 

What is less well known is that you can also use dprintf, which is the file descriptor version of printf to write to the file descriptor. Note: this is Posix standard since 2008

  • dprintf(filedescriptor,formatstring,variablelist)

For example:

char buf[] = "hello world";
int count = write(sfd, buf, 11);
 

can be written

char buf[] = "hello world";
dprintf(sfd,"%s",buf);

The dprintf is very useful when you need to send the value of a numeric variable to a device over the serial connection.

For example:

int total=100;
dprintf(sfd,"%d\n\r",total):

sends "100" followed by a newline and carriage return.

The dprintf function works on most systems, including the Pi. 

There is also the subtle point of when the writing functions return control to your program. It is usually said that writing data to a serial port is either blocking, i.e. it only returns when all the data written, or non-blocking, i.e. it returns at once. In fact, as the Linux device driver effectively implements a 4096 byte buffer in raw mode, there is little difference between the two modes for writing data in most cases.

Non-blocking mode can be set by opening the file using O_NONBLOCK in the open. That is following:

int sfd = open("/dev/serial0", O_RDWR | 
                         O_NOCTTY|O_NONBLOCK );

If you select blocking raw mode then, as long as the data you are writing is less than 4096 bytes and the buffer is empty, the call to write returns immediately even though most of the bytes have still to be transmitted. If you need to wait for all of the data to be sent then use

tcdrain(filedescriptor);

In non-blocking raw mode, see the next section to see how this is set up, the same thing happens when you write data. 

In short because the write is to a buffer the difference between blocking and non-blocking mode for write isn't important.

Reading Data

When programming a serial connection it is reading data that usually causes the most difficulty. You could say writing is easy, reading is hard. Sending data is easy because you just send the data and the device on the other end has the problem of processing it. Receiving data by contrast requires you to know that there is some data to receive. In short, the problem is finding out when the other device has sent you something to process.

It is often said that there are just two modes – blocking and non-blocking, when it comes to a serial read. In fact the situation is much more complicated. There are in fact four possible ways that a serial read can behave controlled by two parameters in the termios struct

c_cc[VTIME]
c_cc[VMIN]

Roughly speaking VTIME sets how long to wait i.e. the timeout and VMIN sets the minimum number of characters before the call is considered satisfied. 

Note that both parameters are single byte char variables so the maximum value you can set is 255 characters for VMIN or 25.5 seconds for VTIME.

To understand how these work you have to keep in mind that the Linux serial driver will read data from the serial port as it becomes ready and store it in a fairly large buffer irrespective of what your programming is doing. So when you go to read the serial port there might well be data waiting to be read.

The read call specifies the number of bytes to read but this doesn't determine what happens when there aren't enough bytes in the buffer to satisfy the read. That is if you use:

read(sfd,buff,10);

then if there are more than 10 bytes in the serial buffer the call returns at once with 10 bytes - leaving the rest in the buffer for future reads.

In other words, the byte count you specify in read determines what happens when there are more than that number of bytes in the buffer. It is the maximum number of bytes that will be read.  

The question is what happens if there aren't 10 bytes in the buffer?

The answer depends on the setting of c_cc[VTIME] and c_cc[VMIN]:

  • c_cc[VTIME]=0 and c_cc[VMIN]>0

    VMIN sets the number of characters to receive before the read is satisfied. There is no time out and the call will wait forever if the number of characters is never received. The default is

    c_cc[VTIME]=0 and c_cc[VMIN]=1

and this is usually called a blocking read. 

  • c_cc[VTIME]>0 and c_cc[VMIN]=0

the read will be satisfied if a single character is available to read. If there is no character to read then the call will wait for the specified time in tenths of a second.

  • c_cc[VTIME]>0 and c_cc[VMIN]>0

now the time specified is an inter-character timer. The call waits for at least the number of characters to be received but will return if the time between characters exceeds the timeout. The timer is reset each time a character is received. It is very important to note that the timer is only started after the first character is received and this means that the call can block forever is no characters are received.

  • c_cc[VTIME]=0 and c_cc[VMIN]=0

the read will be satisfied immediately. The number of characters currently available or the number of characters requested will be returned.  This is usually refereed to as non-blocking call and it is the way to set one up after the serial port has been opened.

To summarize

  • The number of bytes you specify in the read function sets the maximum number of bytes that will be read. The actual number of bytes read is returned by the read function.

  • c_cc[VMIN] sets the minimum number of bytes that will satisfy the read function.

  • c_cc[VTIME] sets the time out to wait for each character to receive

For example:

options.c_cc[VTIME]=10;
options.c_cc[VMIN]=5;

will cause read to return when five characters have been received or when more than 1 second has elapsed between characters being received. As already mentioned this call will block indefinitely if no characters are received i.e. there is no overall timeout.

You can now see that there isn’t just blocking and non-blocking mode. You can adjust the time that the read waits and how many characters are requred before it returns.

The setting

options.c_cc[VTIME]=0;
options.c_cc[VMIN]=1;

corresponds to what is usually called a blocking call because the read will wait for any amount of time until at least one character is ready to read and the setting

options.c_cc[VTIME]=0;
options.c_cc[VMIN]=0;

corresponds to what is usually called a non-blocking read because it returns at once perhaps with no characters read.

Notice that the most useful configuration c_cc[VTIME]>0 and c_cc[VMIN]>0 which will wait for at least c_cc[VMIN] but with a time out of c_cc[VTIME] between characters has a problem.

This is most useful because it corresponds to reading a burst of data. The device being read is assumed to send a block of data and then fall silent for a period. The end of the block is detected by the inter-character time out but the problem is that there is no overall time out. If you start a read with say c_cc[VTIME]>1 and c_cc[VMIN]>100 then you could wait forever if the device doesn’t send any data at all. It only needs to send one character to start the time out but if this doesn’t happen you don’t recognize that no block is being sent. The solution to this problem is to not start a read until at least one character is available in the buffer.

To discover how many characters are in the buffer we need to use the lower level ioctl function. The FIONREAD command will return the number of characters waiting:

#include <sys/ioctl.h>
int bytes;
ioctl(sfd, FIONREAD, &bytes);

 

Following this bytes contains the number of characters you can read. Notice that this is a minimum number of characters because more could be received while you are setting up the read.  



Last Updated ( Thursday, 01 December 2016 )