FreeRtos学习笔记(12)systemView 分析任务调度情况
使用stm32f429 + freertosV10.5.1 + systemView 3.5 + keil AC5
systemView 移植
- 从官网下载 systemView 软件
- 将下面文件添加到工程中
freertos 修改
- systemView 需要 FreeRTOSConfig.h 开启如下宏, 并添加头文件 “SEGGER_SYSVIEW_FreeRTOS.h”
#define configCHECK_FOR_STACK_OVERFLOW 2
#define configUSE_TRACE_FACILITY 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_pxTaskGetStackStart 1
#include "SEGGER_SYSVIEW_FreeRTOS.h"
此时工程应该可以通过编译
- 对freertos 的源码打补丁,来更好的适配systemView
下载对应版本的 SystemView, Target Sources,或者打开systemView软件的安装目录,找到freertos对应版本的补丁文件, 这里用的是freertosV10.4, 因此使用 Src\Sample\FreeRTOSV10.4\Patch 文件
diff -rupN org/config/FreeRTOSConfig.h new/config/FreeRTOSConfig.h
--- org/config/FreeRTOSConfig.h 2020-12-15 19:53:08.000000000 +0100
+++ new/config/FreeRTOSConfig.h 2021-03-10 13:28:14.645130255 +0100
@@ -91,6 +91,10 @@ to exclude the API function. */
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_eTaskGetState 1
+#define INCLUDE_xTaskGetIdleTaskHandle 1
+#define INCLUDE_pxTaskGetStackStart 1
+
+#include "SEGGER_SYSVIEW_FreeRTOS.h"
/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
diff -rupN org/FreeRTOS/Source/include/FreeRTOS.h new/FreeRTOS/Source/include/FreeRTOS.h
--- org/FreeRTOS/Source/include/FreeRTOS.h 2020-12-15 19:54:26.000000000 +0100
+++ new/FreeRTOS/Source/include/FreeRTOS.h 2021-03-10 14:58:58.000000000 +0100
@@ -182,6 +182,10 @@
#define INCLUDE_uxTaskGetStackHighWaterMark2 0
#endif
+#ifndef INCLUDE_pxTaskGetStackStart
+ #define INCLUDE_pxTaskGetStackStart 0
+#endif
+
#ifndef INCLUDE_eTaskGetState
#define INCLUDE_eTaskGetState 0
#endif
@@ -448,6 +452,23 @@
#define tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )
#endif
+#ifndef traceREADDED_TASK_TO_READY_STATE
+ #define traceREADDED_TASK_TO_READY_STATE( pxTCB ) traceMOVED_TASK_TO_READY_STATE( pxTCB )
+#endif
+
+#ifndef traceMOVED_TASK_TO_DELAYED_LIST
+ #define traceMOVED_TASK_TO_DELAYED_LIST()
+#endif
+
+#ifndef traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST
+ #define traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST()
+#endif
+
+#ifndef traceMOVED_TASK_TO_SUSPENDED_LIST
+ #define traceMOVED_TASK_TO_SUSPENDED_LIST( pxTCB )
+#endif
+
+
#ifndef traceQUEUE_CREATE
#define traceQUEUE_CREATE( pxNewQueue )
#endif
@@ -696,6 +717,18 @@
#define traceTASK_NOTIFY_GIVE_FROM_ISR( uxIndexToNotify )
#endif
+#ifndef traceISR_EXIT_TO_SCHEDULER
+ #define traceISR_EXIT_TO_SCHEDULER()
+#endif
+
+#ifndef traceISR_EXIT
+ #define traceISR_EXIT()
+#endif
+
+#ifndef traceISR_ENTER
+ #define traceISR_ENTER()
+#endif
+
#ifndef traceSTREAM_BUFFER_CREATE_FAILED
#define traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer )
#endif
diff -rupN org/FreeRTOS/Source/include/task.h new/FreeRTOS/Source/include/task.h
--- org/FreeRTOS/Source/include/task.h 2020-12-15 19:54:26.000000000 +0100
+++ new/FreeRTOS/Source/include/task.h 2021-03-03 10:07:46.000000000 +0100
@@ -1538,6 +1538,25 @@ UBaseType_t uxTaskGetStackHighWaterMark(
*/
configSTACK_DEPTH_TYPE uxTaskGetStackHighWaterMark2( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
+/**
+ * task.h
+ * <PRE>uint8_t* pxTaskGetStackStart( TaskHandle_t xTask);</PRE>
+ *
+ * INCLUDE_pxTaskGetStackStart must be set to 1 in FreeRTOSConfig.h for
+ * this function to be available.
+ *
+ * Returns the start of the stack associated with xTask. That is,
+ * the highest stack memory address on architectures where the stack grows down
+ * from high memory, and the lowest memory address on architectures where the
+ * stack grows up from low memory.
+ *
+ * @param xTask Handle of the task associated with the stack returned.
+ * Set xTask to NULL to return the stack of the calling task.
+ *
+ * @return A pointer to the start of the stack.
+ */
+uint8_t* pxTaskGetStackStart( TaskHandle_t xTask) PRIVILEGED_FUNCTION;
+
/* When using trace macros it is sometimes necessary to include task.h before
* FreeRTOS.h. When this is done TaskHookFunction_t will not yet have been defined,
* so the following two prototypes will cause a compilation error. This can be
diff -rupN org/FreeRTOS/Source/portable/GCC/ARM_CM0/port.c new/FreeRTOS/Source/portable/GCC/ARM_CM0/port.c
--- org/FreeRTOS/Source/portable/GCC/ARM_CM0/port.c 2020-12-15 19:54:26.000000000 +0100
+++ new/FreeRTOS/Source/portable/GCC/ARM_CM0/port.c 2021-03-03 10:20:34.000000000 +0100
@@ -359,13 +359,19 @@ void xPortSysTickHandler( void )
uint32_t ulPreviousMask;
ulPreviousMask = portSET_INTERRUPT_MASK_FROM_ISR();
+ traceISR_ENTER();
{
/* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE )
{
+ traceISR_EXIT_TO_SCHEDULER();
/* Pend a context switch. */
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
}
+ else
+ {
+ traceISR_EXIT();
+ }
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulPreviousMask );
}
diff -rupN org/FreeRTOS/Source/portable/GCC/ARM_CM0/portmacro.h new/FreeRTOS/Source/portable/GCC/ARM_CM0/portmacro.h
--- org/FreeRTOS/Source/portable/GCC/ARM_CM0/portmacro.h 2020-12-15 19:54:26.000000000 +0100
+++ new/FreeRTOS/Source/portable/GCC/ARM_CM0/portmacro.h 2021-03-03 10:21:08.000000000 +0100
@@ -82,7 +82,7 @@
#define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portYIELD() vPortYield()
- #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired ) portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT
+ #define portEND_SWITCHING_ISR( xSwitchRequired ) { if( xSwitchRequired ) { traceISR_EXIT_TO_SCHEDULER(); portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; } else { traceISR_EXIT(); } }
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
diff -rupN org/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c new/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c
--- org/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c 2020-12-15 19:54:26.000000000 +0100
+++ new/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c 2021-03-03 10:17:16.000000000 +0100
@@ -436,14 +436,19 @@ void xPortSysTickHandler( void )
* save and then restore the interrupt mask value as its value is already
* known. */
portDISABLE_INTERRUPTS();
+ 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();
+ }
}
portENABLE_INTERRUPTS();
}
diff -rupN org/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h new/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h
--- org/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h 2020-12-15 19:54:26.000000000 +0100
+++ new/FreeRTOS/Source/portable/GCC/ARM_CM3/portmacro.h 2021-03-03 10:18:26.000000000 +0100
@@ -90,7 +90,7 @@
#define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
- #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
+ #define portEND_SWITCHING_ISR( xSwitchRequired ) { if( xSwitchRequired != pdFALSE ) { traceISR_EXIT_TO_SCHEDULER(); portYIELD() } else { traceISR_EXIT(); } }
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
diff -rupN org/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c new/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c
--- org/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c 2020-12-15 19:54:26.000000000 +0100
+++ new/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c 2021-03-03 10:25:28.000000000 +0100
@@ -498,14 +498,20 @@ void xPortSysTickHandler( void )
* save and then restore the interrupt mask value as its value is already
* known. */
portDISABLE_INTERRUPTS();
+ 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();
+ }
}
portENABLE_INTERRUPTS();
}
diff -rupN org/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h new/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h
--- org/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h 2020-12-15 19:54:26.000000000 +0100
+++ new/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h 2021-03-03 10:26:06.000000000 +0100
@@ -90,7 +90,7 @@
#define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
- #define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
+ #define portEND_SWITCHING_ISR( xSwitchRequired ) { if( xSwitchRequired != pdFALSE ) { traceISR_EXIT_TO_SCHEDULER(); portYIELD(); } else { traceISR_EXIT(); } }
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
diff -rupN org/FreeRTOS/Source/tasks.c new/FreeRTOS/Source/tasks.c
--- org/FreeRTOS/Source/tasks.c 2020-12-15 19:54:28.000000000 +0100
+++ new/FreeRTOS/Source/tasks.c 2021-03-10 14:59:11.000000000 +0100
@@ -1735,7 +1735,7 @@ static void prvAddNewTaskToReadyList( TC
{
mtCOVERAGE_TEST_MARKER();
}
-
+ traceMOVED_TASK_TO_SUSPENDED_LIST(pxTCB);
vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
#if ( configUSE_TASK_NOTIFICATIONS == 1 )
@@ -3927,6 +3927,20 @@ static void prvCheckTasksWaitingTerminat
#endif /* INCLUDE_uxTaskGetStackHighWaterMark */
/*-----------------------------------------------------------*/
+#if (INCLUDE_pxTaskGetStackStart == 1)
+ uint8_t* pxTaskGetStackStart( TaskHandle_t xTask)
+ {
+ TCB_t *pxTCB;
+ UBaseType_t uxReturn;
+ (void)uxReturn;
+
+ pxTCB = prvGetTCBFromHandle( xTask );
+ return ( uint8_t * ) pxTCB->pxStack;
+ }
+
+#endif /* INCLUDE_pxTaskGetStackStart */
+/*-----------------------------------------------------------*/
+
#if ( INCLUDE_vTaskDelete == 1 )
static void prvDeleteTCB( TCB_t * pxTCB )
@@ -5311,12 +5325,14 @@ static void prvAddCurrentTaskToDelayedLi
{
/* Wake time has overflowed. Place this item in the overflow
* list. */
+ traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST();
vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else
{
/* The wake time has not overflowed, so the current block list
* is used. */
+ traceMOVED_TASK_TO_DELAYED_LIST();
vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
/* If the task entering the blocked state was placed at the
@@ -5345,11 +5361,13 @@ static void prvAddCurrentTaskToDelayedLi
if( xTimeToWake < xConstTickCount )
{
+ traceMOVED_TASK_TO_OVERFLOW_DELAYED_LIST();
/* Wake time has overflowed. Place this item in the overflow list. */
vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else
{
+ traceMOVED_TASK_TO_DELAYED_LIST();
/* The wake time has not overflowed, so the current block list is used. */
vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
由于使用的是STMF429 和keil 的AC5, 因此按照上述补丁文件,逐条对以下文件进行修改(由于补丁是V10.4.3的,而实际使用的freertos版本为10.5.1,因此补丁的行数信息不准确,需要根据上下文搜索确定文件修改位置)
- config/FreeRTOSConfig.h
此文件上面已经修改过了
- FreeRTOS/Source/include/FreeRTOS.h
- FreeRTOS/Source/include/task.h
- FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c
- FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h
- FreeRTOS/Source/tasks.c
systemView 使用
- 配置
systemView 可以简单看成当RTOS进行任务切换、消息队列发送接收时,会向RAM写入时间戳等信息,systemView通过jlink直接读取RAM,将RAM中的时间戳等信息翻译成图表信息。因此时间戳怎么获取是很重要的,cortex-M3/M4/M7内核中有一个DWT定时器,分辨率是系统时钟,systemView就是使用的这个定时器。
systemView通过jlink直接读取RAM时,会从该地址开始进行查找。
- 初始化
traceSTART();
打开 systemView 即可
- 添加想要测量的中断
- 添加描述符
SysTick_IRQn 为15, 所以 TIM8_TRG_COM_TIM14_IRQn 为 16 + 45 = 61
2. 中断服务函数中添加trace
- 测量代码段运行时长
systemView 溢出
-
提高 jlink 速度
-
增大RAM缓冲区
-
如果使用了SEGGER RTT打印log,关闭RTT打印