深入理解_FreeRTOS的內部實現(2)

1.事件組

事件組結構體:

事件組 “不關中斷” 的核心邏輯


事件組操作時,優先選擇 “關調度器” 而非 “關中斷” ,原因和實現如下:

關調度器(而非關中斷)
FreeRTOS 提供 taskENTER_CRITICAL()(關調度器 + 按需關中斷,取決于 configKERNEL_INTERRUPT_PRIORITY 配置 )或 vTaskSuspendAll()(僅關調度器 ),來保護事件組的任務級操作(如任務調用 xEventGroupSetBits )。
關調度器后,中斷仍可正常觸發(硬件中斷不受影響),但任務無法切換,保證事件組操作的原子性。
中斷里的事件組操作
中斷函數中不能直接修改事件組(因為中斷設置事件組的時候有可能喚醒多個滿足條件的任務導致中斷時間不確定),而是通過 xEventGroupSetBitsFromISR 觸發 “守護任務”(daemon task) 來異步處理:
中斷里向守護任務的隊列發消息,請求設置事件位
守護任務(任務上下文)真正執行 xEventGroupSetBits,此時用關調度器保證安全。

事件組創建流程:

開始↓
調用 xEventGroupCreate() 函數↓
動態分配事件組內存(若支持靜態分配,則使用 xEventGroupCreateStatic())↓
成功? ——→ 是 ——→ 初始化事件組狀態(默認所有位為0)↓           ↓否          返回事件組句柄↓           ↓
返回 NULL    結束

設置事件位流程:

開始↓
[上下文判斷] → 任務中調用 xEventGroupSetBits() / 中斷中調用 xEventGroupSetBitsFromISR()↓
設置指定的事件位(按位或操作更新組值)(操作EventGroup_t 結構體)↓
檢查是否有任務因等待這些位被阻塞?↓
是 ——→ 解除阻塞符合條件的任務↓        ↓否      觸發上下文切換(若在任務中)或標記延遲調度(若在中斷中)↓        ↓
結束 ←←←←←←

等待事件位流程:

開始↓
調用 xEventGroupWaitBits(),傳入等待的位掩碼、清除標志、阻塞時間等參數↓
檢查當前事件位是否滿足條件:是否所有指定位被置位?(邏輯AND)或任意指定位被置位?(邏輯OR)↓
滿足? ——→ 是 ——→ 根據參數清除事件位↓           ↓否          返回當前事件位值↓           ↓
進入阻塞狀態(若阻塞時間 > 0),釋放CPU↓           ↓
等待事件被設置或超時 →→→ 超時? ——→ 是 ——→ 返回超時狀態↓                               ↓否(事件觸發)                    ↓↓                               ↓
返回觸發后的事件位值              結束

2.任務通知

FreeRTOS 任務通知是一種輕量級任務間通信機制,用于任務或中斷向指定任務發送事件或數據:
一、基本概念
核心原理:每個任務的控制塊(TCB)中內置通知相關成員(如 ulNotifiedValue 存儲通知值 ),無需額外創建通信結構體,可直接向目標任務發送 “通知”。
啟用條件:需在 FreeRTOSConfig.h 中定義 configUSE_TASK_NOTIFICATIONS = 1 開啟功能。
二、優勢與局限
優勢
高效性:無需額外結構體,操作直接,比隊列、信號量、事件組更快,節省內存(每個任務僅額外占 8 字節存儲通知狀態和值 )。
靈活更新:支持多種通知值更新方式(如覆蓋、保留原值、置位、遞增等 ),適配不同場景。
局限
單播特性:僅能指定一個任務接收通知,無法廣播給多任務。
數據緩存限制:任務控制塊只有一個通知值,無法緩存多個數據,發送方也不能因發送受阻進入阻塞。
中斷交互限制:可從中斷發通知給任務,但無法給中斷發通知(中斷無任務結構體 )。

發通知流程:

開始↓
關閉中斷 (taskENTER_CRITICAL)↓
目標任務存在?——否——→ 開啟中斷 ——→ 返回失敗 ——→ 結束↓是
目標任務在等待通知?↓
是 ——→ 設置通知值↓從延遲列表移除目標任務↓將目標任務設為就緒狀態↓目標任務優先級更高?——是——→ 開啟中斷 ——→ 設置需要上下文切換標志↓否                              ↓開啟中斷 ←————————————————————————— 觸發任務調度 (portYIELD)↓                              ↓返回成功 ←————————————————————————— 返回成功↓                              ↓結束                           結束↓否
設置通知值(累加或覆蓋)↓
開啟中斷 (taskEXIT_CRITICAL)↓
返回成功↓
結束

等待通知流程:

開始↓
關閉中斷 (taskENTER_CRITICAL)↓
檢查是否有待處理的通知↓
有通知? ——是——→ 清除/遞減通知值 ——→ 開啟中斷 ——→ 返回通知值 ——→ 結束↓否
等待時間為0? ——是——→ 開啟中斷 ——→ 返回0 ——→ 結束↓否
將任務添加到延遲列表↓
設置任務狀態為阻塞↓
開啟中斷 (taskEXIT_CRITICAL)↓
觸發任務調度 (portYIELD)↓
其他任務運行...↓
收到通知或超時?↓
關閉中斷 (taskENTER_CRITICAL)↓
從延遲列表移除任務↓
設置任務為就緒狀態↓
開啟中斷 (taskEXIT_CRITICAL)↓
返回通知值(成功)或0(超時)↓
結束

3.軟件定時器

軟件定時器的核心機制就是時間到達預設值后自動觸發回調函數執行

FreeRTOS 軟件定時器的核心是基于系統 tick 的有序鏈表管理低優先級檢測任務,通過回調函數實現定時事件處理。

內部實現:

一、核心數據結構

1. 定時器控制塊(Timer_t

typedef struct tmrTimerControl {const char *pcTimerName;           // 定時器名稱(調試用)ListItem_t xTimerListItem;         // 用于鏈表管理的節點TickType_t xTimerPeriodInTicks;    // 定時周期(tick數)UBaseType_t uxAutoReload;          // 是否自動重載(周期/單次模式)void (*pxCallbackFunction)(TimerHandle_t xTimer); // 回調函數指針void *pvTimerID;                   // 定時器ID(用戶數據)TickType_t xExpireTime;            // 下次超時的絕對tick時間// ...其他內部字段
} Timer_t;

2. 定時器列表(按超時時間排序)

static List_t xActiveTimerList1;  // 活躍定時器列表1
static List_t xActiveTimerList2;  // 活躍定時器列表2(用于溢出處理)

二、實現機制

1.定時器任務(prvTimerTask

  • 核心職責
    • 優先級通常設為較低值(如configTIMER_TASK_PRIORITY),避免影響關鍵任務。
    • 周期性檢查定時器列表,處理超時定時器。

執行流程:

void prvTimerTask(void *pvParameters) {for (;;) {// 1. 進入臨界區,防止任務調度干擾taskENTER_CRITICAL();// 2. 獲取當前系統tickTickType_t xTimeNow = xTaskGetTickCount();// 3. 檢查活躍列表頭部定時器是否超時while (listLIST_IS_EMPTY(&xActiveTimerList1) == pdFALSE) {Timer_t *pxTimer = (Timer_t *)listGET_OWNER_OF_HEAD_ENTRY(&xActiveTimerList1);if (pxTimer->xExpireTime <= xTimeNow) {// 4. 移除超時定時器(void)uxListRemove(&pxTimer->xTimerListItem);// 5. 退出臨界區,執行回調(避免長時間持有鎖)taskEXIT_CRITICAL();pxTimer->pxCallbackFunction((TimerHandle_t)pxTimer);taskENTER_CRITICAL();// 6. 若為周期模式,重新計算超時時間并加入列表if (pxTimer->uxAutoReload == pdTRUE) {pxTimer->xExpireTime += pxTimer->xTimerPeriodInTicks;vListInsertInOrder(&xActiveTimerList1, &pxTimer->xTimerListItem);}} else {break; // 后續定時器未超時,退出循環}}// 7. 退出臨界區,進入阻塞狀態直到下一個定時器超時或被喚醒taskEXIT_CRITICAL();vTaskDelayUntil(&xTimeNow, pdMS_TO_TICKS(10)); // 10ms檢查一次}
}

2. 定時器添加 / 刪除機制


添加定時器(xTimerStart()):
計算超時時間(當前tick + 定時周期)。
將定時器按超時時間插入有序鏈表(保證頭部為最近超時的定時器)。
若新定時器成為鏈表頭部,喚醒定時器任務重新計算阻塞時間。
刪除定時器(xTimerDelete()):
從活躍鏈表中移除定時器節點。
標記定時器為無效狀態,防止重復操作。

4.兩套API

FreeRTOS 設計兩套 API 的核心目標是保證中斷處理的實時性和系統穩定性:

任務上下文 API:面向普通任務場景,允許阻塞和直接調度,簡化編程。
中斷安全 API:面向中斷場景,避免長時間關中斷,通過參數間接控制調度,確保中斷快速響應

對比維度任務上下文 API(常規版本)中斷安全 API(FromISR 版本)
命名規則無特殊后綴(如?xQueueSendvTaskDelay后綴為?FromISR(如?xQueueSendFromISRvTaskDelayFromISR
調用場景僅能在任務函數中調用,禁止在中斷服務程序(ISR)中使用專門用于 ISR 或異常處理程序,可在中斷環境中安全調用
中斷狀態處理無需顯式處理中斷狀態(任務上下文默認開中斷)需保存并恢復中斷狀態(如?portSET_INTERRUPT_MASK_FROM_ISR),避免破壞 ISR 上下文
上下文切換觸發直接調用內核調度器(如?taskYIELD),主動觸發切換通過?pxHigherPriorityTaskWoken?參數標記是否需切換,由 ISR 決定是否調用?portYIELD_FROM_ISR
關鍵參數差異常規參數(如隊列句柄、數據指針、超時時間)部分函數增加?BaseType_t* pxHigherPriorityTaskWoken?參數,用于標記高優先級任務是否被喚醒
臨界區保護機制使用?taskENTER_CRITICAL()?和?taskEXIT_CRITICAL()使用?portSET_INTERRUPT_MASK_FROM_ISR()?和?portCLEAR_INTERRUPT_MASK_FROM_ISR(),適配中斷環境
返回值含義直接返回操作結果(如?pdPASSpdFAILpdTRUE除返回操作結果外,需通過?pxHigherPriorityTaskWoken?間接傳遞調度需求
阻塞特性支持阻塞(如等待隊列或信號量時可指定超時時間)不支持阻塞(中斷場景需快速返回,超時參數無效或被忽略)
典型函數示例xQueueSendxSemaphoreTakevTaskDelayvTaskSuspendxQueueSendFromISRxSemaphoreTakeFromISRvTaskDelayFromISRvTaskSuspendFromISR
內核調度介入方式函數內部主動觸發調度(如任務切換)需由 ISR 根據函數返回結果決定是否觸發調度
對系統實時性的影響可能因阻塞操作降低實時性(任務上下文允許)無阻塞操作,中斷處理更高效,保證系統實時響應

FreeRTOS 在中斷中檢測到高優先級任務就緒時,會立即請求切換,但實際切換發生在中斷返回后的安全時機(不是立即切換)。這一設計在保證中斷處理完整性的同時,確保高優先級任務以最小延遲獲得 CPU 資源

中斷API切換高優先級任務流程:

5.FreeRTOS里的兩類中斷

特性系統中斷用戶中斷
優先級范圍高優先級(通常 0~4)低優先級(通常 5~15,取決于配置)
是否可調度否(不可搶占其他系統中斷)是(可被系統中斷搶占)
能否調用 FreeRTOS API僅能調用帶FromISR后綴的 API可調用所有 API(需注意上下文)
對任務調度的影響可能直接觸發任務切換(如 PendSV、SysTick)通過pxHigherPriorityTaskWoken標記間接觸發切換
典型示例PendSV、SysTick、HardFault、NMI外設中斷(如 UART、GPIO、定時器)

顯然在 FreeRTOS 中,任務調度器依賴的定時器中斷(通常是 SysTick 中斷 )和 PendSV 中斷,優先級配置是刻意設計為低優先級,當我們關閉中斷時,任務也不再調度

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/86711.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/86711.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/86711.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【圖論題典】Swift 解 LeetCode 最小高度樹:中心剝離法詳解

文章目錄 摘要描述題解答案題解代碼分析思路來源&#xff1a;樹的“中心剝離法”構造鄰接表和度數組循環剝葉子終止條件 示例測試及結果時間復雜度空間復雜度總結 摘要 樹是一種重要的數據結構&#xff0c;在許多應用里&#xff0c;我們希望選一個根&#xff0c;讓這棵樹的高度…

Docker的介紹與安裝

? Docker 對初學者的簡單解釋和應用場景 1.什么是 Docker&#xff1f; 簡單來說&#xff0c;Docker 就像一個“裝箱子”的工具&#xff0c;這個箱子叫做“容器”。 你寫的程序和它運行需要的環境&#xff08;比如操作系統、軟件、工具&#xff09;都裝進一個箱子里。這個箱…

引導相機:工業自動化的智能之眼,賦能制造業高效升級

在工業自動化浪潮中&#xff0c;精準的視覺引導技術正成為生產效率躍升的關鍵。作為遷移科技——一家成立于2017年、專注于3D工業相機和3D視覺系統的領先供應商&#xff0c;我們深知"引導相機"的核心價值&#xff1a;它不僅是一個硬件設備&#xff0c;更是連接物理世…

智能相機如何重塑工業自動化?遷移科技3D視覺系統的場景革命

從硬件參數到產業價值&#xff0c;解碼高精度視覺系統的落地邏輯 一、工業視覺的“智慧之眼” 遷移科技深耕3D工業相機領域&#xff0c;以“穩定、易用、高回報”為核心理念&#xff0c;打造覆蓋硬件、算法、軟件的全棧式視覺系統。成立6年累計融資數億元的背后&#xff0c;是…

【數據挖掘】聚類算法學習—K-Means

K-Means K-Means是一種經典的無監督學習算法&#xff0c;用于將數據集劃分為K個簇&#xff08;clusters&#xff09;&#xff0c;使得同一簇內的數據點相似度高&#xff0c;不同簇間的相似度低。它在數據挖掘、模式識別和機器學習中廣泛應用&#xff0c;如客戶細分、圖像壓縮和…

linux環境內存滿php-fpm

檢查 PHP-FPM 配置 pm.max_children&#xff1a;該參數控制 PHP-FPM 進程池中最大允許的子進程數。過高的子進程數會導致內存占用過大。你可以根據服務器的內存大小來調整 pm.start_servers&#xff1a;控制 PHP-FPM 啟動時創建的進程數。根據實際情況調整此值。 pm.min_spare_…

基于CNN卷積神經網絡圖像識別小程序9部合集

基于CNN卷積神經網絡圖像識別小程序合集-視頻介紹下自取 ? 內容包括&#xff1a; 基于python深度學習的水果或其他物體識別小程序 003基于python深度學習的水果或其他物體識別小程序_嗶哩嗶哩_bilibili 代碼使用的是python環境pytorch深度學習框架&#xff0c;代碼的環境安…

WebRTC(九):JitterBuffer

JitterBuffer Jitter “Jitter”指的是連續到達的媒體包之間時間間隔的變化。在網絡傳輸中&#xff0c;由于&#xff1a; 網絡擁塞路由路徑變化隊列排隊不同鏈路帶寬差異 導致包之間的接收時間不一致&#xff0c;這就是網絡“抖動”。 作用 **JitterBuffer&#xff08;抖…

【推薦100個unity插件】在 Unity 中繪制 3D 常春藤,模擬生長——hedera插件的使用

注意&#xff1a;考慮到后續接觸的插件會越來越多&#xff0c;我將插件相關的內容單獨分開&#xff0c;并全部整合放在【推薦100個unity插件】專欄里&#xff0c;感興趣的小伙伴可以前往逐一查看學習。 效果演示 文章目錄 效果演示前言一、常春藤生成器工具下載二、工具使用1、…

【三維重建】【3DGS系列】【深度學習】3DGS的理論基礎知識之高斯橢球的幾何變換

【三維重建】【3DGS系列】【深度學習】3DGS的理論基礎知識之高斯橢球的幾何變換 文章目錄 【三維重建】【3DGS系列】【深度學習】3DGS的理論基礎知識之高斯橢球的幾何變換前言模型變換(Model Transformation)觀測變換(Viewing Transformation)視圖變換(View Transformation)投影…

EXISTS 和 NOT EXISTS 、IN (和 NOT IN)

在 SQL 中&#xff0c;EXISTS、NOT EXISTS 和 IN 都是用于子查詢的條件運算符&#xff0c;用于根據子查詢的結果過濾主查詢的行。它們之間的區別主要體現在工作方式、效率、對 NULL 值的處理以及適用場景上。 1. EXISTS 和 NOT EXISTS 作用&#xff1a; EXISTS: 檢查子查詢是…

GitHub 趨勢日報 (2025年06月25日)

&#x1f4ca; 由 TrendForge 系統生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日報中的項目描述已自動翻譯為中文 &#x1f4c8; 今日獲星趨勢圖 今日獲星趨勢圖 880 awesome 788 build-your-own-x 691 free-for-dev 427 best-of-ml-python 404 …

互聯網大廠Java求職面試:Java虛擬線程實戰

互聯網大廠Java求職面試&#xff1a;Java虛擬線程實戰 文章內容 開篇&#xff1a;技術總監與程序員鄭薪苦的三輪對話 在一場緊張而嚴肅的Java工程師面試中&#xff0c;技術總監張工正對候選人鄭薪苦進行深入提問。鄭薪苦雖然性格幽默&#xff0c;但對技術有著扎實的理解。今天…

網絡安全的兩大威脅:XSS與CSRF攻擊實例解析

在網絡攻擊中,XSS跨站腳本攻擊(Cross Site Scripting)與CSRF跨站請求偽造攻擊(Cross-Site Request Forgery)是兩種常見的攻擊方式,它們之間存在顯著的區別。以下是對這兩種攻擊方式的詳細比較: 一、攻擊原理 XSS跨站腳本攻擊 攻擊者通過在Web頁面中注入惡意腳本來實現攻…

如何一次性將 iPhone 中的聯系人轉移到 PC

許多重要的聯系人都存儲在您的 iPhone 上。為了保護關鍵信息&#xff0c;您可能需要將聯系人從 iPhone 轉移到 PC&#xff0c;這是一種有效的聯系人備份方法。如果您在將 iPhone 聯系人轉移到電腦上遇到困難&#xff0c;現在可以從本文中學習 5 個有效的解決方案&#xff0c;然…

Spring Boot開啟定時任務的三種方式 【@EnableScheduling注解,SchedulingConfigurer接口,Quartz 框架】

Spring Boot 開啟定時任務的三種方式? ? ? 在 Spring Boot 應用開發過程中&#xff0c;定時任務是十分常見的需求&#xff0c;比如定時清理日志文件、定期備份數據庫數據、定時發送郵件提醒等。Spring Boot 提供了多種開啟定時任務的方式&#xff0c;本文將詳細介紹三種常見…

LLM 編碼器 怎么實現語義相關的 Token 向量更貼近? mask訓練:上下文存在 ;; 自回歸訓練:只有上文,生成模型

LLM 編碼器 怎么實現語義相關的 Token 向量更貼近? 目錄 LLM 編碼器 怎么實現語義相關的 Token 向量更貼近?mask訓練:上下文存在自回歸訓練:只有上文,生成模型一、核心機制:損失函數與反向傳播的“語義校準”1. 損失函數的“語義約束”2. 嵌入層參數的“動態調整”二、關…

從OCR瓶頸到結構化理解來有效提升RAG的效果

當人們探討如何讓人工智能系統更好地從文檔中查找和使用信息時&#xff0c;通常關注的是令人矚目的算法和前沿的大型語言模型。但問題是&#xff1a;如果文本提取的質量很差&#xff0c;那么后續的努力都將付諸東流。本文探討OCR質量如何影響檢索增強生成&#xff08;RAG&#…

SpringBoot -- 整合Junit

11.SpringBoot 整合 Junit 11.1 為什么需要單元測試 由于在SpringBoot開發過程中&#xff0c;每開發一個模塊&#xff0c;有時需要從 controller、service、mapper 到甚至 xml 文件的編寫全部開發完畢才能進行測試&#xff0c;這是十分浪費時間的&#xff0c;比如開發人員想測…

虛擬機遠程連接編譯部署QT程序

概要 邏輯 我們需要湊齊 QT庫、交叉編譯工具、sysroot這三大件。 交叉編譯的程序是部署到板卡環境運行,需要構建和板卡一樣的庫環境。 sysroot是我們在虛擬機上自己命名的一個文件夾,包含開發板的運行系統所需的所有文件。 虛擬機是x64版本,開發板是arm64版本。 如果開發板…