📄 avr-bootloader.c
字号:
#include <iom128v.h>
#define SPM_PAGESIZE 256
#define BAUD_H 0x00
#define BAUD_L 0x17
#define DATA_BUFFER_SIZE SPM_PAGESIZE
//定义Xmodem控制字符
#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";
const char startupString[]="Please press 'd' to bootloader within 3 seconds![Encrypted!]\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");
SPMCSR=code;
asm("spm\n");
}
//填充Flash缓冲页中的一个字
void boot_page_fill(unsigned int address,int data)
{
asm("mov r30,r16\n"
"mov r31,r17\n"
"mov r0,r18\n"
"mov r1,r19\n");
SPMCSR=0x01;
asm("spm\n");
}
//等待一个Flash页的写完成
void wait_page_rw_ok(void)
{
while(SPMCSR&0x40)
{
while(SPMCSR&0x01);
SPMCSR=0x11;
asm("spm\n");
}
}
///对BIN文件的数据进行解密
char de_encryptdata(char i)
{
char chr,tmpchrH,tmpchrL;
chr=data[i];
tmpchrH=0xf0&chr;
tmpchrL=0x0f&chr;
chr=tmpchrH/16+tmpchrL*16;
return (0xff-0x86^chr);
}
//更新一个Flash页的完整处理
void write_one_page(void)
{
int i;
boot_page_ew(address,0x03);
wait_page_rw_ok();
for(i=0;i<SPM_PAGESIZE;i+=2)
{
boot_page_fill(i,de_encryptdata(i)+(de_encryptdata(i+1)<<8));
}
boot_page_ew(address,0x05);
wait_page_rw_ok();
}
//从RS232发送1个字节
void uart_putchar(char c)
{
while(!(UCSR0A&0x20));
UDR0=c;
}
//从RS232接收1个字节
int uart_getchar(void)
{
unsigned char status,res;
if(!(UCSR0A&0x80)) return -1;
status=UCSR0A;
res=UDR0;
res=res;
if(status&0x1c) return -1;
return res;
}
//等待从RS232接收1个有效字节
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;
}
while(--i);
}
return (crc);
}
//退出Bootloader程序,从0x0000处执行应用程序
void quit(void)
{
uart_putchar('O');uart_putchar('K');uart_putchar('?');
uart_putchar(0x0d);uart_putchar(0x0a);
while(!(UCSR0A&0x20));
MCUCR=0x01;
MCUCR=0x00;
RAMPZ=0x00;
asm("jmp 0x0000\n");
}
//主程序
void main(void)
{
int i=0;
unsigned char timercount=0;
unsigned char packNO=1;
int bufferPoint=0;
unsigned int crc;
//初始化M128的USART0
UBRR0H=BAUD_H;
UBRR0L=BAUD_L;
UCSR0B=0x18;
UCSR0C=0x0E;
OCR0=0xEA;
//////////
MCUCR = 0x00;
EICRA = 0x00; //extended ext ints
EICRB = 0x00; //extended ext ints
EIMSK = 0x00;
TIMSK = 0x00; //timer interrupt sources
ETIMSK = 0x00; //extended timer interrupt sources
TCCR0 = 0x00; //stop
ASSR = 0x00; //set async mode
TCNT0 = 0x29; //set count
OCR0 = 0xD7;
//TCCR0 = 0x07; //start timer
///////////
while(startupString[i]!='\0')
{
uart_putchar(startupString[i]);
i++;
}
TCCR0 = 0x07; //start timer
//////3秒等待PC机发'd',否则退出Bootloader程序,从0x0000处执行应用程序
while(1)
{
if(uart_getchar()=='d')break;
if(TIFR&0x02)
{
if(++timercount>200) quit(); //3秒
// if(++timercount>20) quit(); //1秒 林树亮 2007-6-25改
TCNT0 = 0x29; //set count
TIFR=TIFR|0x02;
}
}
////每秒向PC机发送一个控制字符C,等待控制字
while(uart_getchar()!=XMODEM_SOH)
{
if(TIFR&0x02)
{
if(++timercount>67)
{
uart_putchar(XMODEM_RECIEVING_WAIT_CHAR);
timercount=0;
}
TIFR=TIFR|0x02;
}
}
//////开始接收数据块
do
{
if((packNO==uart_waitchar())&&(packNO==(~uart_waitchar())))
{
for(i=0;i<128;i++)
{
data[bufferPoint]=uart_waitchar();
bufferPoint++;
}
crc=uart_waitchar()<<8; //修改处
crc+=uart_waitchar(); //修改处
if(calcrc(&data[bufferPoint-128],128)==crc)
{
while(bufferPoint>=SPM_PAGESIZE)
{
write_one_page();
address+=SPM_PAGESIZE;
bufferPoint=0;
}
uart_putchar(XMODEM_ACK);
packNO++;
}
else
{
uart_putchar(XMODEM_NAK);
}
}
else
{
uart_putchar(XMODEM_NAK);
}
}
while(uart_waitchar()!=XMODEM_EOT);
uart_putchar(XMODEM_ACK);
if(bufferPoint)
write_one_page();
quit();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -