Last edited 12 hours ago

How to port StarterAppM33TD demonstration to a new board

Applicable for STM32MP21x lines, STM32MP25x lines

Info white.png Trusted domain applicability
This article is only applicable to M33-TD flavor More info green.png of STM32MP2 series
Warning DB.png Important
In this article, the STM32MP215F-DK Discovery kit Info.png is taken as example. Nevertheless, it is also applicable for STM32MP257F-EV1 Evaluation board More info green.png.

Info white.png Information
This article uses the STM32MP257F-EV1 Evaluation board More info green.png as a reference. The microprocessor is then fixed to the STM32MP25x lines More info.png, so startup, system, and linker files remain unchanged when porting to custom boards based on the same microprocessor. Only board-specific BSP (Board Support Package) changes are required for porting. All instructions and project structures in this article are tailored for use with **STM32CubeIDE**.


1. Introduction[edit | edit source]

The Cortex-M33-TD software ecosystem for STM32MP2 series platforms is designed to provide a secure, flexible, and robust foundation for embedded system bring-up.

In this architecture, the Cortex-M33 processor is responsible for early system initialization and management, working in tandem with the Cortex-A35 processor. The software stack includes:

  • MCUboot for secure boot and firmware updates,
  • Trusted Firmware-M (TF-M)' [1] for secure services,
  • STM32CubeMPU firmware as the nonsecure application manager built on FreeRTOS.


Within this ecosystem, the STM3CubeMPU firmware —referred below as the StarterApp_M33TD— serves as the main nonsecure application manager which is essential for system operation: it schedules user and system tasks, manages remote processor control (such as starting and resetting the Cortex-A35), and interacts with secure services. While the full-featured StarterApp_M33TD demonstrates these capabilities on STM32 MPU boards, porting to a custom board is best approached with a focus on the essentials.

This article helps you port the StarterApp_M33TD to your custom hardware as a STM32CubeIDE project, focusing on a bare minimum application.
By concentrating on board-dependent features — UART logging, remote processor management, and a simple LED heartbeat — you can quickly validate your hardware and establish a solid foundation for further development. SoC-level startup and system files remain unchanged, allowing you to focus exclusively on the board support package (BSP) and minimal application logic.

Info white.png Information
Full-featured StarterApp_M33TD projects are available for evaluation and discovery boards, such as STM32MP215F-DK Discovery kit Info.png and STM32MP257F-EV1 Evaluation board More info green.png. This page is a generic starting point for custom board bring-up with minimal features, using STM32CubeIDE.


2. Prerequisites[edit | edit source]

STM32CubeIDE must be installed.

3. StarterApp_M33TD overview[edit | edit source]

StarterApp_M33TD is a demonstration example delivered in the STM32CubeMP2 Package, acting as a nonsecure application manager.

It is designed to:

  • Integrate with FreeRTOS as middleware.
  • Manage system integration and scheduling.
  • Provide a minimal set of tasks for system bring-up for M33-TD flavor More info green.png.

3.1. Minimal task setup for porting StarterApp_M33TD[edit | edit source]

Only the following FreeRTOS tasks are required for a functional StarterApp_M33TD:

  • remoteproc_task: Handles lifecycle management of the high-performance Cortex-A35 coprocessor (SoC-dependent, board-agnostic for MP25xx).
  • userapp_task: Simple heartbeat logic (LED toggle, board-dependent).

Other tasks (if present) can be commented out in app_freertos.c for the initial port.

4. StarterApp_M33TD flow overview[edit | edit source]

Below is the high-level flow from main.c to the FreeRTOS scheduler kickoff, with board-specific steps clearly marked and the minimal FreeRTOS tasks shown as branches from the scheduler.

main.c entry
   |
   v
System/Clock Init
   |
   v
[Board-Specific] LED Init
   |
   v
[Board-Specific] UART Init
   |
   v
Print System Info
   |
   v
osKernelInitialize()
   |
   v
MX_FREERTOS_Init() (Task creation)
   |
   v
osKernelStart()
   |
   v
FreeRTOS Scheduler
   |
   +---------------------+
   |                     |
   v                     v
remoteproc_task   userapp_task

5. Step-by-step porting guide[edit | edit source]

5.1. 1. Prepare your custom board BSP[edit | edit source]

  • Ensure your custom board has a BSP (Board Support Package) with:
    • LED initialization and control (for userapp_task)
    • UART initialization (required for system-level printf output and for any application task that needs to print to the terminal)

5.2. 2. Copy StarterApp_M33TD project[edit | edit source]

  • Copy the StarterApp_M33TD project for the reference board (e.g., STM32MP257F-EV1) into the target path.
  • Import it into your STM32CubeIDE workspace as a new project new project for your custom board.
Info white.png Information

For more information on how to import StarterApp_M33TD project for custom board, Refer following article: How_to_import,_build_and_debug_STM32CubeMP2_StarterAppM33TD_demonstration_in_STM32CubeIDE

5.3. 3. Update board-specific initialization[edit | edit source]

  • In main.c, update:
    • BSP_LED_Init(LED3); and BSP_LED_Toggle(LED3); to use your board's LED.
    • Replace the default STM32 MPU board UART initialization logic with the appropriate UART initialization for your custom board.
    • This may involve:
      • Requesting a different UART resource (e.g., RESMGR_RIFSC_UARTx_ID for your chosen UART instance),
      • Calling your custom board’s BSP UART initialization API,
      • Or directly configuring the UART using HAL functions in main.c.
  • In stm32mp2xx_hal_msp.c, update:
    • GPIO and peripheral clock enables to match your board's pinout and hardware resources.
    • Any resource manager requests for GPIOs, clocks, or peripherals.

5.4. 4. Minimal task configuration in app_freertos.c[edit | edit source]

  • In MX_FREERTOS_Init(), keep only the following tasks:
RemoteProcTask_Init();
UserAppTask_Init();
// Comment out other tasks for a bare minimum port
  • Comment out or remove other task initializations.

5.5. 5. Porting each task[edit | edit source]

remoteproc_task
Purpose: Manages lifecycle (start/stop/crash) of the Cortex-A35 processor.
Porting:
The task logic is board-agnostic and does not require changes for custom boards based on STM32MP25x lines More info.png.
EXTI, GPIO, and NVIC initialization for remote processor management is SoC-dependent and already correct for all STM32MP25x lines More info.png-based boards.
No changes are needed in remoteproc_task.c for custom board porting.
userapp_task
Purpose: Simple heartbeat (LED toggle).
Porting:
Update BSP_LED_Toggle(LED3); to use your board's LED.
If your board uses a different LED or GPIO, update the macro or function accordingly.

5.6. 6. Build and test[edit | edit source]

  • Build the project in STM32CubeIDE for your custom board.
  • Flash the firmware and observe:
    • UART logs (system-level messages and any output from application tasks)
    • LED heartbeat (from userapp_task)
    • Remote processor management (from remoteproc_task)
Warning white.png Warning
  • If you encounter build errors related to missing BSP functions or incorrect pin mappings, review your board's BSP and update all references in the StarterApp_M33TD code.
Info white.png Information

For more information on how to build and debug StarterApp_M33TD[2] project, Refer following article: How_to_import,_build_and_debug_STM32CubeMP2_StarterAppM33TD_demonstration_in_STM32CubeIDE

6. Minimal project structure (after porting)[edit | edit source]

Below is the recommended minimal project structure for a clean custom board port of the StarterApp_M33TD Demo application in STM32CubeIDE:

StarterApp_M33TD_CM33_NonSecure
├── Application
│   ├── Startup
│   │   └── startup_stm32mp257ccx_m33.s      <-- Startup file (unchanged for MP25xx SoC)
│   └── User
│       ├── Core
│       │   └── Src
│       │       ├── main.c
│       │       ├── stm32mp2xx_hal_msp.c
│       │       ├── stm32mp2xx_hal_timebase_tim.c
│       │       └── stm32mp2xx_it.c
│       └── FREERTOS
│           └── App
│               ├── app_freertos.c
│               ├── remoteproc_task.c
│               └── userapp_task.c
├── TFM
│   └── App
│       ├── tfm_ioctl_cpu_api.c
│       ├── tfm_ns_interface.c
│       ├── tfm_platform_api.c
│       ├── tfm_scmi_api.c
│       └── tfm_tz_psa_ns_api.c
├── Drivers
│   ├── BSP
│   │   └── (Custom board BSP files only)
│   └── CMSIS
│       ├── system_stm32mp2xx_m33_ns.c      <-- System file (unchanged for MP25xx SoC)
│       └── STM32MP2xx_HAL_Driver
├── Middlewares
│   └── FreeRTOS
├── Utilities
└── (Trusted Firmware-M as submodule or reference)

Note:

  • The startup file (startup_stm32mp257ccx_m33.s) and system file (system_stm32mp2xx_m33_ns.c) are SoC-dependent and should remain unchanged for all custom boards based on the STM32MP25x lines More info.png.
  • Only the BSP (Board Support Package) and application logic need to be adapted for your custom hardware.

7. Project cleanup[edit | edit source]

After porting, perform the following cleanup steps in your STM32CubeIDE project to ensure a minimal and maintainable project:

  • Remove unnecessary task files:
 Delete source/header files for tasks not required in the minimal application. 
  • Clean up app_freertos.c:
 Remove or comment out initialization calls for unused tasks.
  • Clean up app_tasks_config.h:
 This header defines stack sizes, priorities, and configuration macros for all tasks.  
 - Remove or comment out configuration macros for tasks that are not part of the minimal application.
 - Ensure only the macros for remoteproc_task, and userapp_task remain.
 - Example (after cleanup):
#define REMOTEPROC_TASK_STACK_SIZE    1024
#define REMOTEPROC_TASK_PRIORITY      osPriorityNormal

#define USERAPP_TASK_STACK_SIZE       512
#define USERAPP_TASK_PRIORITY         osPriorityBelowNormal
  • Remove evaluation board BSP files:
 If you are not using the STM32MP257x-EV1 Evaluation board More info green.png BSP, delete its files and add your custom board’s BSP.
  • Update build/project files:
 Remove references to deleted files from Makefiles, CMakeLists.txt, or project configuration files. 
  • Check includes and dependencies:
 Ensure only the necessary includes and dependencies remain for the minimal application.   
  • Review application logic:
 Remove any code, function calls, or references to tasks and features that are not part of the minimal port, ensuring a clean and maintainable codebase.

8. Code Section References[edit | edit source]

Below are code snippets and sections you may need to adapt:

8.1. main.c: Board UART initialization example[edit | edit source]

Default (Evaluation board) Example:

if(ResMgr_Request(RESMGR_RESOURCE_RIFSC, RESMGR_RIFSC_UART5_ID) == RESMGR_STATUS_ACCESS_OK) {
    COM_Init.BaudRate    = 115200;
    COM_Init.WordLength  = UART_WORDLENGTH_8B;
    COM_Init.StopBits    = UART_STOPBITS_1;
    COM_Init.Parity      = UART_PARITY_NONE;
    COM_Init.HwFlowCtl   = UART_HWCONTROL_NONE;
    /* Initialize and select COM1 which is the COM port associated with current Core */
    BSP_COM_Init(COM_VCP_CM33, &COM_Init);
    BSP_COM_SelectLogPort(COM_VCP_CM33);
}

For a custom board: Replace the above initialization logic with the appropriate UART initialization for your hardware.
This may involve:

  • Requesting a different UART resource (e.g., RESMGR_RIFSC_UARTx_ID for your chosen UART instance),
  • Calling your custom board’s BSP UART initialization API,
  • Or directly configuring the UART using HAL functions in main.c.

Examples:

// Using a different UART instance
if(ResMgr_Request(RESMGR_RESOURCE_RIFSC, RESMGR_RIFSC_UART3_ID) == RESMGR_STATUS_ACCESS_OK) {
// Or using a custom BSP API
CustomBoard_UART_Init(&COM_Init);
CustomBoard_SelectLogPort();

// Or direct HAL initialization
MX_USARTx_UART_Init(); // Your own initialization function
}

8.2. App_freertos.c: minimal task initialization[edit | edit source]

void MX_FREERTOS_Init(void) {
    RemoteProcTask_Init();
    UserAppTask_Init();
    // Comment out other tasks for bare minimum port
}

8.3. Userapp_task.c: heartbeat task[edit | edit source]

static void UserAppTask(void *argument)
{
    for (;;) {
        BSP_LED_Toggle(LED3); // Update LED3 as per your board
        osDelay(1000);
    }
}

9. Troubleshooting[edit | edit source]

  • UART not working: Check pin mapping and initialization in both BSP and main.c.
  • LED not toggling: Verify correct GPIO and LED macros for your board.
  • remote processor not managed: Ensure EXTI and GPIO resources are correctly configured (for STM32MP25x lines More info.png, the reference implementation is already correct).

10. Extending the application[edit | edit source]

Once the minimal port is functional, you can incrementally enable and port additional tasks as needed for your application.

11. References[edit | edit source]

  1. Refer trusted-firmware-m
  2. For STM32MP257F-EV1 refer StarterApp_M33TD