logo资料库

ATMEGA128 bootloader详解.docx

第1页 / 共12页
第2页 / 共12页
第3页 / 共12页
第4页 / 共12页
第5页 / 共12页
第6页 / 共12页
第7页 / 共12页
第8页 / 共12页
资料共12页,剩余部分请下载后查看
AVR BootLoader 详解(转) ATmega128 具备引导加载支持的用户程序自编程功能(In-System Programming by On-chipBoot Program),它提供了一个真正的由 MCU 本身自动下载和更新(采用读/写同时"Read-While-Write"进行的方式)程序 代码的系统程序 自编程更新的机制。利用 AVR 的这个功能,可以实现在应用 编程(IAP)以及实现系统程序的远程自动更新的应用。 IAP 的本质就是,MCU 可以灵活地运行一个常驻 Flash 的引导加载程序 (Boot Loader Program),实现对用户应用程序的在线自编程更新。引导加 载程序的设计可以使用任何的可用的数据接口和相关的协议读取代码,或者从 程序存储器中读取 代码,然后将代码写入(编程)到 Flash 存储器中。 引导加载程序有能力读写整个 Flash 存储器,包括引导加载程序所在的引导加 载区本身。引导加载程序还可以对自身进行更新修改,甚至可以将自身删除, 使系 统的自编程能力消失。引导加载程序区的大小可以由芯片的熔丝位设置, 该段程序区还提供两组锁定位,以便用户选择对该段程序区的不同级别的保护。 本节将给出一个实际的的 Boot Loader 程序,它可以配合 Windows 中的超级 终端程序,采用 Xmodem 传输协议,通过 RS232 接口下载更新用户的应用 程序。 5.2.1 基本设计思想 1. Boot Loader 程序的设计要点 Boot Loader 程序的设计是实现 IAP 的关键,它必须能过通过一个通信接口, 采用某种协议正确的接收数据,再将完整的数据写入到用户程序区中。本例 Boot Loader 程序的设计要点有: (1)采用 ATmega128 的 USART 口实现与 PC 之间的简易 RS232 三线通信; (2) 采用 Xmodem 通信协议完成与 PC 机之间的数据交换; (3)用户程序更新完成后自动转入用户程序执行; (4) Boot Loader 程序采用 C 语言内嵌 AVR 汇编方式编写,阅读理解方便, 可移植性强,代码小于 1K 字。 2. Xmodem 通信协议
Xmodem 协议是一种使用拨号调制解调器的个人计算机通信中广泛使用的异 步文件运输协议。这种协议以 128 字节块的形式传输数据,并且每个块都使用 一个 校验和过程来进行错误检测。如果接收方关于一个块的校验和与它在发送 方的校验和相同时,接收方就向发送方发送一个认可字节。为了便于读者阅读 程序,下面简 要说明该协议的主要特点,有关 Xmoden 的完整的协议请参考 其它相关的资料。 (1) Xmodem 的控制字符: 01H、 04H、 06H、 15H、 18H、 1AH。 (2) Xmodem 传输数据块格式:" 个字节的数据块...> "。其中为起始字节; 为数据块编号字节,每次加一;是前一字节的反码;接下来是长度为 128 字节 的数据块;最后的是 128 字节数据的 CRC 校验码,长度为 2 个字节。 (3)接收端收到一个数据块并校验正确时,回送;接收错误回送;而回送表 示要发送端停止发送。 (4) 发送端收到后,可继续发送下一个数据块(packNO+1);而收到则可 再次重发上一个数据块。 (5)发送端发送表示全部数据发送完成。如果最后需要发送的数据不足 128 个字节,用填满一个数据块。 (6) 控制字符"C"有特殊的作用,当发送端收到"C"控制字符时,它回重新开 始以 CRC 校验方式发送数据块(packNO = 1)。 (7) 每发送一个新的数据块 加 1,加到 OxFF 后下一个数据块的 为零。 (8) 校验方式采用 16 位 CRC 校验(X^16 + X^12 + X^5 + 1)。 5.2.2 源程序代码 下面给出的源程序是在 ICCAVR 中实现的。 /***************************************************** 采用串行接口实现 Boot_load 应用的实例 华东师大电子系 马 潮 2004.07 Compiler: ICC-AVR 6.31 Target: Mega128
T/C0,USART0 //M128 的一个 Flash 页为 256 Crystal: 16Mhz Used: *****************************************************/ #include #define SPM_PAGESIZE 256 字节(128 字) #define BAUD 38400 #define CRYSTAL 16000000 //计算和定义 M128 的波特率设置参数 #define BAUD_SETTING (unsigned char)((unsigned long)CRYSTAL/(16*(unsigned long)BAUD)-1) #define BAUD_H (unsigned char)(BAUD_SETTING>>8) #define BAUD_L (unsigned char)BAUD_SETTING #define DATA_BUFFER_SIZE SPM_PAGESIZE //波特率采用 38400bps //系统时钟 16MHz //定义接收缓冲区 长度 //定义 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_RECIEVING_WAIT_CHAR 'C' //定义全局变量 const char startupString[]="Type 'd' download, Others run app.\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"); //将页地址放入 Z 寄存器和 RAMPZ 的 Bit0 中 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"); //R0R1 中为一个指令字 //寄存器 SPMCSR 中为操作码 //对指定 Flash 页进行操作 //Z 寄存器中为填冲页内地址 SPMCSR = 0x01; asm("spm\n"); } //等待一个 Flash 页的写完成 void wait_page_rw_ok(void) { while(SPMCSR & 0x40) { while(SPMCSR & 0x01); SPMCSR = 0x11; asm("spm\n"); } }
//更新一个 Flash 页的完整处理 void write_one_page(void) { int i; boot_page_ew(address,0x03); wait_page_rw_ok(); for(i=0;i//将数据填入 Flash 缓冲页中 { //擦除一个 Flash 页 //等待擦除完成 boot_page_fill(i, data+(data[i+1]//将缓冲页数据写入一个 Flash 页 //等待写入完成 //no data to be received // If error, return -1 wait_page_rw_ok(); } //从 RS232 发送一个字节 void uart_putchar(char c) { while(!(UCSR0A & 0x20)); UDR0 = c; } //从 RS232 接收一个字节 int uart_getchar(void) { unsigned char status,res; if(!(UCSR0A & 0x80)) return -1; status = UCSR0A; res = UDR0; if (status & 0x1c) return -1; return res; } //等待从 RS232 接收一个有效的字节 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++ //退出 Bootloader 程序,从 0x0000 处执 行应用程序 void quit(void) { uart_putchar('O');uart_putchar('K'); uart_putchar(0x0d);uart_putchar(0x0a); while(!(UCSR0A & 0x20)); MCUCR = 0x01; MCUCR = 0x00; 部 //等待结束提示信息回送完成 //将中断向量表迁移到应用程序区头 RAMPZ = 0x00; asm("jmp 0x0000\n"); //RAMPZ 清零初始化 //跳转到 Flash 的 0x0000 处,执行用户 的应用程序 } //主程序 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; //初始化 M128 的 T/C0,15ms 自动重载 //Set baud rate //Enable Receiver and Transmitter //Set frame. format: 8data, 2stop bit OCR0 = 0xEA; TCCR0 = 0x0F; //向 PC 机发送开始提示信息 while(startupString!='\0') { uart_putchar(startupString); i++; } //3 秒种等待 PC 下发"d",否则退出 Bootloader 程序,从 0x0000 处执行应 用程序 while(1) { if(uart_getchar()== 'd') break; if (TIFR & 0x02) { //timer0 over flow if (++timercount > 200) quit(); //200*15ms = 3s TIFR = TIFR|0x02; } }
//每秒向 PC 机发送一个控制字符"C",等待控制字〈soh〉 while(uart_getchar()!=XMODEM_SOH) Xmodem { //receive the start of if(TIFR & 0x02) { //timer0 over flow if(++timercount > 67) { //wait about 1 second uart_putchar(XMODEM_RECIEVING_WAIT_CHAR); //send a "C" timercount="0"; } TIFR="TIFR" | 0x02; } } //开始接收数据块 do { if ((packNO == uart_waitchar()) && (packNO ==(~uart_waitchar()))) { //核对数据块编号正确 for(i=0;i//接收 128 个字节数据 { data[bufferPoint]= uart_waitchar(); bufferPoint++; } crc = (uart_waitchar()//接收 2 个字节的 CRC 效验字 if(calcrc(&data[bufferPoint-128],128)==crc) //CRC 校验验证 { //正确接收 128 个字节数据
分享到:
收藏