Blog:
Asymmetric Multiprocessing with the NXP i.MX 95 and Zephyr

Thursday, May 29, 2025
Zephyr
Zephyr
Overview

Although most embedded software applications target a single microprocessor or microcontroller, there are certain use cases that require a distributed application. In the automotive industry, different subsystems may be implemented as distinct applications on separate microprocessors. For example, the embedded software responsible for the engine control system is located on a different microcontroller than the application responsible for the anti-lock braking system.

The medical device industry is another example where the embedded software is distributed across multiple microprocessors. For example, the user interface is implemented on one microprocessor but the control system responsible for patient interactions is present on another microcontroller.

As we can see, responsibilities are disseminated based on functionality, and processors are selected based on responsibility. For example, the user interface is typically implemented on a Linux-based system, which in turn is designed for a processor similar to an ARM Cortex-A core. However, the critical embedded software application leverages a Realtime Operating System (RTOS), which is ideal for a processor similar to an ARM Cortex-R or Cortex-M core.

Nonetheless, if multiple processors are employed, inter-processor communication becomes essential. For example, the CAN bus is used in the automotive industry for this purpose. In the medical device industry, processors can use UART, SPI, or I2C communicate among themselves, as shown below:

ARM A-Core ARM M-Core

However, multiple processors on distinct pieces of silicon increases the complexity of the underlying hardware, software, and firmware. In turn, this can result in additional development and debugging efforts, which can affect product timelines and costs.

To mitigate the additional complexity, we can combine multiple processors onto the same piece of silicon, as shown below:

ARM A-Core GUI ARM M-Core FuSa

In the above image, the ARM Cortex-A and ARM Cortex-M cores are placed on the same silicon, referred to as a System on Chip (SoC). A SoC combines the CPU cores with other necessary controllers for a comprehensive and powerful processor. In the above image, the functional safety (FuSAa) portion of the embedded software is implemented on the ARM Cortex-M core using The Zephyr Project RTOS, while the graphical user interface (GUI) is implemented in Linux on the ARM Cortex A-core.

This design reduces the hardware development and debugging time significantly. Instead of managing the electrical and mechanical hardware associated with multiple distinct processors and their interconnects, the problem is reduced to hardware design surrounding a single processor. Instead, the challenges are reduced mostly to firmware and software, since the embedded software on each core needs a mechanism to communicate with the embedded software on the other cores.

In this blog post, we will learn how we can load firmware running on the ARM Cortex-M core from the Linux kernel running on the ARM Cortex-A core. We will see an example of how to achieve this using the Toradex Verdin iMX95 SoC.

The OpenAMP Project

The Open Asymmetric Multi-Processing (OpenAMP) project was formulated to allow different cores on the same SoC to efficiently communicate with each other. It built off of Texas Instruments’ early work to incorporate Remoteproc and RPMsg into the Linux kernel. Remoteproc was developed to allow the Linux kernel to manage the lifecycle of the embedded software on a remote processor, and RPMsg allowed the Linux kernel to communicate with the firmware running on the remote processor. The OpenAMP project expanded Texas Instruments’ implementation of these features to a generic framework that can be used in different systems. The OpenAMP project standardized communication between the Linux kernel and RTOS-based embedded software applications. It also provides reference implementations for RTOS-based and bare metal embedded software applications that wish to take advantage of its features, such as RPMsg.

As mentioned, Remoteproc and RPMsg are the two main features of the OpenAMP project that allow us to manage embedded software running on different cores of the same SoC. Remoteproc is responsible for loading firmware onto the remote processor, and starting and stopping execution of the remote processor. Remoteproc is typically used in Linux to manage the lifecycle of the embedded software running on the Cortex-M core equivalent. RPMsg is responsible for supporting message exchange between the embedded software running on the Cortex-M core and Linux running on the Cortex-A core.

Toradex Verdin iMX95

The Toradex Verdin iMX95 is a high-performance System on Module (SoM) based on the NXP iMX95 SoC. The iMX95 SoC has three distinct ARM core types, as shown in the image below:

Verdin iMX95 ARM Cores

The ARM Cortex-A55 runs the Linux operating system, the ARM Cortex-M7 is meant to run time critical firmware, and the ARM Cortex-M33 is responsible for managing execution of the Cortex-A55 and Cortex-M7.

The Zephyr Project RTOS

Although “Real-time Operating System” is in the official name of The Zephyr Project RTOS, “Zephyr” is much more than just an RTOS. It’s an entire ecosystem. While it does contain the typical features and data structures of an RTOS, such as tasks, semaphores, mutexes, and message queues, it also has software stacks responsible for other functionality that is important for an embedded system. For example, it has:

  • Drivers to control and exercise vendor-specific hardware
  • Software to implement entire communication stacks, such as Bluetooth Low Energy (BLE) and WiFi
  • Modules that implement entire subsystems, such as a filesystem and bootloader

Zephyr also has support for more than 750 boards from a multitude of different vendors, including the Toradex Verdin iMX95. If we retrieve the Zephyr codebase, we can see support for the iMX95 EVK under boards/nxp/imx95_evk, as shown in the image below:

Zephyr support for different boards

Zephyr borrows the Kconfig and Devicetree features from the Linux kernel and we can see that in the image above. The iMX95 EVK “device driver” in the image above contains:

  • “board.c”, which is the C source code responsible for initial board bring-up
  • “imx95_evk_mimx9596_m7.dts”, which is the Devicetree that instructs Zephyr of the peripherals that are present on the board
  • “Kconfig.imx95_evk”, which is the set of Kconfig options that need to be enabled to support key features of the board

For example, if we open the “Kconfig.imx95_evk” file, as shown in the image below, we can see that it enables the iMX95 SoC Kconfig option. This Kconfg option will then enable other features that are required by the SoC:

iMX95 SoC Kconfig

For example, the Verdin iMX95 “device driver” is located under soc/nxp/imx/imx9/imx95 as shown in the image below:

Verdin iMX95 device driver

Again, we see that “soc.c” is the C source code responsible for initial SoC bring-up, and we can see that the Kconfig file for the SoC defines the Flash size by analyzing the appropriate node in the Devicetree.

Putting It All Together

Let’s see how we can compile a Zephyr application for the iMX95 and load it onto the Cortex-M core from the Cortex-A core running on the same board. First, we can ensure that our environment is appropriately configured by following the steps outlined in the Zephyr Getting Started guide here: https://docs.zephyrproject.org/latest/develop/getting_started/index.html

Then, we can use West to fetch the Zephyr source code by executing the following commands:

$> west init -m https://github.com/mabembedded/zephyr.git 
$> west update 

Afterward, we can execute the following command to compile a simple “Hello World” application for the Verdin iMX95:

$> west build -p -b imx95_evk/mimx9596/m7 samples/hello_world 

Then, we can transfer the compiled binary, in ELF format, to Linux running on the iMX95 Cortex-A core by executing the following command (making sure to replace the IP address listed below with the address of our board):

$> scp build/zephyr/zephyr.elf root@10.10.2.22:~/ 

Subsequently, if we log in to our iMX95, we can run the following commands to instruct the Linux kernel to load the Zephyr ELF binary into the Cortex-M7 on the Verdin iMX95:

root@imx95-19x19-verdin:~# cd /sys/devices/platform/imx95-cm7/remoteproc/remoteproc1/ 
root@imx95-19x19-verdin:~# echo ~/zephyr.elf > firmware 

Finally, we can type the following command into the iMX95 Linux console to start the Cortex-M7 core:

root@imx95-19x19-verdin:~# echo start > state 

We should see the following on a console to the Cortex-M7 on the iMX95:

Booting Zephyr OS build

The above example demonstrated the Remoteproc feature of The OpenAMP project in the Linux kernel.

We can also explore RPMsg in Zephyr with the openamp_rsc_table sample application shown below:

openamp_rsc_table

As we can see in the image above, “imx95_evk_mimx9596_m7.conf” contains the Kconfig options that are enabled for this application. As we can see in the image below, this file enables the relevant OpenAmp and Mbox Kconfig options:

OpenAmp and Mbox Kconfig options

The directory also contains a Devicetree “overlay”, which customizes the board Devicetree for this specific application. As shown in the image below, the overlay defines features needed by the RPMsg application and references specific hardware components:

RPMsg application and references specific hardware components

These features are:

  • The shared memory used by the cores to exchange data
  • The resource table, which is used by the Linux kernel to determine the capabilities supported by the remote processor and firmware
  • The mailbox, which is used for signalling between the two cores

Let’s see how we can compile and run the RPMsg Zephyr application. First, we can compile the application by executing the following command:

$> west build -p -b imx95_evk/mimx9596/m7 samples/subsys/ipc/openamp_rsc_table 

Then, we can use the steps outlined earlier to transfer and load the resulting ELF binary into the Cortex-M7 from Linux on the Cortex-A55. After starting the Cortex-M7 from the Linux side, we should see the following on the Cortex-M7’s console, which demonstrates messages received from the Linux side:

Cortex-M7 console

Similarly, if observe the logs from the Linux kernel on the Cortex-A55 side, we can also see that it has received messages via RPMsg from the Zephyr application on the Cortex-M7, as shown below:

RPMsg from the Zephyr application on the Cortex-M7
Summary

In this blog post, we learned about the advantages of leveraging features of the OpenAMP project to simplify hardware design of our embedded system. We learned about the Toradex Verdin iMX95 and how the different ARM cores on the SoC can enable interesting applications. We also learned how easy it is to build a simple Hello World application using The Zephyr Project RTOS and load it into the Cortex-M7 core of the Verdin iMX95 from Linux running on the Cortex-A55. Finally, we learned how to compile a RPMsg Zephyr application, load it from Linux, and confirm the message exchange between Zephyr and Linux.

Author:
Mohammed Billoo
, Founder and Embedded Software Consultant, MAB Labs

2 comments

Rudhi Nair - 5 months 11 days | Reply

Thanks for the blog post. Could you please specify the exact hardware, BSP versions and Zephyr project branch that you used in this project?

Mohammed Billoo - 5 months 10 days | Reply

Hi,

Thanks for your question and I'm glad you found the blog post helpful. At the time of writing this blog post, I used the following:
* Verdin iMX95 development board
* NXP's iMX95 release L6.6.36-2.1.0 (you'll need to reach out to Toradex for access). I had to flash the imx-boot-variant-alt-imx95-19x19-verdin-sd.bin-flash_alt variant to the board to allow me to control the M7 firmware.
* Zephyr v3.5.0

Please let me know if you have any more questions.

Henrique Garcia - 5 months 10 days | Reply

Hi all!

Small note on accessing NXP releases for i.MX 95 Verdin EVK: they are publicly available on https://www.nxp.com/pages/alpha-beta-bsps-for-microprocessors:IMXPRERELEASES.

Best regards,
Henrique

Leave a comment

Please login to leave a comment!

Get in Touch with Our Experts


Latest Blog

Tuesday, December 16, 2025
Bringing Displays to Life: Developing a MIPI DSI Panel Driver for Linux
Thursday, December 11, 2025
Accelerating Robot Prototyping with ROS 2 on Toradex Hardware:
A Technical Perspective from SiBrain
Tuesday, July 8, 2025
定制 Linux Kernel Driver 编译示例
Have a Question?