Do not use IRQs and remove vector table

Do not use ISRs and poll for interrupt flags in the main loop.
No need for moving vector table into bootloader and back.

Remove vector table by adding LDFLAGS = -nostartfiles.
Manually add some code which is now removed, but still needed by C
runtime:
- make sure that r1 is 0x00 (zero register).
- on some MCUs the stack pointer is not initialized correctly after
reset.
- main() need to be placed in special section .init9 to be called at all.

Not sure why the BSS and DATA segment are still initialized.

This change is heavily based on the optiboot bootloader.
This commit is contained in:
Olaf Rempel 2019-11-03 18:31:30 +01:00
parent b60a0fe735
commit fc61d39288
3 changed files with 56 additions and 35 deletions

View File

@ -63,6 +63,7 @@ endif
CFLAGS = -pipe -g -Os -mmcu=$(MCU) -Wall -fdata-sections -ffunction-sections CFLAGS = -pipe -g -Os -mmcu=$(MCU) -Wall -fdata-sections -ffunction-sections
CFLAGS += -Wa,-adhlns=$(*F).lst -DBOOTLOADER_START=$(BOOTLOADER_START) CFLAGS += -Wa,-adhlns=$(*F).lst -DBOOTLOADER_START=$(BOOTLOADER_START)
LDFLAGS = -Wl,-Map,$(@:.elf=.map),--cref,--relax,--gc-sections,--section-start=.text=$(BOOTLOADER_START) LDFLAGS = -Wl,-Map,$(@:.elf=.map),--cref,--relax,--gc-sections,--section-start=.text=$(BOOTLOADER_START)
LDFLAGS += -nostartfiles
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------

View File

@ -10,10 +10,10 @@ Currently the following AVR MCUs are supported:
AVR MCU | Flash bytes used (.text + .data) | Bootloader region size AVR MCU | Flash bytes used (.text + .data) | Bootloader region size
--- | --- | --- --- | --- | ---
atmega8 | 872 (0x368) | 512 words atmega8 | 724 (0x2D4) | 512 words
atmega88 | 918 (0x396) | 512 words atmega88 | 744 (0x2E8) | 512 words
atmega168 | 970 (0x3CA) | 512 words atmega168 | 744 (0x2E8) | 512 words
atmega328p | 970 (0x3CA) | 512 words atmega328p | 744 (0x2E8) | 512 words
(Compiled on Ubuntu 18.04 LTS (gcc 5.4.0 / avr-libc 2.0.0) with EEPROM and LED support) (Compiled on Ubuntu 18.04 LTS (gcc 5.4.0 / avr-libc 2.0.0) with EEPROM and LED support)
@ -91,6 +91,5 @@ Issue reports, feature requests, patches or simply success stories are much appr
## Roadmap ## ## Roadmap ##
Some ideas that I want to investigate / implement in twiboot: Some ideas that I want to investigate / implement in twiboot:
- [ ] do not use interrupts and remove vector table to save flash space - find a way to not rely on TWI clock stretching during write access
- [ ] find a way to not rely on TWI clock stretching during write access - support AVR TINYs (USI peripheral, no bootloader fuse, no Read-While-Write flash)
- [ ] support AVR TINYs (USI peripheral, no bootloader fuse, no Read-While-Write flash)

77
main.c
View File

@ -132,7 +132,7 @@ const static uint8_t chipinfo[8] = {
/* wait 40 * 25ms = 1s */ /* wait 40 * 25ms = 1s */
static uint8_t boot_timeout = TIMEOUT; static uint8_t boot_timeout = TIMEOUT;
volatile static uint8_t cmd = CMD_WAIT; static uint8_t cmd = CMD_WAIT;
/* flash buffer */ /* flash buffer */
static uint8_t buf[SPM_PAGESIZE]; static uint8_t buf[SPM_PAGESIZE];
@ -355,7 +355,7 @@ static uint8_t TWI_data_read(uint8_t bcnt)
/* ************************************************************************* /* *************************************************************************
* TWI_vect * TWI_vect
* ************************************************************************* */ * ************************************************************************* */
ISR(TWI_vect) static void TWI_vect(void)
{ {
static uint8_t bcnt; static uint8_t bcnt;
uint8_t control = TWCR; uint8_t control = TWCR;
@ -410,7 +410,7 @@ ISR(TWI_vect)
/* ************************************************************************* /* *************************************************************************
* TIMER0_OVF_vect * TIMER0_OVF_vect
* ************************************************************************* */ * ************************************************************************* */
ISR(TIMER0_OVF_vect) static void TIMER0_OVF_vect(void)
{ {
/* restart timer */ /* restart timer */
TCNT0 = TIMER_RELOAD; TCNT0 = TIMER_RELOAD;
@ -433,6 +433,26 @@ ISR(TIMER0_OVF_vect)
static void (*jump_to_app)(void) __attribute__ ((noreturn)) = 0x0000; static void (*jump_to_app)(void) __attribute__ ((noreturn)) = 0x0000;
/* *************************************************************************
* init1
* ************************************************************************* */
void init1(void) __attribute__((naked, section(".init1")));
void init1(void)
{
/* make sure r1 is 0x00 */
asm volatile ("clr __zero_reg__");
/* on some MCUs the stack pointer defaults NOT to RAMEND */
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega8515__) || \
defined(__AVR_ATmega8535__) || defined (__AVR_ATmega16__) || \
defined (__AVR_ATmega32__) || defined (__AVR_ATmega64__) || \
defined (__AVR_ATmega128__) || defined (__AVR_ATmega162__)
SP = RAMEND;
#endif
} /* init1 */
/* /*
* For newer devices the watchdog timer remains active even after a * For newer devices the watchdog timer remains active even after a
* system reset. So disable it as soon as possible. * system reset. So disable it as soon as possible.
@ -456,55 +476,56 @@ void disable_wdt_timer(void)
/* ************************************************************************* /* *************************************************************************
* main * main
* ************************************************************************* */ * ************************************************************************* */
int main(void) __attribute__ ((noreturn)); int main(void) __attribute__ ((OS_main, section (".init9")));
int main(void) int main(void)
{ {
LED_INIT(); LED_INIT();
LED_GN_ON(); LED_GN_ON();
/* move interrupt-vectors to bootloader */ /* timer0: running with F_CPU/1024 */
/* timer0: running with F_CPU/1024, OVF interrupt */
#if defined (__AVR_ATmega8__) #if defined (__AVR_ATmega8__)
GICR = (1<<IVCE);
GICR = (1<<IVSEL);
TCCR0 = (1<<CS02) | (1<<CS00); TCCR0 = (1<<CS02) | (1<<CS00);
TIMSK = (1<<TOIE0);
#elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__) || \ #elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__) || \
defined (__AVR_ATmega328P__) defined (__AVR_ATmega328P__)
MCUCR = (1<<IVCE);
MCUCR = (1<<IVSEL);
TCCR0B = (1<<CS02) | (1<<CS00); TCCR0B = (1<<CS02) | (1<<CS00);
TIMSK0 = (1<<TOIE0);
#endif #endif
/* TWI init: set address, auto ACKs with interrupts */ /* TWI init: set address, auto ACKs */
TWAR = (TWI_ADDRESS<<1); TWAR = (TWI_ADDRESS<<1);
TWCR = (1<<TWEA) | (1<<TWEN) | (1<<TWIE); TWCR = (1<<TWEA) | (1<<TWEN);
sei(); while (cmd != CMD_BOOT_APPLICATION)
while (cmd != CMD_BOOT_APPLICATION); {
cli(); if (TWCR & (1<<TWINT))
{
TWI_vect();
}
#if defined (__AVR_ATmega8__)
if (TIFR & (1<<TOV0))
{
TIMER0_OVF_vect();
TIFR = (1<<TOV0);
}
#elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__) || \
defined (__AVR_ATmega328P__)
if (TIFR0 & (1<<TOV0))
{
TIMER0_OVF_vect();
TIFR0 = (1<<TOV0);
}
#endif
}
/* Disable TWI but keep address! */ /* Disable TWI but keep address! */
TWCR = 0x00; TWCR = 0x00;
/* disable timer0 */ /* disable timer0 */
/* move interrupt vectors back to application */
#if defined (__AVR_ATmega8__) #if defined (__AVR_ATmega8__)
TCCR0 = 0x00; TCCR0 = 0x00;
TIMSK = 0x00;
GICR = (1<<IVCE);
GICR = (0<<IVSEL);
#elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__) || \ #elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__) || \
defined (__AVR_ATmega328P__) defined (__AVR_ATmega328P__)
TIMSK0 = 0x00;
TCCR0B = 0x00; TCCR0B = 0x00;
MCUCR = (1<<IVCE);
MCUCR = (0<<IVSEL);
#endif #endif
LED_OFF(); LED_OFF();