悶騷程序猿的乾貨之二:單片機Bootloader程序簡介
本文將以STM32單片機為例,簡要介紹Bootloader程序的實現過程。
一.基本概念
1.1.IAP
IAP是In Application Programming的首字母縮寫,IAP是用戶自己的程序在運行過程中對User Flash的部分區域進行燒寫,目的是為了在產品發布后可以方便地通過預留的通信口對產品中的固件程序進行更新升級。
通常在用戶需要實現IAP功能時,即用戶程序運行中作自身的更新操作,需要在設計固件程序時編寫兩個項目代碼,第一個項目程序不執行正常的功能操作,而只是通過某種通信管道(如USB、USART)接收程序或數據,執行對第二部分代碼的更新;第二個項目代碼才是真正的功能代碼。
1.2.Bootloader
Advertisements
在上述IAP的概念中,bootloader就是其第一個項目程序。bootloader主要實現的功能:從串口、USB等媒介接收數據;存儲和搬運數據;程序跳轉等功能。
1.3.App程序
對IAP概念中,對第二個項目代碼的一種稱呼。
1.4.Ymodem
YModem協議是由XModem協議演變而來的,每包數據可以達到1024位元組,是一個非常高效的文件傳輸協議。
圖1. Ymodem一幀數據的結構
解釋:
第一位元組:1.為SOH,有效數據包大小為128位元組;
2.為STX,有效數據包大小為1024位元組。
第二位元組:數據包的編號,第一幀數據,編號為00。
第三位元組:數據包編號的反碼,第一幀數據,為FF。
有效數據區:根據第一個位元組的內容,有效數據區大小為128位元組或1024位元組。
Advertisements
倒數第二個位元組:CRC校驗高位。
最後一個位元組:CRC校驗低位。
註:參加CRC校驗的只有有效數據區。
所以,一幀Ymode數據有(3+1024+2)個位元組,或(3+128+2)個位元組
二.Smt32-bootloader設計思路
本bootloader的主要作用是,通過串口進行程序的升級。
2.1 Nand flash分區情況
圖2. 自定義flash分區情況
2.2大致流程
板子開機后,由用戶觸發進入程序更新界面。
a.通過串口接收上位機發送的bin文件,並存儲在分區C。
b.接收完bin文件后,將分區C中的bin文件搬運到分區B,並將搬運的狀態保存在分區D。
c.bin文件全部搬運到分區B后,重置中斷向量表,並實現程序跳轉。
d.如果在步驟b,搬運代碼的過程中,出現意外狀況,導致搬運中斷,則在下次開機后,會再次重新搬運,直到搬運成功。
三.具體實現
3.1選擇晶元類型
在option for Target菜單中的Device欄中,選擇晶元類型;
3.2各類設置
1.定義晶元flash大小
方法a.在Flash->Configure flash tools…->C/C++-->Define中定義宏,
比如STM32F10X_HD(stm32單片機的內置flash為大容量)
方法b.在stm32f10x.h文件中,增加STM32F10X_HD的宏定義.
#if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD) && !defined (STM32F10X_HD_VL) && !defined (STM32F10X_XL) && !defined (STM32F10X_CL)
#define STM32F10X_HD
#endif
使用方法a和方法b都可以設置。選擇不同的宏,則內嵌的nand flash的總大小及每頁的大小是不一樣的。並且對於內嵌的nand flash,其擦除是以頁為單位的,而不是塊。
圖3. 片內flash大小與宏定義的關係
2.設置程序下載的地址
步驟1.在Flash->Configure flash tools…->Target中,設置IROM1的Start和Size。
步驟2.system_stm32f10x.c文件中
#define VECT_TAB_OFFSET 0x00000設置中斷向量表的偏移地址。(以flash的起始地址為基準)
所以bootloader程序和app程序的這兩個設置都是不一樣的。
3.3程序跳轉實現(抄網上的代碼的)
typedef void (*iapfun)(void);
iapfun jump2app;
__asm void MSR_MSP(u32 addr)
{
MSR MSP, r0 //set Main Stack value
BX r14
}
voidCloseIQHard(void)
{
GPIO_DeInit(GPIOA);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, DISABLE);
//關輔助時能時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,DISABLE);
__disable_irq(); // 關閉總中斷
}
void BootloaderJump2App(uint32_t appxaddr)
{
CloseIQHard();
//檢查棧頂地址是否合法.
if(((*(vu32*)appxaddr)&0x2FFE0000)==0x20000000)
{
//用戶代碼區第二個字為程序開始地址(複位地址)
jump2app = (iapfun)*(vu32*)(appxaddr+4);
//初始化APP堆棧指針(用戶代碼區的第一個字用於存放棧頂地址)
MSR_MSP(*(vu32*)appxaddr);
jump2app();//跳轉到APP.
}
}
在void BootloaderJump2App(uint32_t appxaddr),其中appxaddr為需要跳轉到的flash地址。
因為在跳轉程序中,將總中斷關閉,所以在應用程序中,要將總中斷打開。
3.4.程序流程
圖4.程序流程圖
註:串口下載的具體流程:
串口接收文件使用Ymodem協議。使用串口中斷接收。首先根據第一幀數據判斷文件的大小,然後進行flash的擦陳。接收正式數據時,先接收一幀數據並校驗,然後在將數據存儲到flash中,再接收下一幀數據。