Running FreeRTOS on the Cortex-M7 of a Verdin iMX8M Plus
Introduction
The objective of this article is to guide you through case-oriented examples on the implementation of FreeRTOS on the Cortex-M of a Verdin iMX8M Plus System on Module, focusing on the execution of a sample application firmwares leveraging the Heterogeneous Multicore Processing architecture.
The use cases described in this article were tested and validated with FreeRTOS on the Cortex-M running alongside an embedded Linux image (Linux BSP) on the A-cores.
Prerequisites
- Set up the NXP SDK and GCC Toolchain as described in the article Setting Up MCUXpresso SDK and Toolchain for Cortex-M development
- Consider the architecture and memory areas of the specific i.MX-based SoC as explained in the article Cortex-M and Memory Areas Overview on Toradex SoMs
Preparing the Environment
Download the MCUXpresso SDK as described at Setting Up MCUXpresso SDK and Toolchain for Cortex-M development. For Verdin iMX8M Plus you should download:
- Verdin iMX8M Plus Quad: MIMX8ML8xxxKZ
- Verdin iMX8M Plus QuadLite: MIMX8ML4xxxKZ
Verify the source code structure from the
boards/evkmimx8mp
folder$ cd <verdin-imx8mp-sdk>/boards/
$ tree -L 2
.
└── evkmimx8mp
├── cmsis_driver_examples
├── demo_apps
├── driver_examples
├── evkmimx8mp.png
├── freertos_examples
├── multicore_examples
└── project_templateDownload and setup the GCC toolchain as explained at Setting Up MCUXpresso SDK and Toolchain for Cortex-M development. We recommend the Arm GNU Toolchain AArch32 bare-metal target (arm-none-eabi) for your host OS.
Case-oriented Examples
Hello World Example
Go to the demo directory on the SDK folder.
$ cd ./boards/evkmimx8mp/demo_apps/hello_world
$ tree -L 1
.
├── armgcc
├── board.c
├── board.h
├── clock_config.c
├── clock_config.h
├── empty_rsc_table.c
├── fsl_iomuxc.h
├── hello_world.bin
├── hello_world.c
├── hello_world_v3_13.xml
├── pin_mux.c
├── pin_mux.h
└── readme.txtWrite and compile the necessary devicetree overlays as explained at Run the Firmware.
Run the script to build the demo
$ export ARMGCC_DIR=<PATH_TO_GCC_TOOLCHAIN>/<GCC_TOOLCHAIN_FOLDER>
$ cd armgcc/
$ ./build_debug.shCopy the generated binary to your device
$ scp debug/hello_world.bin root@<board-ip>:/home/root
Load the firmware on Flash. On U-boot terminal, run the following commands:
> setenv load_cmd "ext4load mmc 0:2"
> setenv cm_image "/home/root/hello_world.bin"
> setenv cm_image_size 20000
> setenv load_cm_image "${load_cmd} ${loadaddr} ${cm_image}"
> setenv cm_boot "${load_cm_image}; cp.b ${loadaddr} 0x7e0000 ${cm_image_size}; dcache flush; bootaux 0x7e0000"
> saveenvStart the firmware at boot level
> run cm_boot
RPMsg Examples
Before diving into the examples:
Apply the related devicetree overlay:
verdin-imx8mm_hmp_overlay.dtbo
.Make sure that the rpmsg driver is loaded.
# dmesg | grep -i rpmsg
[ 0.045742] imx rpmsg driver is registered.
RPMsg TTY Example
Go to the demo directory on the SDK folder.
$ cd ./boards/evkmimx8mp/multicore_examples/rpmsg_lite_str_echo_rtos
$ tree -L 2
.
├── armgcc
├── board.c
├── board.h
├── clock_config.c
├── clock_config.h
├── FreeRTOSConfig.h
├── fsl_iomuxc.h
├── main_remote.c
├── pin_mux.c
├── pin_mux.h
├── readme.txt
├── remoteproc.h
├── rpmsg_config.h
├── rpmsg_lite_str_echo_rtos_imxcm4_v3_13.xml
├── rsc_table.c
└── rsc_table.hRun the script to build the demo
$ export ARMGCC_DIR=<PATH_TO_GCC_TOOLCHAIN>/<GCC_TOOLCHAIN_FOLDER>
$ cd armgcc/
$ ./build_debug.shCopy the generated binary to your device
$ scp debug/rpmsg_lite_str_echo_rtos_imxcm7.bin root@<board-ip>:/home/root
Reset the module and load the firmware on U-boot:
> setenv load_cmd "ext4load mmc 0:2"
> setenv cm_image "/home/root/rpmsg_lite_str_echo_rtos_imxcm7.bin"
> setenv cm_image_size 20000
> setenv load_cm_image "${load_cmd} ${loadaddr} ${cm_image}"
> setenv cm_boot "${load_cm_image}; cp.b ${loadaddr} 0x7e0000 ${cm_image_size}; dcache flush; bootaux 0x7e0000"
> saveenv
> run cm_bootBoot and then load the
imx_rpmsg_tty
kernel module.# sudo modprobe imx_rpmsg_tty
After the kernel module has been loaded, the Cortex-M should print a "Hello World" in the screen, showing that the channel has been created correctly.
RPMSG String Echo FreeRTOS RTOS API Demo...
Nameservice sent, ready for incoming messages...
Get Message From Master Side : "hello world!" [len : 12]Check if ttyRPMSG device was created:
# ls /dev/ | grep -i rpmsg
rpmsg_ctrl0
ttyRPMSG30Write through this device and check on the serial port connected to Cortex-M7
# echo Toradex! > /dev/ttyRPMSG30
Which results in
RPMSG String Echo FreeRTOS RTOS API Demo...
Nameservice sent, ready for incoming messages...
Get Message From Master Side : "hello world!" [len : 12]
Get Message From Master Side : "Toradex!" [len : 8]
Get New Line From Master Side
RPMsg Ping Pong Example
Go to the demo directory on the SDK folder.
$ cd ./boards/evkmimx8mp/multicore_examples/rpmsg_lite_pingpong_rtos
$ tree -L 2
.
└── linux_remote
├── armgcc
├── board.c
├── board.h
├── clock_config.c
├── clock_config.h
├── FreeRTOSConfig.h
├── fsl_iomuxc.h
├── main_remote.c
├── pin_mux.c
├── pin_mux.h
├── readme.txt
├── remoteproc.h
├── rpmsg_config.h
├── rpmsg_lite_pingpong_rtos_linux_remote_v3_13.xml
├── rsc_table.c
└── rsc_table.hRun the script to build the demo
$ export ARMGCC_DIR=<PATH_TO_GCC_TOOLCHAIN>/<GCC_TOOLCHAIN_FOLDER>
$ cd linux_remote/armgcc/
$ ./build_debug.shCopy the generated binary to your device
$ scp debug/rpmsg_lite_pingpong_rtos_linux_remote.bin root@<board-ip>:/home/root
Reset the module and load the firmware on U-boot:
> setenv load_cmd "ext4load mmc 0:2"
> setenv cm_image "/home/root/rpmsg_lite_pingpong_rtos_linux_remote.bin"
> setenv cm_image_size 20000
> setenv load_cm_image "${load_cmd} ${loadaddr} ${cm_image}"
> setenv cm_boot "${load_cm_image}; cp.b ${loadaddr} 0x7e0000 ${cm_image_size}; dcache flush; bootaux 0x7e0000"
> saveenv
> run cm_bootBoot the module and then you will be able to see the following message on the Cortex-M7
RPMSG Ping-Pong FreeRTOS RTOS API Demo...
RPMSG Share Base Addr is 0xb8000000
Link is up!
Nameservice announce sent.Load the kernel module:
# sudo modprobe imx_rpmsg_pingpong
And on the Cortex-M7 side you can see
Sending pong...
Waiting for ping...
Sending pong...
Waiting for ping...
Sending pong...
Waiting for ping...