AVR BootLoader應用範例

2021-01-13 電子產品世界

/***********************************************
**** AVR BootLoader應用範例 ***
**** ***
**** 作者: HJJourAVR ***
**** 編譯器:WINAVR20050214 ***
**** ***
****www.OurAVR.com2005.10.17 ***
***********************************************/
//程序參考 馬潮老師的M128 Boot_load應用的實例,ICCAVR版本
//Stephen更改:9600bps, MEGA16, 8M INTERNAL RC,BOOTSZ1=0, BOOTSZ0=0, BOOTRST=1
/*
本程序簡單的示範了AVR ATMEGA16的IAP應用,實現智能升級
Boot Loader
XMODEM-CRC傳輸協議
CRC16校驗

出於簡化程序考慮,各種數據沒有對外輸出,學習時建議使用JTAG ICE硬體仿真器。
熔絲位設置
BOOTSZ1=0
BOOTSZ0=0 Boot區為1K字(2K字節)大小。
BOOTRST=0 復位向量位於Boot區。//Stephen: 設BOOTRST=1,允許啟動

makefile中的程序基地址偏移
LDFLAGS += -Wl,--section-start=.text=0x3800 //0x3800位元組=0x1C00字

移植程序時,可根據實際大小設定Boot區,但要注意更改makefile和更改BootAdd常數,以及頁寫的大小分配;

本文引用地址:http://www.eepw.com.cn/article/201611/316385.htm

採用115200bps的通訊速率,升級14KB程序需要耗時約5秒[上位機是WINDOWS 2000的超級終端]

疑問:
1 用HEX文件燒錄工作正常,但elf仿真有問題。
用AVRstudio仿真elf(熔絲設定BOOTRST=0,程序基地址偏移=0x3800)時,所有SRAM變量丟失初始化,
表現為put_s()的都是亂碼或不可見字符。
但如果改成應用程式(熔絲設定BOOTRST=1,沒有程序基地址偏移),則put_s()可以正常顯示

2 XMODEM的結束應答(EOT/CAN)後需加 delay_ms(500)的延時(程序優化,統一寫在跳轉到用戶程序前),
否則在下面的情況將會無法正常結束XMODEM的傳輸,但其實程序已經升級成功
特殊情況:用戶程序裡面使用了串口,而且波特率較低(如9600bps)且開機即發送大量數據

*/

#include <avr/io.h>
#include
//時鐘定為外部晶體7.3728MHz,F_CPU=7372800 使用USART,115200bps
#include
/*
boot_page_erase ( address )
擦除FLASH 指定頁,其中address 是以字節為單位的FLASH 地址
boot_page_fill ( address, data )
填充BootLoader 緩衝頁,address 為以字節為單位的緩衝頁地址(對mega16 :0~128),
而data 是長度為兩個字節的字數據,因此調用前address 的增量應為2。
此時data 的高字節寫入到高地址,低字節寫入到低地址。
boot_page_write ( address )
boot_page_write 執行一次的SPM 指令,將緩衝頁數據寫入到FLASH 指定頁。
boot_rww_enable ( )
RWW 區讀使能

根據自編程的同時是否允許讀FLASH 存儲器,FLASH 存儲器可分為兩種類型:
可同時讀寫區( RWW Read-While-Write ) 和 非同時讀寫區( NRWW NotRead-While-Write)。
對於MEGA16 RWW 為前14K 字節 NRWW 為後2K 字節。
引導加載程序對RWW 區編程時MCU 仍可以從NRWW 區讀取指令並執行,而對NRWW 區編程時MCU 處於掛起暫停狀態。
在對RWW 區自編程(頁寫入或頁擦除)時,由硬體鎖定RWW 區 , RWW 區的讀操作被禁止
在對RWW 區的編程結束後應當調用boot_rww_enable() 使RWW 區開放。
*/
#include
/*
GCCAVR內置函數,可以不用頭痛CRC16了
關於CRC的詳細說明,可以查看一下網站:
http://www.nongnu.org/avr-libc/user-manual/group__avr__crc.html
函數原形
static __inline__ uint16_t _crc16_update(uint16_t __crc, uint8_t __data);
多項式Polynomial: x^16 + x^15 + x^2 + 1 (0xa001)
crc初始值Initial value: 0xffff
通常用於磁碟控制器(disk-drive controllers)
static __inline__ uint16_t _crc_xmodem_update(uint16_t __crc, uint8_t __data);
多項式Polynomial: x^16 + x^12 + x^5 + 1 (0x1021)
crc初始值Initial value: 0x0
專用於XMODEM通訊協議,等效於C寫的
uint16_t crc_xmodem_update (uint16_t crc, uint8_t data)
{
int i;
crc = crc ^ ((uint16_t)data << 8);
for (i=0; i<8; i++)
{
if (crc & 0x8000)
crc = (crc << 1) ^ 0x1021;
else
crc <<= 1;
}
return crc;
}
static __inline__ uint16_t _crc_ccitt_update (uint16_t __crc, uint8_t __data)
多項式Polynomial: x^16 + x^12 + x^5 + 1 (0x8408)
crc初始值Initial value: 0xffff
專用於PPP和IrDA通訊協議
*/

//管腳定義
#define PIN_RXD 0 //PD0
#define PIN_TXD 1 //PD1

//常數定義
#define SPM_PAGESIZE 128 //M16的一個Flash頁為128位元組(64字)
#define DATA_BUFFER_SIZE SPM_PAGESIZE //定義接收緩衝區長度
#define BAUDRATE 9600 //115200 //波特率採用115200bps
//#define F_CPU 7372800 //系統時鐘7.3728MHz

//定義Xmoden控制字符
#define XMODEM_NUL 0x00
#define XMODEM_SOH 0x01
#define XMODEM_STX 0x02
#define XMODEM_EOT 0x04
#define XMODEM_ACK 0x06
#define XMODEM_NAK 0x15
#define XMODEM_CAN 0x18
#define XMODEM_EOF 0x1A
#define XMODEM_WAIT_CHAR C

//定義全局變量
struct str_XMODEM
{
unsigned char SOH; //起始字節
unsigned char BlockNo; //數據塊編號
unsigned char nBlockNo; //數據塊編號反碼
unsigned char Xdata[128]; //數據128位元組
unsigned char CRC16hi; //CRC16校驗數據高位
unsigned char CRC16lo; //CRC16校驗數據低位
}
strXMODEM; //XMODEM的接收數據結構

unsigned long FlashAddress; //FLASH地址
#define BootAdd 0x3800 //Boot區的首地址(應用區的最高地址)
/* GCC裡面地址使用32位長度,適應所有AVR的容量*/

unsigned char BlockCount; //數據塊累計(僅8位,無須考慮溢出)

unsigned char STATUS; //運行狀態
#define ST_WAIT_START 0x00 //等待啟動
#define ST_BLOCK_OK 0x01 //接收一個數據塊成功
#define ST_BLOCK_FAIL 0x02 //接收一個數據塊失敗
#define ST_OK 0x03 //完成


//長延時 max 65536ms
void delay_ms(unsigned int t)
{
while(t--)
{
_delay_ms(1);
}
}

//更新一個Flash頁的完整處理
void write_one_page(void)
{
unsigned char i;
unsigned char *buf;
unsigned int w;
boot_page_erase(FlashAddress); //擦除一個Flash頁
boot_spm_busy_wait(); //等待頁擦除完成
buf=&strXMODEM.Xdata[0];
for(i=0;i {
w =*buf++;
w+=(*buf++)<<8;
//boot_page_fill(FlashAddress+i, w); //原句
boot_page_fill(i, w); //只是低7位(128位元組/頁)有效
}
boot_page_write(FlashAddress); //將緩衝頁數據寫入一個Flash頁
boot_spm_busy_wait(); //等待頁編程完成
}

//發送採用查詢方式
void put_c(unsigned char c) //發送採用查詢方式
{
loop_until_bit_is_set(UCSRA,UDRE);
UDR=c;
}

//發送字符串
void put_s(unsigned char *ptr)
{
while (*ptr)
{
put_c(*ptr++);
}
put_c(0x0D);
put_c(0x0A); //結尾發送回車換行
}


//接收指定字節數據(帶超時控制,Timer0的1ms時基)
// *ptr 數據緩衝區
// len 數據長度
// timeout 超時設定,最長65.536S
// 返回值 已接收字節數目
unsigned char get_data(unsigned char *ptr,unsigned char len,unsigned int timeout)
{
unsigned count=0;
do
{
if (UCSRA & (1< {
*ptr++=UDR; //如果接收到數據,讀出
count++;
if (count>=len)
{
break; //夠了?退出
}
}
if(TIFR & (1< {
TIFR|=(1< timeout--; //倒計時
}
}
while (timeout);
return count;
}

//計算CRC16
unsigned int calcrc(unsigned char *ptr, unsigned char count)
{
unsigned int crc = 0;
while (count--)
{
crc =_crc_xmodem_update(crc,*ptr++);
}
return crc;
}

//主程序
//int main() __attribute__((section(".stephen_bootloader"))); //stephen_bootloader
int main()
{
unsigned char c;
unsigned char i;
unsigned int crc;
//考慮到BootLoader可能由應用程式中跳轉過來,所以所用到的模塊需要全面初始化
DDRA=0x00;
DDRB=0x00;
DDRC=0x00;
PORTA=0xFF; //不用的管腳使能內部上拉電阻
PORTB=0xFF;
PORTC=0xFF;
PORTD=0xFF;
DDRD=(1< GICR = (1< GICR = (0<asm volatile("cli": : ); //關全局中斷
//這個BootLoader沒有使用中斷。

//初始化USART 115200 8, n,1 PC上位機軟體(超級終端)也要設成同樣的設置才能通訊
UCSRC = (1< UBRRL = (F_CPU/BAUDRATE/16-1)%256; //設定波特率
UBRRH = (F_CPU/BAUDRATE/16-1)/256;
UCSRA = 0x00;
UCSRB = (1< //初始化T/C0,CTC模式,256分頻,1ms自動重載
OCR0 = 28;
TCCR0 = (1< //CTC模式下,溢出標誌是輸出比較匹配OCF0,對應的中斷是輸出比較匹配中斷;

//向PC機發送開始提示信息
put_s("************************************************************");
//put_s(" ");
put_s("IC ATMega16 Firmware 智能升級引導程序(Bootloader)VER20070107");
put_s(" 使用Windows2000/xp 超級終端 串口發送 9600bps,8-N-1 ");
put_s("如需更新用戶程序,請在3秒鐘內按下[d]鍵,否則3秒後運行用戶程序 ");
put_s(">");

//3秒種等待PC下發「d」,否則退出Bootloader程序,從0x0000處執行應用程式
c=0;
get_data(&c,1,3000); //限時3秒,接收一個數據
if ((c==d)||(c==D))
{
STATUS=ST_WAIT_START; //並且數據=d或D,進入XMODEM
put_s("請選擇BIN文件,使用XMODEM協議傳輸,最大14KB");
}
else
{
STATUS=ST_OK; //退出Bootloader程序
}

//進入XMODEM模式
FlashAddress=0x0000;
BlockCount=0x01;
while(STATUS!=ST_OK) //循環接收,直到全部發完
{
if (STATUS==ST_WAIT_START)
{//XMODEM未啟動
put_c(XMODEM_WAIT_CHAR); //發送請求XMODEM_WAIT_CHAR
}
i=get_data(&strXMODEM.SOH,133,1000); //限時1秒,接收133位元組數據
if(i)
{
//分析數據包的第一個數據 SOH/EOT/CAN
switch(strXMODEM.SOH)
{
case XMODEM_SOH: //收到開始符SOH
if (i>=133)
{
STATUS=ST_BLOCK_OK;
}
else
{
STATUS=ST_BLOCK_FAIL; //如果數據不足,要求重發當前數據塊
put_c(XMODEM_NAK);
}
break;
case XMODEM_EOT: //收到結束符EOT
put_c(XMODEM_ACK); //通知PC機全部收到
STATUS=ST_OK;
put_s(" 用戶程序升級成功!");
break;
case XMODEM_CAN: //收到取消符CAN
put_c(XMODEM_ACK); //回應PC機
STATUS=ST_OK;
put_s("警告:用戶取消升級,用戶程序可能不完整");
break;
default: //起始字節錯誤
put_c(XMODEM_NAK); //要求重發當前數據塊
STATUS=ST_BLOCK_FAIL;
break;
}
}
if (STATUS==ST_BLOCK_OK) //接收133位元組OK,且起始字節正確
{
if (BlockCount != strXMODEM.BlockNo)//核對數據塊編號正確
{
put_c(XMODEM_NAK); //數據塊編號錯誤,要求重發當前數據塊
continue;
}
if (BlockCount !=(unsigned char)(~strXMODEM.nBlockNo))
{
put_c(XMODEM_NAK); //數據塊編號反碼錯誤,要求重發當前數據塊
continue;
}
crc=strXMODEM.CRC16hi<<8;
crc+=strXMODEM.CRC16lo;
//AVR的16位整數是低位在先,XMODEM的CRC16是高位在先
if(calcrc(&strXMODEM.Xdata[0],128)!=crc)
{
put_c(XMODEM_NAK); //CRC錯誤,要求重發當前數據塊
continue;
}
//正確接收128個字節數據,剛好是M16的一頁
if (FlashAddress { //如果地址在應用區內
write_one_page(); //將收到128位元組寫入一頁Flash中
FlashAddress+=SPM_PAGESIZE; //Flash頁加1
}
else
{
put_c(XMODEM_CAN); //程序已滿,取消傳送
put_c(XMODEM_CAN);
put_c(XMODEM_CAN);
STATUS=ST_OK;
put_s(" 程序已滿,取消傳送!");
break;
}
put_c(XMODEM_ACK); //回應已正確收到一個數據塊
BlockCount++; //數據塊累計加1
}
}

//退出Bootloader程序,從0x0000處執行應用程式
put_s("退出Bootloader升級程序!");
delay_ms(500); //很奇怪,見頂部的說明
loop_until_bit_is_set(UCSRA,UDRE); //等待結束提示信息回送完成
GICR = (1< GICR = (0< /* 無論BootLoader是否使用中斷,將中斷向量表遷移到應用程式區頭部,會增強程序的健壯性*/
boot_rww_enable (); //RWW區讀允許,否則無法馬上執行用戶的應用程式
asm volatile("jmp 0x0000": : ); //跳轉到Flash的0x0000處,執行用戶的應用程式
}

/*
FLASH程序存儲器的編程方法常見的有以下幾種:

(1)傳統的並行編程方法;
(2)通過串行口進行在線編程ISP(In System Programmability) 對器件或電路甚至整個系統進行現場升級或功能重構;
(3)在運行中,應用程式控制下的應用在線編程IAP (In Applocation Programing) 簡單地說就是在某一個section中運行程序,同時對另一個section進行擦除、讀取、寫入等操作。
ISP方式相對於傳統方式有了極大的進步,它不需要將晶片從電路板上卸下就可對晶片進行編程,減少了開發時間,簡化了產品製造流程,並大大降低了現場升級的困難。
而IAP方式是對晶片的編程處於應用程式控制之下,對晶片的編程融入在通信系統當中,通過各種接口(UART/SPI/IIC 等)來升級指定目標晶片的軟體。

BootLoader 功能介紹
BootLoader 提供我們通常所說的IAP(In Applicaion Program)功能。
多數Mega系列單片機具有片內引導程序自編程功能(BootLoader)。
MCU 通過運行一個常駐FLASH 的BootLoader 程序,利用任何可用的數據接口讀取代碼後寫入自身FLASH存儲器中 ,實現自編程目的

基本設計思想(參考了馬潮老師的文章)
1. Boot Loader程序的設計要點
Boot Loader程序的設計是實現IAP的關鍵,它必須能過通過一個通信接口,採用某種協議正確的接收數據,再將完整的數據寫入到用戶程序區中。本例Boot Loader程序的設計要點有:
1 採用ATmega16的USART口實現與PC之間的簡易RS232三線通信;
2 採用Xmodem通信協議完成與PC機之間的數據交換;
3 用戶程序更新完成後自動轉入用戶程序執行;
2. Xmodem通信協議
Xmodem協議是一種使用撥號數據機的個人計算機通信中廣泛使用的異步文件運輸協議。
這種協議以128位元組塊的形式傳輸數據,並且每個塊都使用一個校驗和過程來進行錯誤檢測。
如果接收方關於一個塊的校驗和與它在發送方的校驗和相同時,接收方就向發送方發送一個認可字節。
為了便於讀者閱讀程序,下面簡要說明該協議的主要特點,有關Xmoden的完整的協議請參考其它相關的資料。
1 Xmodem的控制字符: 01H、 04H、 06H、 15H、 18H、 1AH、c 43H。
2 XMODEM有兩種校驗模式:
一種是一字節的checksum校驗模式,不常用。
另一種是2位元組的CRC16校驗模式(X^16 + X^12 + X^5 + 1),糾錯率高達99.9984%。
兩種模式的選擇由接收端發送的啟動控制符來決定,啟動發送後不能切換。
當發送端收到「NAK」控制字符時,它將會開始以checksum校驗方式發送數據塊。
當發送端收到「C」控制字符時,它將會開始以CRC校驗方式發送數據塊。
3 Xmodem-CRC傳輸數據塊格式:「 <255-BlockNO> 」。
其中為起始字節;
為數據塊編號字節,每次加一;
<255-BlockNO>是前一字節的反碼;
接下來是長度為128位元組的數據塊;
最後的是128位元組數據的CRC校驗碼,長度為2個字節,crc16hi,crc16lo。
5 接收端收到一個數據塊並校驗正確時,回送;接收錯誤回送;而回送表示要發送端停止發送。
6 BlockNO的初值為0x01,每發送一個新的數據塊加1,加到OxFF後下一個數據塊的為零,即8位無符號數。
7 發送端收到後,可繼續發送下一個數據塊(BlockNO+1);而收到則可再次重發上一個數據塊。
8 發送端發送表示全部數據發送完成。如果最後需要發送的數據不足128個字節,用填滿一個數據塊。

*/

makefile中的程序基地址偏移
LDFLAGS += -Wl,--section-start=.text=0x3800 //0x3800位元組=0x1C00字

即增加下圖中的27行

然後在options 中勾擇Use External Makefile 選中剛才改的Makefile


這是,編譯完成的hex文件大約15k?? 好像是5k

升級的程序,不能是HEX文件,因為HEX文件是內含格式且每行信息可以不等長的(下圖)。對於這個BOOTLOADER升級程序,只能接
收原始的二進位文件信息並覆寫到相應的flash區內,因此只能使用BIN格式。將HEX轉為BIN有一個小軟體



而BIN文件是連續且等長的

相關焦點

  • avr單片機和stm32區別與優缺點分析
    摘要:avr單片機和stm32單片機是目前使用較廣泛的單片機,那麼avr單片機和stm32單片機有什麼區別呢?有什麼優劣勢呢?片上資源豐富:帶E2PROM,PWM,RTC,SPI,UART,TWI,ISP,AD,Analog Comparator,WDT等;   ● 大部分avr除了有ISP功能外,還有IAP功能,方便升級或銷毀應用程式。
  • 官方確認:谷歌商店所售 Pixel/XL 均支持 root 和解鎖 bootloader
    IT之家訊 10月14日消息,相信不少安卓用戶都有root甚至解鎖bootloader的需求,然而部分廠商為將用戶綁定在自家生態下,可能會選擇鎖掉bootloader,而谷歌顯然並不擔心這個問題。
  • AVR開發前準備—熔絲位(Fuse)快速入門
    應用舉例:  比如我們想使用片內的RC振蕩(即不需要接晶振),可以選擇選擇下面三者之一:  Int. RC Osc. 8 MHz; Start-up time: 6 CK + 0 ms;  [CKSEL=0100 SUT=00] Int.
  • 淺談avr和arm的區別
    增強性的高速同/異步串口,具有硬體產生校驗碼、硬體檢測和校驗偵錯、兩級接收緩衝、波特率自動調整定位(接收時)、屏蔽數據幀等功能,提高了通信的可靠性,方便程序編寫,更便於組成分布式網絡和實現多機通信系統的複雜應用,串口功能大大超過MCS-51/96單片機的串口,加之AVR單片機高速,中斷服務時間短,故可實現高波特率通訊。
  • 「範例卷積神經網絡」和信息最大化
    這一方法也能被理解為「卷積神經網絡範例」。本文內容摘要:本文對「範例卷積神經網絡」的訓練方法僅作了簡單簡單的概述,所以如果想要獲得更多、更真實的信息,請閱讀論文原文。本文簡要介紹了「變分信息最大化」,並將其運用到了「範例卷積神經網絡」的案例中。
  • ProE、Creo玩具手槍外形設計範例整體思路與主要知識點剖析
    本典型設計範例要完成的玩具手槍外形如圖1和圖2所示。在該玩具產品範例中,只要求設計該玩具的基本整體效果,而不涉及扣機部件和內部的一些配件。在該實例中,將綜合應用到拉伸工具、倒圓角工具、實體化工具、拔模工具、陣列工具、殼工具、基準平面工具、偏移工具和鏡像工具等。在進行該玩具手槍的外形設計之前,應該對其外形的整體效果有所把握,分析其整體設計思路和注意事項。
  • 5個教育論文提綱範例
    範例1 數學教學中學生質疑習慣的培養 一、追因求果法 按以下兩個步驟操作: 1.教師示範2.個別輔導 二、修改題目法
  • 另一種普遍主義:範例的力量
    我試圖把康德原本關於美學有效性的理解去美學化,並使範例的效力成為一個適用於藝術作品的評價以外,適用於政治和一般意義上的公共領域的概念。因此,我將首先談談範例的力量(the force of the example),以及為什麼它在我們這個時代引起了更大的興趣。為了表明它為什麼獲得了這種新的相關性,我將對我們浸身於其中的哲學視域進行一番概括的鳥瞰。
  • Bootloader中LCD硬體初始化和軟體驅動程序設計
    在高通代碼中,Android Bootloader位於bootable\bootloader\1k目錄下,Bootloader的功能性設計主要在app\aboot.c下,aboot_init函數是LK的功能入口點。aboot_init的執行過程如下: ①設置NAND/EMMC讀取信息頁面大小; ②讀取按健信息。
  • 範例分析:多元線性回歸分析
    基礎回顧簡單線性和多元線性回歸理論基礎請回顧:相關與回歸分析基礎;一元(簡單線性)相關分析與回歸分析;回歸參數的區間估計;一元(簡單線性)回歸方程的假設檢驗;範例分析:一元(簡單線性)相關與回歸分析;多元線性回歸分析;線性回歸的步驟不論是一元還是多元相同,步驟如下:1、散點圖判斷變量關係(簡單線性);2、求相關係數及線性驗證;3、求回歸係數,建立回歸方程;4、回歸方程檢驗;5、參數的區間估計;6、預測;範例分析
  • 第三節 PCR操作範例及反應體系的組成
    第三節 PCR操作範例及反應體系的組成   一、PCR操作範例   在一個典型的PCR反應體系中需加入:適宜的緩衝液、微量的模板DNA、4×dNTPs、耐熱性多聚酶、Mg2+和兩個合成的DNA引物。
  • 音圈電機直線電機通用選型計算方法及範例
    音圈電機直線電機通用選型計算方法及範例音圈電機直線電機通用選型計算方法及範例 根據速度、行程、負載等需求來選擇合適的音圈電機直線電機,進行選配工作的基本流程如以 下三點:l 決定運動規劃及設定運動參數 l 最大推力與連續推力的計算 l 計算電機負載能力和驅動器的電流電壓的匹配
  • 化肥農藥減量增效優秀範例徵集結果公示
    食品夥伴網訊  12月23日,從全國農技推廣網獲悉,根據中國農業技術推廣協會和《中國農技推廣》《中國植保導刊》雜誌社《關於開展化肥農藥減量增效優秀範例徵集活動的通知》(中農協函〔2020〕48號)要求,活動組委會組織有關專家對申報材料進行評審,評選出化肥減量增效優秀範例58個,其中示範企業22個、創新產品26個、雙減之星
  • 北京大學林崇熙老師核磁系列講座:NMR應用--如何靈活應用內標毛細管
    【網絡會議】:NMR應用--如何靈活應用內標毛細管 【講座時間】:2015年06月23日 14:30 【主講人】:林崇熙 (博士後 北京大學化學與分子工程學院副教授、主要研究領域核磁共振的應用、有機合成、氮葉立德化學、有機技術化學。)