【學習FreeRTOS】第9章——FreeRTOS任務調度

1.開啟任務調度器

vTaskStartScheduler()

作用:用于啟動任務調度器,任務調度器啟動后, FreeRTOS 便會開始進行任務調度【動態創建任務為例】

  • 創建空閑任務
  • 如果使能軟件定時器,則創建定時器任務
  • 關閉中斷,防止調度器開啟之前或過程中,受中斷干擾,會在運行第一個任務時打開中斷
  • 初始化全局變量,并將任務調度器的運行標志設置為已運行
  • 初始化任務運行時間統計功能的時基定時器 【可選】
  • 調用函數 xPortStartScheduler()

xPortStartScheduler()

作用:該函數用于完成啟動任務調度器中與硬件架構相關的配置部分,以及啟動第一個任務

  • 檢測用戶在 FreeRTOSConfig.h 文件中對中斷的相關配置是否有誤
  • 配置 PendSV 和 SysTick 的中斷優先級為最低優先級
  • 調用函數 vPortSetupTimerInterrupt()配置 SysTick(清空計數值、配置節拍頻率、重裝載值、啟動計數與中斷)
  • 初始化臨界區嵌套計數器為 0
  • 調用函數 prvEnableVFP()使能 FPU
  • 將FPCCR寄存器的[31:30]置l,這樣在進出異常時,FPU的相關寄存器就會自動地保存和恢復(M4/M7)
  • 調用函數prvStartFirstTask() 啟動第一個任務

2.啟動第一個任務

prvStartFirstTask()

__asm void prvStartFirstTask( void ) { /* 8字節對齊 */ PRESERVE8 ldr r0, =0xE000ED08 	/* 0xE000ED08為VTOR地址 */ ldr r0, [ r0 ] 					/* 獲取VTOR的值 */ ldr r0, [ r0 ]					/* 獲取MSP的初始值 */ /* 初始化MSP */ msr msp, r0/* 使能全局中斷 */ cpsie i cpsie f dsb isb /* 調用SVC啟動第一個任務 */ svc 0 nop nop 
}

執行過程為:

  • 獲取MSP的初始值(棧頂地址)
  • 將MSP重新賦值為棧底指針(讓MSP回到原點,啟動任務一去不復返)
  • 使能全局中斷
  • 使用SVC指令,傳入系統調用信號,出發SVC中斷vPortSVCHandler ()
  • 關于MSP指針
    程序在運行過程中需要一定的棧空間來保存局部變量等一些信息。當有信息保存到棧中時,MCU 會自動更新 SP 指針,ARM Cortex-M 內核提供了兩個棧空間
    主堆棧指針(MSP)它由 OS 內核、異常服務例程以及所有需要特權訪問的應用程序代碼來使用。
    進程堆棧指針(PSP)用于常規的應用程序代碼(不處于異常服務例程中時)。
    在裸機中,程序全部使用MSP,在FreeRTOS中,中斷使用MSP(主堆棧),中斷以外使用PSP(進程堆棧)
  • 關于0xE000ED08
    0xE000ED08是VTOR(中斷向量表)的地址,向量表的第一個是 MSP 指針,取 MSP 的初始值的思路是先根據向量表的位置寄存器 VTOR (0xE000ED08) 來獲取向量表存儲的地址;在根據向量表存儲的地址,來訪問第一個元素,也就是初始的 MSP。

vPortSVCHandler ()

__asm void vPortSVCHandler( void ) 
{ /* 8字節對齊 */ PRESERVE8 /* 獲取任務棧地址 */ ldr r3, = pxCurrentTCB 		/* r3指向優先級最高的就緒態任務的任務控制塊 */ ldr r1, [ r3 ] 				/* r1為任務控制塊地址 */ ldr r0, [ r1 ] 				/* r0為任務控制塊的第一個元素(棧頂) */ /* 模擬出棧,并設置PSP */ ldmia r0 !, { r4 - r11 } 	/* 任務棧彈出到CPU寄存器 */ msr psp, r0 				/* 設置PSP為任務棧指針 */ isb /* 使能所有中斷 */ mov r0, # 0 msr basepri, /* 使用PSP指針,并跳轉到任務函數 */ orr r14, # 0xd bx r14 }

運行過程為:

  • 獲取優先級最高的就緒任務的TCB,并取其棧頂元素pxTopOfStack
  • 模擬出棧,將寄存器值出棧至CPU寄存器,并設置PSP指針
  • 開啟中斷
  • 線與0xd,將r14設置為線程模式并使用PSP
  • 跳轉到任務的任務函數中運行,CPU自動出棧R0-xPSR等寄存器(M4:若EXC_RETURN使用FPU,則恢復浮點單元)

M4的vPortSVCHandler () ,除了手動出棧r4-r11外,還有r14,這是因為M4等系列支持FPU,需要該變量進行判別
M4的vPortSVCHandler () ,不需要線與0xd,因為在初始化時,已經對EXC_RETURN進行賦值了,不需要再線與
一般情況下,使用動態創建任務,第一個啟動的任務是軟件定時器任務
注意:SVC中斷只在啟動第一次任務時會調用一次,以后均不調用

在這里插入圖片描述
在這里插入圖片描述

開啟任務調度器及啟動第一個任務總結

在這里插入圖片描述

3.任務切換

任務切換的本質:就是CPU寄存器的切換(又稱上下文切換),在PendSV中斷服務函數中完成 主要分為兩步:

  • 需暫停任務A的執行,并將此時任務A的寄存器保存到任務堆棧,這個過程叫做保存現場
  • 將任務B的各個寄存器值(被存于任務堆棧中)恢復到CPU寄存器中,這個過程叫做恢復現場

觸發PendSV中斷方式

  • 滴答定時器中斷調用
  • 執行FreeRTOS提供的相關API函數:portYIELD()
  • 本質:通過向中斷控制和狀態寄存器 ICSR 的bit28 寫入 1 掛起 PendSV 來啟動 PendSV 中斷

在這里插入圖片描述
在這里插入圖片描述

PendSV中斷服務函數xPortPendSVHandler()

  • 進入中斷,使用PSP自動壓棧
  • 當前的psp是正在運行的任務的棧指針,讀取當前PSP進程指針,存入r0(M4還要考慮FPU壓棧)
  • 手動壓棧,并將最終結果封存至pxTopOfStack,方便下次恢復
  • 屏蔽中斷
  • 調用vTaskSeitchContext(),獲取當前最高優先級任務的任務控制塊
  • 使能中斷
  • 從最高優先級的TCB中獲取pxTopOfStack,并手動出棧
  • 更新切換后的任務的的棧指針給PSP
  • PSP負責自動出棧
  • bx r14 執行新任務函數

查找最優先級任務vTaskSwitchContext( )

通過這個函數完成:taskSELECT_HIGHEST_PRIORITY_TASK( )

  • 使用硬件方式(本文使用)
  • 使用軟件方式
 #define taskSELECT_HIGHEST_PRIORITY_TASK()
{UBaseType_t uxTopPriority;portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority );configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0);listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );
}

前導置零指令
所謂的前導置零指令,大家可以簡單理解為計算一個 32位數,頭部 0 的個數。通過前導置零指令獲得最高優先級

#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities )      uxTopPriority = ( 31UL - ( uint32_t ) __clz( ( uxReadyPriorities ) ) )

在這里插入圖片描述

獲取最高優先級任務的任務控制塊
通過該函數獲取當前最高優先級任務的任務控制塊

#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )
{List_t * const pxConstList = ( pxList );( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ){(pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;}( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;
}

在這里插入圖片描述

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

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

相關文章

Microsoft ISA服務器配置及日志分析

Microsoft ISA 分析器工具,可分析 Microsoft ISA 服務器(或 Forefront 威脅管理網關服務器)的日志并生成安全和流量報告。支持來自 Microsoft ISA 服務器組件的以下日志: 數據包過濾器ISA 服務器防火墻服務ISA 服務器網絡代理服務…

透過源碼理解Flutter中widget、state和element的關系

1、framework源碼組成 Flutter中widget、state、element的源碼位于framework.dart中,整個文件6693行(版本Flutter 3.12.0-14.0.pre.28)。整個代碼可劃分為若干部分,主要包括key、widget、state、element四部分。 1.1 key 關于key的代碼65行到272行&am…

NVIDIA GPU驅動和CUDA工具包 Linux CentOS 7 在線安裝指南

挑選指定系統和對應的GPU型號下載驅動和CUDA工具包: Linux CentOS安裝NVIDIA GPU驅動程序和NVIDIA CUDA工具包_centos安裝顯卡驅動和cuda_Entropy-Go的博客-CSDN博客 相比之下,本文是在線安裝NVIDIA GPU驅動和CUDA工具包方式,省去挑選對應正確安裝包的煩…

Uniapp Syntax Error: Error: Unbalanced delimiter found in string

報錯 in ./src/pages/user/components/tasks.vue?vue&typescript&langjs&Syntax Error: Error: Unbalanced delimiter found in string...這邊導致文件的原因:可能是條件編譯語法不小心刪了某個字符,導致不全,無法形成一對。 //…

GuLi商城-前端基礎Vue-生命周期和鉤子函數

下圖展示了實例的生命周期。你不需要立馬弄明白所有的東西,不過隨著你的不斷學習和使用,它 的參考價值會越來越高。 VUE 的生命周期指的是組件在創建、運行和銷毀過程中所經歷的一系列事件,通過這些事件可以 讓開發者在不同階段進行相應的…

vue3 + antv/x6 實現拖拽側邊欄節點到畫布

前篇:vue3ts使用antv/x6 自定義節點 前篇:vue3antv x6自定義節點樣式 1、創建側邊欄 用antd的menu來做側邊欄 npm i --save ant-design-vue4.x//入口文件main.js內 import Antd from ant-design-vue; import App from ./App; import ant-design-vue/…

安卓的代碼加固和其他安全問題

文章目錄 安卓加固apk文件結構dex加固過程 其它安全問題 安卓加固 從App的加固技術來看:主流分為dex加密和so加密,目前來看保護dex文件更為重要,因為dex反編譯后的java代碼可讀性更強。 android-ndk: Native Development Kit 官網解釋:這套工具使您能在 Android 應…

Kvm配置ovs網橋

環境:部署在kvm虛擬環境上(讓虛擬機和宿主機都可以直接從路由器獲取到獨立ip) 1、安裝ovs軟件安裝包并啟動服務(一般采用源碼安裝,此處用yum安裝) yum install openvswitch-2.9.0-3.el7.x86_64.rpm syste…

Git常見操作

一、全局配置命令 配置級別: –local(默認,高級優先):只影響本地倉庫 –global(中優先級):只影響所有當前用戶的git倉庫 –system(低優先級):影響到全系統的git倉庫 1…

【力扣】739. 每日溫度 <單調棧>

【力扣】739. 每日溫度 給定一個整數數組 temperatures ,表示每天的溫度,返回一個數組 answer ,其中 answer[i] 是指對于第 i 天,下一個更高溫度出現在幾天后。如果氣溫在這之后都不會升高,請在該位置用 0 來代替。 …

劍指 Offer 40. 最小的k個數(C+實現)

劍指 Offer 40. 最小的k個數https://leetcode.cn/problems/zui-xiao-de-kge-shu-lcof/ 法1&#xff1a;二叉堆 通過最小堆&#xff0c;直接篩選出最小的k個數 vector<int> getLeastNumbers(vector<int>& arr, int k) {priority_queue<int, vector<int>…

YOLOv8改進后效果

數據集 自建鐵路障礙數據集-包含路障&#xff0c;人等少數標簽。其中百分之八十作為訓練集&#xff0c;百分之二十作為測試集 第一次部署 版本&#xff1a;YOLOv5 訓練50epoch后精度可達0.94 mAP可達0.95.此時未包含任何改進操作 第二次部署 版本&#xff1a;YOLOv8改進版本 首…

WebRTC | ICE詳解

目錄 一、Candidate種類與優先級 二、ICE策略 1. iceServers 2. iceTransportPolicy 三、P2P連接 1.Nat類型 &#xff08;1&#xff09;完全錐型NAT &#xff08;2&#xff09;IP限制錐型NAT &#xff08;3&#xff09;端口限制錐型NAT &#xff08;4&#xff09;對稱…

iPhone 15受益:驍龍8 Gen 3可能缺席部分安卓旗艦機

明年一批領先的安卓手機的性能可能與今年的機型非常相似。硅成本的上漲可能是原因。 你可以想象&#xff0c;2024年許多最好的手機都會在Snapdragon 8 Gen 3上運行&#xff0c;這是高通公司針對移動設備的頂級芯片系統的更新&#xff0c;尚未宣布。然而&#xff0c;來自中國的…

centos上下載redis

1.redis 特點 Redis特性&#xff08;8個&#xff09; 1 速度快&#xff1a;10w ops&#xff08;每秒10w讀寫&#xff09;&#xff0c;數據存在內存中&#xff0c;c語言實現&#xff0c;單線程模型 2 持久化&#xff1a;rdb和aof 3 多種數據結構&#xff1a; 5大數據結構 …

Vue中實現分頁

1.構造分頁組件&#xff0c;并注冊為全局組件 <template><div class"pagination"><button v-if"startNumAndEndNum.start>1" click"$emit(getPageNo,pageNo-1)">上一頁</button><button v-if"startNumAndEn…

C#生產流程控制(串行,并行混合執行)

開源框架CsGo https://gitee.com/hamasm/CsGo?_fromgitee_search 文檔資料&#xff1a; https://blog.csdn.net/aa2528877987/article/details/132139337 實現效果 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37…

Windows11 Docker Desktop 啟動 -wsl kernel version too low

系統環境&#xff1a;windows11 1&#xff1a;docker下載 Docker: Accelerated Container Application Development 下載后雙擊安裝即可 安裝后啟動Docker提示&#xff1a;Docker Desktop -wsl kernel version too low 處理起來也是非常方便 1:管理員身份啟動&#xff1a;…

C#程序隨系統啟動例子 - 開源研究系列文章

今天講講C#中應用程序隨系統啟動的例子。 我們知道&#xff0c;應用程序隨系統啟動&#xff0c;都是直接在操作系統注冊表中寫入程序的啟動參數&#xff0c;這樣操作系統在啟動的時候就根據啟動參數來啟動應用程序&#xff0c;而我們要做的就是將程序啟動參數寫入注冊表即可。此…

C語言慣用法之typedef結構體類型

以前曾問C語言熟手&#xff0c;為什么C語言里面充滿了typedef struct someType TSomeType&#xff1f; 當時&#xff0c;可能他以為我的問題太簡單了&#xff0c;也沒所有說出關鍵出來。 對于現在我的認識而言&#xff0c;這種聲明方式&#xff0c;更多的是為了簡寫&#xff0…