In this lesson, you will learn how to use custom linker sections to migrate performance-critical code into Tightly Coupled Memory (TCM), bypassing the latency overhead of standard instruction caches.
The Bottleneck: Cache Latency
In high-performance embedded systems, the CPU often outpaces the main flash memory. Even with caches, a "cache miss" triggers a fetch from slower non-volatile memory, introducing non-deterministic jitter. When dealing with real-time scheduling or cycle-accurate control loops, this jitter is unacceptable.
TCM acts as an extension of the CPU’s register file, providing single-cycle access times. By default, the linker places your entire binary in flash. To gain an edge, we must instruct the linker to relocate specific hot functions into the RAM address space dedicated to TCM.
Defining a Linker Section
In Rust, we use the #[link_section] attribute to tag specific functions. The linker will then group these functions into a named segment (e.g., .itcm).
#[inline(never)]
#[link_section = ".itcm"]
fn high_precision_control_loop() {
// Critical logic executed from fast memory
unsafe { core::ptr::write_volatile(0x4000_1000 as *mut u32, 0x1); }
}
Directing the Linker
Simply tagging the function isn't enough; your memory.x (or equivalent linker script) must define the memory layout to accommodate this section. You must create an entry that tells the linker where the .itcm section resides:
SECTIONS {
.itcm : ALIGN(4) {
*(.itcm .itcm.*);
} > ITCM_REGION AT > FLASH
}
Because the binary is stored in Flash but needs to execute from RAM, your system’s startup code (the Reset handler) must be responsible for copying these sections from the Flash load address into the TCM execution address during the initialization phase. By partitioning your binary this way, you ensure that your most critical instruction sequences are never subject to the unpredictable stalls of the bus interconnect or flash controller.
Key Takeaway: Use the #[link_section] attribute combined with a custom linker script to map performance-critical code directly into Tightly Coupled Memory, ensuring deterministic, single-cycle instruction execution.