How to use the SERIAL ports

Using the serial port from user space

Python3 examples

Send a sequence of bytes

import serial
import time

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

packet = [0x54,0x51,0x41,0x12,0x00,0x02,0xFF,0xFF]

# convert list to bytearray
byte_array = bytearray(packet)

while True:
        ser.write(byte_array)
        time.sleep(1)

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/ttyUSB0',
    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,end='')
            sys.stdout.flush()
            linecounter=linecounter+1

        print("%02X " % ord(value),end='')
        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;
}

Pinout of the serial ports

Signal Dir Description Acqua Aria G25 Arietta
TXD0 O Transmit data J2.14 (PD18) S23 (PA0) J4.23 (PA0)
RXD0 I Receive data J2.11 (PD17) S22 (PA1) J4.24 (PA1)
RTS0 O Request to send J2.12 (PD16) S21 (PA2)
CTS0 I Clear to send J2.9 (PD15) S20 (PA3)
TXD1 O Transmit data J2.46 (PB29) S18 (PA5) J4.28 (PA5)
RXD1 I Receive data J2.45 (PB28) S17 (PA6) J4.27 (PA6)
RTS1 O Request to send E7 (PC27) J4.30 (PC27)
CTS1 I Clear to send E8 (PC28) J4.29 (PC28)
TXD2 O Transmit data J3.13 (PE26) S16 (PA7) J4.26 (PA7)
RXD2 I Receive data J3.12 (PE25) S15 (PA8) J4.25 (PA8)
RTS2 O Request to send J3.11 (PE24)
CTS2 I Clear to send J3.10 (PE23)
TXD3 O Transmit data J3.7 (PE19) E2 (PC22)
RXD3 I Receive data J3.8 (PE18) E3 (PC23)
RTS3 O Request to send J3.5 (PE17) E4 (PC24)
CTS3 I Clear to send J3.6 (PE16) E5 (PC25)
UTXD0 O Transmit data J3.30 (PC30) N10 (PC8)
URXD0 I Receive data J3.31 (PC29) N11 (PC9)
UTXD1 O Transmit data J3.41 (PA31) N18 (PC16)
URXD1 I Receive data J3.32 (PA30) N19 (PC17)
UTXD2 O Transmit data
URXD2 I Receive data
UTXD4 O Transmit data
URXD4 I Receive data
DTXD O Debug port tx data J3.4 (PB31) S13 (PA10)
DRXD I Debug port rx data J3.3 (PB30) S14 (PA9)

Configure the device tree

Acqua

usart0: serial@f001c000 {
    status = "okay";
};

usart1: serial@f0020000 {
    status = "okay";
};

usart2: serial@f8020000 {
    status = "okay";
};

usart3: serial@f8024000 {
    status = "okay";
};

uart1: serial@f8028000 {
    status = "okay";
};

uart0: serial@f0024000 {
    status = "okay";
};

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

Sergio Tanzilli
Systems designer, webmaster of www.acmesystems.it and founder of Acme Systems srl

Personal email: tanzilli@acmesystems.it
Web pages: https://www.acmesystems.it --- https://www.acmestudio.it
Github repositories: https://github.com/tanzilli --- https://github.com/acmesystems
Telegram group dedicated to the Acme Systems boards: https://t.me/acmesystemssrl