cancel
Showing results for 
Search instead for 
Did you mean: 

Question About Memory Allocation

EmbeddedEnjoyer
Associate

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,

1 ACCEPTED SOLUTION

Accepted Solutions
Pavel A.
Evangelist III

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.

 

 

View solution in original post

3 REPLIES 3
Pavel A.
Evangelist III

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.

 

 

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. 

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.