Purpose of this project is to get some experience with bare metal programming for Raspberry Pi and QEMU ARM machine. Raycasting algorihm is chosen as an interesting and simple showcase example. Project produces four types of outputs:
- reference implementation using SDL library,
- QEMU kernel image,
- Raspberry Pi kernel image that uses framebuffer,
- and Raspberry Pi kernel image that draws on Adafruit PiTFT display.
Install prerequisite packages, build, and run executable.
$ sudo apt-get install libsdl2-2.0-0 libsdl2-dev
$ make sdl
$ ./game
Moving controls: W, A, S, D.
Download and extract ARM toolchain package from https://launchpad.net/gcc-arm-embedded/. Add bin directory of extracted package to the PATH environment variable.
Install prerequisite packages.
$ sudo apt-get install libpixman-1-dev libpixman-1-0 libsdl-image1.2-dev
Download and extract the latest stable version of QEMU from http://wiki.qemu.org/Download.
$ wget http://wiki.qemu-project.org/download/qemu-2.1.0.tar.bz2
$ tar xvjf qemu-2.1.0.tar.bz2
Configure, build, install, and verify qemu-system-arm.
$ cd qemu-2.1.0
$ ./configure --target-list=arm-softmmu,arm-linux-user --enable-sdl
$ make -j 2
$ sudo make install
$ qemu-system-arm --version
$ cd raspi-bare-metal
$ make qemu
$ make runqemu
Moving controls: W, A, S, D.
Build kernel image file. Make sure to have properly configured ARM toolchain.
$ cd raspi-bare-metal
$ make fb
Get a Raspberry PI SD card which has an operating system installed already. On SD card find file kernel.img and rename it to something else, such as kernel.img.original. Then, copy generated file kernel.img onto the SD card. Put the SD card into a Raspberry Pi and turn it on. For left, up, down, and right moving controls are used GPIO ports 23, 22, 21, and 18, respectively.
This image uses Adafruit PiTFT.
$ cd raspi-bare-metal
$ make pitft
Copy file kernel.img onto the SD card. Plug PiTFT into your Raspberry Pi, insert SD card, and turn Raspberry Pi on. For left, up, down, and right moving controls are used GPIO ports 23, 22, 21, and 18, respectively.
One way is to use GDB. Run QEMU kernel image with following parameters.
$ qemu-system-arm -m 128 -kernel kernel.elf -serial stdio -machine integratorcp -S -s
In another console window start remote GDB session.
$ arm-none-eabi-gdb kernel.elf
GNU gdb (GNU Tools for ARM Embedded Processors) 7.6.0.20131129-cvs
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-linux-gnu --target=arm-none-eabi".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /raspi-bare-metal/kernel.elf...(no debugging symbols found)...done.
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x00008010 in pl011_uart_write_char ()
(gdb)
Another way is use of implemented UART functions that print data to stdio.
// Send string to stdio
void pl011_uart_write_string(const char * str);
// Send hex value to stdio
void pl011_uart_write_hex(uint32_t value);
Debugging of bare metal image on Raspberry Pi is not an easy task. The simplest method is use of OK LED for detection of interesting events. Another way is use of UART peripherals of Raspberry Pi. To connect Raspberry Pi and PC you will need console cable. Following C functions are implemented for sending characters to UART peripherals.
// Initialize mini UART
void bcm2835_aux_muart_init(void);
// Send string over mini UART
void bcm2835_aux_muart_transfernb(char* tbuf);
// Send hex value over mini UART
void bcm2835_aux_muart_transfer_hex(uint32_t value);
- Ray-Casting Tutorial
- SDL Documentation
- QEMU Emulator User Documentation
- ARM PrimeCell PS2 Keyboard/Mouse Interface (PL050) - Technical Reference
- PrimeCell UART (PL011) - Technical Reference
- PrimeCell Color LCD Controller (PL110) - Technical Reference
- QEMU source code
- BCM2835 ARM Peripherals - Technical Reference
- C library for Broadcom BCM 2835 as used in Raspberry Pi
- Baking Pi – Operating Systems Development
- RPi Low-level peripherals
- RPi Framebuffer
- RPi SPI
- ILITEK ILI9341 - Technical Reference
- Linux Framebuffer drivers for small TFT LCD display modules
- Library for the Adafruit 2.2" SPI display