Usinge serial lines from user space

Python example

This is a basic example on how to use a serial port in Pyhon using the pySerial module:

import serial
 
ser = serial.Serial(
    port='/dev/ttyS1', 
    baudrate=9600, 
    timeout=1,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS
)  
 
ser.write("A")      # Send a "A" char to the serial port
s = ser.read(1)     # Wait for a char
print s
ser.close()

Read any bytes received on serial line and print out on stdout in hex format:

import sys
import serial
 
ser = serial.Serial(
    port='/dev/ttyUSB1', 
    baudrate=9600, 
    timeout=1,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS
)  

linecounter=0
bytecounter=0
bytesperline = 8
while True:     
    bytesToRead = ser.inWaiting()
    
    if bytesToRead>0:
        value=ser.read(1)
        if (bytecounter % bytesperline) == 0:
            print "\n[%04X] - " % bytecounter ,
            sys.stdout.flush()
            linecounter=linecounter+1
             
        print "%02X " % ord(value) ,
        sys.stdout.flush()
        bytecounter=bytecounter+1
        if bytecounter==0:
            print
            bytecounter=0

C example

This is a basic example on how to use a serial port in C.

Refer to these links to understand how it works.

#include "stdio.h"     
#include "string.h"    
#include "unistd.h"    
#include "fcntl.h"     
#include "errno.h"     
#include "sys/types.h"
#include "sys/stat.h"
#include "stdlib.h"
#include "stdarg.h"
#include "termios.h"
 
int main(void) {
    char txBuffer[10];
    char rxBuffer[10];
    int fd;
    struct termios tty_attributes;
 
    if ((fd = open("/dev/ttyS1",O_RDWR|O_NOCTTY|O_NONBLOCK))<0) {
        fprintf (stderr,"Open error on %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    } else {
        tcgetattr(fd,&tty_attributes);
 
        // c_cflag
        // Enable receiver
        tty_attributes.c_cflag |= CREAD;        
 
        // 8 data bit
        tty_attributes.c_cflag |= CS8;          
 
        // c_iflag
        // Ignore framing errors and parity errors. 
        tty_attributes.c_iflag |= IGNPAR;       
 
        // c_lflag
        // DISABLE canonical mode.
        // Disables the special characters EOF, EOL, EOL2, 
        // ERASE, KILL, LNEXT, REPRINT, STATUS, and WERASE, and buffers by lines.
 
        // DISABLE this: Echo input characters.
        tty_attributes.c_lflag &= ~(ICANON);     
 
        tty_attributes.c_lflag &= ~(ECHO);      
 
        // DISABLE this: If ICANON is also set, the ERASE character erases the preceding input  
        // character, and WERASE erases the preceding word.
        tty_attributes.c_lflag &= ~(ECHOE);     
 
        // DISABLE this: When any of the characters INTR, QUIT, SUSP, or DSUSP are received, generate the corresponding signal. 
        tty_attributes.c_lflag &= ~(ISIG);      
 
        // Minimum number of characters for non-canonical read.
        tty_attributes.c_cc[VMIN]=1;            
 
        // Timeout in deciseconds for non-canonical read.
        tty_attributes.c_cc[VTIME]=0;           
 
        // Set the baud rate
        cfsetospeed(&tty_attributes,B9600);     
        cfsetispeed(&tty_attributes,B9600);
 
        tcsetattr(fd, TCSANOW, &tty_attributes);
 
        txBuffer[0]='A';
        write(fd,txBuffer,1);
 
        // Read a char
        if (read(fd,&rxBuffer,1)==1) {
            printf("%c",rxBuffer[0]);
            printf("\n");
        }   
    }   
 
    close(fd);  
    return EXIT_SUCCESS;
}

Enable the DMA on serial lines

    /* /dev/ttyS1 */
    usart0: serial@f801c000 {
        pinctrl-0 = <&pinctrl_usart0
                 &pinctrl_usart0_rts
                 &pinctrl_usart0_cts
                 >;
        status = "okay";

        atmel,use-dma-rx;
        atmel,use-dma-tx;
        
        dmas = <&dma0 1 0x3>,<&dma0 1 0x204>;
        
        /*dmas = <&dma0 1 AT91_DMA_CFG_PER_ID(3)>,
               <&dma0 1 AT91_DMA_CFG_FIFOCFG_ASAP | AT91_DMA_CFG_PER_ID(4)>;*/
               
        dma-names = "tx", "rx";                     
    };

Related links

Using the RS485 lines

RS-485 is a standard defining the electrical characteristics of drivers and receivers for use in balanced digital multipoint systems. This standard is widely used for communications in industrial automation because it can be used effectively over long distances and in electrically noisy environments

RS485 with DTS on Kernel version >= 3.4

If you are using a recent Linux Kernel with device tree enabled you have to specify inside the device tree source the RS485. After that you can open the serial port as a normal RS232 port.

This is an example for the /dev/ttyS2 on Aria G25 or Arietta G25 module:

usart3: serial@f8028000 {
    compatible = "atmel,at91sam9260-usart";
    reg = <0xf8028000 0x200>;
    interrupts = <8 4 5>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_usart3 &pinctrl_usart3_rts &pinctrl_usart3_cts >;
    linux,rs485-enabled-at-boot-time;
    rs485-rts-delay = <0 20>;
    status = "okay";
};

The rs485-rts-delay parms are in 0.1 mS instead on mS as written on the Kernel doc.

Python example

This example sends a char on the RS485 bus using a DAISY-10 board wired on the /dev/ttyS2 serial port. If you are using a Terra board plug the DAISY-10 on D10 connector (..see the Terra pinout).

import serial,fcntl, struct
 
ser = serial.Serial(
    port='/dev/ttyS2', 
    baudrate=9600, 
    timeout=1,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS
)  
 
fd=ser.fileno()
 
ser.write("0123456789") # Send some char on the RS485 bus
s = ser.read(1)         # Wait for a char
print s
ser.close()

RS485 without DTS on Kernel version < 3.4

If you are using an old Kernel Linux without the device tree you have to setup the rs485 hardware mode as illustrated below:

Python example

import serial,fcntl, struct
 
ser = serial.Serial(
    port='/dev/ttyS2', 
    baudrate=9600, 
    timeout=1,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS
)  
 
fd=ser.fileno()
serial_rs485 = struct.pack('hhhhhhhh', 1, 0, 0, 0, 0, 0, 0, 0)
fcntl.ioctl(fd,0x542F,serial_rs485)
 
 
ser.write("A")      # Send a "A" char to the serial port
s = ser.read(1)         # Wait for a char
print s
ser.close()

C example

#include "stdio.h"     
#include "string.h"    
#include "unistd.h"    
#include "fcntl.h"     
#include "errno.h"     
#include "sys/types.h"
#include "sys/stat.h"
#include "stdlib.h"
#include "stdarg.h"
#include "termios.h"
#include "linux/serial.h"  
 
#define TIOCSRS485 0x542F
 
int main(void) {
    char txBuffer[10];
    char rxBuffer[10];
    int fd;
    struct termios tty_attributes;
    struct serial_rs485 rs485conf;
 
    if ((fd = open("/dev/ttyS2",O_RDWR|O_NOCTTY|O_NONBLOCK))<0) {
        fprintf (stderr,"Open error on %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    } else {
        tcgetattr(fd,&tty_attributes);
 
        // c_cflag
        // Enable receiver
        tty_attributes.c_cflag |= CREAD;        
 
        // 8 data bit
        tty_attributes.c_cflag |= CS8;          
 
        // c_iflag
        // Ignore framing errors and parity errors. 
        tty_attributes.c_iflag |= IGNPAR;       
 
        // c_lflag
        // DISABLE canonical mode.
        // Disables the special characters EOF, EOL, EOL2, 
        // ERASE, KILL, LNEXT, REPRINT, STATUS, and WERASE, and buffers 
        // by lines.
 
        // DISABLE this: Echo input characters.
        tty_attributes.c_lflag &= ~(ICANON);     
 
        tty_attributes.c_lflag &= ~(ECHO);      
 
        // DISABLE this: If ICANON is also set, the ERASE character 
        // erases the preceding input   
        // character, and WERASE erases the preceding word.
        tty_attributes.c_lflag &= ~(ECHOE);     
 
        // DISABLE this: When any of the characters INTR, QUIT, SUSP, 
        // or DSUSP are received, generate the corresponding signal.    
        tty_attributes.c_lflag &= ~(ISIG);      
 
        // Minimum number of characters for non-canonical read.
        tty_attributes.c_cc[VMIN]=1;            
 
        // Timeout in deciseconds for non-canonical read.
        tty_attributes.c_cc[VTIME]=0;           
 
        // Set the baud rate
        cfsetospeed(&tty_attributes,B9600);     
        cfsetispeed(&tty_attributes,B9600);
 
        tcsetattr(fd, TCSANOW, &tty_attributes);
 
        // Set RS485 mode: 
        rs485conf.flags |= SER_RS485_ENABLED;
        if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) {
            printf("ioctl error\n");
        }
 
        txBuffer[0]='A';
        write(fd,txBuffer,1);
 
        // Read a char
        if (read(fd,&rxBuffer,1)==1) {
            printf("%c",rxBuffer[0]);
            printf("\n");
        }   
    }   
 
    close(fd);  
    return EXIT_SUCCESS;
}

Related links