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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...