STM32單片機的Bootloader詳解(1)

2021-12-23 Lovelessing

        當你熟悉了程序的仿真和下載,你就應該了解一下IAP了。本質上IAP和單片機內部固化的ISP程序一樣,都是負責幫你把新程序下進單片機的FLASH。那為什麼還需要IAP呢?

        舉個例子,ISP的啟動一般需要硬體控制BOOT0,因此對於加USB轉TTL和三極體電容電阻等組成自動下載電路這種燒錢做法一般做產品肯定是不提倡的。而即便是不使用自動下載電路,也需要你手動去設置這個管腳,而產品批量的版本BOOT0一般都是直接通過電阻接地甚至電阻也省略了。所以很難做到像開發板一樣輕易使用ISP。這還是在硬體方面,你還需要抱著電腦連上位機去發送hex或者bin文件。即便是用下載器,不還是需要接線連上SWD接口才能下載嘛。

        那如果是產品已經裝殼了呢?如果還是那種膠封的防水外殼,那麼這時候拆殼下載很明顯外殼就報廢了。而基本上產品也沒有把下載接口引出來的,比如你家的路由器、WIFI燈泡等等。再例如如果是太陽能路燈控制器呢?如果是池塘水質檢測器呢?總不能下一次程序抱電腦爬一次路燈杆、劃一次水吧。雖然也有很多的脫機下載器了,但是終究還是需要連接產品去更新。如果是傳感器節點的話可能同時還會有成百上千個產品需要下載程序。

        因此出現bootloader是必然的過程。通過前面的內容,我們知道下載新程序的辦法主要是兩個,ISP和仿真器。操作都比較麻煩。一個是系統存儲區程序,一個是RAM存儲區程序。那麼IAP就是主存儲區程序了。

        IAP就是In Application Programming,也還是編程,也就是寫FLASH程序。對於主存儲區(也就是0x0800 0000那塊存儲)裡面存儲的就是用戶程序(User Application)了。那麼In Application Programming也就是在這塊區域寫FLASH。

        前面我們分析過,程序就運行在這裡,那麼再寫新程序的話,無疑會把自己寫掛掉。而IAP又無疑是在主存儲區運行的。那怎麼辦呢?

        我們首先翻到復位中斷入口處的程序。

復位程序入口

        然後跳轉到系統初始化程序SystemInit,在這裡我們可以看到中斷向量表偏移的設置。

中斷向量表偏移量設置

        由於工程中未啟用宏:VECT_TAB_SRAM


MDK工程宏定義

        所以執行下方的語句:SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;翻譯過來就是:內部FLASH中的向量表重定位。

FLASH基地址定義

        說人話就是中斷向量表設置的0x0800 0000,也就是我們的程序運行的位置。

        我們知道中斷函數也是個函數,並且中斷函數在發生中斷時可以及時響應運行。那麼CPU調用中斷函數的時候就得知道中斷函數的入口地址,而MDK完全不知道你用的什麼單片機、有幾塊存儲、多大存儲、存儲在哪(FLASH地址)等等。所以需要設置這些內容,當然這些東西你當初裝的pack包都幫你做好了。

        其實如果程序是從0地址(0x0000 0000)運行的話那就不需要偏移,但是STM32的FLASH是0x0800 0000,所以這個入口地址要加上0x0800 0000(關於為什麼stm32的FLASH地址為什麼是0x0800 0000可以查看安富萊的帖子:https://www.bilibili.com/read/cv13767372),而如果是F7的XIP模式,那麼外置FLASH的地址還需要設置,比如F730、F750就是0x0900 0000。

DM00514974.pdf 13頁

        欸,不是說IAP嘛,怎麼又扯到了中斷向量表?因為存在中斷像量表,並且是可以設置的,所以才具有了靈活性。比如我們給它往後挪一下呢?

        比如我們把中斷向量表設置成0x0800 0000 | 0x10000,也就是FLASH_BASE | VECT_TAB_OFFSET,定義VECT_TAB_OFFSET為0x10000,這時候程序就在FLASH基地址也就是0x0800 0000往後64K的地址跑起來了。

        是這樣嗎?並不是。從主存儲區啟動的時候程序依舊是從主存儲區地址:0x0800 0000開始跑的。對勁嗎?不對勁,不對勁嗎?好像又對勁。如果電腦這麼設置可以的話,那系統崩了是不是就沒法重裝系統了。所以從主存儲區啟動是對的,但是目前還沒法跑挪過去後面的那段程序。

        再回想一下中斷怎麼執行來著?是要知道中斷函數的入口地址對吧。那麼我們也這麼做。首先定義一個函數指針,然後把函數指針指嚮往後挪的那段程序。是0x0800 0000 + 0x10000嗎?不是的。

        回顧一下你的開發板上電第一個跑的復位中斷程序,也就是Reset_Handler。它的地址在哪呢?

中斷函數偏移地址

        是的,它在4位元組的位置,也就是一個32位數之後。所以你的新程序的地址還要+4。

typedef  void (* iapfun)(void);iapfun go_app;go_app = (iapfun)*(__IO uint32_t *)((0x0800 0000 | 0x10000) + 4);__set_MSP(*(__IO uint32_t *)(0x0800 0000 | 0x10000));go_app();

        新的程序還需要新的堆棧,因此再設置一下堆棧指針。之後直接調用函數就可以了。

        棧頂指針也就是程序最開始的位置,即0x0000 0000,比如像這樣。

棧頂地址

        同樣的,往後4個字節就是復位中斷函數入口地址。

復位中斷入口地址

        這些說明在Cortex權威說明手冊裡有寫。

Cortex M3/4權威指南114頁

         我們的程序不是存儲的0x0800 0000嗎?為什麼在0這裡也可以查到呢?這就是存儲區重映射的。其實在0x0800 0000也是一樣的。

系統存儲區數據

        好了,到現在為止,我們已經可以通過主存儲區先啟動的程序來創建函數指針然後讓往後挪的程序跑起來了。還有一個問題,怎麼把程序寫進往後挪的那個位置呢?這其實就比較簡單了。之前我們說的FLASH編程就行。把新程序編譯出來bin文件。然後再用首先啟動的這段程序把新程序寫到往後挪的那個位置。

FLASH構成

        最簡單的寫法,把新程序存成數組,這樣第一段程序就包含新程序了,再往後面寫一遍屬實沒必要,所以一般不這麼淦。

        反正還是把新程序變成數組寫進FLASH,那方法可就多了去了。跟ISP一樣,用串口把新程序數組發給第一段程序讓它寫到後面。這樣就行了。又或者你用SPI、CAN、USB等等,或者直接用文件系統,讓第一段程序從SD卡或者SPI FLASH裡面直接讀取bin文件寫到後面。當然如果你用了文件系統,或者屏幕顯示,那麼可能第一段程序就比較大了,這時候就得把新程序再往後挪一下了,比如0x0801 2000。如果沒有串口、USB、卡槽呢?比如你的WIFI燈泡,對的,你還有WIFI和藍牙,說白了它倆不也是串口嘛,所以你還可以無線更新,還是串口。

        這樣算一個IAP了嗎?還不行,為什麼呢?總不能每次插電都寫一次FLASH吧,FLASH寫壽命相對來說還是比較短的。這時候你可以做個標誌位,寫好之後就標記一下,下次上電開機就不再寫了。但是,你如果還想再接著更新新的程序呢?顯然這時候又不行了。

        比較常用的做法是,正常情況下不更新,比如100次開機可能99次都是正常使用。那什麼時候不正常呢?正常開機怎麼開呢?懟一下開關或者長按開機對吧,如果還有其他按鍵,我們可以讓第一段程序檢測是不是開機和其他的按鍵一起按下去了,是的話就更新,不是的話那就是正常開機,不去更新程序就是了。比如你的手機開機的時候和電源鍵一起長按音量-就可以刷機。

Bootloader流程

        對了,我們的標題不是Bootloader嗎,怎麼說了一堆的IAP呢?其實實現IAP功能方便我們更新程序的這個程序就是Bootloader,由它來引導新程序的運行。它總是最先運行的,因此才能引導和更新別的程序。就和linux的uboot、windiws的BOOT一樣,它在一開機的時候就跑起來了,如果你快速點del按鍵就能讓它不引導windows,這時候你就可以裝新系統了。

        再來歸納一下Bootloader,首先它是系統運行時跑的第一個程序。在stm32單片機中就是0x0800 0000這裡的程序。其次如果沒有更新需求(比如沒有特殊組合按鍵按下),它就引導新的程序,就是跳轉過去執行。如果有呢,它就從別處更新新的程序,然後再跳轉過去引導剛更新過的程序。Bootloader還需要知道自己的體積,把新程序寫在自己的後面。或者再往後寫一點留一點空間,比如後期需要換成SD卡更新呢,可能之前的空間就不夠了。

        對於新的程序,需要知道自己的位置,然後把中斷向量表偏移過去,也就是自己存儲的首地址。就像bootloader和普通的程序同樣都是偏移到0x0800 0000一樣。而新程序還要在此基礎上加上自己存儲的偏移量。比如0x0801 0000。

        至此我們才設計完成了一個完整的最簡單的IAP。

        在此基礎上,你還可以設計多個新程序,存儲在bootloader之後的不同的位置,選擇性跳轉,想跑哪個跑哪個,想怎麼跑怎麼跑。或者你還可以在新程序中設置變量,讓bootloader重啟的時候根據這個變量來更新,又或者讓bootloader自己搜一下SD卡或者USB接口什麼的甚至聯網查一下有沒有新的程序,有的話就讓它自己更新。

        最後值得注意的是中斷,因為bootloader是函數指針式跳轉,不是重啟,所以bootloader中有的中斷服務函數在新程序中找不到的話,可能中斷時找不到入口程序就崩了。因此在運行新程序的時候關閉所有的中斷,之後再跳轉。或者Bootloader程序直接觸發一下復位。即調用__NVIC_SystemReset。 

相關焦點

  • STM32單片機的Bootloader詳解(2)
    總不能需要編輯個文檔就買一套Word吧,總不能學個單片機花數十萬買MDK和AD授權吧。一定程度上這些也是大多數人需求。這裡關於故意引導用戶習慣養成、低價&盜版擠壓壟斷軟體市場壟斷等等的話題我們就不談了。        那麼如果你不想你做的產品輕輕鬆鬆被人家複製,你就需要花一點功夫了。
  • 詳解STM32單片機的堆棧
    普通單片機啟動時,不需要用bootloader將數據 從ROM搬移到RAM。但是STM32單片機需要。這裡我們可以先看看單片機程序執行的過程,單片機執行分三個步驟:    根據PC的值從程序存儲器讀出指令,送到指令寄存器。然後分析執行執行。這樣單片機就從內部程序存儲器去代碼指令,從RAM存取相關數據。
  • ARM、單片機、stm32、51單片機、和開發板的概念、區別及包含關係
    為了滿足消費電子的需求而改進arm7,代號為cortex -m,這樣st或nxp等產家以這個新的核心來加自己的外設就得到了stm32或lpc系列的單片機了。可以清楚得到stm32是基於ARM Cortex-M3內核的,但不屬於ARM。因為ARM公司只提供了處理器,st(意法半導體)還有nxp(恩智浦半導體)廠家以此內核為核心添加外設得到了stm32或lpc系列單片機。
  • 如何在keil中仿真stm32單片機
    那麼當切換到stm32系列單片機的時候,protues明顯不支持了,但是keil的模擬功能還是有很大的用處,例如stm32f103單片機,在keil中可以實現很好的模擬效果,我們可以在其中使用中斷、定時器、PWM等功能,可以觀測到GPIO的輸出情況。然而keil對stm32系列單片機不是很好的支持,如果換一個型號,你會發現完全無法模擬!!!
  • 【C++開發Stm32-環境搭建】 Stm32f103c8t6支持Arduino庫開發
    那就用C Plus Plus來寫stm32單片機代碼吧!藉助Arduino的庫,輕鬆使用面向對象的思想開發單片機。本教程分享stm32支持Arduino庫開發的環境搭建。一、硬體準備支持數據通信的micro usb線(普通Android數據線)二、軟體準備GitHub下載 Arduino_STM32 和 STM32duino-bootloader百度雲安裝包共享目錄 提取碼:49jr三、軟體安裝1. 安裝 STM Cube Programmer下載連接,該軟體UI界面簡潔,使用簡單。
  • 深入分析STM32單片機的RAM和FLASH
    最近在一個問答社區回答了一個問題,關於單片機存儲器的,於是有了想專門寫一篇關於單片機存儲器的想法。
  • STM32與Arduino問答集
    www.stm32duino.com       此論壇網專門針對STM32系列晶片板,即時更新相關ArduinoIDE 環境API。 問:我如何開始著手?答:1.在Arduino 1.6.12 環境下安裝stm32duino 支持包視頻:https://www.youtube.com/watch?
  • STM32單片機Bootloader設計(上)
    STM32的啟動文件STM32作為一款單片機,它的啟動方式很簡單,即當Boot配置了從內部
  • STM32系統bootloader應用
    嵌入式開發中,經常需要bootloader進行程序固件升級和系統維護,所以bootloader是必不可少的功能。
  • 手把手教學《60天學會stm32單片機培訓班》今日更新知識點260+
    以下200+知識點,僅僅是《60天學會stm32單片機培訓班》眾多知識點中的一小部分,還有一大批知識點我們會持續更新,敬請關注。1.什麼是單片機?有什麼用?都用在我們生活中什麼地方?2.什麼是掩膜單片機?究竟可以做到多小?3.單片機有什麼特點?價格?功耗等等。。。4.單片機由什麼組成?5.什麼是外設?
  • STM32單片機最小系統詳解
    在最小系統保證正確的基礎上,可以依次添加其他功能模塊或器件,使之單片機具有實際功能。STM32單片機最小系統包括一個復位電路和一個時鐘電路。如下圖1所示。圖中復位電路使用的是上電復位電路,STM32單片機NRST引腳輸入低電平,則發生復位。
  • 汽車電子ECU BootLoader開發之基於CAN總線通信的MPC574xP系列MCU bootloader開發詳解
    而Qorivva MPC57xx系列汽車級MCU相對來說,其外設功能模塊更加複雜,片上集成的存儲器--SRAM和Flas模塊較之前的S12(X)系列MCU尺寸更大而且更加複雜,另外,其軟體開發環境--S32DS for Power V1.0/1/2也是一個推出不到兩年的新環境,用戶相對不是和熟悉,這些因素都導致Qorivva MPC57xx系列汽車級MCU的bootloader
  • STM32單片機輕鬆入門與實踐 — 暢學單片機
    本課程是STM32單片機學習者從入門到深入的一套經典視頻教程,以初學者為對象,從零開始手把手教你學習單片機,循序漸進地基於理論講解並結合實驗項目實戰開發,講解當前最熱門的STM32單片機的C程序設計!
  • STM32 與 Arduino
    stm32duino 對常見的 MCU 做了廣泛的支持,開發板之間的不同大都體現在 MCU 的外圍電路上,去複製同 MCU 的文件夾改動量會小很多。2、讓加入的自定義配置與 Arduino 關聯。下面以 ATMega 單片機(Arduino 原生支持的單片機)為例,說下怎樣在 VSCode 下開發 Arduino(以 Ubuntu 系統為例)。下面的截圖裡看到了 platformio,因為 Sugar 在 Ubuntu 上的 VSCode 下同時裝了 platformio 和 Arduino 兩個組件。但使用的是 Arduino 與 platformio 無關。
  • STM32_IAP詳解(有代碼,有上位機)
    實現iap有兩個很重要的前提,首先,單片機程序能對自身的內部flash進行擦寫,第二,單片機要有能夠和外部進行通訊的方式,無論是網絡還是別的方式,只要能傳輸數據就行通常實現 IAP 功能時,即用戶程序運行中作自身的更新操作,需要在設計固件程序時編寫兩個項目代碼,第一個項目程序不執行正常的功能操作,而只是通過某種通信方式(如 USB、 USART)接收程序或數據,執行對第二部分代碼的更新
  • 預熱 | 萬眾期待的單片機、Linux二合一的STM32MP157開發板亮相
    均支持於100ask_stm32mp157_pro硬體開發平臺,廣泛應用於生活的各種智能場景。百問網STM32mp157開發板GUI演示視頻我們為什麼要做STM32mp157開發板?從教學角度看硬體描述Cortex M4跑單片機、RTOS,用keil開發,跟STM32F103一模一樣Cortex A7*2跑Linux,可以引入SMP的知識,以覆蓋單CPU系統的知識GPU可以實現更炫的GUI效果,可以跑一些AI算法從做產品角度看硬體描述MPU+MCU需要單片機+Linux的場合,用STM32MP157就可以實現GPU可以實現更炫的GUI效果,可以跑一些AI算法性價比高作為多核異構的晶片
  • STM32下載程序新思路--使用串口下載STM32程序
    圖 1 USB 轉串口驅動安裝成功如果識別不了串口,請檢查 USB 線是否完好,可換一根 USB 線試試。注意:STM32F1系列單片機RX/TX分別對應單片機上的PA9/PA10兩個引腳,在使用單片機(第一次下載)時需要將單片機上的BOOT0\BOOT1進行接地處理。
  • 這樣學習STM32單片機,從菜鳥到牛人很簡單!
    我想說,為了學習單片機而去學習單片機的思路不對。你問,如何系統地入門學習stm32呢?
  • 圖解單片機下載程序電路原理之USB轉串口線、CH340、PL2303、MAX232晶片的使用!
    目前為止,我接觸單片機已有不少時日,從選擇元器件、原理圖、PCB、電路硬體調試、軟體開發也算小有心得。單片機軟體開發裡面第一步當屬下載程序了,如果這一步都有問題,那麼後面的一切便無從談起,本人當初剛接觸單片機時,對於下載電路方法及原理也是一頭霧水。好在隨著經驗的積累以及自己的努力探求,現在對此問題算是有了點點自己的理解。故今天在此針對常用51單片機下載程序問題做下詳解,以求新手們少走彎路。當然,有誤之處還望各位指教!
  • STM32單片機和51單片機有何區別?
    而單片機將這些都集中在了一個晶片上。應用最廣泛的8位單片機,當然也是初學者們最容易上手學習的單片機。最早由Intel推出,由於其典型的結構和完善的總線專用寄存器的集中管理,眾多的邏輯位操作功能及面向控制的豐富的指令系統,堪稱為一代「經典」,為以後的其它單片機的發展奠定了基礎。