2024-07-31 12:32 PM - edited 2024-07-31 02:51 PM
If this question is silly or obvious, I apologize, but I'd like some guidance on understanding this.
I am playing around with C++ and freeRTOS on a STM32L476RGT6, below is a code snippet that creates an object main function of my program. This object contains a task function which blinks and an LED via calling a set(bool on) member method.
int main_cpp() {
Led led_1(GPIO_PORT, GPIO_NUM); //case 1 (broken): allocating object application stack/main stack of program (RAM)
//static Led led_2(GPIO_PORT, GPIO_NUM); //case 2 (works): allocating in .bss segment (Flash)
//Led *led_3 = new Led(GPIO_PORT, GPIO_NUM) //case 3 (works): allocating on heap (RAM)
vTaskStartScheduler();
return 0;
}
//inside Led.cpp:
#include "Led.h"
Led::Led(GPIO_TypeDef *gpio_port, uint16_t gpio_num):
gpio_port(gpio_port), gpio_num(gpio_num){
xTaskCreate(blink_task_trampoline, "Blink Task", 255, this, 1, &task_blink_hdl);
}
void Led::set(bool on)
{
HAL_GPIO_WritePin(gpio_port, (1U << 8), on ? GPIO_PIN_RESET : GPIO_PIN_SET); //set pin according to led_state
}
void Led::blink_task_trampoline(void *pvParameters)
{
//recast void pointer to led object pointer
Led *this_led = (Led *)pvParameters;
//launch the blink task
this_led->blink_task();
}
void Led::blink_task()
{
static bool led_state = true; //whether the led is on or off
set(true); //initially set LED high
while (1) {
//delay for 200ms, portTICK_PERIOD_MS is the duration of 1 tick period in ms
vTaskDelay(200 / portTICK_PERIOD_MS);
//toggle led
set(led_state);
led_state = !led_state;
}
}
In the main function, initializing via case 2 or case 3 works correctly, case 1 has an issue in which member variables gpio_num and gpio_port are overwritten with different values once the set method is called.
My hunch is that when vTaskScheduler() is called, freeRTOS uses the portion of the application stack that the Led object lives on, overwriting some of its members. Therefore, case 2 and 3 work correctly as declaring as static places it in .bss segment of flash, and using new places it on the heap.
Here are my questions:
1. Is my assumption most likely correct? How can I go about proving it and what are the best methods for debugging issues like this?
2. For those of you who've worked on professional embedded code bases, what is generally best practice for declaring large objects or critical objects containing tasks?
Outside of edge cases, is it usually best to place them in flash for safety reasons?
Thanks for your time and patience,
Solved! Go to Solution.
2024-07-31 03:23 PM
> Is my assumption most likely correct?
Yes. When vTaskStartScheduler is called, the "main stack" is reset and reused, so it isn't a good idea to leave objects on this stack.
> How can I go about proving it
It's up to you )) A hint: try to read some documentation. Reading the actual sources of FreeRTOS can help too.
> what is generally best practice for declaring large objects or critical objects containing tasks?
Not on stacks, sure enough )) Splitting objects to read-only (ROM) and read-write (RAM) parts is a common practice. Not only for safety, rather to save the RAM.
2024-07-31 03:23 PM
> Is my assumption most likely correct?
Yes. When vTaskStartScheduler is called, the "main stack" is reset and reused, so it isn't a good idea to leave objects on this stack.
> How can I go about proving it
It's up to you )) A hint: try to read some documentation. Reading the actual sources of FreeRTOS can help too.
> what is generally best practice for declaring large objects or critical objects containing tasks?
Not on stacks, sure enough )) Splitting objects to read-only (ROM) and read-write (RAM) parts is a common practice. Not only for safety, rather to save the RAM.
2024-08-01 09:05 AM
I just want to say, I'm not trying to sound snarky here, but I did consult the documentation for all the freeRTOS APIs I am using, and none of them mention the main stack is reset. Looking at the source is a great tip though, thank you.
I did find some forum posts about it, but it turns out it's specific to certain ports of freeRTOS, not a blanket issue.
I'm coming from doing a lot of development with esp-idf which spoiled me in some ways, it's nice to return to something a little closer to the hardware.
On a side note, do you have any advice for setting up an ide for a bare metal approach without using any of the cube/HAL business? I've switched to Keil but I'd prefer a more minimalist editor.
2024-08-08 01:45 PM
ST supports now VS Code as a cross platform editor or IDE. They provide the ARM toolchain package for this kind of setup. However, the debugger in this environment is still not as good as in CubeIDE and commercial IDEs.