Development Guide

These instructions will demonstrate to you how to get a simple Hello World via the UART interface, demonstrating the full functionality of the Pi Kit.

You can follow these instructions on any of the CPSC lab computers, using the Development VM, or by setting up your own toolchain (eg via WSL). Please note that CPSC ULS only supports development in the labs or using the VM.

This guide assumes the reader has some familiarity with basic Linux tools.

Hooking up the Pi

Your Raspberry Pi Kit contains all of the hardware necessary for development. The custom Pi HAT provides a number of interfaces enabling you to debug the Pi, write to the Pi’s memory, and connect devices (such as the controllers).

To get started you’ll need to plug the Pi in using the included power supply. It is important to only use the included power supply with the Pi. Take the USB type B cable and plug the B end into the top of the Pi HAT and the USB A end into your computer. Finally, plug the HDMI cable into a monitor.

Optionally - though not required at this stage - you can plug the SNES controller into the RJ45 port A.

Opening the UART interface and using OpenOCD

The Pi HAT provides several interfaces, including UART and JTAG. Using standard Linux tools we can work with these interfaces to send code and receive messages.

First of all, let’s open the UART interface to see if the program on the Pi is sending any data over UART. You can do this with a Linux tool called screen. Open a Terminal and enter the following:

screen /dev/ttyUSB0 115200,cs8,ixoff,-istrip

NOTE: You may get an error at this stage that /dev/ttyUSB0 cannot be found. Due to the way Linux assigns devices, the correct path could be /dev/ttyUSB1.

This Terminal will now display any data sent by the Pi over the UART interface.

Next we’ll open a debug interface using openocd and work with it using gdb.

Open another Terminal (hint: ctrl+shift+t will open a new tab in the same window!) and enter the following command:

openocd -f interface/rpi4.cfg

NOTE: The path to interface/rpi4.cfg is valid only in the development VM and on the CPSC lab computers. In your own environment you will need to get the rpi4.cfg file from your instructor.

You’ll see some output letting you know that a debug interface has been opened. You can think of it as a “server” that we’ll connect to using gdb.

You’ll now need to open another Terminal and enter: gdb.

gdb has its own command line where you will need to enter the following commands to finish setting up the environment:

set architecture aarch64
target extended-remote :3333

With the debug interface open you can send new code to the Pi by overwriting its memory - we’ll discuss compiling code in the next section - but assuming you have some, you can do:

load /path/to/code.elf 0x0
continue

Watch your UART interface as you do this - if you send text to UART in your program, you should see it immediately! When you want to send new code to the Pi, you can press ctrl+c in the gdb window and repeat the load command.

With this in mind you will be able to iterate your code more conveniently, sending new variations of your code to the Pi as you compile it.

Writing some code

Your TA / instructor should have provided you some code to bootstrap the Pi. This will be files named similar to start.S, uart.c etc. If you don’t have these, speak to your instructor.

The boilerplate bootstrap contains code to initiate the UART interface so text can be sent. The function as defined in uart.c for this is uart_init(). So with that in mind, let’s see a simple boilerplate Hello World:

#include "types.h"
#include "uart.h"
#include "mbox.h"
#include "ssp.h"

void main() {
    uart_init();

    uart_puts("Hello world!\n");
}

There should be a Makefile with the boilerplate, using that, simply make your code. Two files will be generated: kernel8.elf and kernel8.img. We are interested in the elf file at this stage.

In the gdb window you opened in the previous step, enter the following, while watching your Terminal window with the UART interface:

load /path/to/kernel8.elf 0x0
continue

As soon as you type in continue (or c! gdb has lots of abbreviations), you should see Hello World! output in the the UART interface window.

Now try adding an extra uart_puts into your code and compile it. Press ctrl+c in gdb and then run the load command again (hint: use the UP arrow on your keyboard as a neat shortcut). Your new text should appear in the UART interface!