Skip to main content

Cortex-M Shared Memory Guide

Introduction​

The objective of this article is to demonstrate a method for data exchange between two cores within the Heterogeneous Multi-processing (HMP) configuration, without employing drivers or RPMsg protocols. The approach involves reserving a buffer in the RAM and accessing its data from the two cores.

If you are looking for information about other approaches for exchanging data between two cores with different architectures, refer to the following articles:

Prerequisites​

Exchanging Data Through Shared Memory​

These steps illustrate a basic data exchange technique, but lacks the data safety of RPMsg and Remoteproc. Therefore, it shouldn't be used in production without substantial code improvements and safeguards.

  1. Create the demo project. For that, simply go to the demo_apps folder and copy the hello-world demo that comes from the SDK and edit the code.

    $ cd boards/evkmimx8mm/demo_apps/
    $ cp -r hello_world shared_memory
  2. Delete the main.c code and replace it with the following code:

    #include "FreeRTOS.h"
    #include "task.h"
    #include "board.h"
    #include "debug_console_imx.h"

    #define SHARED_MEM_ADDRESS 0x8FF00000

    void SharedMemTask(void *pvParameters)
    {
    uint32_t *ddr_shared_mem = (uint32_t*) SHARED_MEM_ADDRESS;

    // Print the initial banner
    PRINTF("\\r\\nShared Memory Demo!\\n\\n\\r");
    PRINTF("Shared address: 0x%X\\n\\r", SHARED_MEM_ADDRESS);
    PRINTF("READ: $devmem2 0x%X\\n\\r", SHARED_MEM_ADDRESS);
    PRINTF("-------------------------------------------------------------------------------\\n\\r");

    // write 0xBB in the shared memory address
    *ddr_shared_mem = 0xBB;

    while(1)
    {
    PRINTF("\\r\\n0x%X: 0x%X\\n\\r", SHARED_MEM_ADDRESS, *ddr_shared_mem);
    for (int i = 0; i < 10000000; i++);
    }
    }

    int main(void)
    {
    hardware_init();

    xTaskCreate(SharedMemTask, "Print Task", configMINIMAL_STACK_SIZE,
    NULL, tskIDLE_PRIORITY+1, NULL);

    vTaskStartScheduler();

    // Should never reach this point.
    while (true);
    }

    This code will read the address 0x8FF00000 and keep printing its contents in a loop. The content is 4 bytes long.

  3. Compile the code and send it to the module. For information on how to set up the SDK and compile your code, refer to Setting Up MCUXpresso SDK and Toolchain for Cortex-M development.

  1. Create a device tree overlay that has a reserved-memory node that reserve 1MB in the address 0x8FF00000.

    /dts-v1/;
    /plugin/;

    / {
    compatible = "toradex,verdin-imx8mm";
    };

    &{/} {
    reserved-memory {
    #address-cells = <1>;
    #size-cells = <1>;
    ranges;

    m4_shm: cm4@8FF00000 {
    reg = <0x8FF00000 0x100000>;
    no-map;
    };
    };
    };
  2. Compile the overlay and deploy to the module. Then, edit the overlays.txt file to enable the overlay.

  3. Reboot the module. At this point, during boot, you should be able to see Cortex-M printing messages on UART:

    Shared Memory Demo!

    Shared address: 0x8FF00000
    READ: $devmem2 0x8FF00000
    -------------------------------------------------------------------------------

    0x8FF00000: 0xBB

    0x8FF00000: 0xBB

    0x8FF00000: 0xBB

    0x8FF00000: 0xBB

    In this case, Cortex-M wrote 0xBB to 0x8FF00000 and it’s printing the content.

  4. In runtime, change the value using devmem2:

    # devmem2 0x8FF00000 w 0xFF
    /dev/mem opened.
    Memory mapped at address 0xb6f0a000.
    Read at address 0x8FF00000 (0xb6f0a000): 0x000000BB
    Write at address 0x8FF00000 (0xb6f0a000): 0x000000FF, readback 0x000000FF

    You will see that the value on Cortex-M changed:

    0x8FF00000: 0xFF

    0x8FF00000: 0xFF

    0x8FF00000: 0xFF

    0x8FF00000: 0xFF

    You can also read it back on Linux:

    # devmem2 0x8FF00000
    /dev/mem opened.
    Memory mapped at address 0xb6f99000.
    Read at address 0x8FF00000 (0xb6f99000): 0x000000FF
  5. Change this value on the Cortex-M side. For this, edit the code from the step 1 by writing to the 0x8FF00000 address.

    uint32_t value = 0;
    PRINTF("\\r\\nWrite a value for this register (in HEX): \\n\\r");
    SCANF("%X", &value);
    PRINTF("\\r\\nValue: 0x%X \\n\\r",value);
    *ddr_shared_mem = value;


Send Feedback!