Wu Jianying Microcontroller Development Board Address
Store:【Wu Jianying’s Shop】
Address:【https://item.taobao.com/item.htm?_u=ukgdp5a7629&id=524088004171】
The compiler uses two stacks: one is the hardware stack for subroutine calls and interrupt operations, and the other is the software stack for temporary variables and local variables passed in a stack structure. The hardware stack is allocated starting from the top of the data memory, with a certain number of bytes allocated below it for the software stack. Both the hardware stack and the software stack grow downwards (note: this is opposite to the 51 microcontroller).
Typically, if your program does not call subroutines and does not use library functions like printf() with the %f format, the default 16 bytes should work well in most cases. In the vast majority of programs, except for very heavy recursive calls or reentrant functions, a maximum of 40 bytes of hardware stack should be sufficient.
If the call depth of functions is too deep, there may be a hardware stack overflow into the software stack, altering the data in the software stack. Similarly, defining too many local variables or having too many local collection variables may cause the software stack to overflow into the dynamically allocated data area. Both stacks can overflow, and if a stack overflow occurs, it can lead to unpredictable errors. A stack checking function can be used to detect whether either stack has overflowed.
On the Target page, there is a Return Stack Size option to specify the size of the hardware stack (which saves function return values). Typically, if subroutine calls are not nested deeply (no more than 4 layers), using the default 16 bytes is sufficient. If floating-point functions are used, it should be set to at least 30 bytes. Generally, except for very deep recursive calls and when using the %f format specifier, setting it to 40 bytes is adequate.
The hardware stack is allocated starting from the top of the data memory, while the software stack is allocated a certain number of bytes below it. The size of the hardware stack and data memory is limited by the target device settings in the compiler options. The data area starts allocation from 0x60. It is correct to have the data area grow towards the IO space. The data area and software stack are allowed to grow towards each other.
If the target device you choose has 32K or 64K of external SRAM, then the stack is placed at the top of the internal SRAM and grows towards lower memory addresses. A significant reason for any program failure is stack overflow into other data memory ranges; either stack can overflow, and when one stack overflows, it can lead to bad things happening. You can use the stack checking function to detect overflow conditions.
About the Stack Checking Function:
The startup code writes a code (0xaa) into the lowest byte of the hardware and software stacks, referred to as a guard line. If either the hardware or software stack overflows, the guard byte’s code (0xaa) will be altered. The stack checking function determines whether the two stacks have overflowed by checking if the lowest byte’s code has changed. By calling _StackCheck(void), if the guard line byte retains its correct value, the check passes, indicating no overflow. If a stack overflow occurs, the guard line byte may be corrupted, and the _StackCheck(void) function detects that the guard line byte’s code has changed, indicating the corresponding stack overflow (when the program stack overflows, the program may run incorrectly or crash). This function then calls _StackOverflowed(char c); if the parameter is 1, the hardware stack has overflowed; if the parameter is 0, the software stack has overflowed.
When using the stack checking function, note the following points:
1. Before using the stack checking function, include #include “macros.h” for preprocessing.
2. If using your own startup file, in ICCAVR6.20 and later versions, if the startup file does not contain guard line content, ICCAVR will automatically add the guard line. In versions prior to ICCAVR6.20, you must add this part yourself; otherwise, the generated code will not include stack allocation without a guard line.
3. If using dynamic memory allocation, you must skip the guard line byte _bss_end to allocate your heap (i.e., add one byte). See the memory allocation function description for details.
4. When the _StackCheck(void) function detects that the guard line byte has changed, it will call a default _StackOverflowed function to jump to the program memory location 0 (reset vector address). You can specify or rewrite a new function to replace it, for example, using a new function to indicate which stack overflowed, but this function cannot perform too many functions or restore the program to a normal state. Because after a stack overflow, some useful data will be altered, causing unpredictable errors or even crashing the program.
Below is a simple example to illustrate the function of the stack checking function:
main( )
{
init( ) // Call initialization program
float a,b;
a=1.0;
b=1.0;
printf(“a = %fn”, a);
printf(“b = %fn”, b);
_StackCheck( ); // Call stack checking function
}
_StackOverflowed(char c)
{
if (c == 1)
puts(“trashed HW stack”); // Hardware stack overflow
else
puts(“trashed SW stack”); // Software stack overflow
}
If you like this article, welcome to like it!


Technology Comes from Accumulation, Success Comes from Perseverance ——Microcontroller Expert Wu Jianying |