前言:
源碼下載鏈接:
https://gitee.com/yang456/STM32_IAP_Learn.git
后期所有出售的升級程序皆在此代碼之上進行優化和開發
請必須把此文章各個的地方的說明看懂,其它教程不再重復敘述.
下載bootloader程序 我用stlink下載哈,方便


選擇程序文件

首先需要發送一條指令
updata start

然后發送程序文件



說明接收並運行了咱寫的APP程序.
IAP詳細說明:
所謂單片機的升級實質上就是把手動用軟件下載程序,改為咱人為通過某種方式寫到Flash
打開下面的程序

如果編譯出錯,可能是這里

我這里是讓軟件幫忙生成bin文件
我寫的是
E:\MDK5\ARM\ARMCC\bin\fromelf.exe --bin -o .\Progect\Progect.bin .\output\Progect.axf
E:\MDK5\ARM\ARMCC\bin\fromelf.exe --bin -o 這是命令,意思是讓軟件生成bin文件
前面這個路徑和自己安裝軟件的路徑有關,下面是我的路徑

.\Progect\Progect.bin 就是生成的bin文件名字是 Progect.bin ,路徑是工程目錄的 Progect文件夾里面(如果沒有則會自動建個文件夾)
所謂工程目錄

.\output\Progect.axf 當前工程目錄的output文件夾里面的Progect.axf文件
.axf這個文件也是由軟件生成的,這個文件里面有咱要的bin文件數據,當然還有一些調試信息
我設置的是生成的文件名字是Progect.axf

我自己設置的 讓文件生成到output文件夾



其實整理下就是
E:\MDK5\ARM\ARMCC\bin\fromelf.exe --bin -o .\Progect\Progect.bin .\output\Progect.axf
用fromelf.exe里面的--bin -o指令,把Progect.axf文件里面的bin數據提取出來以后生成一個新的文件 Progect.bin
現在看bin文件 和 hex文件的區別


看沒看到hex比bin文件多了前面一部分,和后面一部分
大家下載單片機程序應該都知道是下載hex文件
但是大家了解整個的下載過程不
其實咱用軟件下載的時候首先單片機需要知道下載的這段程序下載到哪個地址上(把程序數據寫到哪個Flash地址)
所以hex文件的前面部分就是地址信息,就是告訴芯片我后面的代碼段存儲到哪個地址上
當然為了保險起見,數據需要加校驗,其實hex文件的最后一位就是校驗位
像51單片機,STM32的串口下載,下載的時候需要斷電上電,或者復位一下,其實咱的單片機里面有一段程序(接收單片機程序,寫入Flash) 就是咱所說的bootloader
記不記得都是先點一下下載軟件的下載按鈕,然后再復位單片機
其實點一下下載軟件,下載軟件就一直串口輸出下載命令呢!單片機一啟動是先執行里面內嵌的bootloader,bootloader一檢測到下載命令,就開始執行下載操作了,接收下載軟件過來的數據,然后寫到Flash里面.....寫完了,有的單片機重啟下才運行,有的就直接運行了
好,現在說bin文件為啥去掉了前面的地址信息
記住,咱自己更新的時候咱就規定好了程序的運行位置
注:大家應該知道0x08000000 和 0x8000000 是相等的
STM32默認一開始是從0x8000000開始運行的,程序默認也寫到這里(注意這個是不可改變的)
但是呢咱可以手寫個代碼把一個完整的程序文件寫到一個位置(假設寫到 0x8004000開始)
然后呢!調用STM32給的跳轉函數,填上跳轉地址(0x8004000),程序就跳轉到新地址運行了
我這幾代碼呢!是這樣做的,第一部分代碼(簡稱:bootloader),什么也不配置,就是默認運行在 0x8000000地址
bootloader 代碼主要做的就是串口接收程序文件(簡稱APP,注意是bin文件哈),然后把程序bin文件寫到指定的Flash地址,寫完之后,跳轉到這個地址執行
不過呢!APP代碼除了上面說的是下載bin文件以外,還需要配置
我先說明 APP程序寫到哪個地址其實和bootloader程序有關
注意沒

咱的bootloader 程序需要占用10KB的空間,也就是說
10KB = 10*1024 = 10240字節 = 0x2800

那么咱的APP程序一開始寫入的地址必須大於 0x8002800
如果寫入的地址占用了bootloader的地址,那么程序就崩了
我的bootloader 代碼主要做的就是串口接收程序文件(簡稱APP,注意是bin文件哈),然后把程序bin文件寫到指定的Flash地址,寫完之后,跳轉到這個地址執行,你可不能讓這個代碼崩....程序一開始就是執行bootloader,如果這個程序有問題了,整個就崩了...
現在看用戶程序的其它配置
假設我想讓APP個程序運行在0x8004000地址,那么需要讓軟件生成可以運行在這個地址的bin文件才可以,所以

默認是0x8000000
還需要修改下SIZE,上面寫的是0x10000 也就是65536字節 = 64KB 我用的單片機是C8T6哈,Flash就是64KB的
咱改為 0x8004000
0x4000 就是 16384字節 其實整個FLASH還剩下 65536 - 16384 = 49152 字節 也就是 0xC000

好,現在生成的程序就是可以運行在 0x8004000的程序了
但是呢還有個問題!
中斷問題!
咱可以在bootloader MAP文件里面看到


往下還有各種中斷
如果咱不在APP程序里面做一下設置,那么APP程序里面的中斷其實會跳進 bootloader 里面(假設bootloader 也使用了一樣的中斷)
這個我的視頻會給大家演示
咱需要讓APP里面生成自己單獨的一套中斷
所以呢咱需要設置下中斷向量偏移,一般都是咱的APP程序相對於Flash地址偏移了多少,咱就設置中斷向量偏移多少
SCB->VTOR = FLASH_BASE | 0x4000;
這樣的話,所有的APP里面分配的中斷函數地址最起碼是在0x8004000地址的基礎上的

其實現在APP程序就准備好了,
不過大家百度STM32 IAP,有很多人在bootloader里面這樣寫
if(((*(vu32*)(UpdateAddrCopy+4))&0xFF000000)==0x08000000 && ((*(vu32*)UpdateAddrCopy)&0x2FFE0000)==0x20000000)
這就是對接收bin數據的(看的bootloader的bin數據) 

這兩個位置進行判斷
前面的四位是說明咱的整個程序占用的RAM空間最高地址 注意:STM32是小端模式,低位存在低位,高位存在高位
所以上面的是 0x20000978
大家應該知道咱的全局變量和局部變量都是存在RAM里面的

咱的STM32 RAM的首地址是0x20000000 我的后面是0x5000 = 20480字節 = 20KB (20480/1024)
咱可以看一下那個MAP

其實咱知道咱用的RAM空間是 0x20005000
其實在細致一點就是判斷高16位是不是 0x2000 然后低16位是不是小於0x5000
而程序中只是 ((*(vu32*)UpdateAddrCopy)&0x2FFE0000)==0x20000000
然后還有個 ((*(vu32*)(UpdateAddrCopy+4))&0xFF000000)==0x08000000
大家看MAP文件
bootloader 的MAP文件為例

0x08001F35

實際上這個Flash地址里面存儲的是復位中斷入口地址,得到這個地址以后執行復位中斷服務程序
復位中斷入口地址是0x08001F35
這個數據存在了 Flash的 0x08000004 (1F35) 和 0x08000006 (0800) 地址里面
注意:所有的中斷入口地址都存在了Flash里面,咱定義的函數的入口地址也是在Flash里面
咱編譯的時候,軟件就給中斷函數和咱寫的普通函數分配空間 (從0x08000XXX)開始分,注意不是從0x08000000開始哈,具體前面的空間具體給誰我也不知道,但是呢!看上面就知道第一個32位(0x08000000 - 0x08000003),存儲的是堆棧棧頂地址(整個程序占用的RAM空間最高地址)
第二個32位(0x08000004 - 0x08000007) 存儲的是復位中斷入口地址
可以看下MAP,這是分配的地址

分完以后函數的首地址就有了
然后再把這些地址存到Flash里面,從0x08000000開始存
不過Cortex-M3內核規定,Flash起始地址必須存放堆頂指針,而第二個地址則必須存放復位中斷入口向量地址
其它的我就不知道按照什么規則存了
當然后面的

不可屏蔽中斷,就是說系統出現了不可挽回的錯誤的時候會進去這個中斷

還有

硬件錯誤中斷,像數組越界,內存溢出等等都會進去

然后,發現后面基本上都是各種中斷函數...如果大家想判斷的更准確的話,就多判斷幾個08
其實各種中斷函數的地址都存在了Flash里面,由於一開始是初始化各種中斷,所以才出現這么多08

接收完程序就可以跳轉了

其實呢跳轉是固定形式,上面有注釋
所有涉及到的主要的IAP知識點就說完了
現在說下我的源碼思路
我為了方便我修改用戶程序軟件上的配置

我設置的bootloader使用了16K,實際上我的bootloader只用了10K

其實只要內存充足,自己願意定義多少就定義多少,前提看APP程序占用多少空間,只要預留的夠APP使用就可以

總共 64K 去掉 16K 還有 48K...足夠用
然后我再主函數里面打印了一下


其實就對應用戶程序

這樣方便一點
bootloader函數接收到 updata start以后先擦除APP程序所用的Flash地址空間

然后咱發bin數據的時候

環形隊列: https://www.cnblogs.com/yangfengwu/p/11670917.html
環形隊列實際上就是用一些函數操作數組,可以一邊往里面存數據,一邊取數據

我就是用5字節大小的數組,來接收的APP程序(21K),然后寫入Flash

由於讀環形隊列然后寫入其實挺快的,有時候串口接收數據的速度趕不上,所以


其實就是類似於空閑中斷,10ms的時間內串口都沒有接收到數據,就認為接收到一條完整的數據

其實用戶程序也就是上面說的那些配置
來吧!說說這節升級程序的BUG
來吧!說說這節升級程序的BUG
來吧!說說這節升級程序的BUG
記住一句話: BootLoader 程序里面設置的硬件配置,中斷配置在跳轉到APP程序里面的時候同樣有效!!!!
除非APP里面重寫硬件配置,中斷配置,否則,還是默認運行的BootLoader里面配置的
所以,看一下BootLoader函數里面的

而,用戶程序里面

實際上BootLoader里面的

在加載用戶程序的過程中還在運行,
由於加載用戶程序的時候會重新分配RAM,
導致了BootLoader定時器里面的用到的那些變量沒有了,
那么執行用戶程序就可能造成死機,
注意:不是用戶程序導致的死機,而是由於運行BootLoader里面的定時器中斷里面的程序導致的死機
因為變量沒有了,所以程序執行就崩潰了.
但是大家測試這節的時候發現並沒有死機,
我認為原因是加載用戶程序的時候及時的重新重新配置了 延時函數

大家可以把這個函數往后放放試一試.
解決方法
首先要明確: 凡是BootLoader程序里面用到的中斷函數,在用戶程序里面都需要重寫

可以什么也不干,但是必須寫上
最好的方式是凡是BootLoader里面用到的中斷函數,用戶程序全部重新寫一遍.可以不用,但是必須重寫!
