Cortex-M 實現互斥操作的三種方法

来源:https://www.cnblogs.com/miaoxiong/archive/2019/04/22/10749438.html
-Advertisement-
Play Games

註:本文僅針對Cortex-M3/4 系列進行講述。 在傳統的ARM處理器架構中,常使用SWP指令來實現鎖的讀/寫原子操作,但從ARM v6開始,讀/寫訪問在獨立的兩條匯流排上進行,SWP指令已無法在此架構下保證讀/寫訪問的原子操作,因此互斥訪問指令應運而生。本文結合項目中運用的相關方法,總結Cort ...


註:本文僅針對Cortex-M3/4 系列進行講述。

在傳統的ARM處理器架構中,常使用SWP指令來實現鎖的讀/寫原子操作,但從ARM v6開始,讀/寫訪問在獨立的兩條匯流排上進行,SWP指令已無法在此架構下保證讀/寫訪問的原子操作,因此互斥訪問指令應運而生。本文結合項目中運用的相關方法,總結Cortex-M晶元常用的互斥訪問方法。

 

互斥訪問方式1--LDREX/STREX指令

ARM支持的互斥指令對有LDREX/STREX、LDREXB/STREXB 及 LDREXH/STREXH(專有的寄存器載入/存儲指令),其分別支持字/位元組/半字訪問,本節以LDREX/STREX為例.

 

語法格式

LDREX{cond} Rt, [Rn {, #offset}]

STREX{cond} Rd, Rt, [Rn {, #offset}] 

其中

 cond: 可選狀態碼-若指令包含此狀態碼,則只有當APSR寄存器中的狀態位滿足狀態碼條件時,指令才會執行

 Rd: 目的寄存器-指令執行後的返回狀態,0執行成功,1執行失敗

 Rt: 待載入/存儲的寄存器

 Rn: 寄存器地址

 offset: 可選的地址偏移

 

基本要求

使用互斥訪問指令時,需滿足以下基本要求,以防不可預期的結果出現。

 1. LDREX/STREX必須成對出現

 2. LDREX/STREX的Rn寄存器地址必須一致,操作的寄存器長度必須一致

 3. LDREX/STREX之間不得使用PC指針,操作的寄存器不使用SP指針

 4. LDREX/STREX之間的指令要儘可能的簡短,offset需4位元組對齊,範圍在0~1020之間(不同的廠商設置範圍不同) 

 

互斥寫失敗情況

在滿足基本要求後,互斥寫不一定成功,如互斥操作中途遇到以下情況:

 1. 調用CLREX指令清除互斥狀態

 2. 發生上下午切換(如中斷)

 3. 之前未執行過LDREX

 4. 匯流排反饋的互斥錯誤

 

使用方法

以nRF52源碼中的 nrf_atomic_internal_orr() 函數為例,該函數實現了或運算的原子操作,其中p_ptr為初始值,value為或運算因數,p_new為運算後的值,函數返回原為子操作之前的p_ptr的值。

先簡單描述上述各行代碼:

89: r0/r1/r2分別存儲的p_ptr/value/p_new的值

94:將p_ptr地址付給r4

 

97:將r4所指向的值賦給r0,r0獲得了p_ptr此時的值

98:對r0存儲的值進行或運算,運算值賦給r5

99:將r5的值存儲給r4指向的地址,即更新p_ptr的值,同時將本條指令的執行結果賦給r3

 

100/101:判斷返回值r3,若不為0,重試 97~99的操作

103/104/105:將運算值賦給r2指向的值,即得到新值

 

代碼的關鍵在97行,需註意的是,當函數執行結束返回時,r0存儲函數的返回值,因此此函數的返回值為原子操作之前的p_ptr值,而不是調用此函數時傳入的p_ptr值(中途可能有變)

 

以實際場景為例,假若存在兩個任務A和B,以及一個共用記憶體Mem,互斥變數Flag標記Mem是否正在被占用(0:空閑中,1:占用中),要如何實現呢?

 

情況1. A/B先後訪問Mem,則

  1. A首先調用 nrf_atomic_internal_orr() 函數(Flag=0),嘗試原子操作,此時R0=0,執行結束後,由返回值R0可知,Flag成功由0->1,A占用Mem成功

  2. 此時發生任務切換

  3. B調用 nrf_atomic_internal_orr() 函數(Flag=1),嘗試原子操作,此時R0=1,執行結束後,由返回值R0可知,Flag在置位之前已經是1,B占用Mem失敗

  註:因為只有A/B先後訪問nrf_atomic_internal_orr()函數,因此各自只需要嘗試一次原子操作即可成功。

 

情況2.A/B同時訪問Mem,A在原子操作過程中被B搶占,則

  1. A首先調用 nrf_atomic_internal_orr() 函數(Flag=0),嘗試第一次原子操作,此時R0=0,此時發生任務切換

  2. A被搶占,上下文切換退出

  3. B調用 nrf_atomic_internal_orr() 函數(Flag=0),嘗試第一次原子操作,此時R0=0,執行結束後,由返回值R0可知,Flag成功由0->1,B占用Mem成功

  4. 此時發生任務切換

  5. A繼續執行第一次原子操作,因在LDREX/STREX之間已發生上下文切換,此次原子操作STREX返回 1,執行失敗

  6. A繼續執行第二次原子操作,註意:此時R0重載,R0=1,執行結束後,由返回值R0可知,Flag在置位之前已經是1,A占用Mem失敗

 

因此本例中,調用nrf_atomic_internal_orr() 執行原子操作後,通過判斷函數返回值可知,本次互斥操作是否搶占資源成功。

 

互斥訪問方式2--Bit-Band操作

 在支持 “locked transfers”或僅有單個匯流排主機的記憶體系統中,使用位帶操作也可實現信號量操作。要實現互斥訪問某個資源,操作過程中需遵循以下幾點:

 1. 系統為每個需互斥訪問的任務分配一個位帶bit位,

 2. 任務僅能對自己的bit位進行讀-修改-寫操作。

 2. 不能以常規的寫方式來直接修改位帶區域值,否則可能丟失已鎖定的位信息

 

具體操作過程直接上圖:

優點:可使用C代碼直接實現上述互斥訪問邏輯。

  

互斥訪問方式3--關中斷

最為簡單粗暴的互斥訪問方法,FreeRTOS的信號量獲取/釋放操作便採用此方式進入臨界區。

 

關中斷實現起來雖然簡單,但也需根據具體場景來選擇關總中斷還是外設中斷,否則可能降低系統的實時性甚至造成數據丟失。

舉例來說,在之前經歷的一個項目中,有一款MCU既需要負責USB數據的收發,同時還得處理無線數據的轉發,如在處理USB臨界區數據時選擇關總中斷,則可能導致無線數據無法及時處理甚至導致丟包,在該場景下,若選擇只關閉USB中斷,則MCU依然能夠在實現局部互斥操作的同時實時響應優先順序更高的事件。

 

參考手冊

 

TI 《Cortex-M3/M4F Instruction Set》

宋岩 《Cortex -M3 權威指南》

《The Definitive guild to the ARM Cortex-M3》Second Edition》

《The Definitive guild to the ARM Cortex-M3 and Cortex-M4 Processors》Third Edition


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

-Advertisement-
Play Games
更多相關文章
  • rpm -ivh software_name安裝軟體 列印詳情rpm -q software_name查詢軟體是否安裝rpm -ql software_name查詢安裝目錄rpm -e software_name卸載軟體rpm -Uvh software_name升級軟體包rpm -ivh http ...
  • ls 作用:顯示目標列表,在Linux中是使用率較高的命令。ls命令的輸出信息可以進行彩色加亮顯示,以分區不同類型的文件。 參數: 實例: 顯示當前目錄下非隱藏文件的文件 顯示當前目錄下包括影藏文件在內的所有文件列表 輸出長格式 [root@iZuf61bne18a1bikx6z7bvZ /]# l ...
  • 需求: 自己有個功能變數名稱,原來直接扔在了伺服器的文件夾里(根據客服人員指導),自己玩了一遍nginx的安裝部署等操作之後,功能變數名稱的指向發生了改變,到了nginx成功的界面。 自己抱著極大的好奇心來配置nginx,已達到我能訪問到我的主頁的樣子,當然啦。做個功能變數名稱主頁對我來說最主要的作用就是學(裝)習(逼)。 ...
  • man 查看英文命令幫助 可以看作--help 拷貝目錄的命令cp -a 包含所有 ls -a 顯示所有文件包括隱藏文件 -ld ls -F 過濾目錄文件(給不同類型文件結尾加上不同的符號) -h顯示文件的k,M,G -i顯示文件的索引inode ls -l --time-style=long-is ...
  • 遇到了好幾個centos6.5,一直嘗試想提權。暫未成功,靶機內核:2.6.32-696.18.7.el6.x86_64。glibc版本:ldd (GNU libc) 2.12目前編譯過程中都發現很多坑。最開始編譯報錯,指定gcc路徑/usr/bin/gcc,指定std為c99,使用-std=c99... ...
  • 最近在學習Liunx,從裝虛擬機到敲命令出了一些問題,95%的問題從搜索引擎都可以找到。本來想寫個虛擬機安裝步驟結果忘記截圖了,不過沒事,網上一大把。寫寫博文勒就是記錄下自己的成長,雖然現在還是個小白。同時也讓一起在學習的小伙伴們一起交流學習。 1.開啟虛擬機出現了“內部錯誤”,截圖如下 解決方法: ...
  • 1、begin #! 是一個約定的標記,它告訴系統這個腳本需要什麼解釋器來執行,即使用哪一種 Shell。 echo 命令用於向視窗輸出文本。 2、運行shell的2種方式 2.1、作為可執行程式 將上面的代碼保存為 test.sh,並 cd 到相應目錄: 2.2、作為解釋器參數 這種運行方式是,直 ...
  • ps 查看進程,列出執行ps命令的那個時刻的進程快照。如果想要動態顯示,使用top命令 參數格式: UNIX格式:一個"-"開頭 BSD格式:沒有"-"開頭 GNU長格式:兩個"-"開頭 a # 顯示與終端相關的所有進程,包含每個進程的完整路徑 u # 顯示進程的用戶信息 x # 顯示與終端無關的所 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...