SystemView 记录Trace通过Event进行事件记录。
举个简单的例子
prvAddCurrentTaskToDelayedList函数中
traceMOVED_TASK_TO_DELAYED_LIST();
Freertos内核代码中有很多traceXXX的函数,SystemView重新定义这些函数。
SEGGER_SYSVIEW_FreeRTOS.h
#define traceMOVED_TASK_TO_DELAYED_LIST() SEGGER_SYSVIEW_OnTaskStopReady((U32)pxCurrentTCB, (1u << 2))
#define traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST() SEGGER_SYSVIEW_OnTaskStopReady((U32)pxCurrentTCB, (1u << 2))
#define traceMOVED_TASK_TO_SUSPENDED_LIST(pxTCB) SEGGER_SYSVIEW_OnTaskStopReady((U32)pxTCB, ((3u << 3) | 3))
当Freertos的tracexxxxxx函数运行的时候,会执行SEGGER_SYSVIEW定义的trace函数。把对应的 事件写入到指定的事件缓冲区域。所以我们可以人为去增加trace的位点。调试器会读取内存区域的数据传输到PC上,完成图形界面的变化。
trace大致的工作原理就是这样。
1.记录的是tracexxxx,所有没有trace函数的地方不会有trace
2.事件时间不是非常的精确,但是一定程度上已经非常够用了。
代码如下,这里建立两个任务LED0_Task ,LED1_Task
SystemView 记录的文档 点击这里
xTaskCreate(LED0_Task, "LED0_Blink", 128, (void*)NULL,4 , NULL);
xTaskCreate(LED1_Task, "LED1_Blink", 128, (void*)NULL,5 , NULL);
LED0_Task 优先级4
LED1_Task 优先级5
void do_things(int i)
{
int k,n;
for(n=0;n<i;n++)
{
k=0;
while(k<655)
{
k++;
}
}
}
static void LED0_Task(void *args) {
while (1) {
xSemaphoreTake(mutex_1, 0xffff);
do_things(10);
xSemaphoreGive(mutex_1);
vTaskDelay(4);
};
}
static void LED1_Task(void *args) {
while (1) {
vTaskDelay(2);
xSemaphoreTake(mutex_1, 0xffff);
do_things(10);
xSemaphoreGive(mutex_1);
};
}
运行程序,进行记录
sysTick ,是ARM cortex-M3内核专门用来提供操作系统tick的定时器,Freertos在调度器的初始化中对它的间隔进行了设定。上图可以看到每个systick 1ms运行一次,每一次运行都会打断用户函数的运行,并且systick handler处理函数执行也需要花费时间。
这里需要耗费23us的时间执行。
先看Event 这个时候LED1任务接收了队列,对应大码是line85,获取互斥量。然后执行do_things。
经过了多个systick LED1任务释放了信号量,跳回while(1)开头的taskdelay(2),也就是说任务要进入阻塞状态,任务的切换是由调度器完成的。可以看到调度器的执行也需要耗费时间
下一个事件,LED0任务获取了 互斥量,开始执行dothings。
dothings(10)还没完成。systick计数器+1,LED1的Delay2超时解除阻塞状态。调度器执行上下文切换LED1任务执行。
箭头时刻,LED1 尝试获取互斥量,这时互斥量的拥有着LED0 继承优先级,那么LED0优先执行。
直到下一个时刻LED0 do_things(10);执行完成释放互斥量。这个时候优先级回复成原始优先级 。LED1是最高优先级,马上切换运行,获取互斥量。
下一个时间,LED1释放了互斥量进入taskdelay(2),那么任务LED0运行执行delay(4).这个时候所有的用户任务都在阻塞状态,那么空闲任务Idea task运行。
下一个时刻LED1 的Taskdelay(2) 完成切换LED1运行。
上面的过程可以理解以下内容
1.任务的切换需要CPU运行一段时间的调度器任务
2.systick周期性的唤醒短暂的打断正在运行的任务
3.systick,调度器的设计要精简,减少耗时
4.taskdelay计数依赖systick 计数误差1 tick
5.互斥量的优先级继承机制
6.Freertos的 API可以直接发起PendSV,进行上下文切换,不需要在下一个systick来触发