1. Article purpose
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.
![]() |
The Cortex®-M0+ demonstration application is only applicable for STM32MP257x-EV1 Evaluation board ![]() ![]() |
2. Introduction
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+
3.1. Memories
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)
![]() |
In the STM32MPU Embedded Software distribution, the memory mapping of the LPSRAM must necessarily be defined between 0x200C0000 and 0x200C7FFF. |
3.2. Peripherals
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
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)
![]() |
The Cortex®-M0+ has no access to RCC resources (for clock configuration for example). It implies that the clock gating has to be managed by the Cortex®-A35 (Linux kernel or OP-TEE). |
3.4. Security
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
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
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
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.
![]() |
On ecosystem release v6.0.0 ![]() |
4. Linux Kernel configuration
- 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
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
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;
};
![]() |
This memory mapping need to be aligned with the Cortex®-M0+ Cube Firmware memory mapping (Linkerscript). |
5.2. Remoteproc configuration
- 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
- 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
only)
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
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.
- Once IPCC2 interrupt is received, then the firmware:
- Continue printing default message in LPUART1 and waiting for new message from Cortex®-A35.
6.2. Board and connectors
Main access to Cortex®-M0+ is done through the MikroBUS connector available on STM32MP257x-EV1 Evaluation board .
6.3. How to connect LPUART1
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+
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).
6.5. How to run the Cortex®-M0+ demonstration application
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®-A35 wakeup
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
7.1. Linux kernel
drivers/remoteproc/stm32_m0_rproc.c drivers/mailbox/mailbox-client_cdev.c arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
7.2. STM32Cube application
Projects/STM32MP257F-EV1/Demonstrationss/CM0PLUS_DEMO