//meg8bootloader
//BOOTSZ1BOOTSZ0=00
//meg8bootloader
//BOOTSZ1BOOTSZ0=00
#include
#defineSPM_PAGESIZE64//M8的一个Flash页为64字节(32字)
#defineBAUD38400//波特率选用38400bps
#defineCRYSTAL8000000//体系时钟8MHz
//核算和界说M128的波特率设置参数
#defineBAUD_SETTING(unsignedchar)((unsignedlong)CRYSTAL/(16*(unsignedlong)BAUD)-1)
#defineBAUD_H(unsignedchar)(BAUD_SETTING>>8)
#defineBAUD_L(unsignedchar)BAUD_SETTING
#defineDATA_BUFFER_SIZE128//界说接纳缓冲区长度
//界说Xmoden操控字符
#defineXMODEM_NUL0x00
#defineXMODEM_SOH0x01
#defineXMODEM_STX0x02
#defineXMODEM_EOT0x04
#defineXMODEM_ACK0x06
#defineXMODEM_NAK0x15
#defineXMODEM_CAN0x18
#defineXMODEM_EOF0x1A
#defineXMODEM_RECIEVING_WAIT_CHARC
//界说全局变量
constcharstartupString[]=”Typeddownload,Othersrunapp.\n\r\0″;
constcharloadString[]=”downloadover\n\r\0″;
chardata[DATA_BUFFER_SIZE];
unsignedintaddress=0;
//擦除(code=0x03)和写入(code=0x05)一个Flash页
voidboot_page_ew(unsignedintp_address,charcode)
{
asm(“movr30,r16\n”
“movr31,r17\n”
//”out0x3b,r18\n”);
);//将页地址放入Z寄存器和RAMPZ的Bit0中
SPMCR=code;//寄存器SPMCSR中为操作码
asm(“spm\n”);//对指定Flash页进行操作
}
//填充Flash缓冲页中的一个字
voidboot_page_fill(unsignedintaddress,intdata)
{
asm(“movr30,r16\n”
“movr31,r17\n”//Z寄存器中为填冲页内地址
“movr0,r18\n”
“movr1,r19\n”);//R0R1中为一个指令字
SPMCR=0x01;
asm(“spm\n”);
}
//等候一个Flash页的写完结
voidwait_page_rw_ok(void)
{
while(SPMCR&0x40)
{
while(SPMCR&0x01);
SPMCR=0x11;
asm(“spm\n”);
}
}
//更新一个Flash页的完好处理
voidwrite_two_page(void)
{
//128字节分两页
inti;
boot_page_ew(address,0x03);//擦除一个Flash页
wait_page_rw_ok();//等候擦除完结
for(i=0;i
boot_page_fill(i,data[i]+(data[i+1]<<8));
}
boot_page_ew(address,0x05);//将缓冲页数据写入一个Flash页
wait_page_rw_ok();//等候写入完结
//写第2页
address+=SPM_PAGESIZE;//Flash页加1
boot_page_ew(address,0x03);//擦除一个Flash页
wait_page_rw_ok();//等候擦除完结
for(i=0;i
boot_page_fill(i,data[SPM_PAGESIZE+i]+(data[SPM_PAGESIZE+i+1]<<8));
}
boot_page_ew(address,0x05);//将缓冲页数据写入一个Flash页
wait_page_rw_ok();//等候写入完结
}
//从RS232发送一个字节
voiduart_putchar(charc)
{
while(!(UCSRA&0x20));
UDR=c;
}
//从RS232接纳一个字节
intuart_getchar(void)
{
unsignedcharstatus,res;
if(!(UCSRA&0x80))return-1;//nodatatobereceived
status=UCSRA;
res=UDR;
if(status&0x1c)return-1;//Iferror,return-1
returnres;
}
//等候从RS232接纳一个有用的字节
charuart_waitchar(void)
{
intc;
while((c=uart_getchar())==-1);
return(char)c;
}
//核算CRC
intcalcrc(char*ptr,intcount)
{
intcrc=0;
chari;
while(–count>=0)
{
crc=crc^(int)*ptr++<<8;
i=8;
do
{
if(crc&0x8000)
crc=crc<<1^0x1021;
else
crc=crc<<1;
}while(–i);
}
return(crc);
}
//退出Bootloader程序,从0x0000处履行应用程序
voidquit(void)
{
uart_putchar(O);uart_putchar(K);
uart_putchar(0x0d);uart_putchar(0x0a);
uart_putchar(0x0d);uart_putchar(0x0a);
while(!(UCSRA&0x20));//等候完毕提示信息回送完结
MCUCR=0x01;
MCUCR=0x00;//将中断向量表迁移到应用程序区头部
//RAMPZ=0x00;//RAMPZ清零初始化
asm(“jmp0x0000\n”);//跳转到Flash的0x0000处,履行用户的应用程序
}
//主程序
voidmain(void)
{
inti=0;
unsignedchartimercount=0;
unsignedcharpackNO=1;
intbufferPoint=0;
unsignedintcrc;
//初始化M128的USART0
UBRRH=BAUD_H;
UBRRL=BAUD_L;//Setbaudrate
UCSRB=0x18;//EnableReceiverandTransmitter
//UCSRC=0x06;//Setframeformat:8data,2stopbit
UCSRC=0x8e;//8位数据+2位STOP位,m8与m128的URSEL不同
//UCSRC=0x86;//8位数据+1位STOP位,m8与m128的URSEL不同
//初始化M8的T/C2,15ms主动重载
OCR2=0xEA;
TCCR2=0x0F;
//向PC机发送开端提示信息
while(startupString[i]!=\0)
{
uart_putchar(startupString[i]);
i++;
}
//3秒种等候PC下发“d”,不然退出Bootloader程序,从0x0000处履行应用程序
while(1)
{
if(uart_getchar()==d)break;
if(TIFR&0x80)//timer2overflow
{
if(++timercount>200)quit();//200*15ms=3s
TIFR=TIFR|0x80;
}
}
//每秒向PC机发送一个操控字符“C”,等候操控字〈soh〉
while(uart_getchar()!=XMODEM_SOH)//receivethestartofXmodem
{
if(TIFR&0x80)//timer2overflow
{
if(++timercount>67)//waitabout1second
{
uart_putchar(XMODEM_RECIEVING_WAIT_CHAR);//senda”C”
timercount=0;
}
TIFR=TIFR|0x80;
}
}
//开端接纳数据块
do
{
if((packNO==uart_waitchar())&&(packNO==(~uart_waitchar())))
{//核对数据块编号正确
//SPM_PAGESIZEW
for(i=0;i<128;i++)//接纳128个字节数据
{
data[bufferPoint]=uart_waitchar();
bufferPoint++;
}
crc=(uart_waitchar()<<8);
crc+=uart_waitchar();//接纳2个字节的CRC效验字
if(calcrc(&data[bufferPoint-128],128)==crc)//CRC校验验证
{//正确接纳128个字节数据
while(bufferPoint>=SPM_PAGESIZE)
//while(bufferPoint>=64)//(m8每页64字节)
{//正确承受128个字节的数据
//收到128字节写入2页Flash中
write_two_page();
address+=SPM_PAGESIZE;
bufferPoint=0;
}
uart_putchar(XMODEM_ACK);//正确收到一个数据块
packNO++;//数据块编号加1
}
else
{
uart_putchar(XMODEM_NAK);//要求重发数据块
}
}
else
{
uart_putchar(XMODEM_NAK);//要求重发数据块
}
}while(uart_waitchar()!=XMODEM_EOT);//循环接纳,直到悉数发完
uart_putchar(XMODEM_ACK);//告诉PC机悉数收到
i=0;
while(loadString[i]!=\0)
{
uart_putchar(loadString[i]);
i++;
}
quit();//退出Bootloader程序,从0x0000处履行应用程序
}