Course contentsShow
← Embedded Systems & Computer Architecture
Lesson 455 of 9366. Embedded Software Construction and ToolchainsFree lesson

Copying Initialized Data from Flash to RAM

Write a routine that moves constant data from non-volatile storage into read-write memory to satisfy the C standard's requirements for global variables.

Copying Initialized Data from Flash to RAM

In this lesson, you will learn how to manually bridge the gap between non-volatile storage and writable memory to ensure global variables hold their correct values at startup.

The Problem of Initialized Data

When you declare a global variable like int threshold = 50; in C, the compiler places this initial value into the binary’s data section. Since the CPU cannot modify code stored in Flash, and the C standard requires global variables to be modifiable (Read-Write), we must store the initial value in Flash and copy it into RAM before the main() function begins execution.

Using Linker Symbols

To perform this copy, we rely on symbols defined in our linker script. We typically define three key symbols:

  1. _sidata: The address in Flash where the initial values are stored (Load Address).
  2. _sdata: The starting address in RAM where these values belong (Virtual Address).
  3. _edata: The end address in RAM, which helps us determine the size of the block to copy.

Implementing the Routine

Before your C environment is fully initialized, you must execute a startup routine (often called Reset_Handler) that performs this copy. The routine essentially performs a memcpy from the Flash address to the RAM address:

extern uint32_t _sidata, _sdata, _edata;

void copy_data_section(void) {
    uint32_t *src = &_sidata;
    uint32_t *dest = &_sdata;

    // Copy until we reach the end of the data section
    while (dest < &_edata) {
        *dest++ = *src++;
    }
}

By iterating through these addresses, we effectively "populate" the RAM with the values defined at compile time. If you neglect this step, your global variables will contain garbage data—or whatever was left in those RAM addresses from a previous power cycle—causing unpredictable behavior in your application.

This routine is the critical bridge that transforms a static binary image into a functioning, state-aware program.

Key Takeaway: Because global variables must be writable, the startup code must copy their initial values from the static Flash load address to the active RAM virtual address defined in your linker script.