Board-to-Board Communication

In this lab, you will establish UART based communication channels between the Pi 4 and the HiFive 1 boards.

Part 0: Setup the UART connections (for TAs)

In this part, we will connect the HiFive1 and the Raspberry Pi 4 boards via two UART channels.

(Note that this step will be performed by the TAs.)

The Pi 4 has 4 UARTs and we will use two of them (uart2 and uart3). Add the following line at the end of the /boot/config.txt file to enable uart2 and uart3.

dtoverlay=uart2,115200 dtoverlay=uart3,115200

After rebooting the system, /dev/ttyAMA1 and /dev/ttyAMA2 will be created.

Connect HiFive’s UART1 RX (pin7) to Raspberry Pi 4’s UART2 TX (pin 27). This is the main communication line between the Pi 4 and the HiFive1. From the Pi 4, you can access the channel via /dev/ttyAMA1.

For debugging of HiFive 1, connect HiFive1’s UART0 TX (pin1) to Pi 4’s UART3 RX (pin 29). From the Pi 4, it can be accessed via /dev/ttyAMA2.

In summary, you will be able to access the following two files from the Pi 4.

/dev/ttyAMA1             Pi 4 → HiFive1: Send steering angle to HiFive1 (uart1).

/dev/ttyAMA2             HiFive1 → Pi 4: Receive HiFive1’s console (uart0) output

Part 1: Programming the HiFive1

In this part of the lab, you will program the HiFive1 to receive data from the Pi 4.

On your PC (not Pi 4), download the project skeleton as follows.

$  cd  ~/Documents/PlatformIO

$  wget

$  tar  zxvf  l10-comm.tar.gz

Add the l10-interrupt folder into VSCode workspace.

Your task is to receive the data from HiFive1’s UART1 channel and send the received data to UART0 channel. The following is a rough pseudo code of the task.

while  (1)  {

if  (is  UART1  ready?)  { data  =  read  from  UART1. print  data  to  UART0.


} To implement the task, you may need to use the provided serial API shown in the following. Note that devid is 0 to access UART0, while it is 1 to access UART1.

void ser_setup(int devid); int          ser_isready(int devid);

void ser_write(int devid, char c);

void ser_printline(int devid, char *str); char ser_read(int devid);

int  ser_readline(int  devid,  int  n,  char  *str);

In particular, you may need to use ser_isready()  function to check whether a given UART channel has pending data to read. To better understand what the functions are doing, check eecs388_lib.h and eecs388_lib.c files.

int     ser_isready(int devid)


uint32_t regval = *(volatile uint32_t *)(UART_ADDR(devid) + UART_IP); return regval;


Once you finish programming the HiFive1, switch to the Raspberry Pi 4 and open two terminals: one for sending data to the HiFive1, and one for seeing the debug message output from the HiFive1.

Sender’s terminal (term1)

$  screen  /dev/ttyAMA1  115200

Debug terminal (term2)

$  screen  /dev/ttyAMA2  115200

Now, type any strings on the ‘term1’.

If you programmed your HiFive 1 correct, you should see the message coming out from the ‘term2’ terminal.

Part 2: Programming the Raspberry Pi 4.

Instead of using terminals, you now run a python program on the Pi 4 to communicate with the HiFive1. Your task is to extend the from the previous lab to be able to send the steering output to the  /dev/ttyAMA1 serial channel. The following pseudo code provides a general idea of the modifications you will need to make to

Open  serial  connections  to  /dev/ttyAMA1  and  /dev/ttyAMA2 While  True:

image  =

angle  =  dnn_inference(image) Write  ‘angle’  to  /dev/ttyAMA1 Wait_till_next_period()

Close  serial  connections

To achieve the functionality from above, you need to use Python's pySerial API which can be used by importing the serial package:

import  serial

With it, you should create two separate serial channels, one for writing to the HiFive1 over

/dev/ttyAMA1 and another for debugging over /dev/ttyAMA2. Note that both channels should be opened with the baudrate 115200 bps.

ser1  =  serial.Serial(…) ser2  =  serial.Serial(…)

The angles received from the DNN as it processes frames can then be sent to the HiFive1 by using the serial write() function:


However, write() requires a byte value while the angle produced by the DNN is a float32 value, so you will have to convert the angle data in order to send it to the HiFive1. Finally, after all of the frames are processed, the serial connections can be closed by invoking the serial close() function:

ser1.close() ser2.close()


GPIO mapping of Pi 4.

Raspberry Pi 4 Pinout

Not only is the Raspberry Pi 4 bursting with new hardware features but under the hood there are some extra GPIO functions to make life a bit easier, allowing users to expand their peripherals to their projects without requiring additional hardware In particular there are a bunch of extra I2C, UART and SPI interfaces that can be used on the Raspberry Pi 4.

GPIO pinouts

You can find a full list of GPIO pinouts on the Raspberry PI 4 itself, simply go to the command line and type in pinout.

Below is a list of all the new Raspberry Pi 4 extra pinout features:

GPIO – General Purpose Input Output Pins

These digital pins can be programmed to receive digital inputs or output a digital signal. The Raspberry Pi uses a 3V3 logic on each GPIO pin, which means that 3V3 is a digital 1 (ON) and 0V is digital 0 (OFF). Therefore you can connect and digital component to the Raspberry Pi and either provide a 3V3 (ON) signal to it or receive a 3V3 digital signal providing the current is no more than 16mA.

I2C – Inter-Integrated Circuit

This is a fairly common type of communication between devices, it works by having a master and a slave. The master in this case is the Raspberry Pi itself and the slave devices are hardware peripherals that would normally extend the functionality of your projects. Whats great about I2C is that you can connect hundreds of devices up to the same master using the same two-wire interface, providing that each device has a different I2C address. You can access the interface and see which devices are conencted by using the following linux command:

sudo i2cdetect -y 1

Where “1” is the master interface. The Raspberry Pi 4 has 6 in total.

SPI – Serial Peripheral Interface

SPI is another type of communication protocol for communicating between devices. It also uses a master/slave setup but is primarily used in short distances between a main (master) controller and peripheral devices (slaves) such as sensors. SPI typically uses 3-wires to communicate with the Raspberry Pi; SCLK, MOSI and MISO. Before using SPI you need to enable it within the Raspberry Pi configuration menu:

UART – Universal Asynchronous Receiver/Transmitter

Unlike I2c and SPI, UART is not a protocol. UART (Serial) is a physical circuit designed to transmit and receive serial data. UART does not require a clock signal, hence why it is asynchronous. This minimises the required wires need to to send and receive data but it also requires some extra data to be sent with the packets for error checking such as a start bit and a stop bit. Typically with regards to the Raspberry Pi UART is used in a headless setup, which means no GUI or other interface. Instead you can connect the Raspberry Pi to your Desktop/Laptop or other device and communicate with it over UART using the command line interface. This method is for the more advanced users since it requires a bit more know how in setting it up.

Another application, which is typical amongst Raspberry Pi users is to connect a Arduino UNO board to the Raspberry Pi, since the Pi has limited analog functionality.

About The Author

Muhammad Bilal

I am highly skilled and motivated individual with a Master's degree in Computer Science. I have extensive experience in technical writing and a deep understanding of SEO practices.

Scroll to Top