QSPI Memory Overflow and SRAM Boot Failures on ARM Musca Board

The ARM Musca board, a popular development platform for secure and non-secure world applications, often encounters issues related to memory allocation and boot sequence configuration. One common problem arises when the QSPI (Quad Serial Peripheral Interface) memory overflows due to increased code size, forcing developers to relocate code to SRAM (Static Random-Access Memory). However, booting from SRAM is not straightforward and requires careful configuration of the memory map, linker scripts, and bootloader behavior. This post delves into the root causes of QSPI memory overflow, the challenges of booting from SRAM, and provides detailed troubleshooting steps to resolve these issues.


QSPI Memory Overflow Due to Increased Secure World Code Size

The QSPI memory on the ARM Musca board is typically used to store firmware and application code. However, when developing secure world applications, the code size can grow significantly due to additional security features, cryptographic libraries, and secure boot mechanisms. This can lead to QSPI memory overflow, preventing the code from being flashed entirely. Developers often attempt to resolve this by relocating the code to SRAM, which has a different address space (e.g., 0x10000000). However, this approach introduces new challenges, as the Musca board is designed to boot from QSPI by default.

The primary issue here is the mismatch between the memory regions and the boot sequence. The Musca board’s bootloader expects the initial code to reside in QSPI memory, and without proper configuration, it cannot locate or execute code stored in SRAM. Additionally, the linker script and memory map must be adjusted to ensure that the code is correctly placed in SRAM and that the boot process is redirected accordingly.


Bootloader Configuration and Linker Script Misalignment

The inability to boot from SRAM is often caused by misconfigurations in the bootloader and linker script. The bootloader on the Musca board is hardcoded to fetch the initial instructions from QSPI memory. When code is relocated to SRAM, the bootloader cannot find the entry point, resulting in a failed boot sequence. Furthermore, the linker script must define the correct Load Memory Address (LMA) and Virtual Memory Address (VMA) for the code sections. The LMA specifies where the code is stored during flashing (e.g., QSPI), while the VMA defines where the code is executed (e.g., SRAM). If these addresses are not aligned, the code will not execute as intended.

Another potential cause is the omission of runtime code copying mechanisms. When code is stored in QSPI but executed in SRAM, a runtime copy operation is required to transfer the code from QSPI to SRAM before execution. This step is often overlooked, leading to boot failures. Additionally, the memory map must be carefully reviewed to ensure that the SRAM region is correctly defined and accessible during the boot process.


Configuring Linker Scripts and Implementing Runtime Code Copying

To resolve QSPI memory overflow and SRAM boot issues, developers must follow a systematic approach to configure the linker script, update the bootloader behavior, and implement runtime code copying. Below are the detailed steps to achieve this:

Step 1: Modify the Linker Script

The linker script must be updated to define the correct LMA and VMA for the code sections. For example, if the code is stored in QSPI (LMA) but executed in SRAM (VMA), the linker script should specify these addresses explicitly. Below is an example of how to configure the linker script:

MEMORY
{
  QSPI (rx) : ORIGIN = 0x08000000, LENGTH = 0x100000
  SRAM (rwx) : ORIGIN = 0x10000000, LENGTH = 0x20000
}

SECTIONS
{
  .text :
  {
    *(.text*)
  } > SRAM AT > QSPI

  .data :
  {
    *(.data*)
  } > SRAM AT > QSPI

  .bss :
  {
    *(.bss*)
  } > SRAM
}

In this example, the .text and .data sections are stored in QSPI but executed in SRAM. The AT > QSPI directive ensures that the code is placed in QSPI during flashing, while the > SRAM directive specifies the execution address.

Step 2: Implement Runtime Code Copying

To transfer the code from QSPI to SRAM at runtime, a code copying mechanism must be implemented. This is typically done in the startup file or the bootloader. Below is an example of how to perform this operation in C:

extern uint32_t _etext;  // End of text section in QSPI
extern uint32_t _sdata;  // Start of data section in SRAM
extern uint32_t _edata;  // End of data section in SRAM

void copy_code_to_sram(void) {
  uint32_t *src = &_etext;
  uint32_t *dst = &_sdata;

  while (dst < &_edata) {
    *dst++ = *src++;
  }
}

This function copies the code from QSPI to SRAM before the main application starts. It should be called early in the startup sequence, typically after initializing the stack pointer.

Step 3: Verify the Memory Map and Bootloader Behavior

Ensure that the memory map is correctly defined in the project settings and that the bootloader is aware of the SRAM region. If necessary, modify the bootloader to support booting from SRAM. This may involve updating the bootloader’s initialization code to configure the memory controller and set up the SRAM region.

Step 4: Debugging and Validation

Use a debugger to verify that the code is correctly placed in SRAM and that the boot sequence proceeds as expected. Check the following:

  • The code is correctly copied from QSPI to SRAM.
  • The stack pointer and program counter are correctly initialized.
  • The memory controller is configured to allow access to the SRAM region.

By following these steps, developers can resolve QSPI memory overflow issues and successfully boot from SRAM on the ARM Musca board. Proper configuration of the linker script, implementation of runtime code copying, and careful validation of the boot sequence are critical to achieving a reliable solution.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *