Skip to content

Commit be43894

Browse files
committed
bootloader capabilities extended:
- do not start app on UART RX timeout if INT0 was detected - immediately start app on INT1 event - since bootloader does not fit 512 words enable O2 gcc optimization level
1 parent cace964 commit be43894

File tree

4 files changed

+217
-115
lines changed

4 files changed

+217
-115
lines changed

hardware/arduino/boards.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,11 +341,11 @@ atmega8.build.core=arduino
341341
atmega16.name=Arduino w/ ATmega16
342342

343343
atmega16.upload.protocol=stk500
344-
atmega16.upload.maximum_size=15360
344+
atmega16.upload.maximum_size=14336
345345
atmega16.upload.speed=9600
346346

347347
atmega16.bootloader.low_fuses=0xdf
348-
atmega16.bootloader.high_fuses=0xda
348+
atmega16.bootloader.high_fuses=0x98
349349
atmega16.bootloader.path=atmega16
350350
atmega16.bootloader.file=ATmega16BOOT.hex
351351
atmega16.bootloader.unlock_bits=0x3F

hardware/arduino/bootloaders/atmega16/ATmega16BOOT.c

Lines changed: 116 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
/**********************************************************/
3434

3535
#include <inttypes.h>
36+
#include <string.h>
3637
#include <avr/io.h>
3738
#include <avr/pgmspace.h>
3839
#include <avr/eeprom.h>
@@ -92,13 +93,21 @@ static uint8_t getch(void);
9293
static void eat(uint8_t);
9394

9495
static void byte_response(uint8_t val);
95-
static void stream_response(uint8_t *val, uint8_t len);
96+
static void stream_response(const uint8_t *val, uint8_t len);
9697
#define nothing_response() stream_response(0, 0)
9798

9899
static void boot_program_page(uint32_t page, uint8_t *buf);
99100

101+
static void blink_led(uint8_t led);
100102
static void launch_app(void);
101103

104+
#define IT_LEVEL 0
105+
#define IT_RAISING_EDGE 1
106+
#define IT_FALLING_EDGE 2
107+
108+
static void enable_interrupt(uint8_t it, uint8_t sence);
109+
static void disable_interrupt(uint8_t it);
110+
102111
union address {
103112
uint16_t word;
104113
struct {
@@ -115,32 +124,48 @@ union length {
115124
} h;
116125
};
117126

118-
uint8_t buff[256];
127+
static uint8_t buff[256];
128+
static const uint8_t sig[] = {SIG1, SIG2, SIG3};
129+
static volatile uint8_t loop_forever = 0;
130+
131+
ISR(INT0_vect, ISR_BLOCK)
132+
{
133+
disable_interrupt(0);
119134

120-
uint8_t sig[] = {SIG1, SIG2, SIG3};
135+
loop_forever = 1;
136+
137+
outb(LED_PORT, inb(LED_PORT) & ~_BV(LED1));
138+
sbi(LED_DDR, LED1);
139+
}
140+
141+
ISR(INT1_vect, ISR_BLOCK)
142+
{
143+
launch_app();
144+
}
121145

122146
int main(void)
123147
{
124-
uint8_t i, ch;
148+
uint8_t ch;
125149
uint8_t eeprom;
126150
union length length;
127151
union address address;
128152

129-
cli(); // Disable interrupts, just to be sure
130-
131-
/* initialize UART(s) depending on CPU defined */
153+
/* initialize UART */
132154
UBRRH = (((F_CPU/BAUD_RATE)/16)-1)>>8; // set baud rate
133155
UBRRL = (((F_CPU/BAUD_RATE)/16)-1);
134156
UCSRB = (1<<RXEN)|(1<<TXEN); // enable Rx & Tx
135157
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // config USART; 8N1
136158

137-
/* blink the LED */
138-
outb(LED_PORT, inb(LED_PORT) | _BV(LED0));
139-
sbi(LED_DDR, LED0);
140-
for (i=0; i<16; ++i) {
141-
outb(LED_PORT, inb(LED_PORT) ^ _BV(LED0));
142-
_delay_loop_2(0);
143-
}
159+
// Move interrupt vectors to the beginning of bootloader section
160+
GICR = 1<<IVCE;
161+
GICR = 1<<IVSEL;
162+
163+
enable_interrupt(0, IT_RAISING_EDGE);
164+
enable_interrupt(1, IT_RAISING_EDGE);
165+
166+
blink_led(LED0);
167+
168+
sei();
144169

145170
/* forever */
146171
for (;;) {
@@ -154,7 +179,6 @@ int main(void)
154179
nothing_response();
155180
}
156181

157-
#if 0
158182
/* Request programmer ID */
159183
/* Not using PROGMEM string due to boot block in m128 being beyond 64kB boundry */
160184
/* Would need to selectively manipulate RAMPZ, and it's only 9 characters anyway so who cares. */
@@ -171,15 +195,12 @@ int main(void)
171195
putch(0x10);
172196
}
173197
}
174-
#endif
175198

176-
#if 0
177199
/* AVR ISP/STK500 board commands DON'T CARE so default nothing_response */
178200
else if (ch=='@') {
179201
if (getch() > 0x85) getch();
180202
nothing_response();
181203
}
182-
#endif
183204

184205
/* AVR ISP/STK500 board requests */
185206
else if (ch=='A') {
@@ -222,12 +243,10 @@ int main(void)
222243
launch_app();
223244
}
224245

225-
#if 0
226246
/* Erase device, don't care as we will erase one page at a time anyway. */
227247
else if (ch=='R') {
228248
nothing_response();
229249
}
230-
#endif
231250

232251
/* Universal SPI programming command, disabled. Would be used for fuses and lock bits. */
233252
else if (ch=='V') {
@@ -280,6 +299,9 @@ int main(void)
280299
boot_program_page(address.word, b);
281300
#else
282301
asm volatile(
302+
"lds r19,%1 \n" // Save status register and disable interrupts.
303+
"cli \n"
304+
283305
"clr r17 \n" // word count
284306

285307
"ldi r18,0x03 \n" // Erase page pointed to by Z ((1<<PGERS) | (1<<SPMEN))
@@ -298,7 +320,7 @@ int main(void)
298320
"adiw r30,2 \n" // Next word in FLASH
299321

300322
"inc r17 \n"
301-
"cpi r17,%1 \n"
323+
"cpi r17,%2 \n"
302324
"brlo push \n" // Still same page in FLASH
303325
"rjmp write \n"
304326

@@ -308,27 +330,28 @@ int main(void)
308330
"sbrc r16,0 \n"
309331
"rjmp wait_spm \n"
310332
"wait_ee: \n" // Wait for EEPROM writes to complete
311-
"lds r16,%2 \n"
333+
"lds r16,%3 \n"
312334
"sbrc r16,1 \n"
313335
"rjmp wait_ee \n"
314336
"sts %0,r18 \n"
315337
"spm \n"
316338
"ret \n"
317339

318340
"write: \n"
319-
"mov r30,%3 \n" // Address of FLASH location (in words)
320-
"mov r31,%4 \n"
341+
"mov r30,%4 \n" // Address of FLASH location (in words)
342+
"mov r31,%5 \n"
321343

322344
"ldi r18,0x05 \n" // Write page pointed to by Z ((1<<PGWRT) | (1<<SPMEN))
323345
"rcall do_spm \n"
324346

325347
"ldi r18,0x11 \n" // Re-enable RWW section ((1<<RWWSRE) | (1<<SPMEN))
326348
"rcall do_spm \n"
327349

328-
"clr __zero_reg__ \n" // restore zero register
350+
"sts %1,r19 \n" // Re-enable interrupts (if they were ever enabled)
329351

330-
: "=m" (SPMCR) : "M" (SPM_PAGESIZE>>1), "m"(EECR), "r"(address.h.low), "r"(address.h.high), "z"(address.word), "x"(b) : "r0","r1","r16","r17","r18");
352+
"clr __zero_reg__ \n" // restore zero register
331353

354+
: "=m"(SPMCR), "=m"(SREG) : "M"(SPM_PAGESIZE>>1), "m"(EECR), "r"(address.h.low), "r"(address.h.high), "z"(address.word), "x"(b) : "r0","r1","r16","r17","r18","r19");
332355
#endif
333356
b += SPM_PAGESIZE;
334357
n -= SPM_PAGESIZE;
@@ -372,12 +395,10 @@ int main(void)
372395
stream_response(sig, 3);
373396
}
374397

375-
#if 0
376398
/* Read oscillator calibration byte */
377399
else if (ch=='v') {
378400
byte_response(0x00);
379401
}
380-
#endif
381402
} /* end of forever loop */
382403
}
383404

@@ -390,12 +411,20 @@ static void putch(uint8_t ch)
390411

391412
static uint8_t getch(void)
392413
{
393-
uint32_t count = MAX_TIME_COUNT;
414+
uint32_t count;
394415

395-
while (!(inb(UCSRA) & _BV(RXC)) && --count);
416+
for (;;) {
417+
count = MAX_TIME_COUNT;
396418

397-
if (!count)
398-
launch_app();
419+
while (!(inb(UCSRA) & _BV(RXC)) && --count);
420+
421+
if (!count) {
422+
if (!loop_forever)
423+
launch_app();
424+
} else {
425+
break;
426+
}
427+
}
399428

400429
return inb(UDR);
401430
}
@@ -411,7 +440,7 @@ static void byte_response(uint8_t val)
411440
stream_response(&val, 1);
412441
}
413442

414-
static void stream_response(uint8_t *val, uint8_t len)
443+
static void stream_response(const uint8_t *val, uint8_t len)
415444
{
416445
if (getch() == ' ') {
417446
putch(0x14);
@@ -426,52 +455,90 @@ static void boot_program_page(uint32_t page, uint8_t *buf)
426455
uint16_t i, w;
427456
uint8_t sreg;
428457

429-
#if 0
430-
// Save status register and disable interrupts.
458+
// Save status register and disable interrupts
431459
sreg = SREG;
432460
cli();
433-
#endif
434461

435462
eeprom_busy_wait();
436463

437464
boot_page_erase(page);
438-
boot_spm_busy_wait(); // Wait until the memory is erased.
465+
boot_spm_busy_wait(); // Wait until the memory is erased
439466

440467
for (i=0; i<SPM_PAGESIZE; i+=2) {
441-
// Set up little-endian word.
468+
// Set up little-endian word
442469
w = *buf++;
443470
w |= (*buf++) << 8;
444471

445472
boot_page_fill(page + i, w);
446473
}
447474

448-
boot_page_write(page); // Store buffer in flash page.
449-
boot_spm_busy_wait(); // Wait until the memory is written.
475+
boot_page_write(page); // Store buffer in flash page
476+
boot_spm_busy_wait(); // Wait until the memory is written
450477

451478
// Reenable RWW-section again. We need this if we want to jump back
452-
// to the application after bootloading.
479+
// to the application after bootloading
453480
boot_rww_enable();
454481

455-
#if 0
456-
// Re-enable interrupts (if they were ever enabled).
482+
// Re-enable interrupts (if they were ever enabled)
457483
SREG = sreg;
458-
#endif
459484
}
460485

461-
static void launch_app(void)
486+
static void blink_led(uint8_t led)
462487
{
463488
uint8_t i;
464-
void (*app)(void) = 0x0000;
465489

466490
/* blink the LED */
467-
outb(LED_PORT, inb(LED_PORT) | _BV(LED7));
468-
sbi(LED_DDR, LED7);
491+
outb(LED_PORT, inb(LED_PORT) | _BV(led));
492+
sbi(LED_DDR, led);
469493
for (i=0; i<16; ++i) {
470-
outb(LED_PORT, inb(LED_PORT) ^ _BV(LED7));
494+
outb(LED_PORT, inb(LED_PORT) ^ _BV(led));
471495
_delay_loop_2(0);
472496
}
497+
}
498+
499+
static void launch_app(void)
500+
{
501+
void (*app)(void) = 0x0000;
502+
503+
cli();
504+
505+
// Move interrupt vectors to the beginning of FLASH and disable them
506+
GICR = 1<<IVCE;
507+
GICR = 0;
508+
509+
blink_led(LED7);
510+
511+
/* disable all LEDs */
512+
outb(LED_PORT, 0xFF);
473513

474514
app();
475515
}
476516

517+
/* Note: interrupt #2 for ATmega16 is not supported by this routine */
518+
static void enable_interrupt(uint8_t it, uint8_t sence)
519+
{
520+
uint8_t shift = it << 1;
521+
522+
MCUCR &= ~(3<<shift);
523+
switch (sence) {
524+
case IT_LEVEL:
525+
/* nothing to do */
526+
break;
527+
case IT_RAISING_EDGE:
528+
MCUCR |= 3<<shift;
529+
break;
530+
case IT_FALLING_EDGE:
531+
MCUCR |= 2<<shift;
532+
break;
533+
}
534+
535+
GICR |= 1 << (it+6);
536+
}
537+
538+
/* Note: interrupt #2 for ATmega16 is not supported by this routine */
539+
static void disable_interrupt(uint8_t it)
540+
{
541+
GICR &= ~(1 << (it+6));
542+
}
543+
477544
/* end of file ATmega16BOOT.c */

0 commit comments

Comments
 (0)