FreeRTOS教程10 低功耗

来源:https://www.cnblogs.com/lc-guo/p/18073911
-Advertisement-
Play Games

本文主要學習 FreeRTOS 低功耗的相關知識,包括HAL 庫基礎時鐘、FreeRTOS 基礎時鐘、低功耗處理和 Tickless 模式等知識 ...


1、準備材料

正點原子stm32f407探索者開發板V2.4

STM32CubeMX軟體(Version 6.10.0

Keil µVision5 IDE(MDK-Arm

野火DAP模擬器

XCOM V2.6串口助手

2、學習目標

本文主要學習 FreeRTOS 低功耗的相關知識,包括HAL 庫基礎時鐘、FreeRTOS 基礎時鐘、低功耗處理和 Tickless 模式等知識

3、前提知識

3.1、HAL 庫基礎時鐘

當我們使用 STM32CubeMX 軟體配置一個基本的工程時,往往需要首先在 Pinout & Configuration 頁面 RCC 中配置 HSE 和 LSE ,然後在 SYS 中配置 Debug 和 Timebase Source,這些都是必不可少的配置步驟,其中 Timebase Source 可以選擇預設的 SysTick ,也可以選擇任何一個定時器外設

3.1.1、使用 SysTick 定時器

學習 STM32 HAL 庫開發,在 SYS 中配置 Timebase Source 時,一般將時基源保持預設的 SysTick 即可,那麼這個預設的 SysTick 是如何被初始化以及使用呢?

3.1.1.1、工作原理

打開 “STM32CubeMX教程1 工程建立” 文章配置的 STM32 空工程,找到 main.c 文件中的 main() 主函數,SysTick 在主函數第一個被執行的函數HAL_Init() 中得到初始化,具體如下圖所示

其中滴答定時器頻率 uwTickFreq 參數預設為 HAL_TICK_FREQ_DEFAULT(1KHZ) ,當然也可以根據需要修改為 10HZ 和 100HZ,如下述枚舉類型定義

typedef enum
{
  HAL_TICK_FREQ_10HZ         = 100U,
  HAL_TICK_FREQ_100HZ        = 10U,
  HAL_TICK_FREQ_1KHZ         = 1U,
  HAL_TICK_FREQ_DEFAULT      = HAL_TICK_FREQ_1KHZ
} HAL_TickFreqTypeDef;

當初始化完畢之後,滴答定時器就會以固定頻率發生中斷,然後進入中斷回調函數 SysTick_Handler() 中,滴答定時器中斷預設就會開啟

3.1.1.2、中斷處理

在 STM32CubeMX 軟體的 NVIC 管理頁面,可以發現預設開啟的滴答定時器中斷 Time base: System tick timer ,在軟體上該中斷不可關閉,但是可以設置中斷優先順序,具體如下圖所示

在 stm32f4xx_it.c 文件中可以找到滴答定時器的回調函數 SysTick_Handler() ,其只調用了 HAL_IncTick() 函數,該函數只做了一件事情,就是每次發生滴答定時器中斷的時候,將一個名為 uwTick 的全局變數加 1 ( uwTickFreq 參數預設為1),具體如下所示

根據這個全局變數的值我們就可以做一些延時的工作,比如常用到的 HAL_Delay() 延時函數就是通過滴答定時器中斷來實現的,具體如下所述

/**
  * @brief  HAL 庫延時函數
  * @param  Delay:延時時間,單位為ms
  * @retval None
  */
__weak void HAL_Delay(uint32_t Delay)
{
	uint32_t tickstart = HAL_GetTick();
	uint32_t wait = Delay;
	
	/* 最少等待一個頻率時間 */
	if (wait < HAL_MAX_DELAY)
	{
		wait += (uint32_t)(uwTickFreq);
	}
	/* 空迴圈延時等待 */
	while((HAL_GetTick() - tickstart) < wait)
	{
	}
}

另外還有 HAL_SuspendTick() 和 HAL_ResumeTick() 兩個控制滴答定時器中斷停止和啟動的函數,具體如下所述

/**
  * @brief  掛起滴答定時器中斷
  * @retval None
  */
__weak void HAL_SuspendTick(void)
{
  /* 禁用 SysTick 中斷 */
  SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;
}

/**
  * @brief  恢復掛起的滴答定時器中斷
  * @retval None
  */
__weak void HAL_ResumeTick(void)
{
  /* 使能 SysTick 中斷 */
  SysTick->CTRL  |= SysTick_CTRL_TICKINT_Msk;
}

3.1.2、使用其他定時器

當 SysTick 被其他軟體使用時(比如本系列教程的 FreeRTOS),STM32 還可以選擇任何一個定時器外設作為其 HAL 庫的時基源,比如選擇基礎定時器 TIM6

3.1.2.1、工作原理

當在 STM32CubeMX 軟體中配置 SYS 中的 Timebase Source 為 TIM6 然後生成工程之後,與 “3.1.1、使用 SysTick 定時器” 小節不同的是,其首先會在 Core 文件夾下多出一個名為 stm32f4xx_hal_timebase_tim.c 的文件,該文件中涉及了所有關於 TIM6 作為 HAL 庫系統嘀嗒定時器的配置程式,使用 TIM6 作為 HAL 庫系統嘀嗒定時器的初始化步驟如下圖所示

上圖內容其實就是將基礎定時器 TIM6 初始化為一個周期為 1ms 的定時器,並且啟動其周期中斷回調,如果對上述代碼不瞭解可以閱讀 “STM32CubeMX教程5 TIM 定時器概述及基本定時器” 實驗

3.1.2.2、中斷處理

當選擇基礎定時器 TIM6 作為 SysTick 時,在STM32CubeMX軟體的 NVIC 管理中 TIM6 的中斷就會被強制打開並且軟體內不可關閉,但是同樣可以修改優先順序,如下圖所示

同樣可以在 stm32f4xx_it.c 文件中可以找到 TIM6 的中斷回調函數 TIM6_DAC_IRQHandler() ,該函數調用了定時器的統一中斷處理函數 HAL_TIM_IRQHandler() ,該函數根據使用的不同定時器功能最終調用不同的中斷回調函數,這裡讀者只需要知道其調用了定時器周期回調函數 HAL_TIM_PeriodElapsedCallback() 即可,該函數由 STM32CubeMX 軟體在 main.c 文件中自動生成,具體如下所示

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */

  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM6) {
    HAL_IncTick();
  }
  /* USER CODE BEGIN Callback 1 */

  /* USER CODE END Callback 1 */
}

從函數體內內容可以看出其原理與 “3.1.1.2、中斷處理” 小節所敘述的一致,故此處不再贅述

3.2、FreeRTOS 基礎時鐘

STM32CubeMX 軟體配置使用 FreeRTOS 時,預設將 SysTick 滴答定時器分配給 FreeRTOS 使用,因此如果 HAL 庫的時基源也為 SysTick 時,在生成工程代碼時軟體就會警告用戶:“當使用 RTOS 時,強烈建議使用除 Systick 之外的 HAL 時基源,可以從 SYS 下的 Pinout 選項卡更改 HAL 時基源”,具體如下圖所示

因此在 STM32 需要使用 FreeRTOS 時,一般將 SysTick 分配給 FreeRTOS 使用,而 HAL 庫的時基源一般選擇除 SysTick 之外的定時器外設,同時如果用戶明確自己不需要使用 HAL 庫的 HAL_Delay() 延時函數,則可以關閉 HAL 庫的時基源

3.2.1、工作原理

FreeRTOS 的 SysTick 系統時基源是在 vPortSetupTimerInterrupt() 函數中被初始化的,在該函數中有一個名為 configUSE_TICKLESS_IDLE 參數用於設置是否使用 Tickless 模式,這是 FreeRTOS 中提供的一種低功耗模式,將在後面小節介紹,其對 SysTick 的初始化是直接對 SysTick 的寄存器進行操作的,其調用流程如下圖所示

SysTick 的寄存器可以閱讀 Arm® Cortex®-M4 Processor Technical Reference Manual手冊 “4.1 System control registers” 小節,如下圖所示

3.2.2、中斷處理

當將 SysTick 分配給 FreeRTOS 初始化並開啟對應中斷之後,SysTick 的中斷會被定義在 cmsis_os2.c 文件中(從 FreeRTOS_v10.3.1 之後),該函數清除了中斷標誌然後調用了 FreeRTOS 定義的硬體介面文件中的 xPortSysTickHandler() 函數,在 xPortSysTickHandler() 函數中增加了 RTOS 滴答定時器計數量,然後掛起 PednSV 中斷,請求上下文切換,具體如下所述

根據上面的分析我們知道了一件關於 FreeRTOS 很重要的事情,也就是:FreeRTOS 的任務調度發起是在系統滴答定時器中斷中發起的,然後真正進行上下文切換處理是在 PendSV 中斷中執行的

3.3、低功耗處理

3.3.1、睡眠、停止和待機模式

在 “STM32CubeMX教程25 PWR 電源管理 - 睡眠、停止和待機模式” 文章中曾經介紹了關於 STM32 電源管理的睡眠、停止和待機三種低功耗模式,在一個由 FreeRTOS 管理的系統中,一般只使用其中的睡眠模式即可,因為停止和待機模式的喚醒條件相對較為苛刻,感興趣的讀者請自行閱讀上述文章

3.3.2、低功耗思路

在一個 FreeRTOS 管理的多任務系統中,當所有任務處理完畢進入阻塞狀態等待下次處理時機時,空閑任務會一直執行,如果同時使能了 configUSE_IDLE_HOOK 參數,則每當處理器將要進入空閑任務時,就會先進入空閑任務鉤子函數中

因此我們可以在空閑任務鉤子函數中設置處理器進入睡眠模式,但是同時也會存在一個問題,就是每次滴答定時器中斷都會將處理器喚醒,這樣其運行時序圖應該如下圖所示

3.3.3、Tickless 模式

上述低功耗思路中存在的一個問題:“每次滴答定時器中斷都會將處理器喚醒” ,FreeRTOS 提供了一個 Tickless 模式,當處理器空閑時會一直處於睡眠狀態,然後在任務即將退出阻塞狀態之前處理器提前被喚醒,理想的低功耗模式應該如下圖所示

要使用 Tickless 模式只需要啟用 configUSE_TICKLESS_IDLE 參數即可,該參數可以通過 STM32CubeMX 軟體設置,有三個可以配置的選項,選擇 Built in functionality enabled 對應的參數值為 1 ,表示使用 FreeRTOS 內建的函數實現 Tickless 低功耗功能,選擇 User defined functionality enabled 則對應的參數值為 2 ,表示使用用戶自定義的函數實現 Tickless 低功耗功能,一般選擇使用 FreeRTOS 現成的函數來實現 Tickless 低功耗功能,如下圖所示

3.3.3.1、工作原理

當啟用 Tickless 之後,系統滿足以下兩點時就會自動進入睡眠模式

  1. 空閑任務正在運行
  2. 可運行低功耗的時間大於參數 configEXPECTED_IDLE_TIME_BEFORE_SLEEP 設定值時(預設為2)

用戶需要註意的是進入睡眠的時間有最大值 xMaximumPossibleSuppressedTicks 限制,該變數在設置滴答定時器中斷 vPortSetupTimerInterrupt() 函數中被計算,當 MCU 頻率為168MHz,FreeRTOS 頻率為 1000Hz 時,該值為 99 ,也即單次最長進入睡眠時間的最大值為 99 個節拍,具體如下所示

3.3.3.2、vPortSuppressTicksAndSleep() 函數詳解

vPortSuppressTicksAndSleep() 是 Tickless 模式實現的具體函數,該函數會在啟用 Tickless 模式後在空閑任務中被調用,具體可以參考 “freeRTOS 低功耗模式 和 空閑任務” 文章

4、實驗一:Tickless 模式的使用

4.1、實驗目標

  1. 創建任務 Task_Main,在任務中實現 GREEN_LED 和 RED_LED 的閃爍程式
  2. 啟用/關閉 Tickless 模式,對比兩種不同情況下開發板的工作電流

4.2、CubeMX相關配置

首先讀者應按照 "FreeRTOS教程1 基礎知識" 章節配置一個可以正常編譯通過的 FreeRTOS 空工程,然後在此空工程的基礎上增加本實驗所提出的要求

本實驗需要初始化開發板上 GREEN_LED 和 RED_LED 兩個 LED 燈作為顯示,具體配置步驟請閱讀“STM32CubeMX教程2 GPIO輸出 - 點亮LED燈”,註意雖開發板不同但配置原理一致,如下圖所示

單擊 Middleware and Software Packs/FREERTOS ,在 Configuration 中單擊 Tasks and Queues 選項卡,雙擊預設任務修改其參數,如下所示

然後在 Configuration 中單擊 Config parameters 選項卡,在 Kernel settings 中找到 USE_TICKLESS_IDLE 參數,將其設置為 Disabled 或者 Built in functionality enabled,進行對比實驗

最後配置 Clock Configuration 和 Project Manager 兩個頁面,接下來直接單擊 GENERATE CODE 按鈕生成工程代碼即可

4.3、添加其他必要代碼

首先實現任務 Task_Main 使其每隔 500ms 改變一次 GREEN_LED 和 RED_LED 的狀態,具體如下所述

void AppTask_Main(void *argument)
{
	/* USER CODE BEGIN AppTask_Main */
	/* Infinite loop */
	for(;;)
	{
		HAL_GPIO_TogglePin(GREEN_LED_GPIO_Port, GREEN_LED_Pin);
		HAL_GPIO_TogglePin(RED_LED_GPIO_Port, RED_LED_Pin);
		vTaskDelay(pdMS_TO_TICKS(500));
	}
	/* USER CODE END AppTask_Main */
}

然後再進入睡眠模式之前關閉系統滴答定時器,在退出睡眠模式之後開啟系統滴答定時器,具體如下所述

__weak void PreSleepProcessing(uint32_t ulExpectedIdleTime)
{
/* place for user code */
	HAL_SuspendTick();
}

__weak void PostSleepProcessing(uint32_t ulExpectedIdleTime)
{
/* place for user code */
	HAL_ResumeTick();
}

4.4、燒錄驗證

在開啟 Tickless 和關閉 Tickless 兩種模式下讀者可以自行測試開發板工作電流,對比開啟和關閉兩種模式下工作電流的變化

參考資料

STM32Cube高效開發教程(基礎篇)

Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 從.Net Core 開始,.Net 平臺內置了一個輕量,易用的 IOC 的框架,供我們在應用程式中使用,社區內還有很多強大的第三方的依賴註入框架如: Autofac DryIOC Grace LightInject Lamar Stashbox Simple Injector 內置的依賴註入 ...
  • 新建項目 在建項目的時候要註意,選擇Windows 窗體應用(.NET Framework)或者wpf項目,然後打開 安裝包 在解決方案資源管理器中,選擇剛纔的項目名,滑鼠右鍵找到並打開管理NuGet包,然後在瀏覽選項卡裡,輸入一個Costura.Fody並查找,有就點安裝,安裝前需要註意選擇支持的 ...
  • TagProvider [LogProperties] 與 [LogPropertyIgnore] 如果用在DTO不存在任何問題,如果用在Domain實體上,可能有點混亂。 您可能不希望因日誌記錄問題而使您的域模型變得混亂。對於這種情況,可以使用[TagProvider]屬性來豐富日誌。 我們仍然使 ...
  • 概述:本指南詳細解釋了在C#中如何在創建控制項的線程以外的線程中訪問GUI。基礎功能使用`Control.Invoke`(WinForms)或`Dispatcher.Invoke`(WPF),高級功能則利用`SynchronizationContext`實現線程間通信,確保代碼清晰可讀。 在C#中,要 ...
  • 概述:.NET應用程式以管理員身份運行的方法包括修改清單文件、項目文件,或在運行時動態請求管理員許可權。清單文件和項目文件通過聲明UAC請求,而動態請求管理員許可權則在程式啟動時檢查並重新啟動。選擇適當的方法取決於項目需求和配置。 在.NET應用程式中強制以管理員身份運行,可以通過清單文件、項目文件或者 ...
  • Nginx的location匹配順序是Nginx配置中非常核心且重要的概念,它決定了Nginx如何處理進入伺服器的請求。理解location匹配順序不僅有助於優化Nginx的性能,還能確保網站或應用的正確運行。下麵將詳細闡述Nginx的location匹配順序,並通過實例加以說明。 Nginx lo ...
  • 來自chatGPT 在CentOS 7.9系統上安裝Docker,你可以遵循以下步驟: 更新你的系統:首先,確保你的系統是最新的。這可以通過運行下麵的命令來實現: sudo yum update 安裝必要的包:為了使得yum源支持https,你需要安裝幾個必要的包: sudo yum install ...
  • 哈嘍大家好,我是鹹魚。 今天分享一個在壓測過程中遇到的問題,當時排查這個問題費了我們好大的勁,所以我覺得有必要寫一篇文章來記錄一下。 問題出現 周末在進行壓測的時候,測試和開發的同事反映壓測有問題,請求打到 A 服務上被拒絕了。 我們登錄伺服器查看 A 服務的日誌,發現頻繁地報 Too many o ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...