文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

FreeRTOS实时操作系统之可视化追踪调试

2024-04-02 19:55

关注

前言

用RTOS编程,为每个任务分配多大的堆栈空间就成了一项技术活:分配多了浪费系统资源,分配少了又恐怕会发生堆栈溢出。由于中断和抢占式调度器的存在,我们要估算出一个任务需要多少堆栈是非常困难的,今天我们就介绍一种方法,来获取每个任务的剩余堆栈空间。本文以NXP LPC177x_8x系列微控制器为例。

我们将这个功能做成一个命令,添加到FreeRTOS使用任务通知实现命令行解释器一文介绍的命令解释列表中。当程序运行一段时间后,我们在SecureCRT软件中输入命令“task”后回车,能看到如图1-1所示的任务信息。这里只有两个任务,其中堆栈一列中的数字,代表对应任务剩余的堆栈空间,单位是StackType_t类型,这个类型在移植层定义,一般定义为4字节。

图1-1:任务信息

1.使能可视化追踪和运行时间统计功能

如图1-1所示,要实现堆栈使用量信息以及CPU使用率信息,必须将FreeRTOSConfig.h文件中的两个宏设置为1:

         #define configUSE_TRACE_FACILITY          1      
         #define configGENERATE_RUN_TIME_STATS 1

第一个宏用来使能可视化追踪功能,第二个宏用来使能运行时间统计功能。如果第二个宏设置为1,则下面两个宏必须被定义:

portCONFIGURE_TIMER_FOR_RUN_TIME_STATS():

用户程序需要提供一个基准时钟函数,函数完成初始化基准时钟功能,这个函数要被define到宏portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()上。

这是因为运行时间统计需要一个比系统节拍中断频率还要高分辨率的基准定时器,否则,统计可能不精确。

基准定时器中断频率要比统节拍中断快10~100倍。基准定时器中断频率越快,统计越精准,但能统计的运行时间也越短(比如,基准定时器10ms中断一次,8位无符号整形变量可以计到2.55秒,但如果是1秒中断一次,8位无符号整形变量可以统计到255秒)。

portGET_RUN_TIME_COUNTER_VALUE():

用户程序需要提供一个返回基准时钟当前“时间”的函数,这个函数要被define到宏portGET_RUN_TIME_COUNTER_VALUE()上。

我们使用定时器1来产生基准时钟,定时器1初始化函数为:


void init_timer1_for_runtime_state(void)
{
    TIM_TIMERCFG_Type Timer0CfgType;
    Timer0CfgType.PrescaleOption=TIM_PRESCALE_USVAL;        //预分频的单位是微秒
    Timer0CfgType.PrescaleValue=500;                        //预分频后为500微秒,
    TIM_Init(LPC_TIM1,TIM_TIMER_MODE,&Timer0CfgType);
    LPC_TIM1->TCR=0x01;
}

定时器1被配置成每隔500微秒,TC寄存器值增一。我们将定时器1的 TC寄存器值作为基准时钟当前时间。当TC寄存器值溢出时,大概要经过24.8天,这对于我们这个应用是足够的。

在FreeRTOSConfig.h中,定义初始化基准定时器宏和获取当前时间宏:

extern void init_timer1_for_runtime_state(void);
#define TIMER1_TC         ( * ( ( volatile uint32_t * )0x40008008 ) )
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() init_timer1_for_runtime_state()
#define portGET_RUN_TIME_COUNTER_VALUE() TIMER1_TC

2.获取任务信息并格式化

获取每个任务的状态信息使用的是API函数uxTaskGetSystemState(),该函数定义为:

UBaseType_tuxTaskGetSystemState(
                       TaskStatus_t * constpxTaskStatusArray,
                       const UBaseType_tuxArraySize,
                       unsigned long * constpulTotalRunTime );

函数uxTaskGetSystemState()向TaskStatus_t结构体填充相关信息,系统中每一个任务的信息都可以填充到TaskStatus_t结构体数组中,数组大小由uxArraySize指定。结构体TaskStatus_t定义如下:

typedef struct xTASK_STATUS
{
   
   TaskHandle_t xHandle;
   
   const signed char *pcTaskName;
   
   UBaseType_t xTaskNumber;
   
   eTaskState eCurrentState;
   
   UBaseType_t uxCurrentPriority;
   
   UBaseType_t uxBasePriority;
   
   unsigned long ulRunTimeCounter;
   
   unsigned short usStackHighWaterMark;
}TaskStatus_t;

注意,这个函数仅用来调试用,调用此函数会挂起所有任务,直到函数结束后才恢复挂起的任务,因此任务可能被挂起很长时间。在文件FreeRTOSConfig.h中,宏configUSE_TRACE_FACILITY必须设置为1,此函数才有效。

由于我们不使用动态内存分配策略,所以实现定义了最大任务个数并预先分配好了存储任务状态信息的数组:

#defineMAX_TASK_NUM        5
TaskStatus_tpxTaskStatusArray[MAX_TASK_NUM];

正确调用函数uxTaskGetSystemState()后,任务的信息会被放在TaskStatus_t结构体中,我们需要将这些信息格式化为容易阅读的形式,并共通过串口打印到屏幕。完成这些功能的函数叫做get_task_state(),代码如下所示:


voidget_task_state(int32_t argc,void *cmd_arg)
{
    const chartask_state[]={'r','R','B','S','D'};
    volatile UBaseType_t uxArraySize, x;
    uint32_t ulTotalRunTime,ulStatsAsPercentage;
    
    uxArraySize = uxTaskGetNumberOfTasks();
   if(uxArraySize>MAX_TASK_NUM)
    {
        MY_DEBUGF(CMD_LINE_DEBUG,("当前任务数量过多!\n"));
    }
    
    uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, &ulTotalRunTime );
    #if (configGENERATE_RUN_TIME_STATS==1)
    MY_DEBUGF(CMD_LINE_DEBUG,("任务名      状态  ID    优先级  堆栈    CPU使用率\n"));
 
    
    if( ulTotalRunTime > 0 )
    {
        
        for( x = 0; x < uxArraySize; x++ )
        {
            char tmp[128];
            
            ulStatsAsPercentage =(uint64_t)(pxTaskStatusArray[ x ].ulRunTimeCounter)*100 / ulTotalRunTime;
            if( ulStatsAsPercentage > 0UL )
            {
               sprintf(tmp,"%-12s%-6c%-6d%-8d%-8d%d%%",pxTaskStatusArray[ x].pcTaskName,task_state[pxTaskStatusArray[ x ].eCurrentState],
                                                                       pxTaskStatusArray[ x ].xTaskNumber,pxTaskStatusArray[ x].uxCurrentPriority,
                                                                       pxTaskStatusArray[ x ].usStackHighWaterMark,ulStatsAsPercentage);
            }
            else
            {
                
                sprintf(tmp,"%-12s%-6c%-6d%-8d%-8dt<1%%",pxTaskStatusArray[x ].pcTaskName,task_state[pxTaskStatusArray[ x ].eCurrentState],
                                                                       pxTaskStatusArray[ x ].xTaskNumber,pxTaskStatusArray[ x].uxCurrentPriority,
                                                                       pxTaskStatusArray[ x ].usStackHighWaterMark);               
            }
           MY_DEBUGF(CMD_LINE_DEBUG,("%s\n",tmp));
        }
    }
    MY_DEBUGF(CMD_LINE_DEBUG,("任务状态:   r-运行  R-就绪  B-阻塞  S-挂起  D-删除\n"));
    #endif //#if (configGENERATE_RUN_TIME_STATS==1)
}

3.添加到命令解释列表

在FreeRTOS使用任务通知实现命令行解释器一文我们讲过了命令表,这里只需要将get_task_state()函数添加到命令列表中,命令设置为”task”,代码如下所示:


const cmd_list_structcmd_list[]={
   
    {"?",       0,     handle_help,     "?                                  -打印帮助信息"},                 
    {"reset",   0,     handle_reset,    "reset                              -重启控制器"},
    {"arg",     8,     handle_arg,      "arg<arg1> <arg2> ...               -测试用,打印输入的参数"},
    {"hello",   0,     printf_hello,    "hello                              -打印HelloWorld!"},
    {"task",    0,     get_task_state,  "task                               -获取任务信息"},
};

以上就是FreeRTOS实时操作系统之可视化追踪调试的详细内容,更多关于FreeRTOS可视化追踪调试的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-人工智能
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯