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 timer 101 } 102 #pragma interrupt_handler timer0_ovf_isr:17 103 void timer0_ovf_isr(void) 104 { 105 TCNT0 = 0xf9; //reload counter value 106 timer_1ms++; 107 } 108 void watchdog_off(void) 109 { 110 // Write logical one to WDCE and WDE 111 WDTCR = (1<<WDCE) | (1<<WDE); 112 // Turn off WDT 113 WDTCR = 0x00; 114 } 115 void watchdog_init(unsigned char time) 116 { 117 WDR(); //this prevents a timout on enabling 118 // Write logical one to WDCE and WDE 119 WDTCR = (1<<WDCE) | (1<<WDE); 120 time&=0x07; // prescale: n cycles time=0~7,WDCE=0 121 time|=0x08; // prescale: n cycles time=0~7,WDE=1 122 WDTCR=time; //WATCHDOG ENABLED - dont forget to issue WDRs 123 } 124 #if 0 125 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 #endif 143 void init_devices(void) 144 { 145 CLI(); //disable all interrupts 146 XDIV = 0x00; //xtal divider 147 XMCRA = 0x00; //external memory 148 port_init(); 149 uart0_init(); 150 timer0_init(); 151 152 MCUCR = 0x00; 153 EICRA = 0x00; //extended ext ints 154 sbi(TIMSK,TOIE0); 155 // sbi(TIMSK,TOIE1); //容許定時器1溢出中斷 156 // sbi(TIMSK,TOIE2); //容許定時器2溢出中斷 157 watchdog_init(7); 158 //SEI(); //re-enable interrupts 159 //all peripherals are now initialised 160 } 161 #if 0 162 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 interrupt 168 // Wait for completion of previous write 169 while(EECR & (1<<EEWE)) ; 170 // Set up address and data registers 171 EEAR = location; 172 EEDR = byte; 173 // Write logical one to EEMWE 174 EECR |= (1<<EEMWE); 175 // Start eeprom write by setting EEWE 176 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 interrupt 187 // Wait for completion of previous write 188 while(EECR & (1<<EEWE)) ; 189 // Set up address register 190 EEAR = location; 191 // Start eeprom read by writing EERE 192 EECR |= (1<<EERE); 193 194 SREG = oldSREG; 195 // Return data from data register 196 return EEDR; 197 } 198 #endif 199 #if 1 200 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 page 210 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 BIT0 217 SPMCSR = code; // set operate code 218 asm("spm\n"); // operate flash page 219 wait_page_rw_ok(); 220 } 221 // fill one word into a page 222 void boot_page_fill(unsigned int pg_addr,unsigned int data) 223 { 224 pg_addr = pg_addr; 225 data = data; 226 wait_page_rw_ok(); 227 asm("mov r30,r16\n" 228 "mov r31,r17\n" // Z register is page addr 229 "mov r0,r18\n" 230 "mov r1,r19\n" // R0R1 operate word 231 ); 232 SPMCSR = 0x01; 233 asm("spm\n"); // operate flash page 234 } 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 0 249 asm("mov r30,r16\n" 250 "mov r31,r17\n" 251 "out 0x3b,r18\n" 252 ); // put addr into Z register and RAMPZ's BIT0 253 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 #endif 260 return 1; 261 } 262 #else 263 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 #endif 278 #if 0 279 #pragma interrupt_handler uart0_rxc_isr:19 //iv_USART0_RX 280 void uart0_rxc_isr( void ) 281 { 282 #if 0 283 unsigned char data; 284 unsigned char index; 285 data = UDR0; 286 #endif 287 } 288 #endif 289 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 0 304 if(get_sys_time_ms() - time_enter >= SYS_WAIT_TIME){ 305 sys_set_state(SYS_STATE_ERROR); 306 return; 307 } 308 #endif 309 } 310 311 return; 312 } 313 #if 0 314 void sys_ack_process(void) 315 { 316 // Nothing, put ack to read data process 317 return; 318 } 319 #endif 320 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 1 333 if(0 == read_start){ 334 timer++; 335 if((timer > 600000) ){ 336 sys_set_state(SYS_STATE_END); 337 return; 338 } 339 } 340 #endif 341 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 flag 354 cancel_flag = 0; 355 }else if(XMODEM_CAN == dat){ // cancel flag 356 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 1 369 if((dat - packet_sn == 1)|| ((0x0 == dat) &&(0xff == packet_sn))){ // sn ok 370 packet_sn = dat; 371 }else{ // sn error 372 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){ // ok 386 }else{ // error 387 putchar('4'); 388 goto error; 389 } 390 } 391 read_start = 1; 392 count++; 393 if(count > 3 && count < (128 + 4)){ // get data packets 394 checksum += dat; 395 uart0_rx_buf[i++] = dat; 396 } 397 if(count >= 132){ 398 if(dat == checksum){ // checksum ok 399 #if 0 400 for(i = 0; i < FLASH_PG_SIZE; i++){ 401 EEPROMwrite(ee_addr++,uart0_rx_buf[i]); 402 } 403 #else 404 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 #endif 417 putchar(XMODEM_ACK); 418 err_count = 0; 419 420 }else{ // retry 421 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 debug 444 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 0 496 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 #endif 517 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 0 531 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 #endif 537 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 seconds 19 #define SYS_RETRY_MAX (3) 20 #define UART0_BUF_SIZE (150*2) 21 #define XTAL (6) //晶振頻率(MHz) 6MHz 22 #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.hwindows
折騰了差很少3天,終於調試成功了,不過是個初期的東西,之後還須要增強可靠性和易用性及安全性的考慮,好歹如今能夠直接經過bootloader升級程序了,先整理下整個過程吧,方便本身之後查閱,也方便有須要的人,由於開發的過程當中借鑑了好多別人的東西。
開發的原因:公司的定製化軟件比較多,用戶拿到產品後又會有新的需求,其實不少就是純軟件的修改,如今就是工程師到現成開蓋,拿下載器從新燒程序,會比較麻煩,由於產品的對外接口都有串口,並且Atmega 自己支持bootloader功能,因而想到了用串口升級程序這個法子J。安全
開發環境及工具:硬件平臺:用的是公司Atmega128平臺下的板子,AVR的一個並口下載器,軟件:編譯器:ICCAVR 7.22,串口調試助手,serial port monitor(用來監控串口數據的,好東東)及windows的超級終端,下載軟件:PonyProg2000(這個軟件用來讀EEPROM和Flash比較方便,不過用來燒寫Atmega2561的話就不能用它了,有問題),hexbin.exe工具(網上找的現成的),用來將intel的hex文件轉換成純16進制文件(單片機Flash中存儲的格式)。app
要實現的功能:若是要升級程序,則經過超級終端的串口(Xmodem協議),將固件燒寫到flash的0地址中,而後跳轉到flash的0地址中,不然等待一段時間則自動跳轉到flash中的0地址中。bootloader的大小:1024字節之內。async
一些注意事項:ide
1. 熔絲位的燒寫:BOOTRST要進行編程,這樣單片機在復位後自動跳轉到bootloader區執行bootloader的代碼,而後要根據本身bootloader的大小設置boot區的的熔絲位:具體設置以下圖,這裏我選擇的是1024大小(注意1表明爲編程,0表明已編程):工具
2. 設置引導區鎖定位:爲了保護bootloader不被應用程序修改或者擦除,因此要對其進行保護,Atmega提供了熔絲位的保護方式,具體設置以下圖(我設置的爲BLB0爲11,BLB1爲00):this
3. Flash頁的設定:因flash的擦除和寫入是按照頁來操做的,看手冊上說是1頁有128個字節,但實際調試時候發現須要一次寫入256個字節纔有效的,若是按照128來寫入,會將第二個128的內容覆蓋掉第一個128字節的內容,那就按照實際爲準了。編碼
4. Xmodem協議的注意事項:具體的xmodem不在本文敘述了,只說一下要注意的地方,校驗和是能夠選擇的,我使用的是checksum(就是單純的累加),也能夠選擇16爲的CRC,這個是根據單片機第一次返回的響應字節來肯定的,另外當包的序列號超過255時會從新從0開始而不是從1開始,首次傳輸是從1開始編號的,這個要注意一下。spa
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. 」
剩下的沒什麼了,下面附上程序(剛調試完,還沒整理,很亂)