Compile your project code so it prints out the heap pointer and the stack pointer. Print out a global variable address. If you can find it, modify your linker file to swap your uninitialized variables and initialized variables. Verify it is as expected in the memory map. See how that changes your code output.
Turn in your notes on what you found to Discord #assignment-submission by 9am on Jan 29th.
Note: there will be more detailed hints on how to do this as the week goes on. If you get stuck, look in the Discord #homework-help for a Hints thread.
Here's the stack, heap, and global variable addresses printed out the UART:
Given two global variables, one initialized with a value of 42
and the other not initialized:
static int myNotInitializedVariable;
static int myInitializedVariable = 42;
The global addresses for each of the above variable are shown here, the messages sent out of the UART and received by putty
:
Those addresses are confirmed by VisualGDB Global Live Watch:
Upon swapping uninitialized variables and initialized variables the new addresses were observed:
However the Global Live Watch result was unexpected:
Contrary to the Global Watch, the manual watch showed a value and address consistent with the putty
output values:
0x20004440 <myInitializedVariable> {0x0000002a}
:
So which is correct? An additional programmatic assignment confirmed the value is indeed 42
:
volatile int checkValue = myInitializedVariable;
Variables in functions are stored on the stack. Thank you stackoverflow for the reminder on how to determine the address of a variable on the stack, which of course is the most recent stack pointer:
void* p = NULL;
volatile long myStackPointer = (long)((void*)&p);
The address of the next variable on the stack would be the current stack pointer plus the size of the latest object (or pointer) that was pushed onto the stack.
VisualGDB has the capability of showing live FreeRTOS environment details. Here the newly-allocated address of p
has a value of 0x200013F0
:
The live watch also helps us with the address of the stack pointer in this FreeRTOS thread: 0x20001418
. A means of determining this value directly from the inside of [Raw TCB]
(shown above) has not yet been determined.
We can also observe that FreeRTOS apparently has (72-8 = 64) bytes of overhead on the stack, probably for the pre-emptive scheduler.
Also shown is the stack starting in this thread at pxTopOfStack = 0x200013c8
.
The next value of the stack pointer was 0x200013c8
after allocation
of int *q
. (0x200013F0 - 0x200013e8 = 8
) byte change: the size of the volatile long myStackPointer2
.
void* p = NULL;
volatile long myStackPointer = (long)((void*)&p);
void* q = NULL;
volatile long myStackPointer2 = (long)((void*)&q);
int* r = (int*)0xAD;
volatile long myStackPointer3 = (long)((void*)&r);
Unlike the stack, subsequent heap addresses may not be easily predictable, particularly when the heap becomes fragmented.
The heap size and pointers are a bit more interesting, particularly since the Final Project is using and RTOS. The FreeRTOS Memory Management documentation was helpful here. In particular the heap_4.c xPortGetFreeHeapSize() found in the Github.com/STMicroelectronics/STM32CubeL4 library. This code was also found to have been installed via STH32Cube here:
C:\Users\gojimmypi\STM32Cube\Repository\STM32Cube_FW_L4_V1.17.1\Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang
Similar to the Stack Pointers, the heap pointer is determined by allocating heap space via the RTOS pvPortMalloc
, see
myHeapPointer:
myHeapPointer = (long)pvPortMalloc(1); // a non-zero param returns heap pointer
The VisualGDB FreeRTOS Live Watch verified the most recent allocation at address 0x20001ea0
as shown in the putty UART output result, above.
The linker file, STM32L475VG_flash.lds
needed to be manually copied to the project directory, as by default it is located in:
C:\Users\gojimmypi\AppData\Local\VisualGDB\EmbeddedBSPs\arm-eabi\com.sysprogs.arm.stm32\STM32L4xxxx\LinkerScripts
Pressing the Copy to project directory
did exactly that, changing the full path to just a file name located in the root of the project directory:
Delete the filename and leave it blank to have the default changed to the original path. The local project file is not automatically deleted.
The first line of the linker script for VisualGDB indicates that it is generated by this C# app.
No local LinkerScriptGenerator*.*
files were found.
The linker file is configured to save the heap in SRAM, as is the stack.
The .bss section contains statically allocated variables that are declared but have not been assigned a value yet. The default saves this data in SRAM.
TODO: where is uninitialized data defined in the linker file?
The default setting was to not generare a linker map file.
Only a one instance of .isr_vector
was found in the solution:
Specifically, in this directory:
C:\Users\gojimmypi\AppData\Local\VisualGDB\EmbeddedBSPs\arm-eabi\com.sysprogs.arm.stm32\STM32L4xxxx\StartupFiles
But when seaching all files there were three instances
Specifically, .isr_vector
was found in this directory at line 5,519:
C:\workspace\IoT_BBQ\IoT_BBQ_STM32\VisualGDB\Debug
The IoT_BBQ_STM32.map file is over 7,000 lines long. Additionally, when building the project, any manual changes are over-written by a fresh generation of the file.
- VisualGDB Customizing Memory Layout of Embedded Programs with GNU Linker Scripts
- FreeRTOS Memory allocation implementations included in the RTOS source code download
- Stackoverflow Print out value of stack pointer
- ST Community How to check stack and heap usage during run time.
- ST Description of STM32L4/L4+ HAL and low-layer drivers - UM1884
<< Exercise 7 -- Assignments -- Exercise 9 >>