Build and run of Multicore RPMsg-Lite demo

The Multicore RPMsg-Lite string echo project is a simple demonstration program that uses the MCUXpresso SDK software and the RPMsg-Lite library and shows how to implement the inter-core communicaton between cores of the multicore system.

It works with Linux RPMsg master peer to transfer string content back and forth. The name service handshake is performed first to create the communication channels. Next, Linux OS waits for user input to the RPMsg virtual tty. Anything which is received is sent to M4/7. M4/7 displays what is received, and echoes back the same message as an acknowledgement. The tty reader on the Linux side can get the message, and start another transaction. The demo demonstrates RPMsg’s ability to send arbitrary content back and forth.

precautions

The following precautions must be met to run the Multicore RPMsg-Lite demo:

  • the u-boot must support the bootaux command

  • the Linux must provide imx_rpmsg_tty kernel module

  • the Linux device tree must support the Cortex®-M4/7 and reserved memory areas for communication of the two cores.

please note

Ka-Ro electronics provides a special yocto layer in the download area that provides the necessary u-boot patches, kernel configs and device tree changes.

kernel configurations

add the IMX_RPMSG_TTY feature to your kernel configuration:

../../../_images/cm4-imx-rpmsg-tty-drivers.png

add the IMX_REOMOTEPROC feature to your kernel configuration:

../../../_images/cm4-remoteproc-support.png

device tree example for TX8M-1610

setup reseved memory regions for intercore communication and specify imx8mm-cm4 node:

reserved-memory {
   #address-cells = <2>;
   #size-cells = <2>;
   ranges;

   m4_reserved: m4@0x77000000 {
      no-map;
      reg = <0 0x77000000 0 0x1000000>;
   };

   vdev0vring0: vdev0vring0@78000000 {
      reg = <0 0x78000000 0 0x8000>;
      no-map;
   };

   vdev0vring1: vdev0vring1@78008000 {
      reg = <0 0x78008000 0 0x8000>;
      no-map;
   };

   rsc-table {
      reg = <0 0x780ff000 0 0x1000>;
      no-map;
   };

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

   rsc_table: rsc_table@78000000 {
      reg = <0 0x78000000 0 0x8000>;
   };
};

imx8mm-cm4 {
   compatible = "fsl,imx8mm-cm4";
   rsc-da = <0x78000000>;
   clocks = <&clk IMX8MM_CLK_M4_DIV>;
   mbox-names = "tx", "rx", "rxdb";
   mboxes = <&mu 0 1
      &mu 1 1
      &mu 3 1>;
      memory-region = <&vdevbuffer>, <&vdev0vring0>, <&vdev0vring1>, <&rsc_table>;
      syscon = <&src>;
};

do not forget to disable devices for Linux needed by the coprocessor :

&uart4 {
   status = "disabled";
};

&uart2 {
   status = "disabled";
};

boot M4/7 coprocessor from Tightly-Coupled Memory (TCM)

Assuming the coprocessor firmware is stored in the bootfs partition, the coprocessor is booted with the following commands:

fatload mmc ${mmcdev}:1 ${loadaddr} rpmsg_lite_str_echo_rtos.bin
cp.b ${fileaddr} 0x7e0000 0x20000
bootaux 0x7e0000

boot M4 coprocessor from DRAM on a TX8M-1610 SOM

Before the firmware is build for starting from DRAM, the linker skript must be modified according to the address buffers defined in the device tree:

/* Specify the memory areas */
MEMORY
{
  m_interrupts          (RX)  : ORIGIN = 0x77000000, LENGTH = 0x00000240
  m_text                (RX)  : ORIGIN = 0x77000240, LENGTH = 0x001FFDC0
  m_data                (RW)  : ORIGIN = 0x77200000, LENGTH = 0x00200000
  m_data2               (RW)  : ORIGIN = 0x77400000, LENGTH = 0x00C00000
}

Assuming the coprocessor firmware is stored in the bootfs partition, the coprocessor is booted with the following commands:

fatload mmc ${mmcdev}:1 0x77000000 rpmsg_lite_str_echo_rtos.bin
dcache flush
bootaux 0x77000000

boot M7 coprocessor from DRAM on a TX8M-ND00 SOM

The TX8M-ND00 has only 512 MBytes of DRAM. The M7 coprocessor can access the DRAM in its address range 0x4000_0000 - 0x5fff-ffff. Unfortunately, this memory region of the Cortex®-M7 is declared as Peripheral and has the attribute Execute Never (XN). That means that the processor prevents instruction accesses.

Running the firmware from DRAM is possible anyway with a trick. As the 515 MBytes are mirrored 4 times in the 2 GBytes DRAM address range of the Cortex®-M7 coprocessor, we link the firmware for the 2nd 515 MBytes memory region. Therefore, we have to setup the linker skript in the following way:

/* Specify the memory areas */
MEMORY
{
  m_interrupts          (RX)  : ORIGIN = 0x77000000, LENGTH = 0x00000240
  m_text                (RX)  : ORIGIN = 0x77000240, LENGTH = 0x001FFDC0
  m_data                (RW)  : ORIGIN = 0x77200000, LENGTH = 0x00200000
  m_data2               (RW)  : ORIGIN = 0x77400000, LENGTH = 0x00C00000
}

Assuming the coprocessor firmware is stored in the bootfs partition, the coprocessor is booted with the following commands:

fatload mmc ${mmcdev}:1 0x57000000 rpmsg_lite_str_echo_rtos.bin
dcache flush
bootaux 0x57000000

The bootaux command analyses the binary at address 0x5700_0000 and initialises the reset vector for the coprocessor to 0x7700_0240 as specified in the linker skript.

boot M7 coprocessor from DRAM on a QSXP-ML81

Before the firmware is build for starting from DRAM, the linker skript must be modified according to the address buffers defined in the device tree:

/* -----------------------------------------------------------------------

Specify the memory areas

Cortex-M7 Memory map:
0x0000_0000   128kb     ITCM
0x2000_0000   128kb     DTCM
0x4000_0000   2gb       DDR Memory area

---------------------------------------------------------------------------*/

MEMORY
{
        m_interrupts          (RX)  : ORIGIN = 0x80000000, LENGTH = 0x00000400
        m_text                (RX)  : ORIGIN = 0x80000400, LENGTH = 0x001FFC00
        m_data                (RW)  : ORIGIN = 0x80200000, LENGTH = 0x00200000
        m_data2               (RW)  : ORIGIN = 0x80400000, LENGTH = 0x00C00000
}

Assuming the coprocessor firmware is stored in the bootfs partition, the coprocessor is booted with the following commands:

fatload mmc ${mmcdev}:1 0x80000000 rpmsg_lite_str_echo_rtos.bin
dcache flush
bootaux 0x80000000

boot Linux

Boot the Linux with the boot command from u-boot.

load module

Load the imx_rpmsg_tty kernel module:

insmod /lib/modules/5.10.35-1.0.0+g99a35ce31539/kernel/drivers/rpmsg/imx_rpmsg_tty.ko

you should now find a virtual device /dev/ttyRPMSG30.

using a custom yocto for setup

The Ka-Ro download area provides Yocto layers that supports all features to run the multicore example on a imx8 modules.

Setup your build-directory with the desired machine and distro like explained in BSP Setup.

DISTRO=karo-minimal MACHINE=tx8m-1610 source karo-setup-release.sh -b build-tx8m-1610

Copy the custom layer meta-karo-nxp-copro to your sources folder.

To make your layer available, add it to conf/bblayers.conf inside your build-directory.

(...)
BBLAYERS += "${BSPDIR}/sources/meta-karo-nxp"
BBLAYERS += "${BSPDIR}/sources/meta-karo-nxp-distro"
BBLAYERS += "${BSPDIR}/sources/meta-karo-nxp-copro"