In this lesson, you will learn how to direct specific variables or functions into dedicated hardware memory regions, such as Tightly Coupled Memory (TCM) or peripheral buffers, using linker scripts and C attributes.
Why Use Custom Sections?
By default, your compiler places code and data into standard SRAM or Flash. However, high-performance peripherals often have their own specialized memory. For example, a DMA controller might need to access a buffer located in a specific "SRAM Bank 1" to achieve zero-wait-state performance, or you may want to place critical interrupt handlers in TCM to ensure they execute with deterministic timing, independent of the main system bus traffic.
The Two-Step Process
To place a variable or function into a custom memory location, you must bridge the gap between your C code and the linker script.
- Tag the Code/Data: Use the
__attribute__((section(".name")))keyword in your C file. This tells the compiler, "Don't put this in the standard.dataor.textsections; put it in a custom section named.name."
// Place a specific buffer in a custom section
uint32_t dma_buffer[256] __attribute__((section(".dma_buffer_section")));
- Map the Section in the Linker Script: You must then update your linker script to define where that custom section physically lives in your hardware's address space. Within the
SECTIONScommand, you instruct the linker to map your custom tag to a specific memory region defined by yourMEMORYcommand:
SECTIONS {
.dma_buffer_section : {
. = ALIGN(4);
*(.dma_buffer_section)
. = ALIGN(4);
} > DMA_RAM_REGION /* DMA_RAM_REGION must be defined in your MEMORY block */
}
Ensuring Hardware Alignment
When working with peripherals, precision is everything. If a peripheral requires data to be aligned to a 16-byte boundary, ensure your linker script section explicitly uses ALIGN(16) as shown above. Failure to align your custom sections can lead to hardware bus errors or corrupted data during DMA transfers. By creating these custom "pockets" of memory, you guarantee that your critical data is exactly where the hardware expects it to be, maximizing both speed and reliability.
Key Takeaway: Use the __attribute__((section(".name"))) tag in your C code and define a corresponding mapping in your linker script to ensure your data and code are physically located in the memory regions optimized for your specific peripherals.