首页 > 代码库 > 【转】AVR BOOT
【转】AVR BOOT
1 #include <string.h> 2 #include <iom128v.h> 3 #include "main.h" 4 #include <macros.h> 5 //#include "assembly.h" 6 7 static unsigned long timer_1ms = 0; 8 static unsigned char sys_state = 0; 9 static unsigned char uart0_rx_buf[UART0_BUF_SIZE]; 10 static unsigned long flash_addr = 0; 11 void sys_set_state(unsigned char state) 12 { 13 sys_state = state; 14 } 15 unsigned long get_sys_time_ms(void) 16 { 17 return timer_1ms; 18 } 19 extern int _textmode; 20 21 int putchar(char c) 22 { 23 //if (_textmode && c == ‘\n‘) 24 // putchar(‘\r‘); 25 /* Wait for empty transmit buffer */ 26 while ( !(UCSR0A & (1<<UDRE0)) ) 27 ; 28 /* Putting data into buffer , sends the data */ 29 UDR0 = c; 30 return c; 31 } 32 int getchar(void) 33 { 34 unsigned char dat = 0; 35 unsigned char status = 0; 36 WDR(); 37 if(((UCSR0A & 0x80)==0)){ 38 return -1; 39 } 40 status = UCSR0A; 41 dat = UDR0; 42 if(status & 0x1C){ 43 return -2; 44 } 45 46 return dat; 47 } 48 void sendStr(char *str) 49 { 50 int len = 0; 51 unsigned char i = 0; 52 len = strlen(str); 53 for(i = 0; i < len; i++) 54 putchar(str[i]); 55 while ( !(UCSR0A & (1<<UDRE0)) ); 56 } 57 void port_init(void) 58 { 59 // MCUCSR |= 0x80; 60 // MCUCSR |= 0x80; 61 PORTA = 0x07; //PA3~PA7 IS LOW,PA2~PA0 IS HIGH 62 DDRA = 0xFF; 63 PORTB = 0xFb; //MOSI(PB2) is low ***** 64 DDRB = 0xF7; //PB3 IS INPUT 65 PORTC = 0xFF; //m103 output only 66 DDRC = 0xFF; 67 PORTD = 0xFF; 68 DDRD = 0x00; //PD0~7 IS INPUT 69 PORTE = 0xFF; 70 DDRE = 0xFE; 71 PORTF = 0xFF; 72 DDRF = 0x00; 73 PORTG = 0x1F; 74 DDRG = 0x00; 75 } 76 void uart0_init(void) 77 { 78 UCSR0B = 0x00; //disable while setting baud rate 79 UCSR0A = 0x00; 80 UCSR0C = 0x06; 81 //6MHz 82 UBRR0L = 0x26; //set baud rate lo 83 //14.7456MHz 9600bps 84 // UBRR0L = 0x5F; //set baud rate lo 85 //14.7456MHz 115200bps 86 // UBRR0L = 0x07; //set baud rate lo 87 UBRR0H = 0x00; //set baud rate hi 88 // UCSR0B = 0xD8; //0xB8 89 // UCSR0B = 0xB8; //0xD8 90 //UCSR0B = 0x98; //0xD8,0xB8 91 UCSR0B = 0x18; //0xD8,0xB8,disable rcv interrupt 92 } 93 // OSC:6MHz, prescale:1024 94 void timer0_init(void) 95 { 96 TCCR0 = 0x00; //stop 97 ASSR = 0x00; //set async mode 98 TCNT0 = 0xf9; //set count 99 OCR0 = 0xD7;100 TCCR0 = 0x07; //start timer101 }102 #pragma interrupt_handler timer0_ovf_isr:17103 void timer0_ovf_isr(void)104 {105 TCNT0 = 0xf9; //reload counter value106 timer_1ms++;107 }108 void watchdog_off(void)109 {110 // Write logical one to WDCE and WDE111 WDTCR = (1<<WDCE) | (1<<WDE);112 // Turn off WDT113 WDTCR = 0x00;114 }115 void watchdog_init(unsigned char time)116 {117 WDR(); //this prevents a timout on enabling118 // Write logical one to WDCE and WDE119 WDTCR = (1<<WDCE) | (1<<WDE);120 time&=0x07; // prescale: n cycles time=0~7,WDCE=0121 time|=0x08; // prescale: n cycles time=0~7,WDE=1122 WDTCR=time; //WATCHDOG ENABLED - dont forget to issue WDRs123 }124 #if 0125 void delay_1ms(void)126 {127 unsigned int i;128 for(i=1;i<(unsigned int)(XTAL*143-20);i++)129 {130 WDR();131 }132 }133 void delay_ms(unsigned int n)134 {135 unsigned int i=0;136 while(i<n)137 {138 delay_1ms();139 i++;140 }141 }142 #endif143 void init_devices(void)144 {145 CLI(); //disable all interrupts146 XDIV = 0x00; //xtal divider147 XMCRA = 0x00; //external memory148 port_init();149 uart0_init();150 timer0_init();151 152 MCUCR = 0x00;153 EICRA = 0x00; //extended ext ints154 sbi(TIMSK,TOIE0);155 // sbi(TIMSK,TOIE1); //允许定时器1溢出中断156 // sbi(TIMSK,TOIE2); //允许定时器2溢出中断157 watchdog_init(7);158 //SEI(); //re-enable interrupts159 //all peripherals are now initialised160 }161 #if 0162 void EEPROMwrite(unsigned int location, unsigned char byte)163 //unsigned int eepromwrite(unsigned int location, unsigned char byte)164 {165 unsigned char oldSREG;166 oldSREG = SREG;167 SREG &= ~0x80; // disable interrupt168 // Wait for completion of previous write169 while(EECR & (1<<EEWE)) ;170 // Set up address and data registers171 EEAR = location;172 EEDR = byte;173 // Write logical one to EEMWE174 EECR |= (1<<EEMWE);175 // Start eeprom write by setting EEWE176 EECR |= (1<<EEWE);177 178 SREG = oldSREG;179 // return 0; // return Success. ?180 } 181 unsigned char EEPROMread(unsigned int location)182 //unsigned char eepromread(unsigned int location)183 {184 unsigned char oldSREG;185 oldSREG = SREG;186 SREG &= ~0x80; // disable interrupt187 // Wait for completion of previous write188 while(EECR & (1<<EEWE)) ;189 // Set up address register190 EEAR = location;191 // Start eeprom read by writing EERE192 EECR |= (1<<EERE);193 194 SREG = oldSREG;195 // Return data from data register196 return EEDR;197 }198 #endif199 #if 1200 void wait_page_rw_ok(void)201 {202 //while(SPMCSR & 0x40){203 {204 while(SPMCSR & 0x01);205 //SPMCSR = 0x11;206 asm("spm\n");207 }208 }209 // code:0x03:erase, code:0x05:write a page210 void boot_page_ew(unsigned long addr,unsigned char code)211 {212 wait_page_rw_ok();213 asm("mov r30,r16\n"214 "mov r31,r17\n"215 "out 0x3b,r18\n"216 ); // put addr into Z register and RAMPZ‘s BIT0217 SPMCSR = code; // set operate code218 asm("spm\n"); // operate flash page219 wait_page_rw_ok();220 }221 // fill one word into a page222 void boot_page_fill(unsigned int pg_addr,unsigned int data)223 {224 pg_addr = pg_addr;225 data =http://www.mamicode.com/ data;226 wait_page_rw_ok();227 asm("mov r30,r16\n"228 "mov r31,r17\n" // Z register is page addr229 "mov r0,r18\n"230 "mov r1,r19\n" // R0R1 operate word 231 );232 SPMCSR = 0x01;233 asm("spm\n"); // operate flash page234 }235 void write_one_page(unsigned long f_addr)236 {237 int i = 0;238 for(i = 0; i < FLASH_PG_SIZE;i+=2){239 boot_page_fill(i,uart0_rx_buf[i]|(uart0_rx_buf[i+1]<<8));240 }241 boot_page_ew(flash_addr,0x03);242 boot_page_ew(flash_addr,0x05);243 }244 int check_one_page_ok(unsigned long f_addr)245 {246 unsigned char dat = 0;247 int i = 0;248 #if 0249 asm("mov r30,r16\n"250 "mov r31,r17\n"251 "out 0x3b,r18\n"252 ); // put addr into Z register and RAMPZ‘s BIT0253 for(i = 0; i < FLASH_PG_SIZE; i++){254 asm("elpm r0,Z+");255 asm("mov %dat, r0");256 //if(dat != uart0_rx_buf[i])257 // return 0;258 }259 #endif260 return 1;261 }262 #else263 void WriteFlash(void)264 {265 unsigned int i;266 unsigned int TempInt;267 for (i=0;i<FLASH_PG_SIZE;i+=2)268 {269 TempInt=uart0_rx_buf[i]+(uart0_rx_buf[i+1]<<8);270 fill_temp_buffer(TempInt,i); //call asm routine.271 } 272 write_page(flash_addr,0x03); //擦除页273 write_page(flash_addr,0x05); //写页数据274 275 enableRWW();276 }277 #endif278 #if 0279 #pragma interrupt_handler uart0_rxc_isr:19 //iv_USART0_RX280 void uart0_rxc_isr( void )281 {282 #if 0283 unsigned char data;284 unsigned char index;285 data =http://www.mamicode.com/ UDR0; 286 #endif287 }288 #endif289 void sys_choice_process(void)290 {291 unsigned long time_enter = 0;292 int dat = 0;293 time_enter = get_sys_time_ms();294 //sendStr("press ‘d‘ to download fw:");295 while(1){296 dat = getchar();297 //if(‘d‘ == dat){298 {299 putchar(XMODEM_NAK);300 sys_set_state(SYS_STATE_READ_DAT);301 return;302 }303 #if 0304 if(get_sys_time_ms() - time_enter >= SYS_WAIT_TIME){305 sys_set_state(SYS_STATE_ERROR);306 return;307 }308 #endif309 }310 311 return;312 }313 #if 0314 void sys_ack_process(void)315 {316 // Nothing, put ack to read data process317 return;318 }319 #endif320 unsigned char read_start = 0;321 void sys_read_data_process(void)322 {323 int dat = 0;324 int count = 0;325 unsigned int i = 0,ee_addr = 0,err_count = 0,cancel_flag = 0;326 unsigned char checksum = 0;327 //unsigned long flash_addr = 0;328 unsigned char packet_sn = 0,block = 0;329 unsigned long timer = 0;330 read_start = 0;331 while(1){332 #if 1333 if(0 == read_start){334 timer++;335 if((timer > 600000) ){336 sys_set_state(SYS_STATE_END);337 return;338 }339 }340 #endif341 dat = getchar();342 if(dat >= 0){343 344 if(0 == count){345 if(XMODEM_EOT == dat){346 read_start = 1;347 if(1 == block){348 write_one_page(flash_addr);349 }350 putchar(XMODEM_ACK);351 sys_set_state(SYS_STATE_END);352 return;353 }else if(XMODEM_SOH == dat){ // start flag354 cancel_flag = 0;355 }else if(XMODEM_CAN == dat){ // cancel flag356 cancel_flag = 1;357 }358 359 }else if(1 == count){360 if(1 == cancel_flag){361 if(XMODEM_CAN == dat){362 cancel_flag = 2;363 }else{364 putchar(‘1‘);365 goto error;366 }367 }368 // Note:when packet number reach to 255, it reset to zero,not 1369 if((dat - packet_sn == 1)|| ((0x0 == dat) &&(0xff == packet_sn))){ // sn ok370 packet_sn = dat;371 }else{ // sn error372 putchar(‘2‘);373 goto error;374 }375 }else if(2 == count){376 if(2 == cancel_flag){377 if(XMODEM_CAN == dat){378 sys_set_state(SYS_STATE_CANCEL);379 return;380 }else{381 putchar(‘3‘);382 goto error;383 }384 }385 if((dat + packet_sn) == 0xff){ // ok386 }else{ // error387 putchar(‘4‘);388 goto error;389 }390 }391 read_start = 1;392 count++;393 if(count > 3 && count < (128 + 4)){ // get data packets394 checksum += dat;395 uart0_rx_buf[i++] = dat;396 }397 if(count >= 132){398 if(dat == checksum){ // checksum ok399 #if 0400 for(i = 0; i < FLASH_PG_SIZE; i++){401 EEPROMwrite(ee_addr++,uart0_rx_buf[i]);402 }403 #else404 block++;405 if(2 == block){406 write_one_page(flash_addr);407 //WriteFlash();408 //if(!check_one_page_ok(flash_addr)){409 // putchar(‘5‘);410 // goto error;411 //}412 flash_addr += FLASH_PG_SIZE;413 i = 0;414 block = 0;415 }416 #endif417 putchar(XMODEM_ACK);418 err_count = 0;419 420 }else{ // retry421 putchar(XMODEM_NAK);422 err_count++;423 packet_sn--;424 }425 426 427 count = 0;428 checksum = 0;429 if(err_count > SYS_RETRY_MAX){430 putchar(‘6‘);431 goto error;432 }433 }434 }435 }436 return;437 error:438 sys_set_state(SYS_STATE_ERROR);439 return;440 }441 void sys_run_app(void)442 {443 //while(1); // TODO: just for debug444 MCUCR = 0x01; 445 MCUCR = 0x00; //将中断向量移至flash的起始位置446 RAMPZ = 0x00;447 asm("jmp 0x00000\n");448 }449 void sys_end_process(void)450 {451 sendStr("OK.\r\n");452 sys_run_app(); 453 454 return;455 }456 void sys_cancel_process(void)457 {458 sendStr("CANCEL.\r\n");459 sys_run_app();460 461 return;462 }463 void sys_error_process(void)464 {465 sendStr("ERROR.\r\n");466 sys_run_app();467 468 return;469 }470 void sys_run(void)471 {472 473 switch(sys_state){474 case SYS_STATE_CHOICE:475 sys_choice_process();476 break;477 //case SYS_STATE_ACK:478 //sys_ack_process();479 break;480 case SYS_STATE_READ_DAT:481 sys_read_data_process();482 break;483 case SYS_STATE_END:484 sys_end_process();485 break;486 case SYS_STATE_CANCEL:487 sys_cancel_process();488 break;489 case SYS_STATE_ERROR:490 default:491 sys_error_process();492 break;493 }494 }495 #if 0496 void test_flash(void)497 {498 int i = 0;499 for(i = 0; i < FLASH_PG_SIZE; i++){500 uart0_rx_buf[i] = 0x11;501 }502 write_one_page(flash_addr);503 flash_addr += FLASH_PG_SIZE;504 for(i = 0; i < FLASH_PG_SIZE; i++){505 uart0_rx_buf[i] = 0x22;506 }507 write_one_page(flash_addr);508 flash_addr += FLASH_PG_SIZE; 509 for(i = 0; i < FLASH_PG_SIZE; i++){510 uart0_rx_buf[i] = 0x33;511 }512 write_one_page(flash_addr);513 flash_addr += FLASH_PG_SIZE;514 while(1);515 }516 #endif517 void main(void)518 {519 static unsigned long time_last = 0;520 unsigned long time_now = 0;521 522 init_devices();523 sys_set_state(SYS_STATE_CHOICE);524 //sendStr("started.\r\n");525 //EEPROMwrite(0,‘M‘);526 //EEPROMwrite(1,‘W‘);527 //delay_ms(3000);528 529 while(1){530 #if 0531 time_now = get_sys_time_ms();532 if(time_now - time_last > 2000){533 sendStr("alive...\r\n");534 time_last = time_now;535 }536 #endif537 sys_run();538 //test_flash();539 }540 }
main.c
1 #ifndef _MAIN_H 2 #define _MAIN_H 3 #define XMODEM_NUL (0x00) 4 #define XMODEM_SOH (0x01) // Xmodem start header(128 data packets) 5 #define XMODEM_STX (0x02) // 1K xmoder start header(1024 data packets) 6 #define XMODEM_EOT (0x04) 7 #define XMODEM_ACK (0x06) 8 #define XMODEM_NAK (0x15) // 表示接收方想按照累加和的校验方式接收 9 #define XMODEM_CAN (0x18)10 #define XMODEM_EOF (0x1A)11 #define XMODEM_CRC_CK ‘C‘ // 表示接收方想按照CRC的校验方式接收12 #define SYS_STATE_CHOICE (1)13 #define SYS_STATE_READ_DAT (2)14 //#define SYS_STATE_ACK (3)15 #define SYS_STATE_END (4)16 #define SYS_STATE_ERROR (5)17 #define SYS_STATE_CANCEL (6)18 #define SYS_WAIT_TIME (5000) // 5 seconds19 #define SYS_RETRY_MAX (3)20 #define UART0_BUF_SIZE (150*2)21 #define XTAL (6) //晶振频率(MHz) 6MHz22 #define FLASH_PG_SIZE (128*2)23 #define OSC_VAR (6000000)24 #define cbi(reg, bit) (reg &= ~BIT(bit))25 #define sbi(reg, bit) (reg |= BIT(bit))26 27 #endif
main.h
折腾了差不多3天,终于调试成功了,不过是个初期的东西,以后还需要加强可靠性和易用性及安全性的考虑,好歹现在可以直接通过bootloader升级程序了,先整理下整个过程吧,方便自己以后查阅,也方便有需要的人,因为开发的过程中借鉴了好多别人的东西。
开发的缘由:公司的定制化软件比较多,用户拿到产品后又会有新的需求,其实很多就是纯软件的修改,现在就是工程师到现成开盖,拿下载器重新烧程序,会比较麻烦,因为产品的对外接口都有串口,而且Atmega 本身支持bootloader功能,于是想到了用串口升级程序这个法子J。
开发环境及工具:硬件平台:用的是公司Atmega128平台下的板子,AVR的一个并口下载器,软件:编译器:ICCAVR 7.22,串口调试助手,serial port monitor(用来监控串口数据的,好东东)及windows的超级终端,下载软件:PonyProg2000(这个软件用来读EEPROM和Flash比较方便,不过用来烧写Atmega2561的话就不能用它了,有问题),hexbin.exe工具(网上找的现成的),用来将intel的hex文件转换成纯16进制文件(单片机Flash中存储的格式)。
要实现的功能:如果要升级程序,则通过超级终端的串口(Xmodem协议),将固件烧写到flash的0地址中,然后跳转到flash的0地址中,否则等待一段时间则自动跳转到flash中的0地址中。bootloader的大小:1024字节以内。
一些注意事项:
1. 熔丝位的烧写:BOOTRST要进行编程,这样单片机在复位后自动跳转到bootloader区执行bootloader的代码,然后要根据自己bootloader的大小设置boot区的的熔丝位:具体设置如下图,这里我选择的是1024大小(注意1代表为编程,0代表已编程):
2. 设置引导区锁定位:为了保护bootloader不被应用程序修改或者擦除,所以要对其进行保护,Atmega提供了熔丝位的保护方式,具体设置如下图(我设置的为BLB0为11,BLB1为00):
3. Flash页的设定:因flash的擦除和写入是按照页来操作的,看手册上说是1页有128个字节,但实际调试时候发现需要一次写入256个字节才有效的,如果按照128来写入,会将第二个128的内容覆盖掉第一个128字节的内容,那就按照实际为准了。
4. Xmodem协议的注意事项:具体的xmodem不在本文叙述了,只说一下要注意的地方,校验和是可以选择的,我使用的是checksum(就是单纯的累加),也可以选择16为的CRC,这个是根据单片机第一次返回的响应字节来确定的,另外当包的序列号超过255时会重新从0开始而不是从1开始,首次传输是从1开始编号的,这个要注意一下。
5. 文件格式文件:和网上好多人一样,遇到同样的文件,在bootloader将应用程序烧写到flash中后,发现没有执行应用程序,开始我也以为是跳转不成成功的问题,上网查了半天都没找到答案,都是问问题的L。没办法,靠自己了,一致纳闷,烧写到Flash中的程序和原始文件内容一模一样怎么就不能执行啊,后来偶然用烧写软件打开要烧写的固件,发现内容和我用16进制工具打开的并不一样,Oh my god,豁然想到了问题的关键,原来用ICC生成的hex文件是intel hex形式,Intel HEX文件是由一行行符合Intel HEX文件格式的文本所构成的ASCII文本文件。在Intel HEX文件中,每一行包含一个HEX记录。这些记录由对应机器语言码和/或常量数据的十六进制编码数字组成。Intel HEX文件通常用于传输将被存于ROM或者EPROM中的程序和数据。大多数EPROM编程器或模拟器使用Intel HEX文件。而实际存储到Flash中的数据是要从这个HEX文件中提取出来,然后在通过xmodem发送到单片机,不要直接发送ICC生成的HEX文件,转换的话可以自己写一个小工具或者上网搜类似功能的工具,为了省事,我找了一个叫hex2bin的工具做的转换。
6. 在ICC工程中要设置,我的设置如下:
7. 关于C中嵌套汇编的参数和返回值的用法:下面引用ICC的帮助文件“
In the absence of a function prototype, integer arguments smaller than ints (for example, char) must be promoted to int type. If the function prototype is available, the C standard leaves the decision to the compiler implementation. ICCV7 for AVR does not promote the argument types if the function prototype is available.
If registers are used to pass byte arguments, it will use both registers but the higher register is undefined. For example, if the first argument is a byte, both R16/R17 will be used with R17 being undefined. Byte arguments passed on the software stack also take up 2 bytes. We may change the behavior and pack byte arguments tightly in some future release.
The first argument is passed in registers R16/R17 if it is an integer and R16/R17/R18/R19 if it is a long or floating point. The second argument is passed in R18/R19 if available. All other remaining arguments are passed on the software stack. If R16/R17 is used to pass the first argument and the second argument is a long or float, the lower half of the second argument is passed in R18/R19 and the upper half is passed on the software stack.
Integer values are returned in R16/R17 and longs and floats are returned in R16/R17/R18/R19. Byte values are returned in R16 with R17 undefined. ”
剩下的没什么了,下面附上程序(刚调试完,还没整理,很乱)
【转】AVR BOOT