DEBUG


在freerots中断言有两种类型。官网描述

  • 关中断然后进入死循环,使用调试器定位出错位置
  • 进入一个自定义的函数,输出文件名或者文件位置
1
2
3
4
5
6
/* Define configASSERT() to disable interrupts and sit in a loop. */
#define configASSERT( ( x ) )     if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }

/* Define configASSERT() to call vAssertCalled() if the assertion fails.  The assertion
has failed if the value of the parameter passed into configASSERT() equals zero. */
#define configASSERT( ( x ) )     if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ )

值得注意的是,cubemx自动生成第一种类型的中断,而且是在USER code中生成的。 这意味着只需要将configASSERT定义为空就可以关掉debug设置,而且不会被新生成的代码覆盖。

计算任务栈大小


-fstack-usage

这个参数会生成.su文件,文件中会记录每个函数使用栈大小。官网描述

-Wstack-usage=128

如果函数栈超过128 bytes,编译器会给出一个警告。

uxTaskGetStackHighWaterMark

这个函数会返回未用栈大小(word)。官网描述

vApplicationStackOverflowHook

这个钩子函数在监测到有堆栈溢出时调用。官网描述

计算任务栈

  • 在freertos中绝对不可以使用递归
1
2
./avstack.pl *.o
cflow *.c

通过debug检查,防止爆栈

1
2
#define INCLUDE_uxTaskGetStackHighWaterMark  1
configASSERT(usTaskGetStackHighWaterMark(xTask) > 32);

通过钩子函数,防止爆栈

1
2
3
4
#define INCLUDE_uxTaskGetStackHighWaterMark  1
#define configCHECK_FOR_STACK_OVERFLOW 2
void vApplicationStackOverflowHook( TaskHandle_t xTask,
                                    signed char *pcTaskName );

总结

经过编译时检查和运行时检查,几乎能消除freertos所有的栈分配不当,提高代码质量。

jlink官方(UM08001)提供了一种基于内核的调试信息输出。 实现约占ROM 500 bytes,RAM几乎可以忽略。对比串口有如下优点

  • 连线少,debug和终端输出都是使用jlink
  • 速度快,输出调试信息更多
  • RTT库能防止输出冲突
  • 实现简单,只需要添加.c文件即可
  • 多终端输出支持

添加库

RTT库在 SEEGER/JLINK/Samples/RTT文件夹中。

1
2
3
4
SEGGER_RTT_Conf.h
SEGGER_RTT.h
SEGGER_RTT_printf.c
SEGGER_RTT.c

将如上文件加入到项目内,编译通过即可使用。调试使用JLinkRTTViewer图形界面。

1
2
3
4
5
6
7
#include "SEGGER_RTT.c"
/× BufferIndex使用0即可,其他buffer需要注册 */
int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...);
/* 改变接下来的输出终端 */
void SEGGER_RTT_SetTerminal(char TerminalId);
/× 不改变输出终端,输出信息 */
int SEGGER_RTT_TerminalOut(char TerminalID, const char *s);

已知bug

  • JLinkRTTViewer: 如果输出终端号为0,可以识别\n。其它终端号无法识别\n。解决方案:使用JLinkRTTClent
  • 在linux平台对utf8中文字符串识别出错。解决方案:即时调试使用JLinkRTTClient,保存记录使用JLinkRTTViewer