Serial Communication on RPi

GPIO - Raspberry Pi Documentation

RPi 3B+ UARTs

There are two types of UART available on the Raspberry Pi - PL011 and mini UART. The PL011 is a capable, broadly 16550-compatible UART, while the mini UART has a reduced feature set.

All UARTs on the Raspberry Pi are 3.3V only - damage will occur if they are connected to 5V systems. An adaptor can be used to connect to 5V systems. Alternatively, low-cost USB to 3.3V serial adaptors are available from various third parties.

Pi Zero, 1, 2 and 3 - two UARTs

The Raspberry Pi Zero, 1, 2, and 3 each contain two UARTs as follows:

Name Type
UART0 PL011
UART1 mini UART

Primary UART

On the Raspberry Pi, one UART is selected to be present on GPIO 14 (transmit) and 15 (receive) - this is the primary UART. By default, this will also be the UART on which a Linux console may be present. Note that GPIO 14 is pin 8 on the GPIO header, while GPIO 15 is pin 10.

Secondary UART

The secondary UART is not normally present on the GPIO connector. By default, the secondary UART is connected to the Bluetooth side of the combined wireless LAN/Bluetooth controller, on models which contain this controller.

Configuration

By default, only UART0 is enabled. The following table summarises the assignment of the first two UARTs:

Model first PL011 (UART0) mini UART
Raspberry Pi Zero primary secondary
Raspberry Pi Zero W secondary (Bluetooth) primary
Raspberry Pi 1 primary secondary
Raspberry Pi 2 primary secondary
Raspberry Pi 3 secondary (Bluetooth) primary
Raspberry Pi 4 secondary (Bluetooth) primary

Note: the mini UART is disabled by default, whether it is designated primary or secondary UART.

Linux devices on Raspberry Pi OS:

Linux device Description
/dev/ttyS0 mini UART
/dev/ttyAMA0 first PL011 (UART0)
/dev/serial0 primary UART
/dev/serial1 secondary UART

Note: /dev/serial0 and /dev/serial1 are symbolic links which point to either /dev/ttyS0 or /dev/ttyAMA0.

Mini UART and CPU core frequency

In order to use the mini UART, you need to configure the Raspberry Pi to use a fixed VPU core clock frequency. This is because the mini UART clock is linked to the VPU core clock, so that when the core clock frequency changes, the UART baud rate will also change. The enable_uart and core_freq settings can be added to config.txt to change the behaviour of the mini UART. The following table summarises the possible combinations:

Mini UART set to core clock Result
primary UART variable mini UART disabled
primary UART fixed by setting enable_uart=1 mini UART enabled, core clock fixed to 250MHz, or if force_turbo=1 is set, the VPU turbo frequency
secondary UART variable mini UART disabled
secondary UART fixed by setting core_freq=250 mini UART enabled

The default state of the enable_uart flag depends on which UART is the primary UART:

Primary UART Default state of enable_uart flag
mini UART 0
first PL011 (UART0) 1

UARTs on CM3

There are 2 UARTs module on CM3 For more information, you can read pin description. If you want to use 2 UARTs. You can edit /boot/config.txt

#UART0 aka ttyAMA0 pin 14,15
enable_uart=1
dtoverlay=pi3-disable-bt
dtparam=uart0=on

#UART1 aka ttyS0
dtoverlay=uart1,txd1_pin=32,rxd1_pin=33

Enabling Serial Communication On RPi

Enable using raspi-config interface options, then disable linux serial login but enable hardware serial.

Serial Communication Examples

Communication Using Screen (Terminal)

  1. connect the serial port on Mac Using Cool Term:

    image-20200928110212324

  2. Connect the Serial Port on RPi using screen

     screen /dev/serial0 9600
    

Just incase other programming programs are using the port ,we should got the port :

sudo lsof /dev/serial

We can then kill the program using that serial port.

2020-09-28 11.10.14

Example 1: Blinking an LED Using C++ (WiringPI)

RPi-blink_bb-bb

RPi-blink_schem

#include <wiringPi.h>

int main(void)
{
    wiringPiSetupGpio();
    pinMode(16, OUTPUT);
    for (;;)
    {
        digitalWrite(16, HIGH);
        delay(500);
        digitalWrite(16, LOW);
        delay(500);
    }
    return 0;
}

To build the code :

gcc -Wall -o blink blink.cpp -lwiringPi

gcc -Wall option flag

gcc -Wall enables all compiler’s warning messages. This option should always be used, in order to generate better code.

$ gcc -Wall [options] [source files] [object files] [-o output file]
gcc -Wall myfile.c -o myfile

Example 2: Receiving Single Characters

In very many cases all that is needed is to send a single character to the RPi . Between the upper and lower case letters and the numeric characters there are 62 options. For example you could use ‘F’ for forward, ‘R’ for reverse and ‘S’ for stop.

Code to receive a single character is as simple as this:

#include <stdio.h>
#include <wiringPi.h>
#include <wiringSerial.h>

int main()
{
    // intializing some variables
    __uint8_t newData = 0;
    char receivedChar;

    int fd;
    if (wiringPiSetupGpio() < 0)
    {
        return 1; // setup gpio failure.
    }
    if ((fd = serialOpen("/dev/serial0", 9600)) < 0)
    {
        return 1; //failed to open the serial port
    }
    printf("Serial Communication Start:\n");

    // loop
    for (;;)
    {
        // receive data
        if (serialDataAvail(fd) > 0)
        {
            receivedChar = serialGetchar(fd);
            newData = 1;
        }

        // show data
        if (newData)
        {
            printf("This just in ...");
            printf("%c", receivedChar);
            printf("\n");
            newData = 0;
        }
    }
    // loop end

    serialClose(fd);
    return 0;
}

Then build and run the code ;

 gcc -Wall -o recvsc recvsinglec.c -lwiringPi

Code Result;

2020-09-28 12.38.21

Example 2: Receiving several characters from the Serial Monitor.

If you need to receive more than a single character from the Serial Monitor (perhaps you want to input people’s names) you will need some method of letting the RPi know when it has received the full message. The simplest way to do this is to set the line-ending to newline.

This is done with the box at the bottom of the Cool Term Options. You can choose between “No line ending”, “Newline”, “Carriage return” and “Both NL and CR”. When you select the “Newline” option a new-line character (‘\n’) is added at the end of everything you send.

Screen Shot 2020-09-28 at 12.41.21

#include <stdio.h>
#include <wiringPi.h>
#include <wiringSerial.h>

int main()
{
    // intializing some variables
    const __uint8_t numChars = 32;
    char receivedChars[numChars]; // an array to store the received data;
    __uint8_t newData = 0;

    int fd;
    if (wiringPiSetupGpio() < 0)
    {
        return 1; // setup gpio failure.
    }
    if ((fd = serialOpen("/dev/serial0", 9600)) < 0)
    {
        return 1; //failed to open the serial port
    }
    printf("Serial Communication Start:\n");

    // loop
    for (;;)
    {
        // receive data with a marker
        static __uint8_t ndx = 0;
        char endMarker = '\n';
        char rc;
        while (serialDataAvail(fd) > 0 && !newData)
        {
            rc = serialGetchar(fd);
            if (rc != endMarker)
            {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars)
                {
                    ndx = numChars - 1;
                }
            }
            else
            {
                receivedChars[ndx] = '\0'; //terminate the string
                ndx = 0;
                newData = 1;
            }
        }

        // show data
        if (newData)
        {
            printf("This just in ...");
            printf("%s", receivedChars);
            printf("\n");
            newData = 0;
        }
    }
    // loop end

    serialClose(fd);
    return 0;
}
 gcc -Wall -o recvmc recvmultc.c -lwiringPi

2020-09-28 12.51.19

This version of the program reads all the characters into an array until it detects the Newline character as an end marker.