Getting Started with Renode: Simulating an Ada STM32F429disco Blinky Firmware.
by Olivier Henley –
I recently watched the talks from the 28th Ada-Europe International Conference on Reliable Software Technologies (AEiC 2024), which was held in Barcelona last June.
One talk that stood out was HiRTOS: a Multicore RTOS Written in SPARK Ada by J. German Rivera. In his presentation, he mentioned running HiRTOS on Renode, an open-source simulation and virtual development framework for complex embedded systems .
Like many, I’ve primarily dabbled with QEMU, but my curiosity led me to explore an intriguing talk by Sean Cross, Renode: Easy CI for your Weird Hardware. He showcased just how easy and powerful Renode is for configuring and simulating complex embedded hardware. The Renode team even assembled a complete graphical simulation — including vector tables, timers, framebuffer, and firmware — within an hour, all while attending a conference talk!
After watching the presentation (at 1.5x speed), I was eager to try something hands-on with Renode. However, after some searching, I found that up-to-date, straightforward guides on using Renode without diving into the source code or extensive documentation took a lot of work.
I previously ported the Ada Driver Library for the Capstone projects I mentor, creating a reproducible Alire build chain for the STM32F429 discovery dev board. With this setup, I quickly built an STM32F429 blinky app firmware directly using Alire. Armed with a coffee and some outdated videos, I took on the challenge of loading and running the firmware ELF in Renode.
Before diving into the details, If you’re eager to jump straight into the action, the Renode files needed for this simulation are available in the Renode folder of the stm32_blinky_demo repository. You can simply clone the repo and follow the README.md to build the firmware using Alire and launch it on Renode.
For those who want to dig deeper, the following sections will walk you through the content and setup of the Renode files needed to develop a successful simulation.
The Ada Code #
This is your typical “Hello World” for embedded systems, cross-compiled for the ARM Cortex-M4 using the embedded-stm32f429discovery Ada runtime available in Alire:
with Ada.Real_Time; use Ada.Real_Time;
with STM32.Board; use STM32.Board;
procedure STM32_Blinky_Demo is
Period : constant Time_Span := Milliseconds (1000);
Next_Release : Time := Clock;
begin
Initialize_LEDs;
loop
Next_Release := Next_Release + Period;
Toggle_LEDs (All_LEDs);
delay until Next_Release;
end loop;
end STM32_Blinky_Demo;
This simple program toggles all LEDs on the STM32F429 discovery board every second. To obtain the ELF binary, just run
$ alr build
Setting Up the Renode Hardware Configuration #
Renode is written in C# and can be extended primarily to add new hardware peripherals or configure more complex simulation scenarios. However, Renode also provides its hardware description language and scripting language. The .repl
(REnode PLatform) files define your hardware configuration. Many existing device descriptions for various development boards and CPUs are included in the Renode distribution, typically found in the platforms/boards
and platforms/cpus
directories within your Renode installation.
Let’s set up our stm32f429_custom.repl
file step by step. A .repl
file can include other hardware configurations, so we’ll start by incorporating the STM32 ARM device used on the STM32F429 discovery board, which Renode already provides:
using "platforms/cpus/stm32f429.repl"
After thoroughly searching the Renode distribution, I found no pre-configured GPIO Port G connected to an LED. Since our Ada firmware relies on this connection, we’ll first need to enhance our custom Renode hardware description by setting up the GPIO Port G:
gpioPortG: GPIOPort.STM32_GPIOPort @ sysbus <0x40021800, +0x400>
numberOfAFs: 16
[0-15] -> exti@[0-15]
In this snippet:
sysbus
is the central object where you typically connect components in Renode. It’s also the object you interact with in the Renode console to inspect and manipulate everything tied to your simulated system.<0x40021800, +0x400>
indicates that the GPIO Port is memory-mapped at address0x40021800
with a memory range of0x400
. This mapping corresponds directly to the device datasheet, making verifying it easy.numberOfAFs: 16
line shows that this GPIO port supports 16 alternate functions.[0-15] -> exti@[0-15]
line maps each of the GPIO pins (0-15) to the corresponding external interrupt lines (exti
), allowing the GPIO pins to trigger interrupts.
This setup defines how the GPIO Port interacts with the system bus, mapping it into the simulated system’s memory space.
Adding the LED Configuration #
Now, let’s add the LED configuration:
UserLED: Miscellaneous.LED @ gpioPortG
gpioPortG:
13 -> UserLED@0
In this snippet:
UserLED: Miscellaneous.LED @ gpioPortG
defines an LED connected togpioPortG
, our previously configured GPIO port.gpioPortG: 13 -> UserLED@0
maps pin 13 ofgpioPortG
to theUserLED
. The@0
is an internal identifier for theUserLED
instance, allowing Renode to distinguish between multiple instances of LEDs if needed. Pin 13 on the GPIO port, specified in our Ada firmware if you follow the code definition of All_LEDs, will control this particular instance of theUserLED
.
This configuration ensures that activating pin 13 of gpioPortG
in your simulation will trigger the UserLED,
simulating the behavior of an actual LED connected to that pin on your hardware.
Moving to the Renode Simulation Script #
We can now move on to the simulation script .resc
(REnode SCript) using our previous hardware setup.
Renode offers a powerful interactive console where you can create, manipulate, and inspect your simulation or its various components. You can interact with your simulation directly, making real-time adjustments, or script these interactions for automation. This is where our stm32f429_startup.resc
file comes into play.
Let’s walk through setting up the simulation instructions step by step:
Start by creating a new machine named stm32f429_custom
:
mach create "stm32f429_custom"
Next, load the custom platform description for the STM32F429 discovery board:
machine LoadPlatformDescription @/path/to/stm32_blinky_demo/renode/stm32f429_custom.repl
Now, load the ELF firmware for the blinky application:
sysbus LoadELF @/path/to/stm32_blinky_demo/bin/stm32_blinky_demo
To monitor the state changes of the UserLED
, set up logging:
logLevel -1 gpioPortG.UserLED
Finally, start the machine:
start
Running the Script #
As said, these previous instructions are part of the stm32f429_startup.resc
script file. To actually run the simulation, start the Renode console:
$ renode --console
Run the script by including it in the console
include @/path/to/stm32_blinky_demo/renode/stm32f429_startup.resc
If everything goes as planned, you should see the LED state changes being logged at one-second intervals:
... [NOISY] stm32f429_custom/gpioPortG.UserLED: LED state changed to False
... [NOISY] stm32f429_custom/gpioPortG.UserLED: LED state changed to True
Closing Remarks #
This process takes you from setting up your simulation environment to running and observing the behavior of your STM32F429 firmware, all within Renode.
I hope you found this crash course on running Ada code over Renode helpful and that you enjoy watching your LED blink in the virtual world!