The STM32F1 microcontroller based on the Cortex-M3 core contains several boot modes that allow booting from different memory locations. One of these modes is booting from System RAM (SRAM) which can be useful for quickly testing code without needing to flash memory. To enter SRAM boot mode, specific “magic” values need to be written to the first words of SRAM before resetting the chip.
About STM32F1 Boot Modes
The STM32F1 microcontroller supports several boot modes selectable through the BOOT pins and “magic numbers” written to the first words of memory:
- System Memory (Flash) – Boot from flash memory. This is the default boot mode.
- System RAM – Boot code loaded in SRAM.
- Embedded SRAM – Small internal SRAM used as boot space.
- Serial Bootloader – UART bootloader for programming flash.
- CAN Bootloader – CAN bus bootloader.
To select one of these boot modes, the option bytes need to be configured to map the boot pins to the desired mode. Then specific “magic numbers” need to be written to the first word or words of the memory region being booted from. This article focuses on booting from System RAM and the magic values needed.
STM32F1 System RAM
The STM32F1 contains internal SRAM which can be used to hold data and code. The amount of SRAM varies by model but is typically around 20KB. When booting in System RAM mode, code is loaded into SRAM and executed from there rather than flash memory. This allows quickly testing code changes without reflashing the chip.
To use SRAM boot mode, code must first be loaded into the SRAM memory space. This is typically done through JTAG or a bootloader running from flash. Once the code is loaded, the magic values need to be written to the first words of SRAM before reset.
SRAM Boot Magic Values
To enter SRAM boot mode, the following magic values need to be written to the first 8 words of SRAM: 0x42464346: Stack Pointer value 0xCCCCCCCD: Reset Handler value 0x00000001: NMI Handler value 0x00000002: HardFault Handler value 0x00000003: MemManage Handler value 0x00000004: BusFault Handler value 0x00000005: UsageFault Handler value 0xFFFFFFF9: End of magic values
The Stack Pointer value sets up the main stack pointer for the application. The Reset Handler value is the address of the reset handler function which will execute first on boot. The other values are dummy handler addresses which are needed but typically not used.
The last value 0xFFFFFFF9 indicates the end of the magic values. Any remaining words in the first 8 are unused and can be anything.
So in summary, to boot from SRAM:
- Load code into SRAM memory space
- Write the magic values shown above to the first 8 words of SRAM
- Assert reset to boot into SRAM
Writing Magic Values
The magic values need to be written to the correct SRAM addresses before booting. There are several ways this can be accomplished:
- Using a JTAG debugger
- From a bootloader running in flash memory
- Direct memory access (DMA)
- Inline GPIO assembly instructions
A JTAG debugger provides the easiest way to write the values over a debug probe. But a bootloader or other program running on the STM32 can also write the values using direct SRAM writes or DMA transfers.
Bootloader Example
Here is example code for a flash bootloader that writes the magic values to SRAM: // SRAM start address #define SRAM_BASE 0x20000000 // Magic value array uint32_t sram_magic[] = { 0x42464346, // Stack pointer 0xCCCCCCCD, // Reset handler 0x00000001, // NMI handler 0x00000002, // HardFault handler 0x00000003, // MemManage handler 0x00000004, // BusFault handler 0x00000005, // UsageFault handler 0xFFFFFFF9 // End marker }; void boot_sram(uint32_t* code_addr) { // Copy application code to SRAM memcpy((void*)SRAM_BASE, (void*)code_addr, 8192); // Write magic values to start of SRAM for(int i = 0; i < 8; i++) { *(volatile uint32_t*)(SRAM_BASE + (i*4)) = sram_magic[i]; } // Reset the processor to boot from SRAM NVIC_SystemReset(); }
This simple bootloader copies the application code into SRAM, writes the magic values, and then resets the core to boot from SRAM.
SRAM Boot Limitations
While booting from SRAM can be useful for testing, there are some limitations to consider:
- Limited SRAM size – Typically only 20KB or less.
- Data is volatile – SRAM contents are lost on reset.
- Slow execution – Flash memory is faster than SRAM access.
- No code read protection – Code can be viewed and modified.
For these reasons, SRAM booting is best for simple applications and testing code changes quickly. For production firmware, booting from flash memory is recommended.
Cortex-M3 Lockup during SRAM Boot
One issue that you may encounter when booting from SRAM is the Cortex-M3 core locking up during the boot process. This can happen if the clock configuration is not set up properly for the SRAM access speed.
By default, the Cortex-M3 microcontroller expects to be running code from flash memory which has a single wait state. However SRAM may require no wait states or multiple wait states depending on the clock speed.
If the number of wait states is incorrectly configured for the SRAM access speed, the core may fail to boot properly and lock up. This typically occurs right at the start of the reset handler or during the early initialization routines.
Fixing SRAM Boot Lockups
To prevent lockups during SRAM booting, the wait states need to be configured correctly for the SRAM access speed:
- In the flash bootloader, configure the flash access control register for the proper number of SRAM wait states before loading SRAM and jumping to it.
- In the SRAM code, configure wait states early in the reset handler or system initialization code before accessing SRAM.
Consult the microcontroller reference manual for details on the flash access control register (FLASH_ACR) and the number of wait states required for different clock speeds.
As an example, this code snippet shows how to configure 0 wait states for a 72 MHz system clock during SRAM boot: // System clock is 72 MHz –> 0 WS for SRAM FLASH_ACR |= FLASH_ACR_LATENCY_0WS;
With the wait states properly configured, the Cortex-M3 core should boot correctly from SRAM without any lockup issues.
Conclusion
Booting from SRAM can be a useful technique for rapidly testing code on STM32F1 microcontrollers. Specific magic values must be written to the first words of SRAM memory to enable this boot mode. However, limitations like small SRAM size and slower execution speed make this best for simple projects and debugging code changes. With the magic values and proper wait state configuration, developers can take advantage of SRAM booting to quickly iterate on their Cortex-M3 firmware.