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
  • PasteSpider是什麼? 一款使用.net編寫的開源的Linux容器部署助手,支持一鍵發佈,平滑升級,自動伸縮, Key-Value配置,項目網關,環境隔離,運行報表,差量升級,私有倉庫,集群部署,版本管理等! 30分鐘上手,讓開發也可以很容易的學會在linux上部署你得項目! [從需求角度介 ...
  • SQLSugar是什麼 **1. 輕量級ORM框架,專為.NET CORE開發人員設計,它提供了簡單、高效的方式來處理資料庫操作,使開發人員能夠更輕鬆地與資料庫進行交互 2. 簡化資料庫操作和數據訪問,允許開發人員在C#代碼中直接操作資料庫,而不需要編寫複雜的SQL語句 3. 支持多種資料庫,包括但 ...
  • 在C#中,經常會有一些耗時較長的CPU密集型運算,因為如果直接在UI線程執行這樣的運算就會出現UI不響應的問題。解決這類問題的主要途徑是使用多線程,啟動一個後臺線程,把運算操作放在這個後臺線程中完成。但是原生介面的線程操作有一些難度,如果要更進一步的去完成線程間的通訊就會難上加難。 因此,.NET類 ...
  • 一:背景 1. 講故事 前些天有位朋友在微信上丟了一個崩潰的dump給我,讓我幫忙看下為什麼出現了崩潰,在 Windows 的事件查看器上顯示的是經典的 訪問違例 ,即 c0000005 錯誤碼,不管怎麼說有dump就可以上windbg開幹了。 二:WinDbg 分析 1. 程式為誰崩潰了 在 Wi ...
  • CSharpe中的IO+NPOI+序列化 文件文件夾操作 學習一下常見的文件、文件夾的操作。 什麼是IO流? I:就是input O:就是output,故稱:輸入輸出流 將數據讀入記憶體或者記憶體輸出的過程。 常見的IO流操作,一般說的是[記憶體]與[磁碟]之間的輸入輸出。 作用 持久化數據,保證數據不再 ...
  • C#.NET與JAVA互通之MD5哈希V2024 配套視頻: 要點: 1.計算MD5時,SDK自帶的計算哈希(ComputeHash)方法,輸入輸出參數都是byte數組。就涉及到字元串轉byte數組轉換時,編碼選擇的問題。 2.輸入參數,字元串轉byte數組時,編碼雙方要統一,一般為:UTF-8。 ...
  • CodeWF.EventBus,一款靈活的事件匯流排庫,實現模塊間解耦通信。支持多種.NET項目類型,如WPF、WinForms、ASP.NET Core等。採用簡潔設計,輕鬆實現事件的發佈與訂閱。通過有序的消息處理,確保事件得到妥善處理。簡化您的代碼,提升系統可維護性。 ...
  • 一、基本的.NET框架概念 .NET框架是一個由微軟開發的軟體開發平臺,它提供了一個運行時環境(CLR - Common Language Runtime)和一套豐富的類庫(FCL - Framework Class Library)。CLR負責管理代碼的執行,而FCL則提供了大量預先編寫好的代碼, ...
  • 本章將和大家分享在ASP.NET Core中如何使用高級客戶端NEST來操作我們的Elasticsearch。 NEST是一個高級別的Elasticsearch .NET客戶端,它仍然非常接近原始Elasticsearch API的映射。所有的請求和響應都是通過類型來暴露的,這使得它非常適合快速上手 ...
  • 參考delphi的代碼更改為C# Delphi 檢測密碼強度 規則(仿 google) 仿 google 評分規則 一、密碼長度: 5 分: 小於等於 4 個字元 10 分: 5 到 7 字元 25 分: 大於等於 8 個字元 二、字母: 0 分: 沒有字母 10 分: 全都是小(大)寫字母 20 ...