Search by Tags

FreeRTOS on the Cortex-M4 of a Verdin iMX8M Mini


Article updated at 19 Nov 2020
Compare with Revision

Subscribe for this article updates

The i.MX 8M Mini applications processor is a feature and performance-scalable multicore platform including a Cortex-M4 core. This secondary core typically runs an RTOS optimized for microcontrollers or a bare-metal application. Toradex provides FreeRTOS™, a free professional-grade real-time operating system for microcontrollers, along with drivers and several examples that can be used on our Verdin iMX8M Mini platform. The FreeRTOS™ port is based on NXP's MCUxpresso SDK for the i.MX 8M Mini.


The Cortex-M4 CPU core lives side by side with the Cortex-A53 based primary CPU cores. Both CPU complexes have access to the same interconnect and hence have equal access to all peripherals (shared bus topology). The graphic below is an incomplete and simplified drawing of the architecture with emphasis on the relevant sub systems to understand the heterogeneous asymmetric multicore architecture.

  • i.MX 8M Mini Heterogeneous Asymmetric Multicore Architecture Block Diagram

    i.MX 8M Mini Heterogeneous Asymmetric Multicore Architecture Block Diagram

There are several types of memory available. The Cortex-M4 provides local memory (Tightly Coupled Memory, TCM), which is relatively small but can be accessed by the CPU without any latency. For applications requiring more memory, the system DRAM is accessible by the M4 cores. From a performance perspective the TCM memory should be used whenever possible.

A traditional microcontroller typically has internal NOR flash where the firmware is stored and executed from. This is not the case on the Verdin iMX8M Mini: There is no NOR flash where the firmware can be flashed onto. Instead, the firmware needs to be stored on the mass storage device such as an SD card or the internal eMMC flash. The available mass storage devices are not "memory mapped", and hence application can not be executed directly from any of the cores (no Execution-In-Place, XIP). Instead, code need to be loaded into one of the available memory sections before the CPU can start executing it.

The M4 firmware can be placed in the common boot container, so it will be loaded and started by the boot ROM, or it can be placed on a mass storage device. In this case U-Boot needs to be configured to load and execute the M4 firmware.

Memory areas

The two CPU platforms use a different memory layout to access individual sub systems. This table lists some important areas and their memory location for each of the cores side by side. The full list can be found in the i.MX 8M Mini reference manual.

Region Size Cortex-A53 M4-0
DDR Address 2GB(*1) 0x00000000-0x3FFFFFFF 0x40000000-0xBFFFFFFF
TCML for M4 128KB 0x007E0000-0x007FFFFF 0x1FFE0000-0x1FFFFFFF
TCMU for M4 128KB 0x00800000-0x0081FFFF 0x20000000-0x2001FFFF

(*1): Full DRAM range is 0x8_00000000 - 0xB_FFFFFFFF. Only a part of the DRAM is accessible by the M4 cores

The Cortex-M4 CPU has two buses connected to the main interconnect (modified Harvard architecture). One bus is meant to fetch data (system bus) whereas the other bus is meant to fetch instructions (code bus).
To get optimal performance, the program code should be located and linked for a region which is going to be fetched through the code bus, while the data area (e.g. bss or data section) should be located in a region which is fetched through the system bus.

The TCML and TCMU regions can be accessed with zero wait-states and thus provides massively better performance than DRAM, even if it is cached. Therefore it is advisable to place all code and data in the TCM whenever possible.

Get the FreeRTOS Source Code

The FreeRTOS source code is currently only available on NXP's MCUXpresso web page:

Here are the steps to download the resources (as of 2020-08-06)

  1. Register and log into MCUXpresso
  2. On the main page, ↠ Explore and Filter Devices
  3. Select Board on the left side
  4. Navigate to ↠ Processorsi.MX8M Mini QuadMIMX8MMxMIMX8MM6xxxKZ
  5. Click the button to Build MCUXpresso SDK
  6. On the SDK Builder page, select the latest SDK Version (2.8.0 as of 2020-08-06), the toolchain (GCC Arm Embedded) and the Host OS (Linux) for this example. Make sure to check the box to include FreeRTOS into the SDK. You can also include the CMSIS DSP Library.
  7. Click the Download SDK button to get the source code.

The standard FreeRTOS and bare-metal examples provided by NXP use UART_3 on the Verdin iMX8M Mini to communicate with the user. This section describes how to acess in order to make the required UART ports accessible from your development PC, and how to load and run binary examples.

Software Setup

Install the cross-compilation toolchain and dependencies

Download the latest Arm cross-compilation toolchain from the official website and extract it, e.g.:

$ tar xjf ~/Downloads/gcc-arm-none-eabi-9-2020-q2-update-x86_64-linux.tar.bz2

Some Linux distributions might already offer the Arm toolchain in their repositories and you can install it from there. On Ubuntu, for instance, run:

$ sudo apt-get install gcc-arm-none-eabi binutils-arm-none-eabi

You'll also need make and cmake:

$ sudo apt-get install make cmake

Compile examples on Linux

After extracting the SDK you've just downloaded, go to <sdk-directory>/boards/evkmimx8mm/demo_apps/hello_world/armgcc.

The included build scripts expect the ARMGCC_DIR environment variable to be defined. This is your toolchain directory, e.g.:

$ export ARMGCC_DIR=~/gcc-arm-none-eabi-9-2020-q2-update

If you've installed the toolchain using your package manager, then run:

$ export ARMGCC_DIR=/usr

Then run the built-in build script:

$ ./

This will build both the debug and release versions of the application for all possible targets (DDR, FLASH and RAM).

Copy the resulting binary (e.g. hello_world.bin) to an SD card for the next steps.

Hardware Setup

Connection between Verdin Development Board and PC

The Verdin Development Board features a built-in USB to Serial converter which can be used to easily access both the main OS debug UART as well as the default M4 debug UART via a single USB micro-B connector (X66)

  • Connect a USB cable between X66 and your PC (115200 bps, 8N1)

Four USB serial interfaces should be enumerated in your PC (e.g. /dev/ttyUSB0, /dev/ttyUSB1, /dev/ttyUSB2, /dev/ttyUSB3)

Run The Examples from U-Boot

At the time of writing this article, the current U-Boot version was:

U-Boot 2018.03-toradex_imx_v2018.03_4.14.78_1.0.0_ga-bringup+g92d0497781 (Aug 28 2019 - 16:16:39 +0000)

Currently U-Boot does not support loading .elf files. Therefore we need to use .bin files which tend to be less defined and leave more space for usage errors.

Prepare your environment as follows:

  1. Open two terminals on the PC:
    • One for the connection to U-Boot / Linux
    • One for the communication with the M4
  2. Copy the freertos_hello.bin (or whatever example you want to run) onto an SD card
  3. Insert the SD card into the SD card socket of the Verdin Development Board

Then for each time you want to run the example, Put your keyboard focus into the U-Boot/Linux terminal and follow the steps below:

  1. Turn on the Verdin Development Board

  2. Press any key in the terminal to enter U-Boot command line.

  3. Optional: To verify that your binary file is accessible on the SD card, enter:

> ls mmc 1
  1. Enter the following sequence to run the M4 code. We've added the U-Boot output for clarity:
   Verdin iMX8MM # setenv m4addr 0x7e0000
   Verdin iMX8MM # saveenv
   Verdin iMX8MM # fatload mmc 1 ${m4addr} hello_world.bin && dcache flush && bootaux ${m4addr}
   15872 bytes read in 28 ms (552.7 KiB/s)
   ## Starting auxiliary core at 0x007E0000 ...
   Verdin iMX8MM #

hello_world.bin is the name of your application.

  1. You should see the following output on the M4 UART:
Hello World!