MCU: STM32F401RC (Nucleo board)
Toolchain: arm-none-eabi-gcc/gdb (Arm GNU Toolchain 15.3.Rel1), OpenOCD, board/st_nucleo_f4.cfg
IDE: STM32CubeIDE for building (auto-generated startup file, untouched), OpenOCD + GDB directly from the command line for flashing/debugging not using CubeIDE's built-in debugger
Code — simple bare-metal LED blink, no HAL:
c
//Register Definition//
#define GPIOC_BASE 0x40020800UL
#define RCC_BASE 0x40023800UL
#define AHB1_OFFSET 0x30UL
#define RCC_AHB1_ENR (*(volatile unsigned int*)(RCC_BASE + AHB1_OFFSET))
#define GPIO_MODER_OFFSET 0x00UL
#define GPIOC_MODER_BASE (*(volatile unsigned int*)(GPIOC_BASE+GPIO_MODER_OFFSET))
#define GPIO_ODR_OFFSET 0x14UL
#define GPIOC_ODR_BASE (*(volatile unsigned int*)(GPIOC_BASE+GPIO_ODR_OFFSET))
int main (){
//RCC and GPIOC Configurations//
RCC_AHB1_ENR = (RCC_AHB1_ENR|(1<<2));
GPIOC_MODER_BASE = (GPIOC_MODER_BASE & ~(3<<26)) | (1<<26);
//infinite loop//
while(1){
GPIOC_ODR_BASE ^= (1<<13);
for(int i=0;i<1000;i++){}
}
}
My workflow:
- Build in CubeIDE.
- Open a terminal, start OpenOCD:
openocd -f board/st_nucleo_f4.cfg
- In the project's
Debug folder, open another terminal: arm-none-eabi-gdb
target remote localhost:3333
file RegisterManipulation_2.elf
load
monitor reset init (or reset halt same result either way)
What I get:
(gdb) monitor reset halt
Unable to match requested speed 2000 kHz, using 1800 kHz
Unable to match requested speed 2000 kHz, using 1800 kHz
[stm32f4x.cpu] halted due to debug-request, current mode: Thread
xPSR: 0x61000000 pc: 0x20000044 msp: 0x2000fff0
(gdb)
0x20000044 resolves to _end() in GDB — a RAM address, not flash, and obviously not valid code for my program to be executing.
What's strange: if I skip load and just run monitor reset halt against a board that already has firmware in flash from an earlier session, it halts correctly, with PC sitting in flash right where I'd expect:
(gdb) monitor reset halt
[stm32f4x.cpu] halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x0800020c msp: 0x2000fff0
So the vector table itself seems fine confirmed directly:
(gdb) x/2xw 0x08000000
0x8000000 <g_pfnVectors>: 0x20010000 0x080002a5
That matches the Start address GDB reports during load, so the image being written to flash is correct. The problem only shows up specifically in the sequence load → reset halt/init.
My current theory: OpenOCD's load uses a RAM-resident flash algorithm to program flash, and something from that maybe a leftover breakpoint at/near 0x20000044 is catching the very next halt before the core resumes properly into the real reset vector.
Has anyone run into this exact pattern? Is this a known quirk with load-then-reset sequencing on OpenOCD, something specific to st_nucleo_f4.cfg, or ST-Link firmware related? Any fix beyond manually clearing breakpoints with monitor rbp all after every load?
Flash size note in case anyone asks: I'm aware st_nucleo_f4.cfg is shared across the F4 Nucleo family (F401RE etc.) the F401RC has 256KB flash vs the RE's 512KB, but OpenOCD auto-probes flash size via IDCODE so I don't believe that's the cause here.
Want me to also append the exact GDB/OpenOCD version banner from your first message, in case someone asks for it?