STM32 FreeRTOS移植与SystemView集成:步骤及补丁应用指南

一、SEGGER SystemView介绍

   在用RTOS的时候你是否有过疑问,任务之间到底是怎么切换的?任务的优先级、挂起、阻塞、运行又是怎么样的?而SystemView就是用来分析这些问题的工具。它是一个可以在线调试嵌入式系统的工具,它可以分析有哪些中断、任务执行了,以及这些中断、任务执行的先后关系。还可以查看一些内核对象持有和释放的时间点,比如信号量、互斥量、事件、消息队列等。我们可以通过这个软件来实现对整个嵌入式操作系统的调度监测。
   类似的工具还有Tracealzer、μc/Probe。相关的介绍可以自行搜索一下,推荐B站“麦克泰技术”的讲解。本文主要介绍SystemView,它目前支持uC/OS-II、μC/OS-III、FreeRTOS、embOS、RT-Thread等系统以及裸机。它支持几乎所有的CPU,但是,只有支持后台内存访问的CPU(ARM Cortex-M和瑞萨RX)才能进行连续记录。在其他CPU上,SystemView可用于single-shot(单次记录) 和 post-mortem(事后分析)两种模式。


二、环境准备以及资料下载

2.1 环境准备

  本次目标板使用STM32F103也就是cortex-M3内核,由于SystemView使用的是RTT传输技术,所以目前只支持Jlink调试器进行访问。

2.2 资料下载

   通过访问SEGGER官网下载SystemView上位机和源码。SEGGER SystemView 上位机软件版本与源码版本尽量保持一样,下载安装包或exe,和源码压缩包
官网图片


三、安装与源码介绍

3.1 安装上位机移植源码

  • 启动软件会出现下图弹框,该弹框是对当前工程的一个概述,点击OK即可
  • 点击Help -> User Guide 打开SystemView的用户手册,保存到电脑上方便下面以及后面学习使用。
  • 解压源码得到三个大目录
  • 打开用户手册,找到4.1节可以看到官方列出来的移植清单
  • 保持原来的文件结构,在工程下命名同样的文件夹,按照下面目录进行移植即可。在工程下创建SystemView文件夹,在下面分别创建ConfigSampleSEGGER文件夹
  • SystemView
    ├<Config>
    │	├Global.h
    │	├SEGGER_RTT_Conf.h
    │	└SEGGER_SYSVIEW_Conf.h
    ├<Sample>
    │	└<FreeRTOS>
    │	  	├<Config>
    │	  	│	└SEGGER_SYSVIEW_Config_FreeRTOS.c
    │	  	├SEGGER_SYSVIEW_FreeRTOS.c
    │	  	└SEGGER_SYSVIEW_FreeRTOS.h
    └<SEGGER>
      	├SEGGER.h
      	├SEGGER_RTT.c
      	├SEGGER_RTT.h
      	├SEGGER_RTT_ASM_ARMv7M.S
      	├SEGGER_RTT_printf.c
      	├SEGGER_SYSVIEW.c
      	├SEGGER_SYSVIEW.h
      	├SEGGER_SYSVIEW_ConfDefaults.h
      	├SEGGER_SYSVIEW_Int.h
     
    

    注意
    1.按照工程的FreeRTOS版本去移植对应的代码,FreeRTOS版本在FreeRTOS.h的头注释中可以看到。

    2.选择对应的FreeRTOS版本移植,目录下的Patch文件是补丁文件,下一篇用到

  • 移植后,在Keil工程中创建对应的文件夹奖.c文件添加进去,.h文件包含进去
  • 编译没有报错
  • 3.2 修改配置

  • 在FreeRTOSConfig.h中添加头文件
  • 修改配置文件
  • 在main函数中添加头文件#include "SEGGER_SYSVIEW.h",然后在外设函数初始化之后调用 SEGGER_SYSVIEW_Conf() 函数
  • 烧录到单片机中,打开上位机在弹窗中选择Jlink或者在菜单栏打开配置进行选择
  • 然后点击启动按钮进行监测就可以监测到任务了

  • 四、增加配置

  • FreeRTOSConfig.h中增加宏定义 #define INCLUDE_xTaskGetIdleTaskHandle 1
  • 内核宏定义修改

  • 五、打补丁解决中断无法记录的问题

    为什么要打补丁?

      从下图可以看到,Systick属于系统的滴答中断,中断号是15,可见SystemView知道RTOS有这个中断,但是无法识别,可见现在的移植还有缺陷。

    如何让SystemView识别到中断号?

      打开用户手册,搜索中断 Interrupt,对于CORTEX-M3/M4内核,中断使用的是

    //
    // Get the interrupt Id by reading the Cortex-M ICSR[8:0]
    //
    #define SEGGER_SYSVIEW_GET_INTERRUPT_ID() ((*(U32 *)(0xE000ED04)) & 0x1FF)
    


      在工程中搜索该宏定义,由于在本文前面第四章节已经提前修改好了SEGGER_SYSVIEW_CORE为自己对应的工程的内核了,所以现在SystemView按说应该可以识别到中断了,为啥还是不可以呢?

      从上图可以看到#define SEGGER_SYSVIEW_GET_INTERRUPT_ID() ((*(U32*)(0xE000ED04)) & 0x1FF) ,搜索这个宏定义查看哪个地方调用了这个宏函数。在SEGGER_SYSVIEW.c中找到记录进入中断的API函数SEGGER_SYSVIEW_RecordEnterISR()

      在工程中继续搜索这个函数,发现并未有地方调用该函数,难道需要我们去调用?

    #define traceISR_EXIT_TO_SCHEDULER()      SEGGER_SYSVIEW_RecordExitISRToScheduler()  //记录退出中断后进入调度器
    #define traceISR_EXIT()                   SEGGER_SYSVIEW_RecordExitISR()			 //记录退出中断
    #define traceISR_ENTER()                  SEGGER_SYSVIEW_RecordEnterISR()			 //记录进入中断
    

      在工程中的中断函数中调用API,编译、烧录、运行观察上位机监测情况

      这次可以看到,监测到了56号中断、在TimeLine上也显示出了对应的进程、在概况窗口也可以看到中断触发了两次、在上下文切换窗口看到中断进入和退出的上下文。
      由于本工程用的是硬件输入中断,EXTI15_10_IRQHandler,从启动文件中根据SysTick_Handler为15号中断可以得到EXTI15_10_IRQHandler就是56号中断,没有问题。

    修改上位机中的中断名称

      前面的Systick是15号中断,在工程中搜索Systick名字,找与SystemView有关的文件。在SEGGER_SYSVIEW_Config_FreeRTOS.c中找到相关函数,注释中对函数的描述是:发送描述字符串到SystemView

      照猫画虎,把56号中断名字写出来,但是这样有个问题就是中断没触发的时候也会显示出这个名字,但是TimeLine上面没有显示。

    static void _cbSendSystemDesc(void) {
      SEGGER_SYSVIEW_SendSysDesc("N="SYSVIEW_APP_NAME",D="SYSVIEW_DEVICE_NAME",O=FreeRTOS");
      SEGGER_SYSVIEW_SendSysDesc("I#15=SysTick");
      SEGGER_SYSVIEW_SendSysDesc("I#56=EXTI15_10");
    }
    


      到现在,中断可以正常显示了,那么Systick是不是也是类似原理呢?下面就打开补丁文件打补丁


    六、打补丁解决Systick中断无法显示的问题

      打开补丁文件SystemView_Src_V358\Sample\FreeRTOSV10\Patch\FreeRTOSV10_Core.patch

    补丁文件如何用?

    移植与Systick相关的补丁代码

    port.c

    void xPortSysTickHandler( void )
    {
    	/* The SysTick runs at the lowest interrupt priority, so when this interrupt
    	executes all interrupts must be unmasked.  There is therefore no need to
    	save and then restore the interrupt mask value as its value is already
    	known - therefore the slightly faster vPortRaiseBASEPRI() function is used
    	in place of portSET_INTERRUPT_MASK_FROM_ISR(). */
    	vPortRaiseBASEPRI();
    	traceISR_ENTER();
    	{
    		/* Increment the RTOS tick. */
    		if( xTaskIncrementTick() != pdFALSE )
    		{
    			traceISR_EXIT_TO_SCHEDULER();
    			/* A context switch is required.  Context switching is performed in
    			the PendSV interrupt.  Pend the PendSV interrupt. */
    			portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
    		}
    		else
    		{
    			traceISR_EXIT();
    		}
    	}
    	vPortClearBASEPRIFromISR();
    }
    

      这个是关键文件,移植完这个函数之后,就可以看到Systick的中断了,从图中可以看到CPU调度是1ms一次


    七、其他补丁

      其他补丁可能在某些应用场景下有用,按照补丁文件进行移植,下面做一个对比总结

    FreeRTOS.h

    这里是引用

    task.h

    这里是引用

    port.c

    上面已经修改,不需要在修改

    portmacro.h

    这里是引用

    task.c

    这里是引用


    八、遇到的问题

  • Error: L6406E: No space in execution regions with .ANY selector matching
  • SystemView采样溢出
      如果上位机出现这种情况就是溢出了,采样缓冲器太小了,打开SEGGER_SYSVIEW_ConfDefaults.h,修改RTT BUFFER的大小
    #define SEGGER_SYSVIEW_RTT_BUFFER_SIZE 4096 //1024
  • 作者:hpuylx

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32 FreeRTOS移植与SystemView集成:步骤及补丁应用指南

    发表回复