Last edited one month ago

How to use the Cortex-M0+



1. Article purpose[edit | edit source]

This article describes the configuration of the Cortex®-M0+ and its related resources, and how to run a Cortex®-M0+ firmware through a low power demonstration application. Purpose of this application is to demonstrate a low power use case and a communication use case between the Cortex®-M0+ and Cortex®-A35.

2. Introduction[edit | edit source]

The Cortex®-M0+ is used as a coprocessor with access to limited resources, peripherals and memories. The Cortex®-M0+ processor is dedicated to executing small tasks that require few resources. It runs in a separate SmartRun domain, allowing other domains to be turned off to achieve low levels of power consumption.

3. Resources access from Cortex®-M0+[edit | edit source]

3.1. Memories[edit | edit source]

The Cortex®-M0+ can only use the LPSRAM memories for a total of 32KB, with following memory mapping:

  • LPSRAM1 : 0x200C0000 - 0x200C1FFF (8KB)
  • LPSRAM2 : 0x200C2000 - 0x200C3FFF (8KB)
  • LPSRAM3 : 0x200C4000 - 0x200C7FFF (16KB)

3.2. Peripherals[edit | edit source]

The Cortex®-M0+ can only access to a set of limited peripherals:

  • LPTIM3, LPTIM4, LPTIM5
  • SPI8
  • LPUART1
  • I2C8
  • ADF1C
  • GPIOZ
  • LPDMA
  • RTC
  • I3C4
  • IPCC2
  • EXTI2
  • HSEM

3.3. Other resources[edit | edit source]

The Cortex®-M0+ can also access to others resources as:

  • PWR
  • CoreSight Debug through 2 ports :
    • The SWD (Serial Wire Debug)
    • The SWJ-DP (Serial Wire JTAG-Debug Port)

3.4. Security[edit | edit source]

All memories, peripherals and resources access rights are managed by the Resource Isolation Framework (RIF) in the Cortex®-A35.

3.4.1. Memories RIF configuration example[edit | edit source]

The RIF configuration of the LPSRAM memories have to allow the load of the M0+ firmware image by the Cortex®-A35 Linux kernel remoteproc framework and the execution of the firmware on the Cortex®-M0+.

In the following example, the LPSRAM 1/2/3 (respectively RISAL_ID 1/2/3) are configured as a shared memory (subregion A and subregion B) between the Cortex®-A35 (RID_CID1) and Cortex®-M0+ (RIF_CID3):

	st,risal = <
		RISALPROT(RISAL_ID(1), RIFSC_RISAL_BLOCK_A, RIF_CID1, RIF_UNLOCK, RIF_NSEC, RIF_NPRIV, RIFSC_RISAL_SREN)
		RISALPROT(RISAL_ID(2), RIFSC_RISAL_BLOCK_A, RIF_CID1, RIF_UNLOCK, RIF_NSEC, RIF_NPRIV, RIFSC_RISAL_SREN)
		RISALPROT(RISAL_ID(3), RIFSC_RISAL_BLOCK_A, RIF_CID1, RIF_UNLOCK, RIF_NSEC, RIF_NPRIV, RIFSC_RISAL_SREN)
		RISALPROT(RISAL_ID(1), RIFSC_RISAL_BLOCK_B, RIF_CID3, RIF_UNLOCK, RIF_NSEC, RIF_NPRIV, RIFSC_RISAL_SREN)
		RISALPROT(RISAL_ID(2), RIFSC_RISAL_BLOCK_B, RIF_CID3, RIF_UNLOCK, RIF_NSEC, RIF_NPRIV, RIFSC_RISAL_SREN)
		RISALPROT(RISAL_ID(3), RIFSC_RISAL_BLOCK_B, RIF_CID3, RIF_UNLOCK, RIF_NSEC, RIF_NPRIV, RIFSC_RISAL_SREN)
	>;

3.4.2. Peripherals RIF configuration example[edit | edit source]

The RIF access right are applied to the peripherals and their associated RCC registers. If the Cortex®-M0+ controls the peripheral, the Cortex®-A35 has to configure the associated RCC registers before starting the Cortex®-M0+. For this reason, the peripherals' RIF access rights have to be allowed for both the Cortex®-A35 and the Cortex®-M0+.

In the following example, the LPUART1 is configured without any filtering to allow access of the LPUART1 by the Cortex®-A35 and the Cortex®-M0+:

&rifsc {
	st,protreg = <
       ....
		RIFPROT(STM32MP25_RIFSC_LPUART1_ID, RIF_UNUSED, RIF_UNLOCK, RIF_NSEC, RIF_NPRIV, RIF_UNUSED, RIF_SEM_DIS, RIF_CFDIS)
       ....
	>;
	st,glocked = <RIFSC_RIMU_GLOCK>;
};


3.5. Low power constraints[edit | edit source]

The Cortex®-M0+ can be used during low power modes, while Cortex®-A35 and Cortex®-M33 are stopped. A dedicated autonomous mode is available for each peripheral that can be allocated to Cortex®-M0+ in order to avoid from stopping peripherals clocks during Cortex®-A35 low power.

4. Linux Kernel configuration[edit | edit source]

  • To manage the Cortex®-M0+, activate the Cortex®-M0+ remoteproc driver by enabling the STM32_M0_RPROC build configuration,
  • To communicate with the Cortex®-M0+, activate the mailbox char device client by enabling the MAILBOX_CDEV build configuration.

5. Linux Kernel device tree configuration[edit | edit source]

The Cortex®-M0 live cycle in managed by the Linux kernel remoteproc framework.To configure the Cortex®-M0+, we mainly need:

  • to define the memory mapping
  • to define the m0_rproc node in device tree
  • to define the mailbox char device client node configuration.

5.1. Memory configuration[edit | edit source]

In the STM32MPU Embedded Software distribution, the default memory configuration is splited in 3 memory regions that can be customized:

  • Code  : 16KB (LPSRAM1 & LPSRAM2)
  • Data  : 8KB (LPSRAM3)
  • Shared Memory : 8KB (LPSRAM3)

The shared memory is used to shared data between Cortex®-M0+ and Cortex®-A35 through interprocessor communication and mailbox mechanisms.

		cm0_cube_fw: cm0-cube-fw@200C0000 {
			compatible = "shared-dma-pool";
			reg = <0x0 0x200C0000 0x0 0x4000>;
			no-map;
		};

		cm0_cube_data: cm0-cube-data@200C4000 {
			compatible = "shared-dma-pool";
			reg = <0x0 0x200C4000 0x0 0x2000>;
			no-map;
		};

		ipc_shmem_2: ipc-shmem-2@200C6000{
			compatible = "shared-dma-pool";
			reg = <0x0 0x200C6000 0x0 0x2000>;
			no-map;
		};

5.2. Remoteproc configuration[edit | edit source]

  • The memory-region property should list the memories used for the firmware execution and for the interprocessor communication
  • The clocks property should list the peripheral clocks used by the Cortex®-M0+
&m0_rproc {
	mboxes = <&ipcc2 2>; 
	mbox-names = "shutdown";
	memory-region = <&cm0_cube_fw>, <&cm0_cube_data>;
	clocks = <&rcc CK_CPU3>,              <- Enable CPU3 clock
		 <&rcc CK_CPU3_AM>,               <- Enable CPU3 autonomous Mode
		 <&rcc CK_LPUART1_C3>,            <- Allocate LPUART1 to CPU3
		 <&rcc CK_KER_LPUART1>,           <- Enable LPUART1 clock 
		 <&rcc CK_LPUART1_AM>,            <- Enable LPUART1 autonomous Mode 
		 <&scmi_clk CK_SCMI_IPCC2>,       <- Enable IPCC2 clock
		 <&scmi_clk CK_SCMI_IPCC2_AM>;    <- Enable IPCC2 autonomous Mode
	status = "okay";
};

5.3. Mailbox client configuration[edit | edit source]

  • The memory-region property should list the memory used for the interprocessor communication (shared memory)
	mbox_client: mailbox-client@1 {
		compatible = "mbox-cdev";
		reg = <1 0>;
		memory-region =  <&ipc_shmem_2>;
		mboxes = <&ipcc2 0>;
		mbox-names = "rx-tx";
		status = "okay";
	};

6. Cortex®-M0+ demonstration (applicable on STM32MP257x-EV1 Evaluation board More info green.png only)[edit | edit source]

The Cortex®-M0+ demonstration aims to show the Cortex®-A35 wakeup from low power mode (LP-Stop2) from Cortex®-M0+.

The demonstration application consists in:

  • Starting the Cortex®-M0+ firmware through remoteproc driver.
  • Configuring a wakeup delay in Cortex®-CM0+ firmware from Linux userland (Cortex®-A35) by using IPCC communication, shared memory and Mailbox mechanism.
  • Setting the LP-Stop2 low power mode.
  • Waking up the Cortex®-A35 from Cortex®-M0+ firmware through interrupt after the programmed delay is expired.

6.1. STM32Cube Firmware application[edit | edit source]

The Cortex®-M0+ STM32Cube Firmware application is available as an example in STM32CubeMP2 Firmware Package. It allows to wake up the Cortex®-A35 from low power mode after a programmed delay.

This application uses the following features:

  • LPUART1 : to print messages on console
  • IPCC2 : to send / receive notification between Cortex®-M0+ and Cortex®-A35 through interprocessor communication mechanism (interrupt)
  • Shared Memory: to share data between the Cortex®-M0+ and Cortex®-A35

Purpose of this application is to:

  • Initialize LPUART1 for printing messages on the console.
  • Initialize IPCC2 for communication between Cortex®-M0+ and Cortex®-A35.
  • Print a message on LPUART1 every 2 seconds.
  • Wait from an IPCC2 interrupt which corresponds to a message received in shared memory from Cortex®-A35.
    • Once IPCC2 interrupt is received, then the firmware:
      • Reads the first 4 bytes from the shared memory, which represent the delay before sending a notification to the Cortex®-A35.
      • Starts a delay with the value read from shared memory.
      • Once delay has elapsed, send a notification through the IPCC2 to wake up the Cortex®-A35.
  • Continue printing default message in LPUART1 and waiting for new message from Cortex®-A35.

6.2. Board and connectors[edit | edit source]

Main access to Cortex®-M0+ is done through the MikroBUS connector available on STM32MP257x-EV1 Evaluation board More info green.png.

Microbus.png

6.3. How to connect LPUART1[edit | edit source]

To use the LPUART1, you need to :

  • Connect the 3 wired USB-to-TTL Serial UART debug cable to MikroBUS connector through pins RX/TX/GND.

6.4. How to debug Cortex®-M0+[edit | edit source]

The debug of the Cortex®-M0+ can done by 2 ways according to the state of the Cortex®-A35 as the following :

  • When the Cortex®-A35 is running, the debug of Cortex®-M0+ can be done through STLINK connector.
  • When the Cortex®-A35 is in low power mode, the debug of Cortex®-M0+ can be done through the SWD port.

To use the SWD interface, you need to :

  • Connect the debugger to MikroBUS connector through pins MISO/MOSI/3.3V/GND.
  • Enable the SWD debug interface for the Cortex®-M0+ (clear the bit DBG_SWD_SEL_N of the register DBGMCU_CR).

Dbgmcu cr.png

6.5. How to run the Cortex®-M0+ demonstration application[edit | edit source]

The Cortex®-M0+ firmware image has to be copied in folder /lib/firmware in the Linux rootfs. By default the Cortex®-M0+ firmware is named CM0PLUS_Demo_NonSecure.elf.

  • Start from following path and check that the Cortex®-M0+ firmware is available
 cd /lib/firmware
  • Stop the M33 firmware
 echo stop > /sys/class/remoteproc/remoteproc0/state
  • Configure the M0+ firmware
 echo CM0PLUS_Demo_NonSecure.elf > /sys/class/remoteproc/remoteproc1/firmware
  • Start the M0+ firmware
 echo start > /sys/class/remoteproc/remoteproc1/state
[ 1245.086086] remoteproc remoteproc1: powering up m0
[ 1245.120304] remoteproc remoteproc1: Booting fw image CM0PLUS_Demo_NonSecure.elf, size 1017852
[ 1245.123454] remoteproc remoteproc1: remote processor m0 is now up
  • Enabling IPCC2 wakeup source for A35 wakeup
 echo enabled > /sys/devices/platform/soc@0/46250000.mailbox/power/wakeup
  • Configure delay to Cortex®-M0+ before waking-up Cortex®-A35 (ex : 7s)
 echo 7 > /dev/mailbox0

Cortex®-M0+ logs from LPUART1:

**** CM0PLUS Example application ****
(1) Hello from CM0+
(2) Hello from CM0+
(3) Hello from CM0+
(4) Hello from CM0+
(5) Hello from CM0+
(5) A35 wakeup request in 7s
  • Set Cortex®-A35 to low power (during 30 seconds)
rtcwake --date +30sec -m mem

Cortex®-A35 logs from Linux console:

rtcwake: assuming RTC uses UTC ...
rtcwake: wakeup from "mem" using /dev/rtc0 at Tue Oct  8 16:44:29 2024
[  414.922335] PM: suspend entry (deep)
[  414.922538] Filesystems sync: 0.000 seconds
[  414.960147] Freezing user space processes
[  414.962082] Freezing user space processes completed (elapsed 0.001 seconds)
[  414.965543] OOM killer disabled.
[  414.968675] Freezing remaining freezable tasks
[  414.974403] Freezing remaining freezable tasks completed (elapsed 0.001 seconds)
[  414.985780] stm32-dwmac 482d0000.eth2 end0: FPE workqueue stop
[  414.986671] stm32-dwmac 482c0000.eth1 end1: FPE workqueue stop
[  415.070706] Disabling non-boot CPUs ...
[  415.072458] psci: CPU1 killed (polled 0 ms)
INFO:    Entering LP_Stop2 low power mode

Cortex®-M0+ logs from LPUART1:

(5) A35 wakeup request done !
(6) Hello from CM0+

Cortex®-A35 logs from Linux console:

[  415.073956] Enabling non-boot CPUs ...
I/TC: Secondary CPU 1 initializing
I/TC: Secondary CPU 1 switching to normal world boot
[  415.085464] Detected VIPT I-cache on CPU1
[  415.085540] CPU1: Booted secondary processor 0x0000000001 [0x411fd040]
[  415.086106] CPU1 is up
[  415.095505] i2c 0-001a: Unbalanced pm_runtime_enable!
[  415.137097] dwmac4: Master AXI performs any burst length
[  415.137154] stm32-dwmac 482c0000.eth1 end1: No Safety Features support found
[  415.345753] stm32-dwmac 482c0000.eth1 end1: IEEE 1588-2008 Advanced Timestamp supported
[  415.348476] stm32-dwmac 482c0000.eth1 end1: FPE workqueue start
[  415.354080] stm32-dwmac 482c0000.eth1 end1: configuring for phy/rgmii-id link mode
[  415.577092] dwmac4: Master AXI performs any burst length
[  415.577134] stm32-dwmac 482d0000.eth2 end0: No Safety Features support found
[  415.583804] stm32-dwmac 482d0000.eth2 end0: IEEE 1588-2008 Advanced Timestamp supported
[  415.591954] stm32-dwmac 482d0000.eth2 end0: FPE workqueue start
[  415.597751] stm32-dwmac 482d0000.eth2 end0: configuring for phy/rgmii-id link mode
[  416.086930] onboard-usb-hub 1-1: reset high-speed USB device number 2 using ehci-platform
[  416.352327] OOM killer enabled.
[  416.352360] Restarting tasks ... done.
[  416.359329] random: crng reseeded on system resumption
[  416.366896] PM: suspend exit

7. Code source[edit | edit source]

7.1. Linux kernel[edit | edit source]

drivers/remoteproc/stm32_m0_rproc.c 
drivers/mailbox/mailbox-client_cdev.c 
arch/arm64/boot/dts/st/stm32mp257f-ev1.dts 

7.2. STM32Cube application[edit | edit source]

Projects/STM32MP257F-EV1/Demonstrationss/CM0PLUS_DEMO