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 安装上位机移植源码



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文件是补丁文件,下一篇用到

3.2 修改配置


#include "SEGGER_SYSVIEW.h"
,然后在外设函数初始化之后调用 SEGGER_SYSVIEW_Conf()
函数


四、增加配置
#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
八、遇到的问题
如果上位机出现这种情况就是溢出了,采样缓冲器太小了,打开
SEGGER_SYSVIEW_ConfDefaults.h
,修改RTT BUFFER的大小#define SEGGER_SYSVIEW_RTT_BUFFER_SIZE 4096 //1024

作者:hpuylx