The ARM Cortex-M series of processors are very popular in embedded systems and IoT devices due to their low power consumption, good performance and wide tool support. However, working on the real hardware for testing and development can be expensive and time consuming. This is where QEMU comes in – it allows you to simulate Cortex-M processors on your desktop/laptop without needing any real hardware. This enables rapid prototyping, testing and debugging. In this comprehensive article, we will explore some tips and best practices for simulating Cortex-M cores using QEMU.
Choosing the right QEMU emulator
The first step is choosing the right QEMU emulator for Cortex-M simulation. The main options are:
- QEMU user-mode emulation – This uses QEMU’s generic user-mode emulation of ARM CPUs. It can emulate some Cortex-M instructions, but is not fully compliant.
- QEMU system emulation – QEMU’s full system emulation mode with the vexpress-a15 board can emulate Cortex-A cores along with peripheral devices. This does not support Cortex-M simulation.
- QEMU system emulation with Cortex-M specific board – QEMU system emulation for boards like ‘musca-b1’ or ‘microbit’ provide support for emulating Cortex-M processors and on-board peripherals.
For most purposes, using QEMU system emulation with a Cortex-M specific board will provide better support and accuracy for simulating the processor and peripherals.
Installing QEMU
QEMU is available for Linux, Windows and MacOS. On Linux, install QEMU using your distribution’s package manager. For example, on Ubuntu: sudo apt install qemu-system-arm
On Windows and MacOS, download the QEMU binaries from the official website and install them: https://www.qemu.org/download/
Make sure to add the QEMU binaries to your PATH environment variable so you can invoke it easily from the terminal/command prompt.
Choosing a board model
QEMU includes emulation for several development boards featuring Cortex-M processors like STM32F4. Some examples are:
- micro:bit board – Cortex-M0 processor
- STM32F4-Discovery board – Cortex-M4F processor
- OLIMEX STM32-E407 board – Cortex-M4 processor
- Musca-B1 board – Cortex-M33 processor
Choose a board model based on the specific Cortex-M processor you wish to emulate. You can find the available boards by checking the QEMU source code under qemu/hw/arm
.
Obtaining the firmware
To simulate a Cortex-M processor, you will need firmware images built for the target processor and board. These are typically provided by board vendors and chip manufacturers. For example, STMicroelectronics provides firmware images for its Discovery and Nucleo boards.
You can also build the firmware from source code using a toolchain like GCC ARM Embedded. Ensure the firmware is compiled for the correct target processor architecture.
Launching QEMU for Cortex-M simulation
With the firmware image, launching QEMU for Cortex-M simulation is straightforward. Here is an example command-line: qemu-system-arm -M musca-b1 -kernel firmware.img -nographic
This launches QEMU emulating the Musca-B1 board and loads the ‘firmware.img’ binary. The ‘-nographic’ option disables the graphical output.
To enable semihosting for logging debug messages over the terminal, use: -semihosting -semihosting-config enable,target=native
Debugging with GDB
GDB can be used for debugging firmware running on the emulated Cortex-M processor. Pass the ‘-s -S’ options to QEMU to launch it in gdbserver mode: qemu-system-arm -M musca-b1 -kernel firmware.img -s -S -nographic
In another terminal, connect to the gdbserver on port 1234: arm-none-eabi-gdb firmware.elf (gdb) target remote localhost:1234
Now you can set breakpoints and debug as normal using GDB commands. The firmware ‘firmware.elf’ contains the debug symbols to facilitate debugging.
Accessing semihosting logs
With semihosting enabled, log messages from the firmware will be printed to the QEMU console. To save them to a file, redirect the output: qemu-system-arm […options…] 2>&1 | tee log.txt
Monitoring code coverage
QEMU can produce code coverage statistics when run in TCG mode (the default). To enable this, pass the ‘cov’ parameter: -semihosting-config enable=on,target=native,cov
Code coverage data will be saved to ‘qcow2_code_cov.dmp’ file on exit. This can be processed using the ‘lcov’ utility to produce human-readable coverage reports.
Limitations of QEMU simulation
While QEMU provides a useful Cortex-M simulation environment, it does have some limitations to be aware of:
- Timing behavior is not fully accurate compared to real hardware.
- Hardware interrupts and asynchronous events may not be handled precisely.
- Real-time responsiveness will not match that of actual embedded targets.
- Peripheral behavior is modeled in software and could differ from physical devices.
Keep these limitations in mind and test final firmware on real devices before production deployment.
Optimizing simulation performance
QEMU emulation requires significant CPU resources. Here are some tips to improve performance and speed:
- Use ‘-enable-kvm’ option to leverage hardware virtualization capabilities if available.
- Reduce graphical complexity by using ‘-nographic’ and disabling unused peripherals.
- Consider using ‘-singlestep’ option and debugging in bursts rather than continuous execution.
- Profile the virtual machine using vTuner or similar tools to identify and optimize bottlenecks.
Simulating for multiple platforms
A key benefit of QEMU is the ability to simulate different processor and board models – for example, simulating firmware for both STM32 and NXP boards. This makes it easy to develop for multiple platforms.
Create a different firmware build for each target, and launch QEMU with the appropriate ‘-M machine’ model argument to simulate the desired hardware platform.
Integrating with IDEs and other tools
QEMU simulation can be integrated into Cortex-M development workflows using IDEs like Eclipse, Visual Studio Code and command-line tools.
For example, the openocd debugger in VSCode can connect to QEMU’s gdbserver to enable coding, compiling and debugging firmware all within the editor itself.
Try to use the same toolchain and compile options when building firmware for QEMU as you would for deployment on physical hardware.
Summary
QEMU provides a valuable tool for developing, testing and debugging Cortex-M firmware right on your desktop without needing real hardware. With the ability to emulate different processor models and boards, it enables working on a virtual target that closely matches your final embedded platform.
Combine QEMU simulation with real hardware debugging and testing to boost your Cortex-M and embedded systems development workflow.