How to initialising an inmutable static with pre_init when specifying link_section

⚓ Rust    📅 2026-06-14    👤 surdeus    👁️ 2      

surdeus

Hello

The documentation for the cortex-m-rt crate explains how one could place data in other sections than RAM: cortex_m_rt - Rust, but points out:

However, note that these sections are not initialised by cortex-m-rt, and so must be used either with MaybeUninit types or you must otherwise arrange for them to be initialised yourself, such as in pre_init.

The MaybeUninit route fails when trying to use its write() method, and I would prefer to be able to use the static without any level of indirection. I thought the pre_init route (being a special function and all) would allow me to initialize the struct, after all, that is what I understand the cortex-m-rt crate is doing for the "RAM" section. Failing, I tried and searched, to no avail. Online resources (including this forum) always pointing back to some indirection (Mutex, RWLock, Cells...).

Therefore I would like to ask: Can I initialize an immutable static with no indirection, just one initial write?

Here is the situation, with the comments in the before_main function being the compiler errors for my increasingly stubborn attempts.

// Creating static data, not initialised due to the link section.  
#[unsafe(link_section=".dtcm0.BUFFERS")]
static DATA_0000: aligned::Aligned<aligned::A32, [u8; 32]> =
    aligned::Aligned([0; 32]);

use cortex_m_rt::pre_init;
#[pre_init] // Must only exist once in the dependency tree.
unsafe fn before_main() {
    // "cannot assign to immutable static item `DATA_0000`"
    DATA_0000 = aligned::Aligned::<aligned::A32, [u8; 32]>([0; 32]);

    // "expected identifier, found keyword `mut`"
    // "expected type, found keyword `mut`"
    // "expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`,
    //  identifier, `::`, `<`, `dyn`, square brackets, `*`, `&`, `!`, `impl`,
    //  `_`, lifetime"
    DATA_0000 as mut aligned::Aligned::<aligned::A32, [u8; 32]> =
        aligned::Aligned::<aligned::A32, [u8; 32]>([0; 32]);

    // "invalid left-hand side of assignment"
    // "non-primitive cast: `aligned::Aligned<A32, [u8; 32]>` as 
    // `&mut aligned::Aligned<A32, [u8; 32]>`"
    *&mut DATA_0000 as &mut aligned::Aligned::<aligned::A32, [u8; 32]> =
        aligned::Aligned::<aligned::A32, [u8; 32]>([0; 32]);
}

My (hopefully sane) plan is to write to the immutable static with a DMA on the wide, but slower AXI bus of a Cortex-M7 MCU, and defining DTMC0/1 memory sections as RAM, so that the stack and other static data reside close (and fast) to the CPU.
I believe this has 3 advantages:

  1. Less worry about the Data Cache, since the CPU is never allowed to write to the buffers. That allows me to focus on invalidating parts of the Dcache and no worry about the apparently very expensive clean calls.
  2. The code becomes simpler. Effectively, this would make the buffers writable only by a single "thread": the DMA. No unsafe blocks, no &raw mut .... pointers.
  3. Fewer bus collisions. The CPU should rarely need to access AXIRAM when the DMA does too. To further improve this, I could split the "AXIRAM" into its distinct parts "AXIRAM1", "AXIRAM2",... and taking advantage of that.

Given the DMA would be the one filling the buffers with anything useful, I contemplated whether an initialization would be necessary. My motivation for asking is the curiosity whether this is possible (and maybe a sanity check overall). Scrolling through the cortex-m-rt source (lib.rs - source) I see a lot of assembly :confused:. My hope that this can be done in plain rust, and quite quickly, is waning.

Here is an image from the SMT32H7R/S reference manual for some context:

image

3 posts - 2 participants

Read full topic

🏷️ Rust_feed