cancel
Showing results for 
Search instead for 
Did you mean: 

Global variable overlaps with stack.

BigBrick
Associate II

Hi.

I am absolute noob with stm32 and i am currently trying to connect GY-GPS6MV2 module to RobotDyn STM32 Mini(STM32F103C8T6).  I have connected GPS module to pins and set up USART1 in asyncronous mode. I have done everethyng according to official example on how to work with USART1 using DMA. In the interrupt handler i wrote small piece of code to copy data from rx buffer to linked list. But from here things have gone really weird, because in the debugger i see, that my global variable(nmea_head, this is first node in linked list) is allocated in the same memory area where irq handler stack resides(See attached screenshots). What am i doing wrong?
STM32_SP.jpeg

Here you can see, that SP for HAL_UART_RxCpltCallback is at 0x20000104

STM32_Declaration.jpeg

This is definition of global variable nmea_head. On the right side you can see, that it was placed on the address 0x20000110. This address overlaps with stack frame of HAL_UART_RxCpltCallback, so my variable gets corrupted. What am i doing wrong?

This  happens prior to any calls to malloc or free, and i am not accessing this variable from anywhere else, so there should not be any race conditions.

1 ACCEPTED SOLUTION

Accepted Solutions

Looks like the MCU is booting from system memory. The next address (initial PC) is in the System Memory Area (0x1FFFF000-...) with the internal boot loader. Maybe such a little stack space is okay for that boot loader.

The board should have a BOOT0 pin/jumper that must be set to low for booting your code from user flash area (0x08000000-...)

Whats written in the project linker script file (.ld)?

 

View solution in original post

14 REPLIES 14
TDK
Guru

You can increase the size allocated to your stack, but if things are overlapping, you've probably run out of space. You should also use the "Static Stack Analyzer" tab to see any functions which have unnecessarily large stack requirements and address those.

The linker file should show the size of the RAM area where your variables get placed. _estack is where the stack starts (at end of the RAM section generally).

If you feel a post has answered your question, please click "Accept as Solution".

I have tried doubling and quadrupling _min_stack_size,  but my global variable still overlaps with stack. What does 'Hide dead code' checkbox mean in static stack analyzer? What is 'dead code' and how does it affect stack?

KnarfB
Principal III

Do you have larger local variables occupying the stack? If you click through the call stack (left), you can check this and by looking at the value of sp in various depths of the call/exception hierarchy. Expected behaviour:  the initial (downmost) sp is close to the top of the SRAM and decreases only mildly from stage to stage.   

The t_nmea_string_list struct looks suboptimal because, as you said, you have to copy strings and keep the next pointers which can be error-prone. Double check your code here or instrument it with print-logging or assertions.

Even if evrerything is done correctly, you will have many calls to malloc/free which may fragment the heap over time when the strings have variable lengths. 

hth

KnarfB

My project is practically empty, this is code just for testing USART read/write from GPS module, the only code i have is to copy data from rx_buff to linked list, and this situation happens on the first call to this function. I also tried changing Minimum Stack Size in project settings. I checked resulting binary with readelf -lS, and for some reason all section and segment(program) headers are indentical for binaries with 0x800 Mininimum Stack Size and 0xF00 Minimum Stack Size.

The minimum stack size is only used in the .ld file as a placeholder. If th .elf could be linked, this guarantees that you have at least minimum stack size available initially at runtime.

But, what is the sp if you trickle down the call hierarchy?

When using optimization other than -O0, it might take some assembler instructions until you see the correct sp displayed.

I set up breakpoint at the start of startup_stm32f103c8tx.s and the value of SP is 0x200001fc. Shouldn't it be equal to 0x20005000 as defined in .symtab 20005000 0 NOTYPE GLOBAL DEFAULT 1 _estack? Is anything called prior to startup_stm32f103c8tx.s? This value gives me maximum of 508 bytes of stack till beginning of RAM, not counting stuff that was loaded at the beginning of RAM, like my global variables.

This definitely looks wrong. The hardware fetches the initial SP and PC from the flash and then starts executing the code Reset_Handler. The Reset_Handler often sets SP again. Even at the entry of main(), it should be close to the top of SRAM. 

nice readings: Tag: zero-to-main | Interrupt (memfault.com)

Try a newly created project. If the error persists, you have an issue with your toolchain.  

hth

KnarfB

Is there any way to look at bootloader code that CubeIDE loads into my STM?

If you connect via SWD debug interface, there is no bootloader involved. Your code should have start

address 0x08000000. "Independent" check with STM32CubeProgrammer tool.

If you download via UART... DFU, the boot-loader is read-only in a separate flash/ROM area ("system memory") but should also not affect your image.

Don't know RobotDyn, but some cheap 3rd party boards contain fake/clone MCUs... I prefer the Nucleo boards. 

hth

KnarfB