Edit: Problem was solved. It turned out that i was allocating 128KB RAM but the RAM of the board is not contiguous.
I'm hoping someone with more Cortex-M startup experience can point me in the right direction because I've run out of ideas.
I'm writing a fully bare-metal firmware for an STM32L476RG (no HAL, no CubeMX) using:
- arm-none-eabi-gcc 15.2.1
- CMake
- OpenOCD + GDB
The MCU boots, enters my Reset_Handler, and then immediately HardFaults before I ever reach main().
Background
A few weeks ago I completed a bare-metal bootloader for the same STM32L476RG board using almost the same startup code and linker script. That project worked correctly.
For this new robot project, the startup code is almost identical. The main changes are:
- Using the full 1024 KB FLASH and 128 KB RAM instead of the reduced FLASH and RAM layout I used previously.
- Explicitly reserving 4 KB heap and 4 KB stack in the linker script.
- Different application code (which I don't think matters because I never reach
main()).
So this isn't my first startup implementation, which is why this has me so confused.
What happens
The processor reaches Reset_Handler correctly.
The first few instructions are:
push {r7, lr}
sub sp, #24
add r7, sp, #0
When stepping through with GDB:
push {r7, lr} executes.
- Immediately afterwards execution ends up in
HardFault_Handler.
I never reach the first ldr instruction.
I never reach the .data copy loop.
I never reach the .bss zeroing loop.
I never reach main().
Things I've already verified
I've spent quite a while checking the obvious things before posting.
Vector table
- Reset vector is correct.
- MSP is
0x20020000, which matches the top of 128 KB RAM.
- The vector table contents are correct.
- Flash alias at
0x00000000 matches the table at 0x08000000.
Linker
- FLASH origin and length are correct.
- RAM origin and length are correct.
_sdata, _edata, _sidata, _sbss and _ebss all have sensible values.
- The literal pool in
Reset_Handler contains exactly those addresses.
Startup code
Reset_Handler is definitely entered.
- Flash contents match the generated ELF.
- The disassembly matches the actual bytes in flash.
- The startup code is just the normal
.data copy, .bss clear and main() call.
Fault registers
At the HardFault:
HFSR = 0x40000000
CFSR = 0x1400
VTOR is 0x00000000 (Flash is aliased correctly).Fault registersAt the HardFault:HFSR = 0x40000000
CFSR = 0x1400VTOR is 0x00000000 (Flash is aliased correctly).
At this point I'm trying to understand what could cause a HardFault before even reaching the first ldr in Reset_Handler.
Am I overlooking something obvious in my startup code or linker script, or is there another direction I should be investigating?
I've uploaded the startup.c, linker.ld and CMakeLists.txt on the Github Gists link below:
https://gist.github.com/Lobstone7/b0e2303622e5b6d69f3eb64fd544118b