Project

General

Profile

Statistics
| Branch: | Revision:

root / arduino-1.0 / hardware / arduino / bootloaders / atmega8 / ATmegaBOOT.c @ 58d82c77

History | View | Annotate | Download (15.1 KB)

1
/**********************************************************/
2
/* Serial Bootloader for Atmel mega8 AVR Controller       */
3
/*                                                        */
4
/* ATmegaBOOT.c                                           */
5
/*                                                        */
6
/* Copyright (c) 2003, Jason P. Kyle                      */
7
/*                                                        */
8
/* Hacked by DojoCorp - ZGZ - MMX - IVR                   */
9
/* Hacked by David A. Mellis                              */
10
/*                                                        */
11
/* This program is free software; you can redistribute it */
12
/* and/or modify it under the terms of the GNU General    */
13
/* Public License as published by the Free Software       */
14
/* Foundation; either version 2 of the License, or        */
15
/* (at your option) any later version.                    */
16
/*                                                        */
17
/* This program is distributed in the hope that it will   */
18
/* be useful, but WITHOUT ANY WARRANTY; without even the  */
19
/* implied warranty of MERCHANTABILITY or FITNESS FOR A   */
20
/* PARTICULAR PURPOSE.  See the GNU General Public        */
21
/* License for more details.                              */
22
/*                                                        */
23
/* You should have received a copy of the GNU General     */
24
/* Public License along with this program; if not, write  */
25
/* to the Free Software Foundation, Inc.,                 */
26
/* 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */
27
/*                                                        */
28
/* Licence can be viewed at                               */
29
/* http://www.fsf.org/licenses/gpl.txt                    */
30
/*                                                        */
31
/* Target = Atmel AVR m8                                  */
32
/**********************************************************/
33

    
34
#include <inttypes.h>
35
#include <avr/io.h>
36
#include <avr/pgmspace.h>
37
#include <avr/eeprom.h>
38
#include <avr/interrupt.h>
39
#include <avr/delay.h>
40

    
41
//#define F_CPU                        16000000
42

    
43
/* We, Malmoitians, like slow interaction
44
 * therefore the slow baud rate ;-)
45
 */
46
//#define BAUD_RATE                9600
47

    
48
/* 6.000.000 is more or less 8 seconds at the
49
 * speed configured here
50
 */
51
//#define MAX_TIME_COUNT        6000000
52
#define MAX_TIME_COUNT (F_CPU>>1)
53
///#define MAX_TIME_COUNT_MORATORY        1600000
54

    
55
/* SW_MAJOR and MINOR needs to be updated from time to time to avoid warning message from AVR Studio */
56
#define HW_VER         0x02
57
#define SW_MAJOR 0x01
58
#define SW_MINOR 0x12
59

    
60
// AVR-GCC compiler compatibility
61
// avr-gcc compiler v3.1.x and older doesn't support outb() and inb()
62
//      if necessary, convert outb and inb to outp and inp
63
#ifndef outb
64
        #define outb(sfr,val)  (_SFR_BYTE(sfr) = (val))
65
#endif
66
#ifndef inb
67
        #define inb(sfr) _SFR_BYTE(sfr)
68
#endif
69

    
70
/* defines for future compatibility */
71
#ifndef cbi
72
        #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
73
#endif
74
#ifndef sbi
75
        #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
76
#endif
77

    
78
/* Adjust to suit whatever pin your hardware uses to enter the bootloader */
79
#define eeprom_rb(addr)   eeprom_read_byte ((uint8_t *)(addr))
80
#define eeprom_rw(addr)   eeprom_read_word ((uint16_t *)(addr))
81
#define eeprom_wb(addr, val)   eeprom_write_byte ((uint8_t *)(addr), (uint8_t)(val))
82

    
83
/* Onboard LED is connected to pin PB5 */
84
#define LED_DDR  DDRB
85
#define LED_PORT PORTB
86
#define LED_PIN  PINB
87
#define LED      PINB5
88

    
89

    
90
#define SIG1        0x1E        // Yep, Atmel is the only manufacturer of AVR micros.  Single source :(
91
#define SIG2        0x93
92
#define SIG3        0x07
93
#define PAGE_SIZE        0x20U        //32 words
94

    
95

    
96
void putch(char);
97
char getch(void);
98
void getNch(uint8_t);
99
void byte_response(uint8_t);
100
void nothing_response(void);
101

    
102
union address_union {
103
  uint16_t word;
104
  uint8_t  byte[2];
105
} address;
106

    
107
union length_union {
108
  uint16_t word;
109
  uint8_t  byte[2];
110
} length;
111

    
112
struct flags_struct {
113
  unsigned eeprom : 1;
114
  unsigned rampz  : 1;
115
} flags;
116

    
117
uint8_t buff[256];
118
//uint8_t address_high;
119

    
120
uint8_t pagesz=0x80;
121

    
122
uint8_t i;
123
//uint8_t bootuart0=0,bootuart1=0;
124

    
125

    
126
void (*app_start)(void) = 0x0000;
127

    
128
int main(void)
129
{
130
  uint8_t ch,ch2;
131
  uint16_t w;
132

    
133
  //cbi(BL_DDR,BL);
134
  //sbi(BL_PORT,BL);
135

    
136
  asm volatile("nop\n\t");
137

    
138
  /* check if flash is programmed already, if not start bootloader anyway */
139
  //if(pgm_read_byte_near(0x0000) != 0xFF) {
140

    
141
    /* check if bootloader pin is set low */
142
    //if(bit_is_set(BL_PIN,BL)) app_start();
143
  //}
144

    
145
  /* initialize UART(s) depending on CPU defined */
146
  /* m8 */
147
  UBRRH = (((F_CPU/BAUD_RATE)/16)-1)>>8;         // set baud rate
148
  UBRRL = (((F_CPU/BAUD_RATE)/16)-1);
149
  UCSRB = (1<<RXEN)|(1<<TXEN);  // enable Rx & Tx
150
  UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);  // config USART; 8N1
151

    
152
  //UBRRL = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);
153
  //UBRRH = (F_CPU/(BAUD_RATE*16L)-1) >> 8;
154
  //UCSRA = 0x00;
155
  //UCSRC = 0x86;
156
  //UCSRB = _BV(TXEN)|_BV(RXEN);
157

    
158

    
159
  /* this was giving uisp problems, so I removed it; without it, the boot
160
     works on with uisp and avrdude on the mac (at least). */
161
  //putch('\0');
162

    
163
  //uint32_t l;
164
  //uint32_t time_count;
165
  //time_count=0;
166

    
167
  /* set LED pin as output */
168
  sbi(LED_DDR,LED);
169
        for (i = 0; i < 16; i++) {
170
                outb(LED_PORT, inb(LED_PORT) ^ _BV(LED));
171
                _delay_loop_2(0);
172
        }
173
        
174
        //for (l=0; l<40000000; l++)
175
                //outb(LED_PORT, inb(LED_PORT) ^= _BV(LED));
176

    
177
  /* flash onboard LED three times to signal entering of bootloader */
178
  //for(i=0; i<3; ++i) {
179
    //for(l=0; l<40000000; ++l);
180
    //sbi(LED_PORT,LED);
181
    //for(l=0; l<40000000; ++l);
182
    //cbi(LED_PORT,LED);
183
  //}
184

    
185
 /* see comment at previous call to putch() */
186
 //putch('\0'); // this line is needed for the synchronization of the programmer
187

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

    
456
void putch(char ch)
457
{
458
  /* m8 */
459
  while (!(inb(UCSRA) & _BV(UDRE)));
460
  outb(UDR,ch);
461
}
462

    
463
char getch(void)
464
{
465
  /* m8 */
466
        uint32_t count = 0;
467
  while(!(inb(UCSRA) & _BV(RXC))) {
468
                /* HACKME:: here is a good place to count times*/
469
                count++;
470
                if (count > MAX_TIME_COUNT)
471
                        app_start();
472
  }
473
  return (inb(UDR));
474
}
475

    
476
void getNch(uint8_t count)
477
{
478
  uint8_t i;
479
  for(i=0;i<count;i++) {
480
    /* m8 */
481
    //while(!(inb(UCSRA) & _BV(RXC)));
482
    //inb(UDR);
483
                getch(); // need to handle time out
484
  }
485
}
486

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

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

    
504
/* end of file ATmegaBOOT.c */
505

    
506

    
507