【问题标题】:FreeRTOS - The reason for the stack increase?FreeRTOS - 堆栈增加的原因?
【发布时间】:2021-01-23 12:45:43
【问题描述】:

我创建了几个任务,它们的主体是相同的功能。在函数内部,每个任务都有一个相同的延迟。所以,当这个延迟足够大的时候,每个任务的栈都比延迟小的时候少了6个字。 据我了解,当存在多个状态为Ready 的任务的情况时,任务堆栈会增加。

1.在这种情况下,一些额外的 6 字上下文被写入任务堆栈?

2.在我的例子中,结果是 6 个字(24 个字节),这个值可以改变吗?

3.还有什么会影响栈的增加,比如跳转到中断处理程序?

int main(void){
  xTaskCreate(Task_PrintCountString, "Task_1", mySTACK_SIZE, &param1, 1, NUUL);
  xTaskCreate(Task_PrintCountString, "Task_2", mySTACK_SIZE, &param2, 1, NUUL);
  xTaskCreate(Task_PrintCountString, "Task_3", mySTACK_SIZE, &param3, 1, NUUL);
  vTaskStartScheduler();
}
#define myDELAY     100
void Task_PrintCountString(void *pParams){
  uint16_t c=0; 
  for(;;){
    if(xSemaphoreTake(WriteCountMutex, portMAX_DELAY) == pdTRUE){
        PrintCountString(*(uint8_t *)pParams, c++);
        xSemaphoreGive(WriteCountMutex);
    }       
  vTaskDelay(myDELAY/portTICK_PERIOD_MS);//When myDELAY=1, the task stack is 6 words more than when myDELAY= 100!       
  } 
}

地址 0x20000158 是其中一项任务的堆栈顶部。其他人也一样!

唯一的函数PrintCountString 总是相同的深度。但与此同时,堆栈可以在几个阶段中增长到其最大知识,经历数十次任务循环的迭代!原来不仅context被保存到stack中,还有别的东西?

附: 我使用ARM CM0 portheap_1

我做了一个观察: 在PrintCountString 函数中有一个等待SPI 标志的块-while()。我替换了 DMA 传输方法并删除了while() 循环。无论延迟如何,两个任务的堆栈都立即开始填充到最大值。

【问题讨论】:

  • 您如何衡量任务堆栈的使用情况? portTICK_PERIOD_MS 的值是多少?
  • 我查看栈顶,统计剩余字节数为0xA5。 portTICK_PERIOD_MS = 1
  • 如果在所有任务中使用相同的延迟会怎样?可能是答案中提到的信号量函数的不同嵌套。

标签: freertos


【解决方案1】:

通常,堆栈存储器由微控制器本身使用。有几条指令可以向堆栈写入/读取一些数据。

  • PUSH 指令将一个寄存器的内容复制到堆栈中修改堆栈指针寄存器
  • POP 指令从堆栈中读取一个字到寄存器中修改堆栈指针寄存器

这两条指令都由编译器管理。如果一个函数被执行,编译器会创建一些 PUSH 指令来“释放”一些寄存器来使用。在函数结束时,将使用 POP 指令恢复原始寄存器状态,以保证即将到来的控制流。

  • 并且每条分支指令将多个寄存器值存储到堆栈中

使用的堆栈内存量取决于调用层次结构。

根据您的示例,如果调用 SemaphoreTake 函数并找到释放的信号量,则调用层次结构与信号量被阻塞的情况不同。这会产生不同的堆栈用法。

【讨论】:

  • 看起来不像。 1.函数PrintCountString没有嵌套在函数xSemaphoreTake中。 2.在延迟为100的情况下,堆栈中总是有很多空间。而如果延迟为 10,则堆栈会减少到最小值,但不是立即,而是在每个任务数十次迭代之后。在这种情况下,堆栈的减少发生在部分(根据我的观察,4 个字节)。我只明白当延迟较大时,在信号量检查期间只有一个任务有时间获取Ready 状态。
【解决方案2】:

FreeRTOS 只是 C 代码,因此,除了一个例外,堆栈使用情况由编译器确定,包括所选的优化级别。一个例外是,当一个任务没有运行时,它的上下文被保存到它的堆栈中。在所有重要的情况下,上下文大小都是固定的。上下文的大小取决于您使用的 FreeRTOS 端口(超过 40 个)。

您的帖子中有几件事我不确定。

当这个延迟足够大时,每个任务的堆栈都会被填满 比延迟少时少6个字

如上所述,C 代码不会根据您的延迟时间而改变 - 编译器对 FreeRTOS 或延迟的概念一无所知。根据发生中断时代码在调用树中的位置(包括导致上下文切换的中断),您可能会看到不同的堆栈深度。

我查看栈顶,统计剩余字节数 为0xA5

你没有说你正在使用哪个端口,所以我不知道堆栈是向上还是向下。在任何情况下,当创建任务时堆栈都被填充为 0xa5,但内核从未再次触及,因此剩余的 0xa5 数显示了任务自创建以来已使用的最大堆栈量。该值通过调用uxTaskGetStackHighWaterMark() 返回。

【讨论】:

  • 我正在使用端口heap_1。编译器优化禁用level 0uxTaskGetStackHighWaterMark 向我展示了我看到自己的价值。我正在查看pxCurrentTCB->pxStack 中给出的地址处的任务堆栈顶部。我的目标是为自己开发一种计算任务堆栈所需大小的机制。所以我想知道为什么在我的情况下我可以获得不同的最大堆栈大小?
  • 原来压栈的context大小可以不一样?
猜你喜欢
  • 1970-01-01
  • 2012-08-31
  • 1970-01-01
  • 1970-01-01
  • 2013-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-24
相关资源
最近更新 更多