I have encountered a problem in a C program running on an AVR microcontroller (ATMega328P). I believe it is due to a stack/heap collision but I\'d like to be able to confirm
If you're using both stack and heap, then it can be a little more tricky. I'll explain what I've done when no heap is used. As a general rule, all the companies I've worked for (in the domain of embedded C software) have avoided using heap for small embedded projects—to avoid the uncertainty of heap memory availability. We use statically declared variables instead.
One method is to fill most of the stack area with a known pattern (e.g. 0x55) at start-up. This is usually done by a small bit of code early in the software execution, either right at the start of main(), or perhaps even before main() begins, in the start-up code. Take care not to overwrite the small amount of stack in use at that point of course. Then, after running the software for a while, inspect the contents of stack space and see where the 0x55 is still intact. How you "inspect" depends on your target hardware. Assuming you have a debugger connected, then you can simply stop the micro running and read the memory.
If you have a debugger that can do a memory-access breakpoint (a bit more fancy than the usual execution breakpoint), then you can set a breakpoint in a particular stack location—such as the farthest limit of your stack space. That can be extremely useful, because it also shows you exactly what bit of code is running when it reaches that extent of stack usage. But it requires your debugger to support the memory-access breakpoint feature and it's often not found in the "low-end" debuggers.
If you're also using heap, then it can be a bit more complicated because it may be impossible to predict where stack and heap will collide.
Don't use the heap / dynamic allocation on embedded targets. Especially with a processor with such limited resources. Rather redesign your application because the problem will reoccur as your program grows.
Assuming you're using just one stack (so not an RTOS or anything) and that the stack is at the end of the memory, growing down, while the heap is starting after the BSS/DATA region, growing up. I've seen implementations of malloc that actually check the stackpointer and fail on a collision. You could try to do that.
If you're not able to adapt the malloc code, you could choose to put your stack at the start of the memory (using the linker file). In general it's always a good idea to know/define the maximum size of the stack. If you put it at the start, you'll get an error on reading beyond the beginning of the RAM. The Heap will be at the end and can probably not grow beyond the end if it's a decent implemantation (will return NULL instead). Good thing is you know have 2 separate error cases for 2 separate issues.
To find out the maximum stack size, you could fill your memory with a pattern, run the application and see how far it went, see also reply from Craig.
On Unix like operating systems a library function named sbrk() with a parameter of 0 allows you to access the topmost address of dynamically allocated heap memory. The return value is a void * pointer and could be compared with the address of an arbitrary stack allocated variable.
Using the result of this comparison should be used with care. Depending on the CPU and system architecture, the stack may be growing down from a arbitrary high address while the allocated heap will move up from low-bound memory.
Sometimes the operating system has other concepts for memory management (i.e. OS/9) which places heap and stack in different memory segments in free memory. On these operating systems - especially for embedded systems - you need to define the maximum memory requirements of your applications in advance to enable the system to allocate memory segments of matching sizes.
You can check RAM static usage using avr-size
utility, as decribed in
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=62968,
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=82536,
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=95638,
and http://letsmakerobots.com/node/27115
avr-size -C -x Filename.elf
(avr-size documentation: http://ccrma.stanford.edu/planetccrma/man/man1/avr-size.1.html )
Follows an example of how to set this on an IDE: On Code::Blocks, Project -> Build options -> Pre/post build steps -> Post-build steps, include:
avr-size -C $(TARGET_OUTPUT_FILE)
or
avr-size -C --mcu=atmega328p $(TARGET_OUTPUT_FILE)
Example output at the end of build:
AVR Memory Usage
----------------
Device: atmega16
Program: 7376 bytes (45.0% Full)
(.text + .data + .bootloader)
Data: 81 bytes (7.9% Full)
(.data + .bss + .noinit)
EEPROM: 63 bytes (12.3% Full)
(.eeprom)
Data is your SRAM usage, and it is only the amount that the compiler knows at compile time. You also need room for things created at runtime (particularly stack usage).
To check stack usage (dynamic RAM), from http://jeelabs.org/2011/05/22/atmega-memory-use/
Here’s a small utility function which determines how much RAM is currently unused:
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
And here’s a sketch using that code:
void setup () {
Serial.begin(57600);
Serial.println("\n[memCheck]");
Serial.println(freeRam());
}
The freeRam() function returns how many bytes exists between the end of the heap and the last allocated memory on the stack, so it is effectively how much the stack/heap can grow before they collide.
You could check the return of this function around code you suspect may be causing stack/heap collision.
If you can edit the code for your heap, you could pad it with a couple of extra bytes (tricky on such low resources) on each block of memory. These bytes could contain a known pattern different from the stack. This might give you a clue if it collides with the stack by seeing it appear inside the stack or vice versa.