A Real-Time Operating System on the Raspberry Pi
The Raspberry Pi has received a lot of attention since its release in early 2012. It was designed to be a simple, low-cost device for use in schools to encourage interest in computers and computing. Whether that goal has been achieved is perhaps still open to debate, but what is clear is that the device has gained a significant following in the hobbyist and DIY world.
There is a strong, active community and support from the Raspberry Pi foundation focused on their Raspian Linux distribution, which is a Debian derivative with support and optimisation for the Raspberry Pi hardware.
At first glance the features that make the device attractive for hobbyists could also make it useful for professional developers looking for a low-cost development platform for real-time and/or embedded applications.
A platform for professional developers?
The board is centred on a Broadcom BCM2835 media applications system-on-chip device and provides the following:
– VideoCore GPU (graphics processor)
– ARM1176JZF-S CPU (general purpose processor)
– IEEE 754 compliant VFP (ARM hardware floating point)
– 512 MB SDRAM
– General purpose i/O pins
– I2C, I2S, SPI and PWM controllers
– USB host interface
– On-board Ethernet interface
– Bootstrap via external SD card
But there is much more to consider before using this, or any other, platform for something like a real-time embedded control application. For example:
– Hardware availability
– Mechanical stability
– EMC and environmental performance
– Access to documentation and reference material
– Technical support for the hardware and software
– Development tool support
– RTOS and middleware support
The Raspberry Pi was not designed with commercial/industrial applications in mind, which might be reason enough to disregard it as a serious contender as a platform for development. The recent announcement of the Raspberry Pi Compute Module might change that though.
My expertise is in embedded software development so I want to explore the software aspects in more detail, in particular, how to get a real-time operating system (RTOS) or kernel running on the board.
The right tools for job
The ARM1176 core has been around for 10 years and has been used in many commercial products including the Apple iPhone 3G and the Amazon Kindle. It is still being licensed for new designs due to its maturity and low implementation risk.
The documentation for the ARM1176 processor core is freely available from the ARM website. The ARM core is part of the Broadcom BCM2835 processor. There is some documentation for the on-chip peripherals but it is limited and contains various errors and omissions.
A cross-compiler is needed to build software for the Raspberry Pi on a desktop computer. This may be provided by the RTOS vendor but, if not, both free and commercial products are available for use on Windows and Linux hosts. YAGARTO (www.yagarto.de) is a free cross-compiler based on the GNU ARM toolchain.
CrossWorks for ARM from Rowley Associates is a commercially-supported cross compiler that even provides example board support files for the Raspberry Pi required to run a bare metal application or bootstrap a real-time operating system.
An important tool in traditional board bring-up is a JTAG debugger. Most embedded processor boards, whether off-the-shelf or custom designed, will have a JTAG header on the PCB. The Raspberry Pi does not have a dedicated JTAG header but the JTAG signals are available as alternate functions on six of the GPIO pins that are routed to the 26-pin expansion header on the board. So a JTAG interface can be provided by reconfiguring these pins by bootstrap code or later in the software initialisation sequence, if required.
This will require an adaptor to connect a standard JTAG debugger to the header on the Pi, and while these pins are used for JTAG, they are not be available as general purpose I/O.
Boot strap and beyond
One of the nice features of the Raspberry Pi for educational and hobbyists is that it is impossible to ‘brick’- there is no on-board user-programmable flash memory for storage of programs or data. (The Compute Module does have flash memory but it can be programmed via USB interface.)
Following power-on reset, the ARM core is held in reset and the GPU core runs a ROM-based bootloader that looks for configuration data and an operating system or application image to load from an external SD card. If an image is found it is loaded into memory from the SD card and the ARM core is taken out of reset and begins executing the image.
The GPU plays no further role unless the application or operating system wants to make use of its video processing services. This means the development cycle for bringing up a new operating system involves copying the kernel image from the development host to the SD card, inserting the SD card and power-cycling the board.
Running an operating system on a new hardware platform typically involves developing a board support package (BSP). The BSP is a collection of hardware-dependent routines and device drivers that provide support for the fundamental hardware blocks in the processor, enabling the kernel to provide its services to application software. These hardware blocks include the following:
– An external memory controller (for access to the SDRAM)
– An MMU (for virtual memory and cache control)
– A general purpose timer (to provide a system clock tick)
– An interrupt controller
– A UART (for console output)
Device drivers will also be required for other devices and interfaces the application wants to use, for example, USB, networking, SDHC, I2C, SPI, general purpose i/o, etc.
The effort required to get a kernel running on a new board depends partly on how much code can be re-used or adapted from BSPs for similar target boards, and how much has to be written from scratch. It also depends on the quality of the development environment (compiler toolchain, debugger, profiler, etc)and even more importantly on the experience of the team doing the BSP development.
Foundations for supporting an RTOS kernel
My colleagues and I have been developing BSPs for various real-time operating systems and embedded Linux for over twenty years. We have particular experience and expertise with Wind River’s VxWorks real-time operating system going back to the early 1990s. So what would be the steps to get an RTOS like VxWorks running on the Raspberry Pi?
Before starting the development we should consider what off-the-shelf components are available and what would have to be developed specifically for the Pi.
The first thing to check is the support for the ARM1176 core. This is supported by the ARMv6 architecture libraries, which provide support for the MMU and caches in the processor. (The BCM2835 actually has a second MMU that is configured by the GPU at start-up to map the SDRAM and peripherals onto an internal system bus but this can be ignored as far as an RTOS on the ARM core is concerned.)
Setting up the SDRAM controller is an important process and has to be done correctly to avoid random and difficult to track down problems later on. Doing this on a modern processor with fast DDR3 memory is more like magic than engineering. Fortunately, the SDRAM is set up by the GPU so this step does not need to be done by the operating system.
However, the default behaviour is for the available RAM to be split equally between the GPU and the ARM core. A model B Pi has 512 MB of SDRAM, so 256 MB will be available for the RTOS by default. This is controlled by one of the configuration files (config.txt) read by the bootloader from the SD card. This file can be changed if more memory is required for the kernel.
The BCM2835 interrupt controller is responsible for handling interrupts from the ARM core and the VideoCore GPU. The controller is specific to the BCM2835 so a new driver is required for the operating system to enable and disable device interrupts, and dispatch interrupts to handlers registered by individual device drivers. This is another tricky task and one where good debugging or instrumentation tools and techniques are required to ensure a stable foundation.
The VxWorks kernel, like many others, requires a timer to provide a periodic system clock tick to schedule tasks, maintain software timers, and determine when certain operations have timed out. The BCM2835 includes a System Timer peripheral that provides four 32-bit timers and a 64-bit free running counter.
One of the 32-bit timers would be suitable to provide the system clock tick but of course a new device driver would be required.
Console I/O and networking
A serial console is the default for most operating systems. The processor has two UARTs but due to pin multiplexing limitations on the standard boards only one can be used. The Compute Module has much more GPIO so both UARTs could be used.
One of the UARTs is an (almost) 16550-compatible device (known as the mini UART), the other is an ARM Primecell PL011-compatible UART. Drivers for both these types of device are commonly available so it should be fairly straight-forward to get the console running. The default pin multiplexing brings out PL011 UART.
With these components and tools it should be possible to get to the point where the RTOS or kernel is running on the board and console i/o is available. There is still a lot of work to do before the board can be used in an application, however.
Operating system-specific device drivers are required for the
peripherals that will be used by the application software. (And we haven’t even considered using the GPU services to provide output and graphics on the HDMI interface.)
For a VxWorks development project we could start using the standard development tools running over a serial connection to board. This would avoid having to re-program the SD card to download and test new drivers and application software. Using the serial interface for the debug connection means it is not available for application-specific use. It would be preferable to use the network interface to load the kernel and application software onto the target.
The network interface is provided by a SMSC LAN9512 Ethernet controller (it is a LAN9514 on the Model B+), which is connected to the USB host interface. To use the network interface a lot of additional software (and effort) is required:
– A USB host controller driver for the Synopsys DesignWare USB 2.0 OTG
controller embedded in the processor
– A USB host stack with USB networking infrastructure
– A device driver for LAN9512/4 Ethernet controller
These components are not specific to the Raspberry Pi so, if not already available of-the-shelf, development of this software could be done on a suitable reference board which is already supported by the RTOS plus an evaluation board for the LAN9512 such as the EVB9512.
The work could be done in parallel with the RTOS bring-up on the Pi and integrated with the Pi BSP software once it is working on the reference board. VxWorks, for example, supports the Synopsys USB controller and provides a USB networking infrastructure so just the LAN9512 support would have to be developed.
Getting an RTOS to run on the Raspberry Pi provides some interesting technical challenges, albeit challenges we have seen on different real-world projects over the years.
Even though the hardware is low-cost and widely available, the modest GPIO, single UART and USB networking, the potential software development costs could outweigh these benefits if one were considering the standard boards. It will be interesting to see if the new Raspberry Pi Compute Module drives the need for RTOS support on this platform.