Skip to main content
Associate
July 31, 2024
Solved

Global variable overlaps with stack.

  • July 31, 2024
  • 4 replies
  • 4194 views

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.

Best answer by KnarfB

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)?

 

4 replies

TDK
Super User
July 31, 2024

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""."
BigBrickAuthor
Associate
August 1, 2024

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
Super User
August 1, 2024

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

BigBrickAuthor
Associate
August 1, 2024

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.

KnarfB
Super User
August 1, 2024

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.

BigBrickAuthor
Associate
August 1, 2024

I ckecked memory during after reset:

STM32_Boot.jpeg

This is why i have invalid SP/MSP. But where does this value come from?

 

KnarfB
KnarfBBest answer
Super User
August 1, 2024

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)?

 

BigBrickAuthor
Associate
August 2, 2024

Thank you, setting BOOT0 jumper to low fixed it.

Andrei Chichak
Lead
August 1, 2024

There's a few more conflicting things, being a self-professed noob and using malloc and free and linked lists on a processor with 20K of RAM.

Start at the start, get an LED to blink, then work up to getting anything going with the UART in polled mode, then move on. You have to get your mind around new tools, concepts, and flying without a net. If you're worrying about what is getting loaded into the SP at startup, you're doing it wrong.

The NMEA strings are not of a known length, so doing DMA or interrupts that fire on a particular length are going to mess you up since you don't know what the length is.

But for a self-professed noob to be diving directly into the deep end, with all of the bells and whistles in use, is just asking for a disappointing time.