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

本文详细介绍了如何在STM32F429平台上的FreeRTOS10.5.1版本中集成SystemView3.5,涉及配置FreeRTOS以启用堆栈检查和trace功能,以及如何应用SystemView补丁以适应FreeRTOS的源码。内容包括任务调度过程中的跟踪、堆栈管理、中断处理和SystemView的数据获取方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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”
#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 文件

在这里插入图片描述
在这里插入图片描述

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 即可
在这里插入图片描述

  • 添加想要测量的中断
  1. 添加描述符
    在这里插入图片描述

在这里插入图片描述
SysTick_IRQn 为15, 所以 TIM8_TRG_COM_TIM14_IRQn 为 16 + 45 = 61
2. 中断服务函数中添加trace
在这里插入图片描述

在这里插入图片描述

  • 测量代码段运行时长
    在这里插入图片描述
    在这里插入图片描述

systemView 溢出

  • 提高 jlink 速度
    在这里插入图片描述

  • 增大RAM缓冲区
    在这里插入图片描述

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

<think>好的,我需要帮助用户找到关于HAL库和FreeRTOS的学习资料或笔记。首先,用户提供的引用内容提到了FreeRTOS的移植步骤、源码结构以及中断处理机制,这些可能都是用户关心的重点。接下来,我应该整理这些引用中的信息,并结合常见的HAL库和FreeRTOS学习资源给出建议。 首先,用户提到的引用[2]和[3]都涉及FreeRTOS在STM32上的移植,特别是HAL库的集成。这说明用户可能在STM32平台上开发,需要具体的移植步骤和验证方法。引用[4]详细介绍了ARM Cortex-M的中断机制,这对于理解FreeRTOS任务调度和中断处理非常重要。 接下来,我应该推荐用户查阅官方文档,比如AWS FreeRTOS的官方指南,这通常是最权威的资料。然后,考虑到用户可能喜欢实践教程,可以建议参考社区博客或GitHub上的项目,特别是那些结合HAL库和FreeRTOS的示例代码。此外,书籍推荐也是必要的,比如专门讲解FreeRTOS和STM32开发的书籍。 用户还可能对实际应用案例感兴趣,所以需要提及实际项目中的应用场景,如物联网设备,并结合引用[1]中提到的AWS FreeRTOS的应用。最后,确保回答结构清晰,分点列出学习路径、推荐资料、移植指南和深入理解部分,方便用户逐步学习。 需要注意的是,所有提到的参考资料要正确标注引用标识,并检查是否有遗漏的重要资源。同时,生成的相关问题要围绕用户可能的后续疑问,比如移植步骤、中断配置、学习资源推荐等,帮助用户进一步探索。</think>### HAL库与FreeRTOS学习资源指南 #### 一、学习路径建议 1. **HAL库基础** - 学习STM32CubeMX工具配置外设,生成HAL库初始化代码,理解HAL的模块化设计(如GPIO、UART、ADC等驱动接口)。 - 关键文档:ST官方《STM32CubeMX用户手册》和《HAL库API参考手册》[^2]。 2. **FreeRTOS核心概念** - 掌握任务管理(`xTaskCreate`)、队列(`xQueueCreate`)、信号量(`xSemaphoreCreateBinary`)和中断服务例程(ISR)的集成方法。 - 重点理解优先级反转问题及互斥量(Mutex)的解决方案[^1]。 3. **HAL与FreeRTOS结合** - 在HAL库的中断回调函数中调用FreeRTOS的API(如`xQueueSendFromISR`),需注意中断优先级与FreeRTOS内核配置的兼容性[^4]。 --- #### 二、推荐学习资料 1. **官方资源** - **AWS FreeRTOS开发者指南**:涵盖任务调度、内存管理及安全通信(如MQTT)。 - **STM32CubeIDE集成开发环境**:内置FreeRTOS模板项目,支持一键生成带RTOS的工程框架。 2. **实战教程** - **移植FreeRTOS到HAL库**:引用[3]中提到的源码移植步骤,需重点关注`FreeRTOSConfig.h`配置文件中的堆大小(`configTOTAL_HEAP_SIZE`)和时钟源(`configSYSTICK_CLOCK_HZ`)设置。 - 示例代码片段: ```c // FreeRTOS任务与HAL中断协同 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; xQueueSendFromISR(xUartQueue, &received_data, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } ``` 3. **书籍与社区** - 《Mastering STM32》第二版:第12章详解FreeRTOS与HAL库的集成案例。 - STM32中文社区论坛:搜索“HAL+FreeRTOS”关键词,可找到实际项目中的死锁调试记录。 --- #### 三、关键配置注意事项 | 配置项 | 说明 | |-------------------------|----------------------------------------------------------------------| | `configUSE_PREEMPTION` | 设置为1启用抢占式调度,确保高优先级任务及时响应 | | `configMAX_SYSCALL_INTERRUPT_PRIORITY` | 需与NVIC中断优先级分组匹配,避免内核API在中断中被阻塞[^4] | | `configTICK_RATE_HZ` | 通常设置为1000Hz,对应1ms时间片,影响任务延迟精度[^3] | --- #### 四、进阶学习方向 1. **动态内存分配优化** - 替换默认的`heap_4.c`方案,使用内存池(Memory Pool)减少碎片,适用于长期运行的嵌入式系统。 2. **低功耗模式集成** - 在FreeRTOS空闲任务中调用HAL库的`HAL_SuspendTick()`函数,实现STM32的STOP模式节能。 3. **调试工具链** - 使用SEGGER SystemView可视化分析任务调度时序,定位优先级冲突问题。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值