root/trunk/bootloader/stk500boot.c

Revision 21, 25.5 kB (checked in by charlie, 3 years ago)

Added Peter Fleury's GPL licensed bootloader

Line 
1 /*****************************************************************************
2 Title:     STK500v2 compatible bootloader
3 Author:    Peter Fleury <pfleury@gmx.ch>   http://jump.to/fleury
4 File:      $Id: stk500boot.c,v 1.15 2008/05/25 09:09:30 peter Exp $
5 Compiler:  avr-gcc 4.x / avr-libc 1.4.x
6 Hardware:  All AVRs with bootloader support, tested with ATmega8
7 License:   GNU General Public License
8           
9 DESCRIPTION:
10     This program allows an AVR with bootloader capabilities to
11     read/write its own Flash/EEprom. To enter Programming mode   
12     an input pin is checked. If this pin is pulled low, programming mode 
13     is entered. If not, normal execution is done from $0000
14     "reset" vector in Application area.
15     Size < 500 words, fits into a 512 word bootloader section
16         when compiled with avr-gcc 4.1
17   
18 USAGE:
19     - Set AVR MCU type and clock-frequency (F_CPU) in the Makefile.
20     - Set baud rate below (AVRISP only works with 115200 bps)
21     - compile/link the bootloader with the supplied Makefile
22     - program the "Boot Flash section size" (BOOTSZ fuses),
23       for boot-size 512 words:  program BOOTSZ1
24     - enable the BOOT Reset Vector (program BOOTRST)
25     - Upload the hex file to the AVR using any ISP programmer
26     - Program Boot Lock Mode 3 (program BootLock 11 and BootLock 12 lock bits)
27     - Reset your AVR while keeping PROG_PIN pulled low
28     - Start AVRISP Programmer (AVRStudio/Tools/Program AVR)
29     - AVRISP will detect the bootloader
30     - Program your application FLASH file and optional EEPROM file using AVRISP
31     
32 Note:
33     Erasing the device without flashing, through AVRISP GUI button "Erase Device"
34     is not implemented, due to AVRStudio limitations.
35     Flash is always erased before programming.
36     
37     Normally the bootloader accepts further commands after programming.
38     The bootloader exits and starts applicaton code after programming
39     when ENABLE_LEAVE_BOOTLADER is defined.
40     Use Auto Programming mode to programm both flash and eeprom,
41     otherwise bootloader will exit after flash programming.
42     
43         AVRdude:
44         Please uncomment #define REMOVE_CMD_SPI_MULTI when using AVRdude.
45         Comment #define REMOVE_PROGRAM_LOCK_BIT_SUPPORT to reduce code size
46         Read Fuse Bits and Read/Write Lock Bits is not supported
47
48 NOTES:
49     Based on Atmel Application Note AVR109 - Self-programming
50     Based on Atmel Application Note AVR068 - STK500v2 Protocol   
51           
52 LICENSE:
53     Copyright (C) 2006 Peter Fleury
54
55     This program is free software; you can redistribute it and/or modify
56     it under the terms of the GNU General Public License as published by
57     the Free Software Foundation; either version 2 of the License, or
58     any later version.
59
60     This program is distributed in the hope that it will be useful,
61     but WITHOUT ANY WARRANTY; without even the implied warranty of
62     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
63     GNU General Public License for more details.
64
65 *****************************************************************************/
66 #include <inttypes.h>
67 #include <avr/io.h>
68 #include <avr/interrupt.h>
69 #include <avr/boot.h>
70 #include <avr/pgmspace.h>
71 #include "command.h"
72
73 /*
74  * Uncomment the following lines to save code space
75  */
76 //#define REMOVE_PROGRAM_LOCK_BIT_SUPPORT  // disable program lock bits
77 //#define REMOVE_BOOTLOADER_LED            // no LED to show active bootloader
78 //#define REMOVE_PROG_PIN_PULLUP           // disable internal pullup, use external
79 #define REMOVE_CMD_SPI_MULTI             // disable processing of SPI_MULTI commands
80
81 /*
82  *  Uncomment to leave bootloader and jump to application after programming.
83  */
84 #define ENABLE_LEAVE_BOOTLADER           
85
86 /*
87  * Pin "PROG_PIN" on port "PROG_PORT" has to be pulled low
88  * (active low) to start the bootloader
89  * uncomment #define REMOVE_PROG_PIN_PULLUP if using an external pullup
90  */
91 #define PROG_PORT  PORTD
92 #define PROG_DDR   DDRD
93 #define PROG_IN    PIND
94 #define PROG_PIN   PIND2
95
96 /*
97  * Active-high LED on pin "PROGLED_PIN" on port "PROGLED_PORT"
98  * indicates that bootloader is active
99  */
100 #define PROGLED_PORT PORTB
101 #define PROGLED_DDR  DDRB
102 #define PROGLED_PIN  PINB1
103
104 /*
105  * define CPU frequency in Mhz here if not defined in Makefile
106  */
107 #ifndef F_CPU
108 #define F_CPU 16000000UL
109 #endif
110
111
112 /*
113  * define which UART channel will be used, if device with two UARTs is used
114  */
115 //#define USE_USART1        // undefined means use USART0
116
117  
118 /*
119  * UART Baudrate, AVRStudio AVRISP only accepts 115200 bps
120  */
121 #define BAUDRATE 115200
122
123
124 /*
125  *  Enable (1) or disable (0) USART double speed operation
126  */
127 #define UART_BAUDRATE_DOUBLE_SPEED 0
128
129
130 /*
131  * HW and SW version, reported to AVRISP, must match version of AVRStudio
132  */
133 #define CONFIG_PARAM_BUILD_NUMBER_LOW   0
134 #define CONFIG_PARAM_BUILD_NUMBER_HIGH  0
135 #define CONFIG_PARAM_HW_VER                             0x0F
136 #define CONFIG_PARAM_SW_MAJOR                   2
137 #define CONFIG_PARAM_SW_MINOR                   0x0A
138
139
140
141 /*
142  * Calculate the address where the bootloader starts from FLASHEND and BOOTSIZE
143  * (adjust BOOTSIZE below and BOOTLOADER_ADDRESS in Makefile if you want to change the size of the bootloader)
144  */
145 #define BOOTSIZE 512
146 #define APP_END  (FLASHEND -(2*BOOTSIZE) + 1)
147
148
149
150 /*
151  * Signature bytes are not available in avr-gcc io_xxx.h
152  */
153 #if defined (__AVR_ATmega8__)
154     #define SIGNATURE_BYTES 0x1E9307
155 #elif defined (__AVR_ATmega16__)
156     #define SIGNATURE_BYTES 0x1E9403
157 #elif defined (__AVR_ATmega32__)
158     #define SIGNATURE_BYTES 0x1E9502
159 #elif defined (__AVR_ATmega8515__)
160     #define SIGNATURE_BYTES 0x1E9306
161 #elif defined (__AVR_ATmega8535__)
162     #define SIGNATURE_BYTES 0x1E9308
163 #elif defined (__AVR_ATmega88__)
164     #define SIGNATURE_BYTES 0x1E930A
165 #elif defined (__AVR_ATmega162__)
166     #define SIGNATURE_BYTES 0x1E9404
167 #elif defined (__AVR_ATmega168__)
168     #define SIGNATURE_BYTES 0x1E9406
169 #elif defined (__AVR_ATmega128__)
170     #define SIGNATURE_BYTES 0x1E9702
171 #elif defined (__AVR_AT90CAN32__)
172         #define SIGNATURE_BYTES 0x1E9581
173 #elif defined (__AVR_AT90CAN64__)
174         #define SIGNATURE_BYTES 0x1E9681
175 #elif defined (__AVR_AT90CAN128__)
176         #define SIGNATURE_BYTES 0x1E9781   
177 #else
178
179         #error "no signature definition for MCU available"
180 #endif
181
182
183
184 /*
185  *  Defines for the various USART registers
186  */
187 #if  defined(__AVR_ATmega8__)    || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \
188   || defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__)
189 /*
190  * ATMega with one USART
191  */
192 #define UART_BAUD_RATE_LOW           UBRRL
193 #define UART_STATUS_REG          UCSRA
194 #define UART_CONTROL_REG             UCSRB
195 #define UART_ENABLE_TRANSMITTER  TXEN
196 #define UART_ENABLE_RECEIVER     RXEN
197 #define UART_TRANSMIT_COMPLETE   TXC
198 #define UART_RECEIVE_COMPLETE    RXC
199 #define UART_DATA_REG            UDR
200 #define UART_DOUBLE_SPEED        U2X
201
202 #elif  defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) || defined(__AVR_ATmega162__) || defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) \
203         || defined(__AVR_AT90CAN32__) || defined(__AVR_AT90CAN64__) || defined(__AVR_AT90CAN128__)
204 /*
205  *  ATMega with two USART, select USART for bootloader using USE_USART1 define
206  */
207 #ifndef USE_USART1
208
209 #define UART_BAUD_RATE_LOW           UBRR0L
210 #ifdef UBRR0H
211 #define UART_BAUD_RATE_HIGH          UBRR0H
212 #endif
213
214 #define UART_STATUS_REG          UCSR0A
215 #define UART_CONTROL_REG             UCSR0B
216 #define UART_ENABLE_TRANSMITTER  TXEN0
217 #define UART_ENABLE_RECEIVER     RXEN0
218 #define UART_TRANSMIT_COMPLETE   TXC0
219 #define UART_RECEIVE_COMPLETE    RXC0
220 #define UART_DATA_REG            UDR0
221 #define UART_DOUBLE_SPEED        U2X0
222
223 #else
224
225
226 #define UART_BAUD_RATE_LOW           UBRR1L
227 #ifdef UBRR1H
228 #define UART_BAUD_RATE_HIGH      UBRR1H
229 #endif
230
231 #define UART_STATUS_REG          UCSR1A
232 #define UART_CONTROL_REG             UCSR1B
233 #define UART_ENABLE_TRANSMITTER  TXEN1
234 #define UART_ENABLE_RECEIVER     RXEN1
235 #define UART_TRANSMIT_COMPLETE   TXC1
236 #define UART_RECEIVE_COMPLETE    RXC1
237 #define UART_DATA_REG            UDR1
238 #define UART_DOUBLE_SPEED        U2X1
239
240 #endif
241
242
243 #else
244
245         #error "no UART definition for MCU available"
246 #endif
247
248
249
250 /*
251  * Macros to map the new ATmega88/168 EEPROM bits
252  */
253 #ifdef EEMPE                                                                       
254 #define EEMWE EEMPE
255 #define EEWE  EEPE
256 #endif
257
258
259
260 /*
261  * Macro to calculate UBBR from XTAL and baudrate
262  */
263 #if UART_BAUDRATE_DOUBLE_SPEED
264 #define UART_BAUD_SELECT(baudRate,xtalCpu) (((float)(xtalCpu))/(((float)(baudRate))*8.0)-1.0+0.5)
265 #else
266
267 #define UART_BAUD_SELECT(baudRate,xtalCpu) (((float)(xtalCpu))/(((float)(baudRate))*16.0)-1.0+0.5)
268 #endif
269
270
271
272 /*
273  * States used in the receive state machine
274  */
275 #define ST_START                0
276 #define ST_GET_SEQ_NUM  1
277 #define ST_MSG_SIZE_1   2
278 #define ST_MSG_SIZE_2   3
279 #define ST_GET_TOKEN    4
280 #define ST_GET_DATA             5
281 #define ST_GET_CHECK    6
282 #define ST_PROCESS              7
283
284
285 /*
286  * use 16bit address variable for ATmegas with <= 64K flash
287  */
288 #if defined(RAMPZ)
289 typedef uint32_t address_t;
290 #else
291
292 typedef uint16_t address_t;
293 #endif
294
295
296
297 /*
298  * function prototypes
299  */
300 static void sendchar(char c);
301 static unsigned char recchar(void);
302
303
304 /*
305  * since this bootloader is not linked against the avr-gcc crt1 functions,
306  * to reduce the code size, we need to provide our own initialization
307  */
308 void __jumpMain     (void) __attribute__ ((naked)) __attribute__ ((section (".init9")));
309
310 void __jumpMain(void)
311 {   
312     asm volatile ( ".set __stack, %0" :: "i" (RAMEND) );
313    
314     /* init stack here, bug WinAVR 20071221 does not init stack based on __stack */ 
315     asm volatile ("ldi r24,%0":: "M" (RAMEND & 0xFF));         
316     asm volatile ("ldi r25,%0":: "M" (RAMEND >> 8));
317     asm volatile ("out __SP_H__,r25" ::);
318     asm volatile ("out __SP_L__,r24" ::);
319    
320     asm volatile ( "clr __zero_reg__" );                       // GCC depends on register r1 set to 0
321     asm volatile ( "out %0, __zero_reg__" :: "I" (_SFR_IO_ADDR(SREG)) );  // set SREG to 0
322 #ifndef REMOVE_PROG_PIN_PULLUP   
323         PROG_PORT |= (1<<PROG_PIN);                                        // Enable internal pullup
324 #endif    
325     asm volatile ( "rjmp main");                               // jump to main()
326 }
327
328
329 /*
330  * send single byte to USART, wait until transmission is completed
331  */
332 static void sendchar(char c)
333 {
334     UART_DATA_REG = c;                                         // prepare transmission
335     while (!(UART_STATUS_REG & (1 << UART_TRANSMIT_COMPLETE)));// wait until byte sent
336     UART_STATUS_REG |= (1 << UART_TRANSMIT_COMPLETE);          // delete TXCflag
337 }
338
339 /*
340  * Read single byte from USART, block if no data available
341  */
342 static unsigned char recchar(void)
343 {
344     while(!(UART_STATUS_REG & (1 << UART_RECEIVE_COMPLETE)));  // wait for data
345     return UART_DATA_REG;
346 }
347
348
349 int main(void) __attribute__ ((OS_main));
350 int main(void)
351 {
352     address_t       address = 0;
353     address_t       eraseAddress = 0;   
354         unsigned char   msgParseState;
355     unsigned int    i = 0;
356     unsigned char   checksum = 0;
357     unsigned char   seqNum = 0;
358     unsigned int    msgLength = 0;
359     unsigned char   msgBuffer[285];
360     unsigned char   c, *p;
361     unsigned char   isLeave = 0;
362
363
364         /*
365          * Branch to bootloader or application code ?
366          */     
367         if(!(PROG_IN & (1<<PROG_PIN))) 
368         {           
369 #ifndef REMOVE_BOOTLOADER_LED
370         /* PROG_PIN pulled high, indicate with LED that bootloader is active */
371         PROGLED_DDR  |= (1<<PROGLED_PIN);
372         PROGLED_PORT |= (1<<PROGLED_PIN); /*Modified to active HIGH by charlie*/
373 #endif
374
375         /*
376          * Init UART
377          * set baudrate and enable USART receiver and transmiter without interrupts
378          */     
379 #if UART_BAUDRATE_DOUBLE_SPEED
380         UART_STATUS_REG   |=  (1 <<UART_DOUBLE_SPEED);
381 #endif
382
383  
384 #ifdef UART_BAUD_RATE_HIGH   
385         UART_BAUD_RATE_HIGH = 0;     
386 #endif       
387         UART_BAUD_RATE_LOW = UART_BAUD_SELECT(BAUDRATE,F_CPU);
388         UART_CONTROL_REG   = (1 << UART_ENABLE_RECEIVER) | (1 << UART_ENABLE_TRANSMITTER);
389        
390        
391         /* main loop */
392         while(!isLeave)                             
393         {   
394             /*
395              * Collect received bytes to a complete message
396              */           
397             msgParseState = ST_START;
398                 while ( msgParseState != ST_PROCESS )
399                 {
400                         c = recchar();
401                 switch (msgParseState)
402                 {
403                 case ST_START:
404                                     if( c == MESSAGE_START )
405                                     {
406                                             msgParseState = ST_GET_SEQ_NUM;
407                                             checksum = MESSAGE_START^0;
408                                     }
409                                     break;
410                                    
411                                 case ST_GET_SEQ_NUM:
412                     if ( (c == 1) || (c == seqNum) )
413                     {
414                                         seqNum = c;
415                                         msgParseState = ST_MSG_SIZE_1;
416                                         checksum ^= c;
417                     }
418                     else
419                     {
420                         msgParseState = ST_START;
421                     }
422                                 break;
423                                
424                             case ST_MSG_SIZE_1:                     
425                                     msgLength = (unsigned int)c<<8;
426                                     msgParseState = ST_MSG_SIZE_2;
427                                     checksum ^= c;
428                                     break;
429                                    
430                             case ST_MSG_SIZE_2:                 
431                                     msgLength |= c;
432                                     msgParseState = ST_GET_TOKEN;
433                                     checksum ^= c;
434                                     break;
435                            
436                             case ST_GET_TOKEN:
437                                 if ( c == TOKEN )
438                                     {
439                                             msgParseState = ST_GET_DATA;
440                                             checksum ^= c;
441                                             i = 0;
442                                     }
443                                     else
444                                     {
445                                         msgParseState = ST_START;
446                                     }
447                                     break;
448                            
449                             case ST_GET_DATA:                           
450                                     msgBuffer[i++] = c;
451                                     checksum ^= c;
452                                     if ( i == msgLength )
453                                     {
454                                             msgParseState = ST_GET_CHECK;
455                                     }
456                                     break;
457                                                
458                             case ST_GET_CHECK:
459                                     if( c == checksum )
460                                     {
461                                             msgParseState = ST_PROCESS;                                     
462                                     }
463                                     else
464                                     {
465                                         msgParseState = ST_START;
466                                     }
467                                     break;
468                                 }//switch
469                         }//while(msgParseState)
470                         
471                         /*
472                          * Now process the STK500 commands, see Atmel Appnote AVR068
473                          */
474                        
475                 switch (msgBuffer[0])
476                 {
477 #ifndef REMOVE_CMD_SPI_MULTI
478                         case CMD_SPI_MULTI:
479                                 {
480                         unsigned char answerByte = 0;
481
482                     // only Read Signature Bytes implemented, return dummy value for other instructions
483                                         if ( msgBuffer[4]== 0x30 )
484                                         {                                               
485                                                 unsigned char signatureIndex = msgBuffer[6];                                           
486
487                                                 if ( signatureIndex == 0 )
488                                                         answerByte = (SIGNATURE_BYTES >>16) & 0x000000FF;
489                                                 else if ( signatureIndex == 1 )
490                                                         answerByte = (SIGNATURE_BYTES >> 8) & 0x000000FF;
491                                                 else
492                                                         answerByte = SIGNATURE_BYTES & 0x000000FF;
493                                         }                                       
494                                 msgLength = 7;
495                                         msgBuffer[1] = STATUS_CMD_OK;
496                                         msgBuffer[2] = 0;                                       
497                                         msgBuffer[3] = msgBuffer[4];  // Instruction Byte 1
498                                         msgBuffer[4] = msgBuffer[5];  // Instruction Byte 2
499                                         msgBuffer[5] = answerByte;                     
500                                         msgBuffer[6] = STATUS_CMD_OK;
501                                 }
502                                 break;
503 #endif
504
505             case CMD_SIGN_ON:
506                         msgLength = 11;                 
507                         msgBuffer[1]  = STATUS_CMD_OK;
508                         msgBuffer[2]  = 8;
509                         msgBuffer[3]  = 'A';
510                         msgBuffer[4]  = 'V';
511                         msgBuffer[5]  = 'R';
512                         msgBuffer[6]  = 'I';
513                         msgBuffer[7]  = 'S';
514                         msgBuffer[8]  = 'P';
515                         msgBuffer[9]  = '_';
516                         msgBuffer[10] = '2';
517                         break;
518                
519                 case CMD_GET_PARAMETER:
520                     {
521                         unsigned char value;
522                        
523                         switch(msgBuffer[1])
524                         {
525                             case PARAM_BUILD_NUMBER_LOW:
526                                     value = CONFIG_PARAM_BUILD_NUMBER_LOW;
527                                     break;                                 
528                             case PARAM_BUILD_NUMBER_HIGH:
529                                     value = CONFIG_PARAM_BUILD_NUMBER_HIGH;
530                                     break;                                 
531                             case PARAM_HW_VER:
532                                     value = CONFIG_PARAM_HW_VER;
533                                     break;                                 
534                             case PARAM_SW_MAJOR:
535                                     value = CONFIG_PARAM_SW_MAJOR;
536                                     break;
537                             case PARAM_SW_MINOR:
538                                     value = CONFIG_PARAM_SW_MINOR;
539                                     break;                             
540                                 default:
541                                     value = 0;
542                                     break;
543                         }
544                             msgLength = 3;                     
545                             msgBuffer[1] = STATUS_CMD_OK;
546                             msgBuffer[2] = value;
547                         }
548                     break;
549                    
550                 case CMD_LEAVE_PROGMODE_ISP:
551 #ifdef ENABLE_LEAVE_BOOTLADER
552                     isLeave = 1;
553 #endif
554
555                 case CMD_ENTER_PROGMODE_ISP:                       
556                 case CMD_SET_PARAMETER:         
557                         msgLength = 2;                 
558                         msgBuffer[1] = STATUS_CMD_OK;
559                 break;
560
561             case CMD_READ_SIGNATURE_ISP:
562                 {
563                     unsigned char signatureIndex = msgBuffer[4];
564                     unsigned char signature;
565
566                     if ( signatureIndex == 0 )
567                         signature = (SIGNATURE_BYTES >>16) & 0x000000FF;
568                     else if ( signatureIndex == 1 )
569                         signature = (SIGNATURE_BYTES >> 8) & 0x000000FF;
570                     else
571                         signature = SIGNATURE_BYTES & 0x000000FF;
572
573                         msgLength = 4;
574                         msgBuffer[1] = STATUS_CMD_OK;
575                         msgBuffer[2] = signature;
576                         msgBuffer[3] = STATUS_CMD_OK;                   
577                     }
578                 break;
579
580             case CMD_READ_LOCK_ISP:           
581                 msgLength = 4;
582                     msgBuffer[1] = STATUS_CMD_OK;
583                     msgBuffer[2] = boot_lock_fuse_bits_get( GET_LOCK_BITS );
584                     msgBuffer[3] = STATUS_CMD_OK;                                                       
585                 break;
586            
587             case CMD_READ_FUSE_ISP:
588                 {                   
589                     unsigned char fuseBits;                   
590                    
591                     if ( msgBuffer[2] == 0x50 )
592                     {
593                         if ( msgBuffer[3] == 0x08 )
594                             fuseBits = boot_lock_fuse_bits_get( GET_EXTENDED_FUSE_BITS );                           
595                         else
596                             fuseBits = boot_lock_fuse_bits_get( GET_LOW_FUSE_BITS );                           
597                     }
598                     else
599                     {
600                         fuseBits = boot_lock_fuse_bits_get( GET_HIGH_FUSE_BITS );
601                     }                   
602                     msgLength = 4;   
603                         msgBuffer[1] = STATUS_CMD_OK;
604                         msgBuffer[2] = fuseBits;                       
605                         msgBuffer[3] = STATUS_CMD_OK;                                       
606                 }
607                 break;
608                
609 #ifndef REMOVE_PROGRAM_LOCK_BIT_SUPPORT
610             case CMD_PROGRAM_LOCK_ISP:
611                 {
612                     unsigned char lockBits = msgBuffer[4];
613                    
614                     lockBits = (~lockBits) & 0x3C;  // mask BLBxx bits
615                                     boot_lock_bits_set(lockBits);       // and program it
616                                     boot_spm_busy_wait();
617                    
618                     msgLength = 3;
619                         msgBuffer[1] = STATUS_CMD_OK;                   
620                         msgBuffer[2] = STATUS_CMD_OK;                                                           
621                 }
622                 break;
623 #endif
624
625             case CMD_CHIP_ERASE_ISP:
626                 eraseAddress = 0;
627                     msgLength = 2;
628                     msgBuffer[1] = STATUS_CMD_OK;
629                 break;
630
631             case CMD_LOAD_ADDRESS:
632 #if defined(RAMPZ)
633                 address = ( ((address_t)(msgBuffer[1])<<24)|((address_t)(msgBuffer[2])<<16)|((address_t)(msgBuffer[3])<<8)|(msgBuffer[4]) )<<1;
634 #else
635
636                         address = ( ((msgBuffer[3])<<8)|(msgBuffer[4]) )<<1;  //convert word to byte address
637 #endif
638
639                         msgLength = 2;
640                         msgBuffer[1] = STATUS_CMD_OK;
641                 break;
642                
643             case CMD_PROGRAM_FLASH_ISP:
644             case CMD_PROGRAM_EEPROM_ISP:               
645                 {
646                     unsigned int  size = (((unsigned int)msgBuffer[1])<<8) | msgBuffer[2];
647                     unsigned char *p = msgBuffer+10;
648                     unsigned int  data;
649                     unsigned char highByte, lowByte;                   
650                     address_t     tempaddress = address;
651
652                    
653                     if ( msgBuffer[0] == CMD_PROGRAM_FLASH_ISP )
654                     {
655                                 // erase only main section (bootloader protection)
656                                 if  (  eraseAddress < APP_END )
657                                 {
658                                         boot_page_erase(eraseAddress);  // Perform page erase
659                                         boot_spm_busy_wait();           // Wait until the memory is erased.
660                                         eraseAddress += SPM_PAGESIZE;    // point to next page to be erase
661                                 }
662                        
663                             /* Write FLASH */
664                                 do {
665                                     lowByte   = *p++;
666                                     highByte  = *p++;
667                                            
668                                             data =  (highByte << 8) | lowByte;
669                                             boot_page_fill(address,data);
670                                                                                                
671                                             address = address + 2;      // Select next word in memory
672                                             size -= 2;                  // Reduce number of bytes to write by two   
673                                     } while(size);                      // Loop until all bytes written
674                                     
675                                 boot_page_write(tempaddress);
676                                 boot_spm_busy_wait();   
677                                 boot_rww_enable();                              // Re-enable the RWW section                   
678                         }
679                         else
680                         {
681                             /* write EEPROM */
682                                     do {
683                                     EEARL = address;                    // Setup EEPROM address
684                                 EEARH = (address >> 8);
685                                             address++;                                  // Select next EEPROM byte
686         
687                                             EEDR= *p++;                             // get byte from buffer
688                                 EECR |= (1<<EEMWE);                     // Write data into EEPROM
689                                 EECR |= (1<<EEWE);
690                            
691                                             while (EECR & (1<<EEWE));   // Wait for write operation to finish
692                                             size--;                                             // Decrease number of bytes to write
693                                     } while(size);                                      // Loop until all bytes written                             
694                         }
695                             msgLength = 2;
696                             msgBuffer[1] = STATUS_CMD_OK;                       
697                 }
698                 break;
699                
700             case CMD_READ_FLASH_ISP:
701             case CMD_READ_EEPROM_ISP:                                               
702                 {
703                     unsigned int  size = (((unsigned int)msgBuffer[1])<<8) | msgBuffer[2];
704                     unsigned char *p = msgBuffer+1;
705                     msgLength = size+3;
706                    
707                     *p++ = STATUS_CMD_OK;                   
708                     if (msgBuffer[0] == CMD_READ_FLASH_ISP )
709                     {
710                         unsigned int data;
711                        
712                         // Read FLASH
713                         do {                           
714 #if defined(RAMPZ)
715                                         data = pgm_read_word_far(address);
716 #else
717
718                                         data = pgm_read_word_near(address);
719 #endif
720
721                                         *p++ = (unsigned char)data;         //LSB
722                                         *p++ = (unsigned char)(data >> 8);      //MSB 
723                                         address    += 2;         // Select next word in memory
724                                         size -= 2;
725                         }while (size);
726                     }
727                     else
728                     {
729                                     /* Read EEPROM */
730                                     do {
731                                         EEARL = address;                        // Setup EEPROM address
732                                         EEARH = ((address >> 8));
733                                         address++;                                      // Select next EEPROM byte
734                                         EECR |= (1<<EERE);                      // Read EEPROM
735                                         *p++ = EEDR;                            // Send EEPROM data
736                                         size--;                                 
737                                 }while(size);
738                     }
739                     *p++ = STATUS_CMD_OK;
740                 }
741                 break;
742
743                 default:
744                     msgLength = 2;   
745                     msgBuffer[1] = STATUS_CMD_FAILED;
746                     break;
747                 }
748
749             /*
750              * Now send answer message back
751              */
752                 sendchar(MESSAGE_START);     
753                 checksum = MESSAGE_START^0;
754                
755                 sendchar(seqNum);
756                 checksum ^= seqNum;
757                
758                 c = ((msgLength>>8)&0xFF);
759                 sendchar(c);
760                 checksum ^= c;
761                
762                 c = msgLength&0x00FF;
763                 sendchar(c);
764                 checksum ^= c;
765                
766                 sendchar(TOKEN);
767                 checksum ^= TOKEN;
768
769             p = msgBuffer;
770             while ( msgLength )
771             {               
772                c = *p++;
773                sendchar(c);
774                checksum ^=c;
775                msgLength--;               
776             }                   
777                 sendchar(checksum);             
778                 seqNum++;
779
780             }//for
781
782 #ifndef REMOVE_BOOTLOADER_LED
783         PROGLED_DDR  &= ~(1<<PROGLED_PIN);   // set to default     
784 #endif
785
786     }
787    
788         /*
789          * Now leave bootloader
790          */
791 #ifndef REMOVE_PROG_PIN_PULLUP 
792         PROG_PORT &= ~(1<<PROG_PIN);    // set to default
793 #endif 
794         boot_rww_enable();              // enable application section
795         
796         // Jump to Reset vector in Application Section
797         // (clear register, push this register to the stack twice = adress 0x0000/words, and return to this address)
798     asm volatile (
799                 "clr r1" "\n\t"
800                 "push r1" "\n\t"
801         "push r1" "\n\t"
802         "ret"     "\n\t"
803     ::);
804
805      /*
806      * Never return to stop GCC to generate exit return code
807      * Actually we will never reach this point, but the compiler doesn't
808      * understand this
809      */
810     for(;;);
811 }
Note: See TracBrowser for help on using the browser.