ARM單片機OTA解析(一)

文章目錄

  • 一、單片機燒寫程序的幾種方法
  • 二、Bootloader如何加載啟動App


一、單片機燒寫程序的幾種方法

![[Pasted image 20250704203159.png]]

在線應用編程,由開發者實現Bootloader功能,比如ARM單片機的Code分區中的Flash本是存儲用戶應用程序的區間(上電從此處執行用戶代碼),開發者可以將自己實現的Bootloader和應用程序都存放到Flash區間MCU上電啟動先執行用戶的Bootloader代碼,該代碼可為用戶應用程序的下載、校驗、升級、啟動等提供支持,進而實現OTA遠程升級功能。

一般用于給用戶遠程升級,或者是燒寫程序不方便的時候。

![[Pasted image 20250709184234.png]]

復位以后進入Bootloader程序,

![[Pasted image 20250709195510.png]]

需要說明的是這個地方就是我們程序燒寫的其實地址,

這是因為我們要把前面的空間流出來給BOOT程序。

ARM單片機啟動流程(一)(詳細解析)-CSDN博客 在本人的這篇文章里面可以看到我們的Main Flash的物理其實地址就是0x08000000,因此我需要把BOOT程序燒寫到這里,因為CPU執行程序最先
CPU都是從0地址開始訪問的,根據被引導到的地方,有可能直接跳轉到Main Flash 0x0800 0000的原始存儲空間;也有可能跳轉到MCU廠商預置的bootloader開始于0x1FFF F000的原始存儲空間。至于怎么跳轉這兩個以及默認是什么,連接文章在這一塊進行了詳細分析。

一般我們默認就是下面順序:我們就是直接跳轉到Main Flash 0x0800 0000的原始存儲空間;
![[Pasted image 20250709200438.png]]

(CPU通過程序計數器(PC)獲取下一條指令的地址。在無分支的情況下,PC自動增加(如 PC_new = PC_old + 指令長度),實現物理地址的順序執行)

int main(void)
{	InitIrqAfterBoot();DrvInit();AppInit();while (1){TaskHandler();}
}void InitIrqAfterBoot(void)
{nvic_vector_table_set(NVIC_VECTTAB_FLASH, 0x3000);__enable_irq();
}#define NVIC_VECTTAB_FLASH          ((uint32_t)0x08000000) /*!< Flash base address */

值得注意的是在APP程序里面,需要配置中斷向量表里面的初始地址,這是因為原本我們默認的程序初始地址是0x08000000,但是由于BOOT程序的作用導致我們的初始地址變成了((uint32_t)0x08000000)+偏移地址0x3000,中斷向量表的初始位置。

如果我們常規的程序,是CPU直接加載的,就不需要我們初始化,就是內核會默認幫我們搞好,從0x08000000開始。

但是我們現在的程序是從BOOT里面啟動的,那就意味著我們需要自己配置一個中斷向量表初始地址,所以我們需要在應用程序里面做一些CPU需要做的事情,并且在BOOT程序里面一樣需要做一些CPU需要做的事情,說白了就是手動干一些CPU的事情。

同樣需要爛熟于心的還有0x3000表示12KB,0x1000表示4KB,也就是4096個字節(Byte)。

另外需要一點注意的:

        .property = R | W,.address = 0x0004,          // 觸發系統復位 01 06 00 04 00 01.minValue = 0,.maxValue = 1,.WriteCb = ModbusResetSystem,static void ModbusResetSystem(uint16_t value)
{ResetToBoot();
}void ResetToBoot(void)
{__disable_irq();    //關閉所有中斷NVIC_SystemReset(); //復位函數,需要一些執行的時間
}

在APP程序里面,觸發復位的時候,我們一定要先關閉所有中斷,如果不關閉中斷可能會導致我們的BOOT程序會出現錯誤,因為BOOT里面也需要中斷。

此外需要聯系之前的知識在做一次對比:

代碼段1:

__Vectors0x08000000:    20000428    (..     DCD    5368719760x08000004:    08000145    E...    DCD    1342180530x08000008:    0800014d    M...    DCD    1342180610x0800000c:    0800014f    O...    DCD    1342180630x08000010:    08000151    Q...    DCD    1342180650x08000014:    08000153    S...    DCD    1342180670x08000018:    08000155    U...    DCD    1342180690x0800001c:    00000000    ....    DCD    00x08000020:    00000000    ....    DCD    00x08000024:    00000000    ....    DCD    00x08000028:    00000000    ....    DCD    00x0800002c:    08000157    W...    DCD    1342180710x08000030:    08000159    Y...    DCD    1342180730x08000034:    00000000    ....    DCD    00x08000038:    0800015b    [...    DCD    1342180750x0800003c:    0800015d    ]...    DCD    1342180770x08000040:    0800015f    _...    DCD    1342180790x08000044:    0800015f    _...    DCD    1342180790x08000048:    0800015f    _...    DCD    1342180790x0800004c:    0800015f    _...    DCD    1342180790x08000050:    0800015f    _...    DCD    1342180790x08000054:    0800015f    _...    DCD    1342180790x08000058:    0800015f    _...    DCD    134218079

代碼段2:

    __Vectors0x08003000:    20000738    8..     DCD    5368727600x08003004:    08003145    E1..    DCD    1342303410x08003008:    08003d21    !=..    DCD    1342333770x0800300c:    08003965    e9..    DCD    1342324210x08003010:    08003c69    i<..    DCD    1342331930x08003014:    0800356b    k5..    DCD    1342314030x08003018:    08004531    1E..    DCD    1342354410x0800301c:    00000000    ....    DCD    00x08003020:    00000000    ....    DCD    00x08003024:    00000000    ....    DCD    00x08003028:    00000000    ....    DCD    00x0800302c:    0800402d    -@..    DCD    1342341570x08003030:    0800365b    [6..    DCD    1342316430x08003040:    0800315f    _1..    DCD    1342303670x08003044:    0800315f    _1..    DCD    1342303670x08003048:    0800315f    _1..    DCD    1342303670x0800304c:    0800315f    _1..    DCD    1342303670x08003050:    0800315f    _1..    DCD    1342303670x08003054:    0800315f    _1..    DCD    134230367

可以明顯看出初始的中斷向量地址就是0x08003000:開始的,跟之前的0x08000000:有明顯的地址偏移量,而這個地址偏移量就是我們自己設計的0x3000

二、Bootloader如何加載啟動App

在這里插入圖片描述
首先我們看一下ROM空間的分布,

相當于前面12KB劃分給了BOOT,后面的500KB空間給了APP。并且本例程使用的GD32這個單片機一共的FLASH空間就是512KB。

首先是讀取 0x08000000:獲取棧頂地址,

接著是讀取 0x08000004:獲取復位函數的地址

然后跳轉到復位函數地址 0x08000004:執行復位函數的代碼指令,這些是CPU自動完成的。

這里需要說明的為什么CPU需要執行復位函數?
建立可預測的初始狀態,消除不確定性,確保系統行為可預測。
CPU上電或復位時,寄存器、程序計數器(PC)、狀態標志等內部狀態是隨機的或殘留前次運行的錯誤值。復位函數會強制將其清零或設為預設值(如PC指向復位向量地址0xFFFF0),使CPU從已知起點開始執行。
程序計數器(PC)清零?:復位后PC指向固定的啟動地址(如ARM的0x00000000或x86的0xFFFF0),加載第一條指令
?寄存器初始化?:通用寄存器、狀態寄存器(如EFLAGS)恢復默認值,避免殘留數據干擾新程序。

此外當系統遇到致命錯誤時,復位是恢復運行的終極手段:

  • ?軟件錯誤?:如堆棧溢出、死循環、空指針訪問等,通過看門狗定時器觸發復位。看門狗超時未清零則強制復位,脫離卡死狀態。
  • ?硬件故障?:內存錯誤、總線沖突、電源欠壓等觸發復位以保護硬件。例如,STM32的欠壓檢測(VBOR)會直接復位CPU。
  • ?中斷與死鎖?:多核系統中核心間死鎖可通過內核復位(如ARM的VECTRESET)局部恢復,避免全系統重啟。

那如何啟動APP?

我們使用BOOT啟動APP的時候也是需要干這些動作,只不過這些動作不是CPU幫助我們自動完成了,而是需要我們自己手動完成。

代碼詳細解析:

static void BootToApp(void)
{uint32_t stackTopAddr = *(volatile uint32_t*)APP_ADDR_IN_FLASH; if (stackTopAddr > RAM_START_ADDRESS && stackTopAddr < (RAM_START_ADDRESS + RAM_SIZE)) //判斷棧頂地址是否在合法范圍內{__disable_irq();__set_MSP(stackTopAddr);uint32_t resetHandlerAddr = *(volatile uint32_t*) (APP_ADDR_IN_FLASH + 4);/* Jump to user application */pFunction Jump_To_Application = (pFunction) resetHandlerAddr; // int *p = (int *)0x8003145/* Initialize user application's Stack Pointer */Jump_To_Application();}NVIC_SystemReset();
}

文章源碼獲取方式:
如果您對本文的源碼感興趣,歡迎在評論區留下您的郵箱地址。我會在空閑時間整理相關代碼,并通過郵件發送給您。由于個人時間有限,發送可能會有一定延遲,請您耐心等待。同時,建議您在評論時注明具體的需求或問題,以便我更好地為您提供針對性的幫助。

【版權聲明】
本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議。這意味著您可以自由地共享(復制、分發)和改編(修改、轉換)本文內容,但必須遵守以下條件:
署名:您必須注明原作者(即本文博主)的姓名,并提供指向原文的鏈接。
相同方式共享:如果您基于本文創作了新的內容,必須使用相同的 CC 4.0 BY-SA 協議進行發布。

感謝您的理解與支持!如果您有任何疑問或需要進一步協助,請隨時在評論區留言。

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

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

相關文章

C語言基礎教程--從入門到精通

C語言基礎教程–從入門到精通&#xff08;總體概括&#xff09; 接下來會對每一個章節進行詳細的總結與整理&#xff0c;希望對大家有用&#xff01;大家一起學習&#xff01; 目錄C語言基礎教程--從入門到精通&#xff08;總體概括&#xff09;**接下來會對每一個章節進行詳細…

單細胞分析教程 | (二)標準化、特征選擇、降為、聚類及可視化

在完成質控&#xff08;QC&#xff09;后&#xff0c;我們已經過濾掉了低質量細胞、雙細胞和低表達基因&#xff0c;獲得了較為干凈的單細胞數據集單細胞分析教程 | &#xff08;一&#xff09;Python單細胞質控全流程。接下來&#xff0c;我們將進行以下關鍵步驟&#xff1a; …

大模型 Agent(智能體)技術簡介

大模型 Agent&#xff08;智能體&#xff09;技術 是當前人工智能領域的前沿方向&#xff0c;它賦予大型語言模型&#xff08;LLM&#xff09;自主感知、規劃、決策和行動的能力&#xff0c;使其不再局限于“被動應答”&#xff0c;而是能主動完成復雜任務。簡單來說&#xff0…

OneCode 3.0架構深度剖析:工程化模塊管理與自治UI系統的設計與實現

引言 OneCode 3.0作為新一代低代碼開發平臺&#xff0c;其架構設計圍繞"工程模塊化"與"UI自主化"兩大核心目標展開。本文將從底層接口到上層應用&#xff0c;全面解析OneCode 3.0的技術架構&#xff0c;包括核心工廠類、工程管理接口、數據倉庫設計以及動態…

功耗校準數據PowerProfile測試方法建議

場景步驟版本:xxxxA1A2結果&#xff08;mA&#xff09;screen,full1.打開飛行模式&#xff0c;滅屏時間最長&#xff0c;其他的基礎功能關2.進入到日歷應用界面3.將亮度設置至最大&#xff08;4095&#xff09;&#xff0c;待電流穩定后&#xff0c;測試5分鐘&#xff0c;記錄電…

[附源碼+數據庫+畢業論文]基于Spring+MyBatis+MySQL+Maven+vue實現的供電公司安全生產考試管理系統,推薦!

摘 要 使用舊方法對安全生產考試信息進行系統化管理已經不再讓人們信賴了&#xff0c;把現在的網絡信息技術運用在安全生產考試信息的管理上面可以解決許多信息管理上面的難題&#xff0c;比如處理數據時間很長&#xff0c;數據存在錯誤不能及時糾正等問題。 這次開發的供電公…

輸入框過濾選項列表,el-checkbox-group單選

需求&#xff1a;根據輸入的文本動態過濾選項列表&#xff0c;并在下方顯示匹配到的選項。當用戶勾選匹配到的選項時&#xff0c;把該選項的值賦值給輸入框中綁定的值。當用戶取消選擇時&#xff0c;輸入框中的字段可以隨意編輯。組件&#xff1a;el-input、el-checkbox-group、…

身份認證缺陷

Authentication Bypasses審計創建AccountVerificationHelper實例&#xff0c;用于處理賬戶驗證邏輯parseSecQuestions函數的作用是從請求體中遍歷參數名&#xff0c;找到包含secQuestion的參數&#xff0c;將其值存入Map中并返回這里直接把AccountVerificationHelper整個分析一…

火山引擎:字節跳動的技術賦能初解

火山引擎是字節跳動旗下的企業級智能技術服務平臺&#xff0c;于2020年6月正式上線。它通過開放字節跳動在大數據、人工智能、視頻云等領域的核心技術&#xff0c;助力企業實現數字化轉型與業務增長。火山引擎界面核心能力與技術亮點:1.全棧云服務公有云與混合云&#xff1a;提…

VUE 帶有搜索功能的穿梭框(簡單demo)

一、template/ 組件代碼<el-dialog :title"title" :visible.sync"dialogVisible" width"60%" :before-close"handleClose" class"custom-dialog-line" ><div style"text-align: center ; width: 100%; height…

寫個掃雷小游戲

1.test.c&#xff08;測試源文件&#xff09;2.game.c&#xff08;游戲源文件&#xff09;3.頭文件

【Linux庖丁解牛】— system V共享內存!

1. 什么是system VSystem V IPC&#xff08;Interprocess Communication&#xff0c;進程間通信&#xff09;是Unix系統中一種經典的進程間通信機制&#xff0c;由AT&T在System V.2版本中引入&#xff0c;并廣泛應用于Linux等現代操作系統中。它通過三種核心機制實現進程間…

從輸入到路徑:AI賦能的地圖語義解析與可視化探索之旅(2025空間智能全景)

??摘要??在空間智能爆發的2025年&#xff0c;地圖系統已從靜態導航工具進化為??實時決策中樞??。本文深度解析AI如何重構地理信息處理全鏈路&#xff1a;通過??多模態語義理解??&#xff08;文本/語音/圖像→空間意圖&#xff09;、??動態路網建模??&#xff0…

安全運維新趨勢:AI 驅動的自動化威脅檢測

在數字化浪潮中&#xff0c;網絡攻擊正從 “單點突破” 進化為 “鏈狀打擊”&#xff1a;2024 年某金融機構遭遇供應鏈攻擊&#xff0c;惡意代碼通過運維通道潛伏 3 個月&#xff0c;傳統規則引擎因未識別 “正常運維指令中的異常參數”&#xff0c;導致數據泄露損失過億。這背…

數據庫復合索引設計:為什么等值查詢列應該放在范圍查詢列前面?

前言作為后端開發工程師&#xff0c;我們經常會遇到數據庫查詢性能問題。在一次系統優化中&#xff0c;我發現一個簡單的索引順序調整竟然讓查詢速度提升了10倍&#xff01;這讓我意識到復合索引列順序的重要性。今天&#xff0c;我就來分享一下這個經驗&#xff0c;希望能幫助…

【PMP備考】每日一練 - 2

1、一個建筑項目的項目經理發現&#xff0c;他管理的項目所在地附近正在新建一條新的水管線。公司政策要求&#xff0c;在他的團隊繼續完成這個項目之前&#xff0c;必須先填寫一系列有關城市環境變化的表格。這是那兩種情況的例子&#xff1f;&#xff08;選2個選項&#xff0…

【三】ObservableCollection 與 List 的區別

文章目錄前言一、核心概念簡介ObservableCollectionList二、關鍵差異對比三、典型使用場景ObservableCollection 的適用場景List 的適用場景四、在Community Toolkit MVVM中使用ObservableCollection<Data>和List<Data>場景1&#xff1a;動態列表&#xff08;Obser…

網安-SSRF-pikachu

目錄 SSRF:Server-Side Request Forgery PHP curl PHP 可能引起SSRF的函數 PHP其他函數 CURL其他協議 SSRF利用&#xff1a; SSRF的發現 工具 SSRF的防御 pikachu-SSRF 一&#xff1a;curl 1.訪問連接&#xff1a; 2.讀取本地文件 3.dict協議掃描主機端口 二&…

在Centos系統上如何有效刪除文件和目錄的指令匯總

CentOS系統是一款開源的類Unix操作系統&#xff0c;極其親和程序員和技術人員。這個系統最大的優勢就是其高度自由化的特性&#xff0c;世界各地的開發者可以依照實際需求去修改和運行。在這個操作系統中&#xff0c;如果你想刪除文件和目錄&#xff0c;你可以使用各式各樣的命…

Spring(四) 關于AOP的源碼解析與思考

Spring&#xff08;四&#xff09; 關于AOP的源碼解析與思考 每種語言都有其獨特的機制和特點&#xff0c;那么說到Java你可能會首先想到反射&#xff0c;反射是Java語言提供的一種能夠在程序運行時動態操作類或對象的能力&#xff0c;比如獲取某個對象的類定義、獲取類聲明的屬…