|
![](static/image/common/ico_lz.png)
楼主 |
发表于 2007-12-25 16:04:15
|
显示全部楼层
今天終於有空又做了一個GCC版本的162 bootloader程序通訊和顯示的下載程序都說是OK的可是就是不會跳至應用程序
(或者程序沒有真正被下載)
把源程序貼出來,各位前輩幫忙看一下,問題出在那里.
/*本BOOTLADER程序跟据OURAVR网的BOOTLOADER范例修改,原來M16改為M162使用,
設定外部晶体4MHz,F_CPU=4000000 使用USART,19200bps
熔絲位設定: BOOTRST = 0 (复位地址為BOOT區) ,
BOOTSZ1 = 0 , BOOTSZ0 = 1 (BOOT字節大小為512字)
makefile .text首地址改為0x3800
*/
#include <avr/io.h>
#include <util/delay.h>
#include <avr/boot.h>
#include <avr/crc16.h>
//移植至m162
#define UCSRA UCSR0A
#define UCSRB UCSR0B
#define UCSRC UCSR0C
#define UBRRL UBRR0L
#define UBRRH UBRR0H
#define UDR UDR0
//串口腳設定
#define PIN_RXD 0 //PD0
#define PIN_TXD 1 //PD1
//常量定義
//#define SPM_PAGESIZE 128 //M8的一個Flash頁為64字節(32字)
#define DATA_BUFFER_SIZE SPM_PAGESIZE //定義接收字節長度
#define BAUDRATE 19200 //波特率采用19200
//#define F_CPU 4000000 //系統晶振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位(4字節)長度,适用所有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 //完成
void(*reset)(void)=0x0000;
//長延時max 65536ms
void delay_ms(unsigned int t)
{
while(t--)
{
_delay_ms(1);
}
}
//更新一個Flash頁的完整處理
void write_one_page(unsigned char buf_start)
{
unsigned char i;
unsigned char *buf;
unsigned int w;
boot_page_erase(FlashAddress); //擦除一個Flash頁
boot_spm_busy_wait(); //等待擦除完成
buf=&strXMODEM.Xdata[buf_start];
for(i=0;i<SPM_PAGESIZE;i+=2) //數据填入Flash緩沖中
{
w =*buf++;
w+=(*buf++)<<8;
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,UDRE0);
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<<RXC0))
{
*ptr++=UDR; //如果接收到數据,讀出
count++;
if (count>=len)
{
break; //如夠了則退出
}
}
if(TIFR & (1<<OCF2)) //T2溢出 1ms
{
TIFR|=(1<<OCF2); //清除標志位
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可能由應用程序中跳回,所以所用到的模塊需要全面初始化
DDRB=0x00;
DDRC=0x00; //不用的管腳使能內部上拉電阻。
PORTB=0xFF;
PORTC=0xFF;
DDRE=0x00;
PORTE=0xFF;
PORTD=0xFF;
DDRD=(1<<PIN_TXD); //串口的輸出
GICR = (1<<IVCE);
GICR = (0<<IVCE)|(1<<IVSEL); //中斷向量表轉移到Boot頂部
asm volatile("cli"::); //關全局中斷
//初始化USART 19200 8, n,1 PC上位机軟件(超級終端)對等設置
UCSRC = (1<<URSEL0)|(1<<UCSZ01)|(1<<UCSZ00); //异步,8位數据+1停止位,1倍速
UBRRL = (F_CPU/BAUDRATE/16-1)%256; //設定波特率
UBRRH = (F_CPU/BAUDRATE/16-1)/256;
UCSRA = 0x00;
UCSRB = (1<<RXEN0)|(1<<TXEN0); //使能接收,使能傳送
//初始化T/C2,CTC模式,256分分頻,1ms自動重啟
TCNT2 = 0xf0;
OCR2 = 0x0f;
TCCR2 = (1<<WGM21)|(1<<CS22)|(1<<CS21)|(0<<CS20);
//向PC机傳送開始提示信息
put_s("3秒內按下d開始更新");
c=0;
get_data(&c,1,3000); //限時3秒,接收一個數据
if ((c=='d')||(c=='D'))
{
STATUS=ST_WAIT_START; //并且數据='d'或'D',進入XMODEM
put_s("BIN檔最大6KB");
}
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("升級OK");
break;
case XMODEM_CAN: //收到取消符CAN
put_c(XMODEM_ACK); //回應PC机
STATUS=ST_OK;
put_s("升級fail");
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個字節數据,剛好是M162的一頁
if (FlashAddress<(BootAdd-SPM_PAGESIZE))
{ //如果地址在應用區內
write_one_page(0); //接收到0-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("GO");
delay_ms(500);
loop_until_bit_is_set(UCSRA,UDRE0); //等待結束提示信息回送完成
GICR = (1<<IVCE);
GICR = (0<<IVCE)|(0<<IVSEL); //將中斷向量表移到應用程序頂部
/*無論boot程序有無用到中斷,都將向量表移到應用區,以增強程序的鍵壯性*/
boot_rww_enable(); //RWW區重開允許,否則無法馬上執行應用區程序
reset();
//asm volatile("rjmp 0x0000"::); //跳到Flash的0x0000,執行用戶的應用程序
} |
|