RPi – UART Tutorial

HardwareRaspberry Pi 4 Model B (2Gb)
Operating SystemRaspbian GNU/Linux 10 (buster)
LanguagePython 3
RPi.GPIO Revision3
GPIO InteraceGPIO14 & GPIO 15
Linux DeviceSerial0
Parts neededRaspberry PI, Breadboard, Jumpers, Logic Analyzer
Date Last Revised23rd February 2020
Changes MadeCompletely revised (& tested) for Pi 4 and Python 3

Learning OutcomesSetup and use a UART, Enable the UART Service via GUI or Config file, Utilise a Logic Analyzer to view UART transmissions

Our second tutorial is utilising the Uart interface on the GPIO. Again a very simple project and we are keeping it simple so that we can understand what we are looking at when we use a logic analyzer.

The circuit is dead simple. In effect we are implementing a serial loop back. Whilst we could just jumper the pins, we are using a breadboard for a breakout area for the Logic Analyzer to connect to.

Schematic

This image has an empty alt attribute; its file name is Tutorial_2_UART_schem-2.png

and for the more visually inclined, the breadboard looks as follows

Breadboard Diagram

This image has an empty alt attribute; its file name is Tutorial_2_UART_bb-1-1024x976.png

Now for the code – Just scrape the code and save as a file. You can see the filename I have used, but you can make it shorter, just remember the .py extension.

The Code

#!/usr/bin/env python3
#####################################################################################
# Filename    : LogicAnalyzer_UART.py
# Description : Logic_Analyzer_With_UART
# Author      : Bob Fryer / Digital Shack
# modification: 22 Feb 2020
#####################################################################################

#####################################################################################
# Import the required Python Libraries
#####################################################################################

import  serial, time 
import  RPi.GPIO as GPIO

#####################################################################################
# Initialise the Serial Port (ttys0) and flush any serial data from the buffers
#####################################################################################

ser  =  serial.Serial(port  =  "/dev/serial0" , baudrate = 9600 , timeout = 2 )
if  (ser.isOpen()  ==  False):
    ser. open ()                                       # check and open Serial0
ser.flushInput()                                       # clear the UART Input buffer
ser.flushOutput()                                      # clear the UART output buffer

#####################################################################################
# Define our one and only variable
#####################################################################################

echostring  =  "Talking to ourselves!"

#####################################################################################
# Define our main task
#####################################################################################

def echotest():
    while (True):                                      # loop
        ser.flushInput() 			       # Clear UART Input buffer
        ser.flushOutput()                              # Clear UART Output buffer
        ser.write(echostring.encode())                 # write our String in bytes
        print ('What we sent: ', echostring)           # Print what we sent
        time.sleep(0.5)                                # give it a sec to be recvd
        echostringrec = ser.readline().decode("utf-8") # read the rec buffer as UTF8
        print ('What we received: ', echostringrec)    # Print what we received

#####################################################################################
# Define our DESTROY Function
#####################################################################################

def destroy():
    ser.close ()                                          # Closes the serial port
    print ("test complete")

#####################################################################################
# Finally the code for the MAIN program
#####################################################################################

if __name__ == '__main__':                                 # Program entry point
    try:
        echotest()                                         # call echotest function
    except KeyboardInterrupt:                              # Watches for Ctrl-C
        destroy()                                          # call destroy function
    finally:
        destroy()                                          # call destroy function

Important Preparation

Before running this code, you need to make some changes to the O/S Startup.

You can either do this through raspi-config if you are a GUI sort of person, or you can edit the file directly (which honestly is a better way to go). GUI’s have their place, but they hide some of the critical understandings if what is actually happening, and in some cases have a negative impact.

So if you are using raspi-config, you need to issue the following command :

sudo raspi-config

Your menu will appear, select 5 Interfacing options, then select P6 Serial, you will get the following screen :

This image has an empty alt attribute; its file name is raspi_config_serial_screen1.png

Select No, as we want exclusive use of the UART for our “project” and we don’t need to introduce other possible impacts. After you selected No on the above screen, you should see the following screen :

This image has an empty alt attribute; its file name is raspi_config_serial_screen2.png

Select Yes here as this will enable the UART which is what we want.

and finally you should see the following screen

This image has an empty alt attribute; its file name is raspi_config_serial_screen3.png

Clearly showing that the login shell is disabled and that the serial interface is enabled.

It will not ask if you want to reboot. As these are the boot config files which are read at boot time, you need to reboot for the settings to be applied.

If you want to make the modifications manually, then using your favourite editor (nano or vi or similar) modify the following file

/boot/config.txt (as I use nano the command line is nano /boot/config.txt )

This will open up the file with a wide range of settings, but the one we are looking for is enable_uart=1, check it is not there already, and if is not then add it. It should be placed at the end of the file, under the [all] section. It is worth reading the documentation http://rpf.io/configtxt , its a bit to get through, and honestly its more about making yourself aware of whats there, than learning it in its entirety. One more thing, you have made modifications of the boot config files which are read at boot time. So you need to remember to reboot.

Now having said all that about GUI’s and editing the file directly, if you feel more comfortable with the GUI to enable and change services, then go for it, but look for the changes it makes in the config files so you have a better understanding and indeed more confidence of what has been set.

Now we are ready to run the code.

I will explain a little more of what it will do. It will send via the Serial0 port, the string we defined as echostring which was “Talking to ourselves!”. This program basically is a loop which writes to the UART TX and then reads the UART RX buffer. For our project, we don’t actually need to read the RX Buffer, we could just flush it. However the act of sending a string and confirming via code that we receive it as it was originally sent, provides confirmation that :

  1. The Port can be initialised and we access the device
  2. It can send data
  3. It can receive data correctly

So, if everything is working correctly you should see :

This image has an empty alt attribute; its file name is Tutorial_2_UART_Output.png

Connect the Logic Analyzer

Now if that is all working, now we hook up our logic analyzer (as shown on the breadboard diagram)

Prepare Pulseview with 1Mhz and 5M Samples (Maintaining our 4x or better sampling rate). Even with these settings, it was an overkill, as I only expected a 9.6Khz frequency rate for 9600bd, but I always set it way higher than needed just to be sure, and then reduce it.

Once I have the capture I then select my decoder, this case UART, and then fill in the settings for the decoder like so. The Baud Rate, Data bits, Parity type, stop bits, were the standard defaults for the Raspberry PI UART. The best part of the decoder, is even if you have the settings wrong, as you change the settings, it will perform this on that capture. You do not need to sample again.

This image has an empty alt attribute; its file name is Tutorial_2_UART_LA_9600bd_Settings-1.png

You should see something similar to the following

This image has an empty alt attribute; its file name is Tutorial_2_UART_LA_9600bd_fullscreen-1024x489.png

You should see the string that string that we sent to the UART TX.

If we look at it a little closer (zooming in), we can see more detail and we are examining a single bit that makes up the letter k in the transmission

This image has an empty alt attribute; its file name is Tutorial_2_UART_LA_9600bd_zoom-1024x496.png

Lets take it a touch further and increase the baud rate to 115200 Baud. So make the change in the code where it says baudrate = 9600 to baudrate = 115200.

Lets perform a capture again, but remember to change your UART decoder settings to 115200, you will get something similar to

This image has an empty alt attribute; its file name is Tutorial_2_UART_LA_115200bd_zoom.png

Notes :

Use of ttys0, ttyAMA0 & Serial0.

You will find various documentation, code and posts referring to the UART device as either of the above. This varies between versions of Raspberry Pi. The following link is really worth reading https://www.raspberrypi.org/documentation/configuration/uart.md
One of the main things that may surprise you is that the Raspberry PI 4 has six UART interfaces, compared to the PI 3’s two UART interfaces.

What you will also find is that in the code we we use the accepted device name to use which is Serial0, which works across most of the Raspberry PI devices, and references the primary UART interface

UART Interface voltages

We are relatively safe connecting pin to pin on the Raspberry PI, with its voltage of 3.3v, however if you want to interface to an Arduino UART or indeed an RS232 Device you will need a Level Conversion (a Pi Hat or an additional circuit/chip. If you do not perform this Level Conversion, you will cause damage to your Raspberry PI.

dsadmin
Author: dsadmin