Skip to main content

Cortex-M RPMsg Guide

Introduction

The goal of this article is to provide a comprehensive guide on how to use the RPMsg protocol within a Heterogeneous Multicore Processing (HMP) environment. There is a quick overview of how it works and how to leverage Toradex's out-of-the-box resources.

Why RPMsg

RPMsg (or Remote Processor Messaging) is a communication protocol for inter-processor communication on embedded Linux systems. It enables efficient data exchange between processors in a heterogeneous multi-core environment, facilitating seamless integration and improved system performance.

For more information, check the OpenAMP website or, for NXP downstream kernel, check the RPMsg-Lite repository.

Device Tree Modifications

For RPMsg to work properly, it is necessary to allocate the correct RAM buffers in the device tree file. Toradex provides some device tree overlays for an out-of-the-box experience with HMP. The overlays are compatible with all Downstream and upstream-based modules starting from BSP and Torizon OS 6.

Check the following table for information about the status of the overlays:

OverlayStatusDevice Tree Overlays Repository Branch
verdin-imx8mp_hmp_overlay.dtsAvailabletoradex_5.15-2.2.x-imx
verdin-imx8mp_hmp_overlay.dtsComing soonmaster
verdin-imx8mm_hmp_overlay.dtsAvailabletoradex_5.15-2.2.x-imx
verdin-imx8mm_hmp_overlay.dtsAvailablemaster
verdin-am62_hmp_overlay.dtsAvailabletoradex_ti-linux-6.1.y
apalis-imx8_hmp_overlay.dtsComing soontoradex_5.15-2.2.x-imx
colibri-imx8x_hmp_overlay.dts(*1)Availabletoradex_5.15-2.2.x-imx
colibri-imx7_hmp_overlay.dtsComing soonmaster

(*1): Note that this overlay only works to enable RPMsg.

For overlays marked as available, they are pre-compiled (*.dtbo) into Torizon OS and our BSP reference images. Their source code is also available on Toradex device-tree-overlays.git repository under the specific branch.

info

If you are interested in the DTOs marked as "coming soon", get in touch with us on the Toradex Community.

For information on how to add and enable an overlay, refer to First Steps with Device Tree Overlays.

How the Buffer Reservation Works

Let's take the Verdin iMX8M Mini as example. After downloading the MCUXpresso SDK, go to the boards/evkmimx8mm/multicore_examples/rpmsg_lite_str_echo_rtos folder.

On the main_remote.c file , we can see some definitions related to RPMSG:

/*******************************************************************************
* Definitions
******************************************************************************/
#define RPMSG_LITE_SHMEM_BASE (VDEV0_VRING_BASE)
#define RPMSG_LITE_LINK_ID (RL_PLATFORM_IMX8MM_M4_USER_LINK_ID)
#define RPMSG_LITE_NS_ANNOUNCE_STRING "rpmsg-virtual-tty-channel-1"
#define APP_TASK_STACK_SIZE (256)
#ifndef LOCAL_EPT_ADDR
#define LOCAL_EPT_ADDR (30)

And searching for these definitions, we find the memory addresses inside the board.h file:

/* Shared memory base for RPMsg communication. */
#define VDEV0_VRING_BASE (0xB8000000U)
#define RESOURCE_TABLE_OFFSET (0xFF000)

There is also more information in the rsc_table.c file:

    /* Vring rsc entry - part of vdev rsc entry */
{VDEV0_VRING_BASE, VRING_ALIGN, RL_BUFFER_COUNT, 0, 0},
{VDEV0_VRING_BASE + VRING_SIZE, VRING_ALIGN, RL_BUFFER_COUNT, 1, 0},
};

void copyResourceTable(void)
{
/*
* Resource table should be copied to VDEV0_VRING_BASE + RESOURCE_TABLE_OFFSET.
* VDEV0_VRING_BASE is temperorily kept for backward compatibility, will be
* removed in future release
*/
memcpy((void *)VDEV0_VRING_BASE, &resources, sizeof(resources));
memcpy((void *)(VDEV0_VRING_BASE + RESOURCE_TABLE_OFFSET), &resources, sizeof(resources));
}

Using these addresses and also checking the imx_rpmsg.c file, we can set the following memory addresses:

vdev0vring0: vdev0vring0@b8000000 {
reg = <0 0xb8000000 0 0x8000>;
no-map;
};

vdev0vring1: vdev0vring1@b8008000 {
reg = <0 0xb8008000 0 0x8000>;
no-map;
};

rsc_table: rsc_table@b80ff000 {
reg = <0 0xb80ff000 0 0x1000>;
no-map;
};

vdevbuffer: vdevbuffer@b8400000 {
compatible = "shared-dma-pool";
reg = <0 0xb8400000 0 0x100000>;
no-map;
};

Loading the RPMsg Linux Driver

After the device tree has been modified and the module has been rebooted, the driver should appear as "registered" in the dmesg log:

# dmesg | grep -i rpmsg
[ 0.045742] imx rpmsg driver is registered.

Then, you are able to load the rpmsg driver from MCUXpresso. Follow the How to Load Compiled Binaries into Cortex-M guide on how to compile a demo and how to load it to your module.

RPMsg TTY Demo

First, follow the instructions on How to Load Compiled Binaries into Cortex-M article and compile the rpmsg_lite_str_echo_rtos demo binary. Then, send it to the module, and load on U-Boot.

Then, you should see the following message in the debug UART:

RPMSG String Echo FreeRTOS RTOS API Demo...

After booting Linux, if the RPMsg is correctly configured, the following message should appear on the Cortex-M side:

RPMSG String Echo FreeRTOS RTOS API Demo...

Nameservice sent, ready for incoming messages...

The dmesg log will also show that RPMsg has been correctly configured:

# dmesg | grep -i rpmsg
[ 0.045793] imx rpmsg driver is registered.
[ 1.329068] virtio_rpmsg_bus virtio0: rpmsg host is online
[ 1.329111] virtio_rpmsg_bus virtio0: creating channel rpmsg-virtual-tty-channel-1 addr 0x1e

If RPMsg is correctly configured on the system, 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]

And a new tty device will be created:

# ls /dev/ | grep -i rpmsg
rpmsg_ctrl0
ttyRPMSG30

Then, you are able to exchange data by writing to the tty device:

# echo Toradex! > /dev/ttyRPMSG30

You can see the message being received on the Cortex-M side:

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

Ping Pong RPMsg Demo

For this demo, compile the evkmimx8mm/multicore_examples/rpmsg_lite_pingpong_rtos/linux_remote example and load it on U-Boot as explained in the How to load compiled binaries into Cortex-M. The following message will be printed in the Cortex-M debug UART:

RPMSG Ping-Pong FreeRTOS RTOS API Demo...
RPMSG Share Base Addr is 0xb8000000

After Linux has been booted, the following messages should appear:

RPMSG Ping-Pong FreeRTOS RTOS API Demo...
RPMSG Share Base Addr is 0xb8000000
Link is up!
Nameservice announce sent.

Now load the kernel module:

# sudo modprobe imx_rpmsg_pingpong

The messages should appear on the Cortex-M side:

Sending pong...
Waiting for ping...
Sending pong...
Waiting for ping...
Sending pong...
Waiting for ping...
Sending pong...
Waiting for ping...
Sending pong...
Waiting for ping...
Sending pong...
Waiting for ping...
Sending pong...
Waiting for ping...
Sending pong...
Ping pong done, deinitializing...
Looping forever...

And also on the Linux side:

# dmesg | grep ping
[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 516096
[ 0.920924] SMCCC: SOC_ID: ARCH_SOC_ID not implemented, skipping ....
[ 122.533450] imx_rpmsg_pingpong virtio0.rpmsg-openamp-demo-channel.-1.30: new channel: 0x400 -> 0x1e!
[ 122.704607] imx_rpmsg_pingpong virtio0.rpmsg-openamp-demo-channel.-1.30: goodbye!


Send Feedback!