FreeRtos学习笔记(12)systemView 分析任务调度情况

FreeRtos学习笔记(12)systemView 分析任务调度情况

使用stm32f429 + freertosV10.5.1 + systemView 3.5 + keil AC5

systemView 移植

  1. 从官网下载 systemView 软件
  2. 将下面文件添加到工程中




freertos 修改

  1. systemView 需要 FreeRTOSConfig.h 开启如下宏, 并添加头文件 "SEGGER_SYSVIEW_FreeRTOS.h"
c 复制代码
#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"

此时工程应该可以通过编译

  1. 对freertos 的源码打补丁,来更好的适配systemView

下载对应版本的 SystemView, Target Sources,或者打开systemView软件的安装目录,找到freertos对应版本的补丁文件, 这里用的是freertosV10.4, 因此使用 Src\Sample\FreeRTOSV10.4\Patch 文件


c 复制代码
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时,会从该地址开始进行查找。

  • 初始化
c 复制代码
traceSTART();

打开 systemView 即可

  • 添加想要测量的中断
  1. 添加描述符

SysTick_IRQn 为15, 所以 TIM8_TRG_COM_TIM14_IRQn 为 16 + 45 = 61

  1. 中断服务函数中添加trace
  • 测量代码段运行时长

systemView 溢出

  • 提高 jlink 速度

  • 增大RAM缓冲区

  • 如果使用了SEGGER RTT打印log,关闭RTT打印

相关推荐
编程圈子14 分钟前
I.MX6U 裸机开发 24. 电容触摸屏与 I2C 驱动
单片机·嵌入式硬件
Zwawa1 小时前
传感器模块都在交出什么:从模拟电压到数字协议
c语言·单片机·嵌入式
FakeOccupational2 小时前
【电路笔记 STM32】Cortex-M7 UART 中断模式(串口接收中断+串口空闲中断)
笔记·stm32·单片机
小李不想当小白2 小时前
USART串口协议(STM32标准库学习笔记)
经验分享·笔记·stm32·单片机·嵌入式硬件·学习
无垠的广袤3 小时前
拆解电子价签
单片机·蓝牙·diy·调试器·jlink·墨水屏
小何好运暴富开心幸福3 小时前
嵌入式历史与生态
stm32·单片机·mcu
甜甜的大香瓜4 小时前
【MT32F006】MT32F006之Stimer延时(轮询)
单片机
辰哥单片机设计4 小时前
MP3播放器模块(STM32)
stm32·单片机·嵌入式硬件
Brilliantwxx5 小时前
【STM32】 工程实战 WS2812B 全彩 LED 灯控制(DMA 驱动)
stm32·单片机·嵌入式硬件·mcu
科芯创展5 小时前
10~120V宽压1.5A降压DC-DC XZ1830技术特性与应用解析
单片机