Subversion Repositories Projects

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1127 - 1
/*****************************************************************************
2
*
3
* AVRPROG compatible boot-loader
4
* Version  : 0.85 (Dec. 2008)
5
* Compiler : avr-gcc 4.1.2 / avr-libc 1.4.6
6
* size     : depends on features and startup ( minmal features < 512 words)
7
* by       : Martin Thomas, Kaiserslautern, Germany
8
*            eversmith@heizung-thomas.de
9
*            Additional code and improvements contributed by:
10
*           - Uwe Bonnes
11
*           - Bjoern Riemer
12
*           - Olaf Rempel
13
*
14
* License  : Copyright (c) 2006-2008 M. Thomas, U. Bonnes, O. Rempel
15
*            Free to use. You have to mention the copyright
16
*            owners in source-code and documentation of derived
17
*            work. No warranty! (Yes, you can insert the BSD
18
*            license here)
19
*
20
* Tested with ATmega8, ATmega16, ATmega162, ATmega32, ATmega324P,
21
*             ATmega644, ATmega644P, ATmega128, AT90CAN128
22
*
23
* - Initial versions have been based on the Butterfly bootloader-code
24
*   by Atmel Corporation (Authors: BBrandal, PKastnes, ARodland, LHM)
25
*
26
****************************************************************************
27
*
28
*  See the makefile and readme.txt for information on how to adapt
29
*  the linker-settings to the selected Boot Size (BOOTSIZE=xxxx) and
30
*  the MCU-type. Other configurations futher down in this file.
31
*
32
*  With BOOT_SIMPLE, minimal features and discarded int-vectors
33
*  this bootloader has should fit into a a 512 word (1024, 0x400 bytes)
34
*  bootloader-section.
35
*
36
****************************************************************************/
37
/*
38
        TODOs:
39
        - check lock-bits set
40
        - __bad_interrupt still linked even with modified
41
          linker-scripts which needs a default-handler,
42
          "wasted": 3 words for AVR5 (>8kB), 2 words for AVR4
43
        - Check watchdog-disable-function in avr-libc.
44
*/
45
// tabsize: 4
46
 
47
// Fuses ATmega 644P D7 DC FC
48
 
49
 
50
/* MCU frequency */
51
#ifndef F_CPU
52
// #define F_CPU 7372800
53
#define F_CPU (20000000)
54
#endif
55
 
56
#define BOOTSIZE 1024
57
 
58
#define set_LED1()      (PORTC &= ~(1 << PC3))
59
#define clr_LED1()      (PORTC |=  (1 << PC3))
60
#define set_LED2()      (PORTC &= ~(1 << PC2))
61
#define clr_LED2()      (PORTC |=  (1 << PC2))
62
#define set_LED3()      (PORTB &= ~(1 << PB1))
63
#define clr_LED3()      (PORTB |=  (1 << PB1))
64
#define set_LED4()      (PORTB &= ~(1 << PB0))
65
#define clr_LED4()      (PORTB |=  (1 << PB0))
66
 
67
/* UART Baudrate */
68
// #define BAUDRATE 9600
69
// #define BAUDRATE 19200
70
#define BAUDRATE 115200
71
 
72
/* use "Double Speed Operation" */
73
//#define UART_DOUBLESPEED
74
 
75
/* use second UART on mega128 / can128 / mega162 / mega324p / mega644p */
76
#define UART_USE_SECOND
77
 
78
/* Device-Type:
79
   For AVRProg the BOOT-option is prefered
80
   which is the "correct" value for a bootloader.
81
   avrdude may only detect the part-code for ISP */
82
#define DEVTYPE     DEVTYPE_BOOT
83
// #define DEVTYPE     DEVTYPE_ISP
84
 
85
/*
86
 * Pin "STARTPIN" on port "STARTPORT" in this port has to grounded
87
 * (active low) to start the bootloader
88
 */
89
#define BLPORT          PORTA
90
#define BLDDR           DDRA
91
#define BLPIN           PINA
92
#define BLPNUM          PINA4
93
 
94
/*
95
 * Define if Watchdog-Timer should be disable at startup
96
 */
97
#define DISABLE_WDT_AT_STARTUP
98
 
99
/*
100
 * Watchdog-reset is issued at exit
101
 * define the timeout-value here (see avr-libc manual)
102
 */
103
#define EXIT_WDT_TIME   WDTO_250MS
104
 
105
/*
106
 * Select startup-mode
107
 * SIMPLE-Mode - Jump to bootloader main BL-loop if key is
108
 *   pressed (Pin grounded) "during" reset or jump to the
109
 *   application if the pin is not grounded. The internal
110
 *   pull-up resistor is enabled during the startup and
111
 *   gets disabled before the application is started.
112
 * POWERSAVE-Mode - Startup is separated in two loops
113
 *   which makes power-saving a little easier if no firmware
114
 *   is on the chip. Needs more memory
115
 * BOOTICE-Mode - to flash the JTAGICE upgrade.ebn file.
116
 *   No startup-sequence in this mode. Jump directly to the
117
 *   parser-loop on reset
118
 *   F_CPU in BOOTICEMODE must be 7372800 Hz to be compatible
119
 *   with the org. JTAGICE-Firmware
120
 * WAIT-mode waits 1 sec for the defined character if nothing
121
 *    is recived then the user prog is started.
122
 */
123
#define START_SIMPLE
124
//#define START_WAIT
125
//#define START_POWERSAVE
126
//#define START_BOOTICE
127
 
128
/* character to start the bootloader in mode START_WAIT */
129
#define START_WAIT_UARTCHAR 'S'
130
 
131
/* wait-time for START_WAIT mode ( t = WAIT_TIME * 10ms ) */
132
#define WAIT_VALUE 100 /* here: 100*10ms = 1000ms = 1sec */
133
 
134
/*
135
 * enable/disable readout of fuse and lock-bits
136
 * (AVRPROG has to detect the AVR correctly by device-code
137
 * to show the correct information).
138
 */
139
//#define ENABLEREADFUSELOCK
140
 
141
/* enable/disable write of lock-bits
142
 * WARNING: lock-bits can not be reseted by bootloader (as far as I know)
143
 * Only protection no unprotection, "chip erase" from bootloader only
144
 * clears the flash but does no real "chip erase" (this is not possible
145
 * with a bootloader as far as I know)
146
 * Keep this undefined!
147
 */
148
//#define WRITELOCKBITS
149
 
150
/*
151
 * define the following if the bootloader should not output
152
 * itself at flash read (will fake an empty boot-section)
153
 */
154
#define READ_PROTECT_BOOTLOADER
155
 
156
 
157
#define VERSION_HIGH '0'
158
#define VERSION_LOW  '8'
159
 
160
#define GET_LOCK_BITS           0x0001
161
#define GET_LOW_FUSE_BITS       0x0000
162
#define GET_HIGH_FUSE_BITS      0x0003
163
#define GET_EXTENDED_FUSE_BITS  0x0002
164
 
165
 
166
#ifdef UART_DOUBLESPEED
167
// #define UART_CALC_BAUDRATE(baudRate) (((F_CPU*10UL) / ((baudRate) *8UL) +5)/10 -1)
168
#define UART_CALC_BAUDRATE(baudRate) ((uint32_t)((F_CPU) + ((uint32_t)baudRate * 4UL)) / ((uint32_t)(baudRate) * 8UL) - 1)
169
#else
170
// #define UART_CALC_BAUDRATE(baudRate) (((F_CPU*10UL) / ((baudRate)*16UL) +5)/10 -1)
171
#define UART_CALC_BAUDRATE(baudRate) ((uint32_t)((F_CPU) + ((uint32_t)baudRate * 8UL)) / ((uint32_t)(baudRate) * 16UL) - 1)
172
#endif
173
 
174
 
175
#include <stdint.h>
176
#include <avr/io.h>
177
#include <avr/wdt.h>
178
#include <avr/boot.h>
179
#include <avr/pgmspace.h>
180
#include <avr/eeprom.h>
181
#include <avr/interrupt.h>
182
#include <util/delay.h>
183
 
184
#include "chipdef.h"
185
 
186
//#include "lcd.h"
187
 
188
uint8_t gBuffer[SPM_PAGESIZE];
189
 
190
#if defined(BOOTLOADERHASNOVECTORS)
191
#warning "This Bootloader does not link interrupt vectors - see makefile"
192
/* make the linker happy - it wants to see __vector_default */
193
// void __vector_default(void) { ; }
194
void __vector_default(void) { ; }
195
#endif
196
 
197
static void sendchar(uint8_t data)
198
{
199
        while (!(UART_STATUS & (1<<UART_TXREADY)));
200
        UART_DATA = data;
201
}
202
 
203
static uint8_t recvchar(void)
204
{
205
        while (!(UART_STATUS & (1<<UART_RXREADY)));
206
        clr_LED1();
207
        return UART_DATA;
208
}
209
 
210
static inline void eraseFlash(void)
211
{
212
        // erase only main section (bootloader protection)
213
        uint32_t addr = 0;
214
        while (APP_END > addr) {
215
                boot_page_erase(addr);          // Perform page erase
216
                boot_spm_busy_wait();           // Wait until the memory is erased.
217
                addr += SPM_PAGESIZE;
218
        }
219
        boot_rww_enable();
220
}
221
 
222
static inline void recvBuffer(pagebuf_t size)
223
{
224
        pagebuf_t cnt;
225
        uint8_t *tmp = gBuffer;
226
 
227
        for (cnt = 0; cnt < sizeof(gBuffer); cnt++) {
228
                *tmp++ = (cnt < size) ? recvchar() : 0xFF;
229
        }
230
}
231
 
232
static inline uint16_t writeFlashPage(uint16_t waddr, pagebuf_t size)
233
{
234
        uint32_t pagestart = (uint32_t)waddr<<1;
235
        uint32_t baddr = pagestart;
236
        uint16_t data;
237
        uint8_t *tmp = gBuffer;
238
 
239
        do {
240
                data = *tmp++;
241
                data |= *tmp++ << 8;
242
                boot_page_fill(baddr, data);    // call asm routine.
243
 
244
                baddr += 2;                     // Select next word in memory
245
                size -= 2;                      // Reduce number of bytes to write by two
246
        } while (size);                         // Loop until all bytes written
247
 
248
        boot_page_write(pagestart);
249
        boot_spm_busy_wait();
250
        boot_rww_enable();              // Re-enable the RWW section
251
 
252
        return baddr>>1;
253
}
254
 
255
static inline uint16_t writeEEpromPage(uint16_t address, pagebuf_t size)
256
{
257
        uint8_t *tmp = gBuffer;
258
 
259
        do {
260
                eeprom_write_byte( (uint8_t*)address, *tmp++ );
261
                address++;                      // Select next byte
262
                size--;                         // Decreas number of bytes to write
263
        } while (size);                         // Loop until all bytes written
264
 
265
        // eeprom_busy_wait();
266
 
267
        return address;
268
}
269
 
270
static inline uint16_t readFlashPage(uint16_t waddr, pagebuf_t size)
271
{
272
        uint32_t baddr = (uint32_t)waddr<<1;
273
        uint16_t data;
274
 
275
        do {
276
#ifndef READ_PROTECT_BOOTLOADER
277
#warning "Bootloader not read-protected"
278
#if defined(RAMPZ)
279
                data = pgm_read_word_far(baddr);
280
#else
281
                data = pgm_read_word_near(baddr);
282
#endif
283
#else
284
                // don't read bootloader
285
                if ( baddr < APP_END ) {
286
#if defined(RAMPZ)
287
                        data = pgm_read_word_far(baddr);
288
#else
289
                        data = pgm_read_word_near(baddr);
290
#endif
291
                }
292
                else {
293
                        data = 0xFFFF; // fake empty
294
                }
295
#endif
296
                sendchar(data);                 // send LSB
297
                sendchar((data >> 8));          // send MSB
298
                baddr += 2;                     // Select next word in memory
299
                size -= 2;                      // Subtract two bytes from number of bytes to read
300
        } while (size);                         // Repeat until block has been read
301
 
302
        return baddr>>1;
303
}
304
 
305
static inline uint16_t readEEpromPage(uint16_t address, pagebuf_t size)
306
{
307
        do {
308
                sendchar( eeprom_read_byte( (uint8_t*)address ) );
309
                address++;
310
                size--;                         // Decrease number of bytes to read
311
        } while (size);                         // Repeat until block has been read
312
 
313
        return address;
314
}
315
 
316
#if defined(ENABLEREADFUSELOCK)
317
static uint8_t read_fuse_lock(uint16_t addr)
318
{
319
        uint8_t mode = (1<<BLBSET) | (1<<SPMEN);
320
        uint8_t retval;
321
 
322
        asm volatile
323
        (
324
                "movw r30, %3\n\t"              /* Z to addr */ \
325
                "sts %0, %2\n\t"                /* set mode in SPM_REG */ \
326
                "lpm\n\t"                       /* load fuse/lock value into r0 */ \
327
                "mov %1,r0\n\t"                 /* save return value */ \
328
                : "=m" (SPM_REG),
329
                  "=r" (retval)
330
                : "r" (mode),
331
                  "r" (addr)
332
                : "r30", "r31", "r0"
333
        );
334
        return retval;
335
}
336
#endif
337
 
338
static void send_boot(void)
339
{
340
        sendchar('A');
341
        sendchar('V');
342
        sendchar('R');
343
        sendchar('B');
344
        sendchar('O');
345
        sendchar('O');
346
        sendchar('T');
347
}
348
 
349
 
350
 
351
static void (*jump_to_app)(void) = 0x0000;
352
 
353
int main(void)
354
{
355
        uint16_t address = 0;
356
        uint8_t device = 0, val;
357
 
358
        DDRC = 0xFF;
359
        PORTC = PORTC | 0xff;
360
 
361
 
362
 
363
#ifdef DISABLE_WDT_AT_STARTUP
364
#ifdef WDT_OFF_SPECIAL
365
#warning "using target specific watchdog_off"
366
        bootloader_wdt_off();
367
#else
368
        cli();
369
        wdt_reset();
370
        wdt_disable();
371
#endif
372
#endif
373
 
374
#ifdef START_POWERSAVE
375
        uint8_t OK = 1;
376
#endif
377
 
378
        BLDDR  &= ~(1<<BLPNUM);         // set as Input
379
        BLPORT |= (1<<BLPNUM);          // Enable pullup
380
 
381
        // Set baud rate
382
        UART_BAUD_HIGH = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF;
383
        UART_BAUD_LOW = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF);
384
 
385
#ifdef UART_DOUBLESPEED
386
        UART_STATUS = ( 1<<UART_DOUBLE );
387
#endif
388
 
389
        UART_CTRL = UART_CTRL_DATA;
390
        UART_CTRL2 = UART_CTRL2_DATA;
391
 
392
#if defined(START_POWERSAVE)
393
        /*
394
                This is an adoption of the Butterfly Bootloader startup-sequence.
395
                It may look a little strange but separating the login-loop from
396
                the main parser-loop gives a lot a possibilities (timeout, sleep-modes
397
            etc.).
398
        */
399
        for(;OK;) {
400
                if ((BLPIN & (1<<BLPNUM))) {
401
                        // jump to main app if pin is not grounded
402
                        BLPORT &= ~(1<<BLPNUM); // set to default
403
#ifdef UART_DOUBLESPEED
404
                        UART_STATUS &= ~( 1<<UART_DOUBLE );
405
#endif
406
                        jump_to_app();          // Jump to application sector
407
 
408
                } else {
409
                        val = recvchar();
410
                        /* ESC */
411
                        if (val == 0x1B) {
412
                                // AVRPROG connection
413
                                // Wait for signon
414
                                while (val != 'S')
415
                                        val = recvchar();
416
 
417
                                send_boot();                    // Report signon
418
                                OK = 0;
419
 
420
                        } else {
421
                                sendchar('?');
422
                        }
423
                }
424
                // Power-Save code here
425
        }
426
 
427
#elif defined(START_SIMPLE)
428
 
429
        if ((BLPIN & (1<<BLPNUM))) {
430
                // jump to main app if pin is not grounded
431
                BLPORT &= ~(1<<BLPNUM);         // set to default               
432
#ifdef UART_DOUBLESPEED
433
                UART_STATUS &= ~( 1<<UART_DOUBLE );
434
#endif
435
                jump_to_app();                  // Jump to application sector
436
        }
437
 
438
#elif defined(START_WAIT)
439
 
440
        uint16_t cnt = 0;
441
 
442
        while (1) {
443
                if (UART_STATUS & (1<<UART_RXREADY))
444
                        if (UART_DATA == START_WAIT_UARTCHAR)
445
                                break;
446
 
447
                if (cnt++ >= WAIT_VALUE) {
448
                        BLPORT &= ~(1<<BLPNUM);         // set to default
449
                        jump_to_app();                  // Jump to application sector
450
                }
451
 
452
                _delay_ms(10);
453
        }
454
        send_boot();
455
 
456
#elif defined(START_BOOTICE)
457
#warning "BOOTICE mode - no startup-condition"
458
 
459
#else
460
#error "Select START_ condition for bootloader in main.c"
461
#endif
462
 
463
 
464
 
465
        for(;;) {
466
 
467
                set_LED1();
468
 
469
                val = recvchar();
470
 
471
                // Autoincrement?
472
                if (val == 'a') {
473
                        sendchar('Y');                  // Autoincrement is quicker
474
 
475
                //write address
476
                } else if (val == 'A') {
477
                        address = recvchar();           //read address 8 MSB
478
                        address = (address<<8) | recvchar();
479
                        sendchar('\r');
480
 
481
                // Buffer load support
482
                } else if (val == 'b') {
483
                        sendchar('Y');                                  // Report buffer load supported
484
                        sendchar((sizeof(gBuffer) >> 8) & 0xFF);        // Report buffer size in bytes
485
                        sendchar(sizeof(gBuffer) & 0xFF);
486
 
487
                // Start buffer load
488
                } else if (val == 'B') {
489
                        pagebuf_t size;
490
                        size = recvchar() << 8;                         // Load high byte of buffersize
491
                        size |= recvchar();                             // Load low byte of buffersize
492
                        val = recvchar();                               // Load memory type ('E' or 'F')
493
                        recvBuffer(size);
494
 
495
                        if (device == DEVTYPE) {
496
                                if (val == 'F') {
497
                                        address = writeFlashPage(address, size);
498
                                } else if (val == 'E') {
499
                                        address = writeEEpromPage(address, size);
500
                                }
501
                                sendchar('\r');
502
                        } else {
503
                                sendchar(0);
504
                        }
505
 
506
                // Block read
507
                } else if (val == 'g') {
508
                        pagebuf_t size;
509
                        size = recvchar() << 8;                         // Load high byte of buffersize
510
                        size |= recvchar();                             // Load low byte of buffersize
511
                        val = recvchar();                               // Get memtype
512
 
513
                        if (val == 'F') {
514
                                address = readFlashPage(address, size);
515
                        } else if (val == 'E') {
516
                                address = readEEpromPage(address, size);
517
                        }
518
 
519
                // Chip erase
520
                } else if (val == 'e') {
521
                        if (device == DEVTYPE) {
522
                                eraseFlash();
523
                        }
524
                        sendchar('\r');
525
 
526
                // Exit upgrade
527
                } else if (val == 'E') {
528
                        wdt_enable(EXIT_WDT_TIME); // Enable Watchdog Timer to give reset
529
                        sendchar('\r');
530
 
531
#ifdef WRITELOCKBITS
532
#warning "Extension 'WriteLockBits' enabled"
533
                // TODO: does not work reliably
534
                // write lockbits
535
                } else if (val == 'l') {
536
                        if (device == DEVTYPE) {
537
                                // write_lock_bits(recvchar());
538
                                boot_lock_bits_set(recvchar()); // boot.h takes care of mask
539
                                boot_spm_busy_wait();
540
                        }
541
                        sendchar('\r');
542
#endif
543
                // Enter programming mode
544
                } else if (val == 'P') {
545
                        sendchar('\r');
546
 
547
                // Leave programming mode
548
                } else if (val == 'L') {
549
                        sendchar('\r');
550
 
551
                // return programmer type
552
                } else if (val == 'p') {
553
                        sendchar('S');          // always serial programmer
554
 
555
#ifdef ENABLEREADFUSELOCK
556
#warning "Extension 'ReadFuseLock' enabled"
557
                // read "low" fuse bits
558
                } else if (val == 'F') {
559
                        sendchar(read_fuse_lock(GET_LOW_FUSE_BITS));
560
 
561
                // read lock bits
562
                } else if (val == 'r') {
563
                        sendchar(read_fuse_lock(GET_LOCK_BITS));
564
 
565
                // read high fuse bits
566
                } else if (val == 'N') {
567
                        sendchar(read_fuse_lock(GET_HIGH_FUSE_BITS));
568
 
569
                // read extended fuse bits
570
                } else if (val == 'Q') {
571
                        sendchar(read_fuse_lock(GET_EXTENDED_FUSE_BITS));
572
#endif
573
 
574
                // Return device type
575
                } else if (val == 't') {
576
                        sendchar(DEVTYPE);
577
                        sendchar(0);
578
 
579
                // clear and set LED ignored
580
                } else if ((val == 'x') || (val == 'y')) {
581
                        recvchar();
582
                        sendchar('\r');
583
 
584
                // set device
585
                } else if (val == 'T') {
586
                        device = recvchar();
587
                        sendchar('\r');
588
 
589
                // Return software identifier
590
                } else if (val == 'S') {
591
                        send_boot();
592
 
593
                // Return Software Version
594
                } else if (val == 'V') {
595
                        sendchar(VERSION_HIGH);
596
                        sendchar(VERSION_LOW);
597
 
598
                // Return Signature Bytes (it seems that 
599
                // AVRProg expects the "Atmel-byte" 0x1E last
600
                // but shows it first in the dialog-window)
601
                } else if (val == 's') {
602
                        sendchar(SIG_BYTE3);
603
                        sendchar(SIG_BYTE2);
604
                        sendchar(SIG_BYTE1);
605
 
606
                /* ESC */
607
                } else if(val != 0x1b) {
608
                        sendchar('?');
609
                }
610
 
611
        }
612
        return 0;
613
}