AVR之BOOTLOADER技术详解

发布者:hylh2008最新更新时间:2016-08-21 来源: eefocus关键字: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 
Crystal: 16Mhz 
Used:        T/C0,USART0 
*****************************************************/ 
#include  
#define SPM_PAGESIZE 256              //M128的一个Flash页为256字节(128字) 
#define BAUD 38400             //波特率采用38400bps 
#define CRYSTAL 16000000          //系统时钟16MHz 
//计算和定义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        //定义接收缓冲区长度 
//定义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;             //寄存器SPMCSR中为操作码 
asm("spm\n");                    //对指定Flash页进行操作 
}       
//填充Flash缓冲页中的一个字 
void boot_page_fill(unsigned int address,int data) 

asm("mov r30,r16\n" 
       "mov r31,r17\n"          //Z寄存器中为填冲页内地址 
       "mov r0,r18\n" 
       "mov r1,r19\n");          //R0R1中为一个指令字 
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);                    //擦除一个Flash页 
wait_page_rw_ok();                         //等待擦除完成 
for(i=0;i//将数据填入Flash缓冲页中 

       boot_page_fill(i, data+(data[i+1]//将缓冲页数据写入一个Flash页 
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;        //no data to be received 
status = UCSR0A; 
res = UDR0; 
if (status & 0x1c) return -1;        // If error, 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;                    //RAMPZ清零初始化 
    asm("jmp 0x0000\n");        //跳转到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;          //Set baud rate 
UCSR0B = 0x18;          //Enable Receiver and Transmitter 
UCSR0C = 0x0E;          //Set frame. format: 8data, 2stop bit 
//初始化M128的T/C0,15ms自动重载 
   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)        //receive the start of Xmodem 

      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个字节数据 
            while(bufferPoint >= SPM_PAGESIZE) 
            { //正确接受256个字节的数据 
                   write_one_page();       //收到256字节写入一页Flash中 
                   address += SPM_PAGESIZE; //Flash页加1 
                   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机全部收到 
   
if(bufferPoint) write_one_page();        //把剩余的数据写入Flash中 
quit();             //退出Bootloader程序,从0x0000处执行应用程序 

程序的主体部分采用C高级编写,结构性好,程序的相应部分都给出了比较详细的注释说明,读者非常容易读懂和理解。下面再对程序做进一步的说明。 
(1) 函数"void   write_one_page(void)" 实现了对ATmega128一个Flash页的完整编程处理。当程序从串口正确接收到256个字节后,(ATmega128一个Flash页为128个 字),便调用该函数将其写入ATmega128一个Flash页中。函数先将一个指定的Flash页进行擦除;然后将数据填入Flash的缓冲页中,最后 将Flash 缓冲页的数据写入到该指定的Flash页中(详细技术细节见第二章相关内容的介绍)。 
(2) 一个Flash页的擦除、写入,以及填充Flash缓冲页的函数采用内嵌AVR汇编完成,在ICCAVR中,寄存器R16、R17、R18、R19用于传递一个C函数的第1、2个参数(int类型)或第1个乘数(long类型),具体参考ICCAVR应用说明。
(3) 函数"void quit(void)"的用途是退出Bootloader程序,从Flash的0x0000处执行用户的应用程序。在执行强行跳转指令"jmp 0x0000"前,对寄存器MCUCR的操作是将中断向量地址迁移回应用程序区的头部,因为在ICCAVR环境中编译Bootloader程序时,其自动 把中断向量地址迁移到了Bootloader区的头部。为了保证能正确执行用户的程序,在跳转前需要把中断向量地址迁再移回应用程序区的头部。 
(4)在这段Bootloader程序中使用的硬件资源为T/C0和USART0,用户在编写其应用程序时,应首先对这两个硬件资源相关的寄存器重新做初始化。 
(5) Bootloader程序占具并住留在Flash的最高1K字空间内,因此实际的应用程序空间为63K字(126K字节),所以用户编写的应用程序不得超 出126K字节。同时应将ATmega128的熔丝位BLB12、BLB11的状态设置为"00",禁止SPM和LPM指令对Bootloader区的读 写操作,已确保Bootloader程序不被改写和擦除。 
5.2.3 IAP的实现与应用 
1.   Bootloader程序的编译与下载 
首先在ICCAVR中新建一个工程项目,并按照生成Bootloader程序代码的要求进行正确的设置。打开Project -> Options的Compiler Options设置选项窗口,见图5.1: 
(1) 在Device Configration栏中选定器件ATMega128; 
(2) 选定Use RAMPZ/ELPM项(ATMega128的Flash > 64K字节); 
(3) Program Type选定为Boot Loader; 
(4)Boot Size选择1K Words。 
正确设置好编译选项后输入C的源代码,然后编译生成.HEX的下载代码程序。 
在下载HEX文件前还要对ATmega128芯片的熔丝位进行正确的配置: 
(1) 配置M103C熔丝位,使芯片工作于ATmega128方式; 
(2) 配置BOOTSZ1和BOOTSZ0熔丝位,设定BOOTLOADER区的大小为1024个字,起始首地址为0xFC00; 
(3)配置BOOTRST熔丝位,设定芯片上电起动从BOOTLOADER区的起始地址处开始,即每次RESET复位后从0xFC00处执行Bootloader程序; 
(4)下载Bootloader程序的HEX文件; 
(5) 配置LB2和LB1熔丝位,加密程序; 
(6)配置BLB12和BLB11熔丝位,对BOOTLOADER区进行安全锁定。 
特别注意的是,以上对芯片熔丝位的配置以及Bootloader程序的下载,需要由ISP、或JTAG、或并行方式实现,既要实现IAP,首先还需要使用一次非IAP的编程方式来建立IAP的应用环境。 
2. IAP应用 
当你按照上面的方法将Bootloader程序下载完成后,就可以使用它来下载你的应用程序了。具体操作如下。 
(1) 编写你的应用程序,编译生成HEX文件; 
(2)使用HEX2BIN.EXE转换程序,将HEX文件转换成BIN文件; 
(3)使用普通的RS232电缆将PC机的串口与ATmega128的串口连接; 
(4)打开WINDOWS中的超级终端软件,正确设置COM口的参数:38400,1,8,无,2,无(使用2位停止位提高通信可靠性); 
(5)ATmega128上电,在PC超级终端收到"Type 'd' download, Others run app."的Bootloader程序启动的提示详细; 
(6)3秒钟内在PC上按下"d"键,通知Bootloader程序转入接收数据并更新应用程序的处理。3秒钟内没有按"d"键,PC超级终端收 到"OK"提示,Bootloader程序退出,自动转入执行芯片内原有的用户应用程序(如果有的话,否则再次启动Bootloader程序); 
(7)当PC超级终端收到"C"(一秒钟一个),说明Bootloader程序转入接收数据和更新应用程序的处理流程,正在等待PC下发数据; 
(8)在PC超级终端上的工具栏中选择"传送->发送文件",在发送文件窗口选择协议"Xmodem",文件栏中选定要下载应用程序的BIN文件,单击发送按钮; 
(9)   此时出现文件发送窗口,显示文件发送的过程和进度,以及是否出错; 
(10)当文件全部正确发送完成后,PC超级终端收到"OK"提示,Bootloader程序退出,自动转入执行刚更新的用户应用程序。 
在ATmega128中烧入这样一个Bootloader程序,建立了IAP后,最基本的开发AVR的环境就简化成"PC+RS232电缆+目标板"。读 者在掌握了Bootloader程序编写的原理后,可以编写自己的Bootloader程序,实现系统程序的自动远程网络更新等应用。 
AVR的BOOTLOADER功能同其它一些芯片不同,它的BOOTLOADER程序没有固化(固定)在芯片内部(出厂为空),而是需要由用户设计实现 (实际上,你第一次下载BOOTLOADER程序还必须使用其它的方式编程,如ISP、JTAG等),因此对一般的用户掌握起来有一定的困难,不如一些其 它芯片的固化IAP使用方便。但对高手来讲,可以根据实际需要编写高级、高效、专用的BOOTLOADER程序,如从一个U盘读取数据,更新用户的应用程 序;编写一个时间炸弹,或对用户的密码进行验证,10次不对则将系统程序销毁等等。简单意味着使用方便,但灵活和适应性差,而灵活性需要你具备更高的能力 去驾驭它。可能会有一天,在单片机的系统上也出现了"病毒"程序,其原因就是使用了固化的BOOTLOADER程序。由于固化(固定)的程序采用规定公开 (开放)的接口,那么用一个带"病毒"的应用程序更新原来的应用程序也就轻而易举了。

关键字:AVR  Bootloader 引用地址:AVR之BOOTLOADER技术详解

上一篇:AVR BootLoader应用范例
下一篇:自制作并口ISP下载线

推荐阅读最新更新时间:2024-03-16 15:06

用VMLAB进行AVR单片机硬件/软件协仿真
前言 在单片机应用开发过程中,当源文件的编译成功后,就要进行仿真调试工作。仿真调试可分为两大类--芯片级仿真和代码级仿真。芯片级仿真是指使用仿真软件和ICE硬件工具相配合,在实际硬件上进行仿真调试工作;而代码级仿真则完全在计算机上完成,不需要硬件的参与。两种类型的仿真各有特点,使用的场合不同。本文基于VMLAB,讲述了进行AVR单片机硬件/软件协同仿真的方法。 VMLAB的全称为:VisualMicroLab。它针对于AVR以及ST62系列单片机设计,是一个单片机的虚拟原型(virtualprototype)框架(frame),它可以提供给用户一个真正意义上的虚拟微控制器(MCU)设计实验室。它具有强大的多窗口、多文件的编辑器
[单片机]
用VMLAB进行<font color='red'>AVR</font>单片机硬件/软件协仿真
ATmega16单片机(AVR)主要特点总结
下面就总结一下AVR单片机ATmega16的主要特点: (注: 括号内有红色 *x* 符号的表示文章下方会有解释/扩展) 1) 采用 RISC 结构的AVR内核单片机. 131 条机器指令, 大多数指令为单个系统时钟周期执行的指令; 32 个 8 位通用工作寄存器; 全静态工作方式(Fully Static Operation). (*A*) 工作在 16 MHz 时具有 16 MIPS 的性能.(注: ATmega16L 系列最大工作频率为 8 MHz); 内部配备有 2 个时钟周期的硬件乘法器. 2)片内自带大容量, 非易失的程序和数据存储器 (*B*) 16KB 在线可编程(ISP, In-Sys
[单片机]
ATmega16单片机(<font color='red'>AVR</font>)主要特点总结
基于ARM的嵌入式系统Bootloader启动流程分析
一. 引言: 对于PC机,其开机后的初始化处理器配置、硬件初始化等操作是由BIOS(Basic Input /Output System)完成的,但对于嵌入式系统来说,出于经济性、价格方面的考虑一般不配置BIOS,因此我们必须自行编写完成这些工作的程序,这就是所需要的开机程序。而在嵌入式系统中,通常并没有像 BIOS 那样的固件程序,启动时用于完成初始化操作的这段代码被称为Bootloader程序,因此整个系统的加载启动任务就完全由Bootloader 来完成。简单地说,通过这段程序,可以初始化硬件设备、建立内存空间的映射图(有的CPU没有内存映射功能如S3C44B0),从而将系统的软硬件环境设定在一个合适的状态,以便为最终调
[单片机]
基于ARM的嵌入式系统<font color='red'>Bootloader</font>启动流程分析
AVR中如何操作单个IO口
WinAVR中如何操作单个IO口 用PORTA|=(1 7) PORTA|=(1 7) 意思是把00000001左移7位再和porta相或 PORTB |= _BV(n) 和 PORTB &= ~_BV(n) sbi() 可以用的 05版装好后的确不能用 sbi()和cbi()。 仔细看资料后,发现头文件里的确没有这两函数的定义。 发现问题原因后,解决它就不是什么问题了。 方法有无数种。 1. 将下面两行拷到程序中。 #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bi
[单片机]
AVR单片机定时器TIME0普通定时实验程序
/*很简单的问题费了好大的劲,注意中断向量地址和向量号的区别,*/ /*这样的是时钟节拍可以搞到微秒级的,太好了这样对以后搞操作系统是很管用的,节拍直接影响CPU的利用效率*/ /*节拍器越小,时间片就越准确,对于整个系统的统一是绝对有意义的,*/ /*AVR定时器普通定时实验 0415 天津第四项目部宿舍 */ #include iom16v.h #define uchar unsigned char #define uint unsigned int #define set_bit(a,b) a|=(1 b) #define clr_bit(a,b) a&=(1 b) #define get_bit(a,b) a&(
[单片机]
Mouser提供Microchip ATtiny1617系列AVR MCU
贸泽电子(Mouser)近日宣布即日起开始供应Microchip Technology的ATtiny1617微控制器系列。ATtiny1617为Microchip低功率8位AVR微控制器产品组合的其中一个系列,接脚和程序代码均与ATtiny817系列装置兼容,且闪存容量更大。这个8位装置体积轻巧,运作频率最高达20 MHz,提供可自定义的组态与简化流程,适用于电容式触控系统与核心独立周边(CIPs),有助于提高系统的数据传输速率,同时降低整体耗电量。 贸泽电子供应的Microchip ATtiny1617 8位AVR微控制器,具备16KB系统内部可程序闪存、256B EEPROM和2KB的SRAM。这些装置类似于其他的Microc
[半导体设计/制造]
AVR/Arduino定时/计数器、中断入门
在Arduino中,可以使用AnalogWrite来使用硬件产生490Hz/980Hz的pwm波,并可根据参数来设定占空比。不了解这个的同学可以去AnalogWrite学习下,SecretsOfArduinoPWM也是讲了Arduino在avr的定时/计数器上做的封装,我们这里并不讲Arduino相关,而是讲AVR的定时/计数器,如何产生更多PWM波和定时/计数器的中断使用。 AVR Timer/Counter(以下统称Timer) 以ATmega358p为例,其内部拥有一个16位计时器,两个8位计时器,下图则为16位计时器的大致图解: 对于没有接触过avr内部的Arduino同学来说,这张图看不出来任何意思,别急,这些都是AV
[单片机]
<font color='red'>AVR</font>/Arduino定时/计数器、中断入门
基于AVR微控制器的电力机车智能辅保系统的实现
    摘要: 给出了以AVR微控制器为核心的电力机车智能辅保系统的设计方案,并介绍了系统硬件及软件的具体实现方法。     关键词: 智能辅保系统 AVR微控制器 硬件 软件 电气机车辅助系统中有劈相机、空气压缩机、通风机及制动风机等各种类型的电机。运行中为了防止出现短路、过流等异常情况而烧毁电机,通常配置辅助保护系统,起到及时监测电机故障并加以处理的作用。目前电力机车上安装的辅保系统都是模拟电路装置,系统硬件复杂,又不方便司机使用和维修。因此,设计一种实时性高、性能可靠的智能辅保系统替代原有的模拟电路装置势在必行。本文将介绍笔者开发的用于韶山型电力机车的智能辅助保护系统的设计及实现。 1 系统的主要功能
[嵌入式]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved