?? bootloader_main.c
字號:
{
TIFR|=(1<<OCF0); //清除標志位
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(void)
{
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<<PIN_TXD); //串口的輸出
GICR = (1<<IVCE);
GICR = (0<<IVCE)|(1<<IVSEL); //將中斷向量表遷移到Boot區頭部
asm volatile("cli": : ); //關全局中斷
//這個BootLoader沒有使用中斷。
//初始化USART 115200 8, n,1 PC上位機軟件(超級終端)也要設成同樣的設置才能通訊
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); //異步,8位數據,無奇偶校驗,一個停止位,無倍速
UBRRL = (F_CPU/BAUDRATE/16-1)%256; //設定波特率
UBRRH = (F_CPU/BAUDRATE/16-1)/256;
UCSRA = 0x00;
UCSRB = (1<<RXEN)|(1<<TXEN); //使能接收,使能發送
//初始化T/C0,CTC模式,256分頻,1ms自動重載
OCR0 = 28;
TCCR0 = (1<<WGM01)|(1<<CS02)|(0<<CS01)|(0<<CS00);
//CTC模式下,溢出標志是輸出比較匹配OCF0,對應的中斷是輸出比較匹配中斷;
//向PC機發送開始提示信息
put_s(" ");
put_s(" ");
put_s("這是個AVR ATMEGA16通過串口升級用戶程序(IAP應用)的范例程序");
put_s(" www.ouravr.com");
put_s("如需更新用戶程序,請在3秒鐘內按下[d]鍵,否則3秒后運行用戶程序");
//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("請使用XMODEM協議傳輸BIN文件,最大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<(BootAdd-SPM_PAGESIZE))
{ //如果地址在應用區內
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("LET'S GO!");
delay_ms(500); //很奇怪,見頂部的說明
loop_until_bit_is_set(UCSRA,UDRE); //等待結束提示信息回送完成
GICR = (1<<IVCE);
GICR = (0<<IVCE)|(0<<IVSEL); //將中斷向量表遷移到應用程序區頭部
/* 無論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的控制字符:<soh> 01H、<eot> 04H、<ack> 06H、<nak> 15H、<can> 18H、<eof> 1AH、'c' 43H。
2 XMODEM有兩種校驗模式:
一種是一字節的checksum校驗模式,不常用。
另一種是2字節的CRC16校驗模式(X^16 + X^12 + X^5 + 1),糾錯率高達99.9984%。
兩種模式的選擇由接收端發送的啟動控制符來決定,啟動發送后不能切換。
當發送端收到“NAK”控制字符時,它將會開始以checksum校驗方式發送數據塊。
當發送端收到“C”控制字符時,它將會開始以CRC校驗方式發送數據塊。
3 Xmodem-CRC傳輸數據塊格式:“<soh> <BlockNO> <255-BlockNO> <…128個字節的數據塊…> <checksum_crc16>”。
其中<soh>為起始字節;
<BlockNO>為數據塊編號字節,每次加一;
<255-BlockNO>是前一字節的反碼;
接下來是長度為128字節的數據塊;
最后的<checksum_crc16>是128字節數據的CRC校驗碼,長度為2個字節,crc16hi,crc16lo。
5 接收端收到一個數據塊并校驗正確時,回送<ack>;接收錯誤回送<nak>;而回送<can>表示要發送端停止發送。
6 BlockNO的初值為0x01,每發送一個新的數據塊<BlockNO>加1,加到OxFF后下一個數據塊的<BlockNO>為零,即8位無符號數。
7 發送端收到<ack>后,可繼續發送下一個數據塊(BlockNO+1);而收到<nak>則可再次重發上一個數據塊。
8 發送端發送<eot>表示全部數據發送完成。如果最后需要發送的數據不足128個字節,用<eof>填滿一個數據塊。
*/
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -