需求
如何使用 stm32cubeide 开启 threadx 中的 stack check ?
解决
使能 stack check
- 在项目属性中,
C/C++ Build
->Settings
->MCU GCC Compiler
->
Preprocessor
中添加 TX_ENABLE_STACK_CHECKING
- 在
MCU G++ Compiler
中添加同样的TX_ENABLE_STACK_CHECKING
printf 函数
#include "stdio.h"
#include "usart.h"
int _write(int file, char *ptr, int len)
{
HAL_UART_Transmit(&huart1, (uint8_t*)ptr, len, 0xFFFF);
return len;
}
*注意: 需要在头文件中增加 int _write(int file, char *ptr, int len);
, 否则可能无法覆盖由 __attribute__((weak))
修饰的原来 _write
. *
处理函数
VOID StackErrorHandler(TX_THREAD * thread_ptr)
{
printf("=============================================================== \n");
printf("如下任务被检测出栈溢出 \n");
printf("=============================================================== \n");
printf(" 任务优先级 任务栈大小 当前使用栈 最大栈使用 任务名 \n");
printf(" Prio StackSize CurStack MaxStack Taskname \n");
TX_THREAD *p_tcb; /* 定义一个任务控制块指针 */
p_tcb = &ServiceVibration;
/* 遍历任务控制列表TCB list),打印所有的任务的优先级和名称 */
do {
if (p_tcb != (TX_THREAD*) thread_ptr) {
p_tcb = p_tcb->tx_thread_created_next;
} else {
//Log::printf(level, " %2d %5d %5d %5d %s\n",
printf(" %2d %5ld %5d %5d %s\n",
p_tcb->tx_thread_priority, p_tcb->tx_thread_stack_size,
(int) p_tcb->tx_thread_stack_end
- (int) p_tcb->tx_thread_stack_ptr,
(int) p_tcb->tx_thread_stack_end
- (int) p_tcb->tx_thread_stack_highest_ptr,
p_tcb->tx_thread_name);
while (1);
}
} while (1);
}
绑定处理函数
在 app_azure_rtos.c
中的 tx_application_define
中,在申请字节池之后,增加 tx_thread_stack_error_notify(StackErrorHandler);
调试
这个调试比较有难度,如果直接在任务中,使用 int buf[5000]
这样的形式,很有可能直接就进 hard fault
了。所以需要重新思考方法。
经过多次调试发现以下信息:
- 任务堆栈
app_main_stack_ptr
的值末尾是0x0AAC
, 因为堆栈大小是 1024,所以实际的堆栈范围是0x0AAC
到0x0EAC
之间。并且在任务调用的时候,堆栈指针是从高地址向低地址使用,所以先从0x0EAB
开始,逐渐向下开始push
,pop
- 在任务中,
int buf[5000]
这样的数组,比任务堆栈大太多了,会导致在调用任务的函数时,直接hard fault
. - 在任务中,
int buf[100]
这样的数组,如果不使用的时候,当前堆栈指针为0x0E58
, 那么当使用的时候,会从0x0E58
向下获取 100 个字,所以数组首地址是0x0ECC8
, 即数组占据了0x0ECC8
到0x0E58
这一段内存空间。
经过上面的这些信息,得出的可行方案是:
- 先获取当前的任务堆栈指针指向的内存地址,然后向下进行写入,最终写超出任务堆栈空间。
- 并且考虑到只有在任务切换的时候,才会检查堆栈溢出。所以每写入一次,就休眠一下,让任务进行调度。
具体测试代码如下:
int value;
int * buf = &value;
for (int i = 0; i < 1024; i++) {
int * p = buf - i;
*p = i;
tx_thread_sleep(i + 10);
}