Cortex-M Shared Memory Guide
The example in this article lacks the data safety of RPMsg and RemoteProc. Therefore, Toradex doesn't recommend using this method in production without substantial code improvements and safeguards.
Introduction
This article describes how to exchange data between two cores using the MCUXpresso SDK.
The method described in this article doesn't use drivers or RPMsg protocols. To exchange data between cores using RPMsg and RemoteProc, refer to the following articles:
This article complies with the Typographic Conventions for Toradex Documentation.
Prerequisites
The MCUXpresso SDK and all required tools must be configured before proceeding. Refer to the Setting Up the MCUXpresso SDK and Toolchain for HMP Development article for more information about the installation process.
Exchanging Data Through Shared Memory
The following procedure describes how to exchange data between the alternative core and Linux environment using shared memory.
-
Modify the
hello_worldexample to write and read data from a shared memory address in the DDR:warningThe shared memory address used in the following example is
0x8FF00000, but it may need to be adjusted based on the module's memory map. Make sure to choose an address that is not used by any other component and is properly reserved in the device tree overlay. After choosing the shared memory address, make sure to update it in the main file and the device tree overlay accordingly.To check the memory map of the module, run the following command in the Linux environment:
# cat /proc/iomemhello_world.c#include "fsl_device_registers.h"
#include "fsl_debug_console.h"
#include "board.h"
#include "app.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define SHARED_MEM_ADDRESS 0x8FF00000
/*!
* @brief Main function
*/
int main(void)
{
/* Initialize standard SDK demo application pins */
BOARD_InitHardware();
volatile uint32_t *ddr_shared_mem = (uint32_t*) SHARED_MEM_ADDRESS;
/* Print the initial banner */
PRINTF("\r\nShared Memory Demo!\r\n\n");
PRINTF("Shared address: 0x%X\r\n", SHARED_MEM_ADDRESS);
PRINTF("READ: $devmem2 0x%X\r\n", SHARED_MEM_ADDRESS);
PRINTF("--------------------\r\n");
/* Write 0xBB in the shared memory address */
*ddr_shared_mem = 0xBB;
uint8_t index = 1;
while(1)
{
PRINTF("\r\n0x%X: 0x%X\r\n", SHARED_MEM_ADDRESS, *ddr_shared_mem);
PRINTF("Index: %d\r\n", index);
if (index == 25)
index = 1;
else
index++;
for (uint32_t i = 0; i < 10000000; i++);
}
}hello_world.c#include "fsl_device_registers.h"
#include "fsl_debug_console.h"
#include "board.h"
#include "pin_mux.h"
#include "fsl_lpuart.h"
#include "clock_config.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define SHARED_MEM_ADDRESS 0x8FF00000
/*!
* @brief Main function
*/
int main(void)
{
/* Initialize standard SDK demo application pins */
sc_ipc_t ipc;
ipc = BOARD_InitRpc();
BOARD_InitPins(ipc);
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
BOARD_InitMemory();
uint32_t *ddr_shared_mem = (uint32_t*) SHARED_MEM_ADDRESS;
/* Print the initial banner */
PRINTF("\r\nShared Memory Demo!\r\n\n");
PRINTF("Shared address: 0x%X\r\n", SHARED_MEM_ADDRESS);
PRINTF("READ: $devmem2 0x%X\r\n", SHARED_MEM_ADDRESS);
PRINTF("--------------------\r\n");
/* Write 0xBB in the shared memory address */
*ddr_shared_mem = 0xBB;
uint8_t index = 1;
while(1)
{
PRINTF("\r\n0x%X: 0x%X\r\n", SHARED_MEM_ADDRESS, *ddr_shared_mem);
PRINTF("Index: %d\r\n", index);
if (index == 25)
index = 1;
else
index++;
for (uint32_t i = 0; i < 10000000; i++);
}
} -
Create a device tree overlay with a
reserved-memorynode that matches the main device tree file:
For Torizon OS, device tree overlays can be enabled with TorizonCore Builder. For Linux BSP images, refer to the Device Tree Overlays documentation.
/dts-v1/;
/plugin/;
/ {
compatible = "toradex,verdin-imx95";
fragment@0 {
target-path = "/reserved-memory";
__overlay__ {
#address-cells = <2>;
#size-cells = <2>;
m7_shm: m7-shm@8ff00000 {
reg = <0x0 0x8ff00000 0x0 0x100000>;
no-map;
};
};
};
};
/dts-v1/;
/plugin/;
/ {
compatible = "toradex,verdin-imx8mp";
fragment@0 {
target-path = "/reserved-memory";
__overlay__ {
#address-cells = <2>;
#size-cells = <2>;
m7_shm: m7-shm@8ff00000 {
reg = <0x0 0x8ff00000 0x0 0x100000>;
no-map;
};
};
};
};
/dts-v1/;
/plugin/;
/ {
compatible = "toradex,verdin-imx8mm";
fragment@0 {
target-path = "/reserved-memory";
__overlay__ {
#address-cells = <2>;
#size-cells = <2>;
m4_shm: m4-shm@8ff00000 {
reg = <0x0 0x8ff00000 0x0 0x100000>;
no-map;
};
};
};
};
/dts-v1/;
/plugin/;
/ {
compatible = "toradex,colibri-imx8x";
fragment@0 {
target-path = "/reserved-memory";
__overlay__ {
#address-cells = <2>;
#size-cells = <2>;
m4_shm: m4-shm@8ff00000 {
reg = <0x0 0x8ff00000 0x0 0x100000>;
no-map;
};
};
};
};
/dts-v1/;
/plugin/;
/ {
compatible = "toradex,apalis-imx8";
fragment@0 {
target-path = "/reserved-memory";
__overlay__ {
#address-cells = <2>;
#size-cells = <2>;
m4_shm: m4-shm@8ff00000 {
reg = <0x0 0x8ff00000 0x0 0x100000>;
no-map;
};
};
};
};
-
Compile a firmware for the alternative core. Refer to How To Compile Firmware for Alternative Cores (NXP) for instructions.
-
Load and run the compiled firmware, following the instructions available on How To Load and Run Firmware on Alternative Cores (NXP).
-
Boot the module and check the alternative core UART output to confirm that the shared memory is working as expected:
Shared Memory Demo!
Shared address: 0x8FF00000
READ: $devmem2 0x8FF00000
--------------------
0x8FF00000: 0xBB
Index: 1
0x8FF00000: 0xBB
Index: 2
0x8FF00000: 0xBB
Index: 3
0x8FF00000: 0xBB
Index: 4 -
Run the following container to initialize a Debian environment with the required tools:
# docker run --rm -it \
--privileged \
--device=/dev/mem \
torizon/debian:4Install the
busyboxpackage inside the container to use thebusybox devmemcommand:## apt update && apt install busybox -yFinally, run the
busybox devmemcommand to update the value in the shared memory address:## busybox devmem 0x8FF00000 32 0xFFAfter updating the value, check the alternative core UART output again:
0x8FF00000: 0xFF
Index: 5
0x8FF00000: 0xFF
Index: 6
0x8FF00000: 0xFF
Index: 7
0x8FF00000: 0xFF
Index: 8