Cortex-M4 Bare-Metal freezes at TorizonOS 7 login prompt (i.MX7 Clock gating / Hard Fault issue)

I am currently working on my university Supervised Professional Practice project, which involves implementing an Asymmetric Multiprocessing (AMP) architecture on a Colibri i.MX7 module. I am running a Bare-Metal application on the Cortex-M4 and TorizonOS on the Cortex-A7.

I am facing a critical issue where the Cortex-M4 freezes (suffers a Hard Fault) at the exact moment TorizonOS finishes booting and reaches the login: prompt. I suspect this is related to the Linux kernel power management / Common Clock Framework disabling shared clocks.

Here are the full details of my setup, the issue, and everything I have tried so far.

1. Hardware & Software Setup

  • SoM: Toradex Colibri i.MX7D 1GB eMMC V1.1A

  • Carrier Board: Iris V1.1 Carrier Board

  • Cortex-A7 OS: Torizon OS Upstream 7.6.1+build.38 (Kernel 6.6.138-7.6.1)

  • Cortex-M4 OS: Bare-Metal (compiled using NXP FreeRTOS-Colibri-iMX7 SDK, specifically the gpio_imx driver example).

  • Boot Method: Early boot via U-Boot (setenv m4boot 'load mmc 0:1 ${loadaddr} /boot/gpio_imx.elf && bootaux ${loadaddr}').

2. The Problem

My Bare-Metal code simply blinks an LED on GPIO5 and continuously prints a message over UART2. When I power on the board, U-Boot successfully loads the .elf file and the Cortex-M4 starts executing perfectly (LED blinks and UART prints are visible). However, when TorizonOS finishes its boot process and prints the login option, prompt on the A7 console, the M4 LED stops blinking and the UART2 stops printing simultaneously. This indicates a Hard Fault / External Abort on the M4, presumably because Linux disabled the clock for a peripheral the M4 was actively using.

3. What I have tried so far (without success)

  • RDC Isolation (M4 Side): I modified hardware_init.c to assign the M4 to Domain 1 and explicitly lock the RDC for GPIO5 and UART2 (RDC_SetPdapAccess(RDC, rdcPdapGpio5, 3 << (BOARD_DOMAIN_ID * 2), false, false);).

  • CCM Clock Gates (M4 Side): Forced CCM_ControlGate(CCM, ccmCcgrGateGpio5, ccmClockNeededAll);.

  • Device Tree Overlays (Linux Side):

    • Attempt 1: Disabled the peripherals in the A7 device tree (status = "disabled"; for &gpio5 and &uart2).

    • Attempt 2: Tried to trick the power management by setting them to status = "okay"; but with a fake driver (compatible = "pps-bare-metal-reserved";).

    • Attempt 3: Added a reserved-memory node for the M4 at m4@80000000.

  • RPMsg / RemoteProc approach: Since early boot is being aggressively clock-gated by Kernel 6.6, I tried compiling the pingpong_bm and str_echo_bm examples from the NXP SDK to let Linux handle the clocks via RPMsg. However, the modules imx_rpmsg_tty and imx_rproc seem to be missing or built-in without exposing the TTY port in this specific TorizonOS 7 kernel, so /dev/ttyRPMSG never appears, even when adding &rpmsg { status = "okay"; }; to the DT.

4. Cortex-M4 Main Code (main.c)

Here is the simplified Bare-Metal code I am running:

C

#include <stdint.h>
#include <stdbool.h>
#include "board.h"
#include "debug_console_imx.h"
#include "gpio_imx.h"

void delay(void) {
    for (volatile uint32_t i = 0; i < 5000000; ++i) {
        __asm("NOP");
    }
}

int main(void) {
    hardware_init(); /* RDC and CCM isolation applied here */

    configure_gpio_pin(BOARD_GPIO_LED_CONFIG);
    
    gpio_init_config_t ledInitConfig = {
        .pin = BOARD_GPIO_LED_CONFIG->pin,     
        .direction = gpioDigitalOutput,         
        .interruptMode = gpioNoIntmode        
    };

    GPIO_Init(BOARD_GPIO_LED_CONFIG->base, &ledInitConfig);

    while (1) {
        
        GPIO_WritePinOutput(BOARD_GPIO_LED_CONFIG->base, BOARD_GPIO_LED_CONFIG->pin, 1);
        PRINTF("hola, desde M\n\r");
        
        for (volatile uint32_t i = 0; i < 5000000; i++) {}

        GPIO_WritePinOutput(BOARD_GPIO_LED_CONFIG->base, BOARD_GPIO_LED_CONFIG->pin, 0);

        
        for (volatile uint32_t i = 0; i < 5000000; i++) {}
    }
     
}

Questions:

  1. Is there a known workaround or specific Device Tree configuration in TorizonOS 7 (Kernel 6.6) to completely prevent the Common Clock Framework from touching the M4 domain clocks during late boot?

  2. Is RemoteProc/RPMsg the only officially supported way to keep the M4 alive in TorizonOS 7? If so, how can I properly enable the RPMsg TTY interface in this kernel version?

Any guidance, documentation, or tips would be greatly appreciated. Thank you in advance!

Hi, I’m the Toradex AI Assistant.

I might make mistakes or occasionally get you wrong. Our support team will step in if needed.


The issue you’re experiencing is a known problem with TorizonOS 7 and the newer kernel’s power management affecting Cortex-M4 operation. Your analysis about the Common Clock Framework disabling shared clocks is correct.

Solution for TorizonOS 7 Clock Management

For TorizonOS 7 with Kernel 6.6, you need to add specific kernel command line arguments to prevent the Linux kernel from interfering with the M4 core during boot (1). Add these parameters to your kernel command line:

clk_ignore_unused systemd.gpt_auto=0

This prevents the kernel from automatically disabling unused clocks that the M4 might be using (1).

Device Tree Configuration

Your device tree approach is on the right track. You should disable the peripherals used by the M4 in the Linux device tree (2):

&gpio5 {
    status = "disabled";
};

&uart2 {
    status = "disabled";
};

The documentation confirms that “if a device shall be used on the Cortex-M4 which is used by the Linux kernel running on the Cortex-A7 (e.g. I2C), it is important to disable this device in the device tree of the Linux kernel (e.g. set the status property to disabled)” (2).

RPMsg/RemoteProc Alternative

Regarding your RPMsg attempts, there are known issues with TorizonOS 7 where /dev/ttyRPMSG30 devices are not being created (1). The community has identified that this was due to “a small error on the device tree overlay due to a change in the driver in the new kernel version” (1).

For RemoteProc to work properly, you need:

  1. Enable the HMP device tree overlay for Colibri iMX7 (3)
  2. Use .elf format firmware files (not .bin) (3)
  3. Load firmware through the RemoteProc framework (3)

The RemoteProc approach offers better integration with Linux power management since “the remote processor (rproc) framework serves as a robust solution for managing remote processor devices within modern System-on-Chips (SoCs)” (3).

Recommended Approach

For TorizonOS 7, I recommend:

  1. First, try the kernel command line fix: Add clk_ignore_unused systemd.gpt_auto=0 to your kernel parameters
  2. Keep your device tree changes: Disable GPIO5 and UART2 in the Linux device tree
  3. If issues persist, migrate to RemoteProc: This provides better long-term compatibility with newer kernels

The documentation emphasizes that Heterogeneous Multi-core Processing enables you to “pair a high-performance application processor running Linux (Cortex-A) with one or more low-power real-time cores (Cortex-M or Cortex-R)” (4), and RemoteProc is the recommended framework for this integration.

Best regards, Toradex AI Assistant.


Did you like my answer? :+1: :-1:

If I answered your question, please tick the “Solution” checkbox.

For follow-up questions to me, please use @ToradexAI in your post.

Hi @SantiagoA!

1 - Could you please test the clk_ignore_unused parameter suggested by the Toradex AI?

2 - At the moment, we don’t have the official overlay for enabling RemoteProc and/or RPMsg on the Colibri iMX7, and our BSP team is not planning to prioritize this work for now. That said, our recommendation approach for using the Cortex-M on the Colibri iMX7 is through Zephyr.
Although we haven’t tested it for newer Torizon versions, it should not be difficult to implement. You can follow the guide on the Zephyr website (linked above).

Best regards.