Project

General

Profile

Statistics
| Revision:

root / branches / autonomous_recharging / code / projects / bay_bootloader / bayboardBOOT.c @ 650

History | View | Annotate | Download (15.4 KB)

1
/**********************************************************/
2
/* Serial Bootloader for Atmel megaAVR Controllers        */
3
/*                                                        */
4
/* tested with ATmega8, ATmega128 and ATmega168           */
5
/* should work with other mega's, see code for details    */
6
/*                                                        */
7
/* ATmegaBOOT.c                                           */
8
/*                                                        */
9
/* build: 060610                                          */
10
/* date : 06.10.2006                                      */
11
/*                                                        */
12
/* Monitor and debug functions were added to the original */
13
/* code by Dr. Erik Lins, chip45.com. (See below)         */
14
/*                                                                                                                   */
15
/* Borrowed and modified for Fun with Robots by bkirby    */
16
/*                                                        */
17
/* Thanks to Karl Pitrich for fixing a bootloader pin     */
18
/* problem and more informative LED blinking!             */
19
/*                                                        */
20
/* For the latest version see:                            */
21
/* http://www.chip45.com/                                 */
22
/*                                                        */
23
/* ------------------------------------------------------ */
24
/*                                                        */
25
/* based on stk500boot.c                                  */
26
/* Copyright (c) 2003, Jason P. Kyle                      */
27
/* All rights reserved.                                   */
28
/* see avr1.org for original file and information         */
29
/*                                                        */
30
/* This program is free software; you can redistribute it */
31
/* and/or modify it under the terms of the GNU General    */
32
/* Public License as published by the Free Software       */
33
/* Foundation; either version 2 of the License, or        */
34
/* (at your option) any later version.                    */
35
/*                                                        */
36
/* This program is distributed in the hope that it will   */
37
/* be useful, but WITHOUT ANY WARRANTY; without even the  */
38
/* implied warranty of MERCHANTABILITY or FITNESS FOR A   */
39
/* PARTICULAR PURPOSE.  See the GNU General Public        */
40
/* License for more details.                              */
41
/*                                                        */
42
/* You should have received a copy of the GNU General     */
43
/* Public License along with this program; if not, write  */
44
/* to the Free Software Foundation, Inc.,                 */
45
/* 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */
46
/*                                                        */
47
/* Licence can be viewed at                               */
48
/* http://www.fsf.org/licenses/gpl.txt                    */
49
/*                                                        */
50
/* Target = Atmel AVR m128,m64,m32,m16,m8,m162,m163,m169, */
51
/* m8515,m8535. ATmega161 has a very small boot block so  */
52
/* isn't supported.                                       */
53
/*                                                        */
54
/* Tested with m128,m8,m163 - feel free to let me know    */
55
/* how/if it works for you.                               */
56
/*                                                        */
57
/**********************************************************/
58

    
59

    
60
/* some includes */
61
#include <inttypes.h>
62
#include <avr/io.h>
63
#include <avr/pgmspace.h>
64
#include <avr/interrupt.h>
65
#include <avr/wdt.h>
66
#include <avr/eeprom.h>
67

    
68
#define F_CPU     8000000
69

    
70
#include <util/delay.h>
71

    
72
/* set the UART baud rate */
73
#define BAUD_RATE 57600
74
/* SW_MAJOR and MINOR needs to be updated from time to time to avoid warning message from AVR Studio */
75
/* never allow AVR Studio to do an update !!!! */
76
#define HW_VER         0x02
77
#define SW_MAJOR 0x01
78
#define SW_MINOR 0x0f
79

    
80

    
81
/* Adjust to suit whatever pin your hardware uses to enter the bootloader */
82
/* ATmega128 has two UARTS so two pins are used to enter bootloader and select UART */
83
/* BL0... means UART0, BL1... means UART1 */
84
#define BL_DDR  DDRA
85
#define BL_PORT PORTA
86
#define BL_PIN  PINA
87
#define BL      PINA7
88

    
89
/* red and green channels of the tricolor*/
90
#define LED_DDR  DDRD
91
#define LED_PORT PORTD
92
#define LED_PIN  PIND
93
#define LED1     PIND4        //red
94
#define LED2     PIND6        //green
95

    
96

    
97
/* define various device id's */
98
/* manufacturer byte is always the same */
99
#define SIG1        0x1E        // Yep, Atmel is the only manufacturer of AVR micros.  Single source :(
100
#define SIG2        0x94
101
#define SIG3        0x0A
102
#define PAGE_SIZE        0x40U        //64 words
103

    
104

    
105
/* function prototypes */
106
void putch(char);
107
void putst(char *);
108
char getch(void);
109
void getNch(uint8_t);
110
void byte_response(uint8_t);
111
void nothing_response(void);
112
char gethex(void);
113
void puthex(char);
114
void flash_led(uint8_t);
115

    
116
/* some variables */
117
union address_union {
118
    uint16_t word;
119
    uint8_t  byte[2];
120
} address;
121

    
122
union length_union {
123
    uint16_t word;
124
    uint8_t  byte[2];
125
} length;
126

    
127
struct flags_struct {
128
    unsigned eeprom : 1;
129
    unsigned rampz  : 1;
130
} flags;
131

    
132
uint8_t buff[256];
133
uint8_t address_high;
134

    
135
uint8_t pagesz=0x80;
136

    
137
uint8_t i;
138
uint8_t bootuart = 0;
139

    
140
void (*app_start)(void) = 0x0000;
141

    
142

    
143
/* main program starts here */
144
int main(void) {
145
    uint8_t ch,ch2;
146
    uint16_t w;
147
        
148
    asm volatile("nop\n\t");
149

    
150
    /* set pin direction for bootloader pin and enable pullup */
151
    BL_DDR &= ~_BV(BL);
152
    BL_PORT |= _BV(BL);
153

    
154
    /* check if flash is programmed already, if not start bootloader anyway */
155
    if(pgm_read_byte_near(0x0000) != 0xFF) {
156
                /* run program if the button is not pressed */
157
                if(bit_is_set(BL_PIN, BL))
158
                          app_start();
159
    }
160

    
161
    /* initialize UART */
162
    UBRR0 = 16;
163
    UCSR0A = _BV(U2X0);
164
    UCSR0B = _BV(TXEN0)|_BV(RXEN0);
165
    UCSR0C = 0x06;
166

    
167
    /* set LED pins as output */
168
    LED_PORT |= _BV(LED1) | _BV(LED2);
169
    LED_DDR |= _BV(LED1) | _BV(LED2);
170

    
171
    /* flash onboard LED to signal entering of bootloader */
172
    flash_led(3);
173

    
174
    putch('\0');
175
        
176
    /* forever loop */
177
    for (;;) {
178
                
179
                /* get character from UART */
180
                ch = getch();
181
                
182
                /* A bunch of if...else if... gives smaller code than switch...case ! */
183
                
184
                /* Hello is anyone home ? */ 
185
                if(ch=='0') {
186
                        nothing_response();
187
                }
188
                
189
                /* Request programmer ID */
190
                /* Not using PROGMEM string due to boot block in m128 being beyond 64kB boundry  */
191
                /* Would need to selectively manipulate RAMPZ, and it's only 9 characters anyway so who cares.  */
192
                else if(ch=='1') {
193
                        if (getch() == ' ') {
194
                        putch(0x14);
195
                        putch('A'); putch('V'); putch('R'); putch(' ');
196
                        putch('I'); putch('S'); putch('P'); putch(0x10);
197
                        }
198
                }
199
                
200
                /* AVR ISP/STK500 board commands  DON'T CARE so default nothing_response */
201
                else if(ch=='@') {
202
                        ch2 = getch();
203
                        if (ch2>0x85) getch();
204
                        nothing_response();
205
                }
206
                
207
                /* AVR ISP/STK500 board requests */
208
                else if(ch=='A') {
209
                        ch2 = getch();
210
                        if(ch2==0x80) byte_response(HW_VER);                // Hardware version
211
                        else if(ch2==0x81) byte_response(SW_MAJOR);        // Software major version
212
                        else if(ch2==0x82) byte_response(SW_MINOR);        // Software minor version
213
                        else if(ch2==0x98) byte_response(0x03);                // Unknown but seems to be required by avr studio 3.56
214
                        else byte_response(0x00);                                // Covers various unnecessary responses we don't care about
215
                }
216
                
217
                /* Device Parameters  DON'T CARE, DEVICE IS FIXED  */
218
                else if(ch=='B') {
219
                        getNch(20);
220
                        nothing_response();
221
                }
222
                
223
                /* Parallel programming stuff  DON'T CARE  */
224
                else if(ch=='E') {
225
                        getNch(5);
226
                        nothing_response();
227
                }
228
                
229
                /* Enter programming mode  */
230
                else if(ch=='P') {
231
                        nothing_response();
232
                }
233
                
234
                /* Leave programming mode  */
235
                else if(ch=='Q') {
236
                        nothing_response();
237
                }
238
                
239
                /* Erase device, don't care as we will erase one page at a time anyway.  */
240
                else if(ch=='R') {
241
                        nothing_response();
242
                }
243
                
244
                /* Set address, little endian. EEPROM in bytes, FLASH in words  */
245
                /* Perhaps extra address bytes may be added in future to support > 128kB FLASH.  */
246
                /* This might explain why little endian was used here, big endian used everywhere else.  */
247
                else if(ch=='U') {
248
                        address.byte[0] = getch();
249
                        address.byte[1] = getch();
250
                        nothing_response();
251
                }
252
                
253
                /* Universal SPI programming command, disabled.  Would be used for fuses and lock bits.  */
254
                else if(ch=='V') {
255
                        getNch(4);
256
                        byte_response(0x00);
257
                }
258
                
259
                /* Write memory, length is big endian and is in bytes  */
260
                else if(ch=='d') {
261
                        length.byte[1] = getch();
262
                        length.byte[0] = getch();
263
                        flags.eeprom = 0;
264
                        if (getch() == 'E') flags.eeprom = 1;
265
                        for (w=0;w<length.word;w++) {
266
                                buff[w] = getch();          // Store data in buffer, can't keep up with serial data stream whilst programming pages
267
                        }
268
                        
269
                        if (getch() == ' ') {
270
                                if (flags.eeprom) { //Write to EEPROM one byte at a time
271
                                        for(w=0;w<length.word;w++) {
272
                                                eeprom_write_byte((void *)address.word,buff[w]);
273
                                                address.word++;
274
                                        }                        
275
                                }
276
                                else {        //Write to FLASH one page at a time
277
                                        if (address.byte[1]>127) address_high = 0x01;        //Only possible with m128, m256 will need 3rd address byte. FIXME
278
                                        else address_high = 0x00;
279
                                        address.word = address.word << 1;  //address * 2 -> byte location
280
                                        
281
                                        if ((length.byte[0] & 0x01)) length.word++;        //Even up an odd number of bytes
282
                                        
283
                                        cli();        //Disable interrupts, just to be sure
284
                                        
285
                                        while(bit_is_set(EECR,EEPE));        //Wait for previous EEPROM writes to complete
286
                                        
287
                                        asm volatile(
288
                                                 "clr        r17                \n\t"        //page_word_count
289
                                                 "lds        r30,address        \n\t"        //Address of FLASH location (in bytes)
290
                                                 "lds        r31,address+1        \n\t"
291
                                                 "ldi        r28,lo8(buff)        \n\t"        //Start of buffer array in RAM
292
                                                 "ldi        r29,hi8(buff)        \n\t"
293
                                                 "lds        r24,length        \n\t"        //Length of data to be written (in bytes)
294
                                                 "lds        r25,length+1        \n\t"
295
                                                 "length_loop:                \n\t"        //Main loop, repeat for number of words in block                                                                                                                  
296
                                                 "cpi        r17,0x00        \n\t"        //If page_word_count=0 then erase page
297
                                                 "brne        no_page_erase        \n\t"                                                 
298
                                                 "wait_spm1:                \n\t"
299
                                                 "lds        r16,%0                \n\t"        //Wait for previous spm to complete
300
                                                 "andi        r16,1           \n\t"
301
                                                 "cpi        r16,1           \n\t"
302
                                                 "breq        wait_spm1       \n\t"
303
                                                 "ldi        r16,0x03        \n\t"        //Erase page pointed to by Z
304
                                                 "sts        %0,r16                \n\t"
305
                                                 "spm                        \n\t"                                                         
306
                                                 "wait_spm2:                \n\t"
307
                                                 "lds        r16,%0                \n\t"        //Wait for previous spm to complete
308
                                                 "andi        r16,1           \n\t"
309
                                                 "cpi        r16,1           \n\t"
310
                                                 "breq        wait_spm2       \n\t"                                                                         
311
                                                 "ldi        r16,0x11        \n\t"        //Re-enable RWW section
312
                                                 "sts        %0,r16                \n\t"                                                                          
313
                                                 "spm                        \n\t"
314
                                                 "no_page_erase:                \n\t"                                                         
315
                                                 "ld        r0,Y+                \n\t"        //Write 2 bytes into page buffer
316
                                                 "ld        r1,Y+                \n\t"                                                         
317
                                                        
318
                                                 "wait_spm3:                \n\t"
319
                                                 "lds        r16,%0                \n\t"        //Wait for previous spm to complete
320
                                                 "andi        r16,1           \n\t"
321
                                                 "cpi        r16,1           \n\t"
322
                                                 "breq        wait_spm3       \n\t"
323
                                                 "ldi        r16,0x01        \n\t"        //Load r0,r1 into FLASH page buffer
324
                                                 "sts        %0,r16                \n\t"
325
                                                 "spm                        \n\t"
326
                                                        
327
                                                 "inc        r17                \n\t"        //page_word_count++
328
                                                 "cpi r17,%1                \n\t"
329
                                                 "brlo        same_page        \n\t"        //Still same page in FLASH
330
                                                 "write_page:                \n\t"
331
                                                 "clr        r17                \n\t"        //New page, write current one first
332
                                                 "wait_spm4:                \n\t"
333
                                                 "lds        r16,%0                \n\t"        //Wait for previous spm to complete
334
                                                 "andi        r16,1           \n\t"
335
                                                 "cpi        r16,1           \n\t"
336
                                                 "breq        wait_spm4       \n\t"                                                                                                          
337
                                                 "ldi        r16,0x05        \n\t"        //Write page pointed to by Z
338
                                                 "sts        %0,r16                \n\t"
339
                                                 "spm                        \n\t"
340
                                                 "wait_spm5:                \n\t"
341
                                                 "lds        r16,%0                \n\t"        //Wait for previous spm to complete
342
                                                 "andi        r16,1           \n\t"
343
                                                 "cpi        r16,1           \n\t"
344
                                                 "breq        wait_spm5       \n\t"                                                                         
345
                                                 "ldi        r16,0x11        \n\t"        //Re-enable RWW section
346
                                                 "sts        %0,r16                \n\t"                                                                          
347
                                                 "spm                        \n\t"                                                          
348
                                                 "same_page:                \n\t"                                                         
349
                                                 "adiw        r30,2                \n\t"        //Next word in FLASH
350
                                                 "sbiw        r24,2                \n\t"        //length-2
351
                                                 "breq        final_write        \n\t"        //Finished
352
                                                 "rjmp        length_loop        \n\t"
353
                                                 "final_write:                \n\t"
354
                                                 "cpi        r17,0                \n\t"
355
                                                 "breq        block_done        \n\t"
356
                                                 "adiw        r24,2                \n\t"        //length+2, fool above check on length after short page write
357
                                                 "rjmp        write_page        \n\t"
358
                                                 "block_done:                \n\t"
359
                                                 "clr        __zero_reg__        \n\t"        //restore zero register
360
                                                        
361
                                                 : "=m" (SPMCSR) : "M" (PAGE_SIZE) : "r0","r16","r17","r24","r25","r28","r29","r30","r31"
362
                                                 );
363
                                        /* Should really add a wait for RWW section to be enabled, don't actually need it since we never */
364
                                        /* exit the bootloader without a power cycle anyhow */
365
                                }
366
                        putch(0x14);
367
                        putch(0x10);
368
                        }                
369
                }
370
                
371
        
372
                        /* Read memory block mode, length is big endian.  */
373
                        else if(ch=='t') {
374
                        length.byte[1] = getch();
375
                        length.byte[0] = getch();
376
                        if (getch() == 'E') flags.eeprom = 1;
377
                        else {
378
                        flags.eeprom = 0;
379
                        address.word = address.word << 1;                // address * 2 -> byte location
380
                        }
381
                        if (getch() == ' ') {                                // Command terminator
382
                        putch(0x14);
383
                        for (w=0;w < length.word;w++) {                        // Can handle odd and even lengths okay
384
                                if (flags.eeprom) {                                // Byte access EEPROM read
385
                                putch(eeprom_read_byte((void *)address.word));
386
                                address.word++;
387
                                }
388
                                else {
389
        
390
                                if (!flags.rampz) putch(pgm_read_byte_near(address.word));
391
                                address.word++;
392
                                }
393
                        }
394
                        putch(0x10);
395
                        }
396
                }
397
        
398
        
399
                        /* Get device signature bytes  */
400
                        else if(ch=='u') {
401
                        if (getch() == ' ') {
402
                        putch(0x14);
403
                        putch(SIG1);
404
                        putch(SIG2);
405
                        putch(SIG3);
406
                        putch(0x10);
407
                        }
408
                }
409
        
410
        
411
                        /* Read oscillator calibration byte */
412
                        else if(ch=='v') {
413
                        byte_response(0x00);
414
                }
415

    
416
    }
417
    /* end of forever loop */
418

    
419
}
420

    
421

    
422
char gethex(void) {
423
    char ah,al;
424

    
425
    ah = getch(); putch(ah);
426
    al = getch(); putch(al);
427
    if(ah >= 'a') {
428
        ah = ah - 'a' + 0x0a;
429
    } else if(ah >= '0') {
430
        ah -= '0';
431
    }
432
    if(al >= 'a') {
433
        al = al - 'a' + 0x0a;
434
    } else if(al >= '0') {
435
        al -= '0';
436
    }
437
    return (ah << 4) + al;
438
}
439

    
440

    
441
void puthex(char ch) {
442
    char ah,al;
443

    
444
    ah = (ch & 0xf0) >> 4;
445
    if(ah >= 0x0a) {
446
        ah = ah - 0x0a + 'a';
447
    } else {
448
        ah += '0';
449
    }
450
    al = (ch & 0x0f);
451
    if(al >= 0x0a) {
452
        al = al - 0x0a + 'a';
453
    } else {
454
        al += '0';
455
    }
456
    putch(ah);
457
    putch(al);
458
}
459

    
460

    
461
void putch(char ch)
462
{
463
    while (!(UCSR0A & _BV(UDRE0)));
464
    UDR0 = ch;
465
}
466

    
467

    
468
char getch(void)
469
{
470
    while(!(UCSR0A & _BV(RXC0)));
471
    return UDR0;
472
}
473

    
474

    
475
void getNch(uint8_t count)
476
{
477
    uint8_t i;
478
    for(i=0;i<count;i++) {
479
        while(!(UCSR0A & _BV(RXC0)));
480
        UDR0;        
481
    }
482
}
483

    
484

    
485
void byte_response(uint8_t val)
486
{
487
    if (getch() == ' ') {
488
        putch(0x14);
489
        putch(val);
490
        putch(0x10);
491
    }
492
}
493

    
494

    
495
void nothing_response(void)
496
{
497
    if (getch() == ' ') {
498
        putch(0x14);
499
        putch(0x10);
500
    }
501
}
502

    
503

    
504
void flash_led(uint8_t count)
505
{
506
    /* flash onboard LED three times to signal entering of bootloader */
507
    uint32_t l;
508
        int i;
509
    if (count == 0) {
510
      count = 3;
511
    }
512
        
513
    for (i = 0; i < count; ++i) {
514
          LED_PORT |= _BV(LED1);
515
          LED_PORT &= ~_BV(LED2);
516
          for(l = 0; l < (15); ++l)
517
                        _delay_ms(10);
518
                        
519
          LED_PORT &= ~_BV(LED1);
520
          LED_PORT |= _BV(LED2);
521
          for(l = 0; l < (15); ++l)
522
                        _delay_ms(10);
523
                
524
    }
525
}
526

    
527

    
528
/* end of file ATmegaBOOT.c */