?? ref.c~
字號:
正在編寫M128原理與使用指南中的一小節(jié),請?zhí)嵋庖姾徒ㄗh?
?cma?發(fā)表于?2004-8-7?04:12?
5.2?自引導(dǎo)IAP的應(yīng)用設(shè)計
ATmega128具備引導(dǎo)加載支持的用戶程序自編程功能(In-Sysytem?Programming?by?On-chip?Boot?Program),它提供了一個真正的由MCU本身自動下載和更新(采用讀/寫同時“Read-While-Write”進行的方式)程序代碼的系統(tǒng)程序自編程更新的機制。利用AVR的這個功能,可以實現(xiàn)在應(yīng)用編程(IAP)以及實現(xiàn)系統(tǒng)程序的遠程自動更新的應(yīng)用。
IAP的本質(zhì)就是,MCU可以靈活地運行一個常駐Flash的引導(dǎo)加載程序(Boot?Loader?Program),實現(xiàn)對用戶應(yīng)用程序的在線自編程更新。引導(dǎo)加載程序的設(shè)計可以使用任何的可用的數(shù)據(jù)接口和相關(guān)的協(xié)議讀取代碼,或者從程序存儲器中讀取代碼,然后將代碼寫入(編程)到Flash存儲器中。
引導(dǎo)加載程序有能力讀寫整個Flash存儲器,包括引導(dǎo)加載程序所在的引導(dǎo)加載區(qū)本身。引導(dǎo)加載程序還可以對自身進行更新修改,甚至可以將自身刪除,使系統(tǒng)的自編程能力消失。引導(dǎo)加載程序區(qū)的大小可以由芯片的熔絲位設(shè)置,該段程序區(qū)還提供兩組鎖定位,以便用戶選擇對該段程序區(qū)的不同級別的保護。
本節(jié)將給出一個實際的的Boot?Loader程序,它可以配合Windows中的超級終端程序,采用Xmodem傳輸協(xié)議,通過RS232接口下載更新用戶的應(yīng)用程序。
5.2.1?基本設(shè)計思想
1.????Boot?Loader程序的設(shè)計要點
Boot?Loader程序的設(shè)計是實現(xiàn)IAP的關(guān)鍵,它必須能過通過一個通信接口,采用某種協(xié)議正確的接收數(shù)據(jù),再將完整的數(shù)據(jù)寫入到用戶程序區(qū)中。本例Boot?Loader程序的設(shè)計要點有:
l????采用ATmega128的USART口實現(xiàn)與PC之間的簡易RS232三線通信;
l????采用Xmodem通信協(xié)議完成與PC機之間的數(shù)據(jù)交換;
l????用戶程序更新完成后自動轉(zhuǎn)入用戶程序執(zhí)行;
l????Boot?Loader程序采用C語言內(nèi)嵌AVR匯編方式編寫,閱讀理解方便,可移植性強,代碼小于1K字。
2.????Xmodem通信協(xié)議
Xmodem協(xié)議是一種使用撥號調(diào)制解調(diào)器的個人計算機通信中廣泛使用的異步文件運輸協(xié)議。這種協(xié)議以128字節(jié)塊的形式傳輸數(shù)據(jù),并且每個塊都使用一個校驗和過程來進行錯誤檢測。如果接收方關(guān)于一個塊的校驗和與它在發(fā)送方的校驗和相同時,接收方就向發(fā)送方發(fā)送一個認可字節(jié)。為了便于讀者閱讀程序,下面簡要說明該協(xié)議的主要特點,有關(guān)Xmoden的完整的協(xié)議請參考其它相關(guān)的資料。
l????Xmodem的控制字符:<soh>?01H、<eot>?04H、<ack>?06H、<nak>?15H、<can>?18H、<eof>?1AH。
l????Xmodem傳輸數(shù)據(jù)塊格式:“<soh>?<packNO>?<255-packNO>?<…128個字節(jié)的數(shù)據(jù)塊…>?<cksum>”。其中<soh>為起始字節(jié);<packNO>為數(shù)據(jù)塊編號字節(jié),每次加一;<255-packNO>是前一字節(jié)的反碼;接下來是長度為128字節(jié)的數(shù)據(jù)塊;最后的<cksum>是128字節(jié)數(shù)據(jù)的CRC校驗碼,長度為2個字節(jié)。
l????接收端收到一個數(shù)據(jù)塊并校驗正確時,回送<ack>;接收錯誤回送<nak>;而回送<can>表示要發(fā)送端停止發(fā)送。
l????發(fā)送端收到<ack>后,可繼續(xù)發(fā)送下一個數(shù)據(jù)塊(packNO+1);而收到<nak>則可再次重發(fā)上一個數(shù)據(jù)塊。
l????發(fā)送端發(fā)送<eot>表示全部數(shù)據(jù)發(fā)送完成。如果最后需要發(fā)送的數(shù)據(jù)不足128個字節(jié),用<eof>填滿一個數(shù)據(jù)塊。
l????控制字符“C”有特殊的作用,當(dāng)發(fā)送端收到“C”控制字符時,它回重新開始以CRC校驗方式發(fā)送數(shù)據(jù)塊(packNO?=?1)。
l????每發(fā)送一個新的數(shù)據(jù)塊<packNO>加1,加到OxFF后下一個數(shù)據(jù)塊的<packNO>為零。
l????校驗方式采用16位CRC校驗(X^16?+?X^12?+?X^5?+?1)。
5.2.2?源程序代碼
下面給出的源程序是在ICCAVR中實現(xiàn)的。
/*****************************************************
采用串行接口實現(xiàn)Boot_load應(yīng)用的實例
華東師大電子系?馬?潮?2004.07
Compiler:????ICC-AVR?6.31
Target:????Mega128
Crystal:????16Mhz
Used:????????T/C0,USART0
*****************************************************/
#include?<iom128v.h>
#define?SPM_PAGESIZE?256??????????????//M128的一個Flash頁為256字節(jié)(128字)
#define?BAUD?38400????????????????//波特率采用38400bps
#define?CRYSTAL?16000000????????????//系統(tǒng)時鐘16MHz
//計算和定義M128的波特率設(shè)置參數(shù)
#define?BAUD_SETTING?(unsigned?char)((unsigned?long)CRYSTAL/(16*(unsigned?long)BAUD)-1)
#define?BAUD_H?(unsigned?char)(BAUD_SETTING>>8)
#define?BAUD_L?(unsigned?char)BAUD_SETTING
#define?DATA_BUFFER_SIZE?SPM_PAGESIZE????????//定義接收緩沖區(qū)長度
//定義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_RECIEVING_WAIT_CHAR?'C'
//定義全局變量
const?char?startupString[]="Type?'d'?download,?Others?run?app.\n\r\0";
char?data[DATA_BUFFER_SIZE];
long?address?=?0;
//擦除(code=0x03)和寫入(code=0x05)一個Flash頁
void?boot_page_ew(long?p_address,char?code)
{
????asm("mov?r30,r16\n"
????????"mov?r31,r17\n"
????????"out?0x3b,r18\n");????????????//將頁地址放入Z寄存器和RAMPZ的Bit0中
????SPMCSR?=?code;????????????????//寄存器SPMCSR中為操作碼
????asm("spm\n");????????????????????//對指定Flash頁進行操作
}????????
//填充Flash緩沖頁中的一個字
void?boot_page_fill(unsigned?int?address,int?data)
{
????asm("mov?r30,r16\n"
????????"mov?r31,r17\n"?????????????//Z寄存器中為填沖頁內(nèi)地址
????????"mov?r0,r18\n"
????????"mov?r1,r19\n");????????????//R0R1中為一個指令字
????SPMCSR?=?0x01;
????asm("spm\n");
}
//等待一個Flash頁的寫完成
void?wait_page_rw_ok(void)
{
??????while(SPMCSR?&?0x40)
?????{
?????????while(SPMCSR?&?0x01);
?????????SPMCSR?=?0x11;
?????????asm("spm\n");
?????}
}
//更新一個Flash頁的完整處理
void?write_one_page(void)
{
????int?i;
????boot_page_ew(address,0x03);????????????????????//擦除一個Flash頁
????wait_page_rw_ok();????????????????????????????//等待擦除完成
????for(i=0;i<SPM_PAGESIZE;i+=2)????????????????//將數(shù)據(jù)填入Flash緩沖頁中
????{
????????boot_page_fill(i,?data[i]+(data[i+1]<<8));
????}
????boot_page_ew(address,0x05);????????????????????//將緩沖頁數(shù)據(jù)寫入一個Flash頁
????wait_page_rw_ok();????????????????????????????//等待寫入完成
}????????
//從RS232發(fā)送一個字節(jié)
void?uart_putchar(char?c)
{
????while(!(UCSR0A?&?0x20));
????UDR0?=?c;
}
//從RS232接收一個字節(jié)
int?uart_getchar(void)
{
????unsigned?char?status,res;
????if(!(UCSR0A?&?0x80))?return?-1;????????//no?data?to?be?received
????status?=?UCSR0A;
????res?=?UDR0;
????if?(status?&?0x1c)?return?-1;????????//?If?error,?return?-1
????return?res;
}
//等待從RS232接收一個有效的字節(jié)
char?uart_waitchar(void)
{
????int?c;
????while((c=uart_getchar())==-1);
????return?(char)c;
}
//計算CRC
int?calcrc(char?*ptr,?int?count)
{
????int?crc?=?0;
????char?i;
????
????while?(--count?>=?0)
????{
????????crc?=?crc?^?(int)?*ptr++?<<?8;
????????i?=?8;
????????do
????????{
????????if?(crc?&?0x8000)
????????????crc?=?crc?<<?1?^?0x1021;
????????else
????????????crc?=?crc?<<?1;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -