?? bootloader_main.c
字號:
/***********************************************
**** AVR BootLoader應用范例 ***
**** ***
**** 作者: HJJourAVR ***
**** 編譯器:WINAVR20050214 ***
**** ***
**** www.OurAVR.com 2005.10.17 ***
***********************************************/
//程序參考 馬潮老師的M128 Boot_load應用的實例,ICCAVR版本
/*
本程序簡單的示范了AVR ATMEGA16的IAP應用,實現智能升級
Boot Loader
XMODEM-CRC傳輸協議
CRC16校驗
出于簡化程序考慮,各種數據沒有對外輸出,學習時建議使用JTAG ICE硬件仿真器。
熔絲位設置
BOOTSZ1=0
BOOTSZ0=0 Boot區為1K字(2K字節)大小。
BOOTRST=0 復位向量位于Boot區。
makefile中的程序基地址偏移
LDFLAGS += -Wl,--section-start=.text=0x3800 //0x3800字節=0x1C00字
移植程序時,可根據實際大小設定Boot區,但要注意更改makefile和更改BootAdd常數,以及頁寫的大小分配;
采用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 <avr/delay.h>
//時鐘定為外部晶體7.3728MHz,F_CPU=7372800 使用USART,115200bps
#include <avr/boot.h>
/*
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 <avr/crc16.h>
/*
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 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<SPM_PAGESIZE;i+=2) //將數據填入Flash緩沖頁中
{
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<<RXC))
{
*ptr++=UDR; //如果接收到數據,讀出
count++;
if (count>=len)
{
break; //夠了?退出
}
}
if(TIFR & (1<<OCF0)) //T0溢出 1ms
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -