From ad0f55574a3d4e559015f35bb3d3846c38ab6599 Mon Sep 17 00:00:00 2001 From: WestfW Date: Tue, 10 Sep 2019 01:17:13 -0700 Subject: [PATCH] Two important discoveries: 1) Changing the watchdog period (inc turning it on) requires paying attention to synchonization between the WDT clock and system clock. 2) "jmp 512" doesn't work. I'm not sure exactly what happens, but it doesn't go where I expected. For now, do away with the fancy reset-cause logic and revert to old-style bootloader behavior. Don't even do the no-wait mod; at least this permits you to enter the bootloader by power-cycle. Implement LED_INVERT for boards that have the blink LED between +5V and pin. Now working on ATtiny416 Xplained Mini! --- optiboot/bootloaders/optiboot/Makefile | 10 ++- optiboot/bootloaders/optiboot/Makefile.extras | 23 ++++++ optiboot/bootloaders/optiboot/optiboot_x.c | 73 ++++++++++++------- 3 files changed, 78 insertions(+), 28 deletions(-) diff --git a/optiboot/bootloaders/optiboot/Makefile b/optiboot/bootloaders/optiboot/Makefile index 3f923a8..b28461b 100644 --- a/optiboot/bootloaders/optiboot/Makefile +++ b/optiboot/bootloaders/optiboot/Makefile @@ -251,19 +251,23 @@ COMMON_OPTIONS += $(VERSION_CMD) #UART is handled separately and only passed for devices with more than one. HELPTEXT += "Option UART=n - use UARTn for communications\n" +HELPTEXT += "Option UARTTX=pin - describe UART for Mega0, Xtiny ifdef UART UART_CMD = -DUART=$(UART) endif +ifdef UARTTX +UART_CMD = -DUARTTX=$(UARTTX) +endif # Not supported yet -# ifdef TIMEOUT_MS -# TIMEOUT_MS_CMD = -DTIMEOUT_MS=$(TIMEOUT_MS) +# ifdef TIMEOUT +# TIMEOUT_CMD = -DTIMEOUT_MS=$(TIMEOUT) # dummy = FORCE # endif # -#.PRECIOUS: %.elf +.PRECIOUS: %.elf #--------------------------------------------------------------------------- # "Chip-level Platform" targets. diff --git a/optiboot/bootloaders/optiboot/Makefile.extras b/optiboot/bootloaders/optiboot/Makefile.extras index 0bb403c..b166264 100644 --- a/optiboot/bootloaders/optiboot/Makefile.extras +++ b/optiboot/bootloaders/optiboot/Makefile.extras @@ -135,3 +135,26 @@ luminet_isp: EFUSE ?= FE luminet_isp: isp +HELPTEXT += "target atmega4809 - ATmega4809\n" +atmega4809: TARGET = atmega4809 +atmega4809: PROGRAM = optiboot_x +atmega4809: MCU_TARGET = atmega4809 +atmega4809: CFLAGS += $(COMMON_OPTIONS) -DLED=A7 $(UART_CMD) +atmega4809: AVR_FREQ ?= 20000000L +atmega4809: LDSECTIONS = -Wl,--section-start=.text=0 -Wl,--section-start=.version=0x1fe -Wl,--sections-start=.postapp=0x200 +atmega4809: $(PROGRAM)_atmega4809.hex +ifndef PRODUCTION +atmega4809: $(PROGRAM)_atmega4809.lst +endif + +HELPTEXT += "target Xplained416 - ATtiny416 Xplained Nano\n" +xplained416: TARGET = attiny416 +xplained416: PROGRAM = optiboot_x +xplained416: MCU_TARGET = attiny416 +xplained416: CFLAGS += $(COMMON_OPTIONS) $(UART_CMD) -DLED_INVERT=1 +xplained416: AVR_FREQ ?= 20000000L +xplained416: LDSECTIONS = -Wl,--section-start=.text=0 -Wl,--section-start=.version=0x1fe -Wl,--section-start=.postapp=0x200 +xplained416: $(PROGRAM)_attiny416.hex +ifndef PRODUCTION +xplained416: $(PROGRAM)_attiny416.lst +endif diff --git a/optiboot/bootloaders/optiboot/optiboot_x.c b/optiboot/bootloaders/optiboot/optiboot_x.c index f882de5..2aece06 100644 --- a/optiboot/bootloaders/optiboot/optiboot_x.c +++ b/optiboot/bootloaders/optiboot/optiboot_x.c @@ -137,8 +137,10 @@ optiboot_version = 256*(OPTIBOOT_MAJVER + OPTIBOOT_CUSTOMVER) + OPTIBOOT_MINVER; FUSES = { .WDTCFG = 0, /* Watchdog Configuration */ .BODCFG = FUSE_BODCFG_DEFAULT, /* BOD Configuration */ - .TCD0CFG = FUSE_TCD0CFG_DEFAULT, /* TCD0 Configuration */ .OSCCFG = 2, /* 20MHz */ +#ifdef FUSE_TCD0CFG_DEFAULT + .TCD0CFG = FUSE_TCD0CFG_DEFAULT, /* TCD0 Configuration */ +#endif .SYSCFG0 = 0xC4, /* RESET is not yet */ .SYSCFG1 = 0x06, /* startup 32ms */ .APPEND = 0, /* Application Code Section End */ @@ -290,42 +292,51 @@ int main (void) { // SP points to RAMEND __asm__ __volatile__ ("clr __zero_reg__"); // known-zero required by avr-libc - +#define RESET_EXTERNAL (RSTCTRL_EXTRF_bm|RSTCTRL_UPDIRF_bm|RSTCTRL_SWRF_bm) +#ifndef FANCY_RESET_LOGIC + ch = RSTCTRL.RSTFR; // get reset cause + RSTCTRL.RSTFR = ch; // and reset them all! + if (ch & RSTCTRL_WDRF_bm) { + // Start the app. + __asm__ __volatile__ ("mov r2, %0\n" :: "r" (ch)); + watchdogConfig(WDT_PERIOD_OFF_gc); + __asm__ __volatile__ ( + "jmp app\n" + ); + } +#else /* * Protect as much Reset Cause as possible for application * and still skip bootloader if not necessary */ ch = RSTCTRL.RSTFR; -// RSTCTRL.RSTFR = ch; // reset causes, for now. - ch &= ~RSTCTRL_UPDIRF_bm; // clear "reset by UPDI." - // Skip all logic and run bootloader if cause is cleared (application request) if (ch != 0) { /* - * To run the boot loader, External Reset Flag must be set. - * If not, we could make shortcut and jump directly to application code. - * Also WDRF set with EXTRF is a result of Optiboot timeout, so we - * shouldn't run bootloader in loop :-) That's why: - * 1. application is running if WDRF is cleared - * 2. we clear WDRF if it's set with EXTRF to avoid loops - * One problematic scenario: broken application code sets watchdog timer - * without clearing MCUSR before and triggers it quickly. But it's - * recoverable by power-on with pushed reset button. + * We want to run the bootloader when an external reset has occurred. + * On these mega0/XTiny chips, there are three types of ext reset: + * reset pin (may not exist), UPDI reset, and SW-request reset. + * One of these reset causes, together with watchdog reset, should + * mean that Optiboot timed out, and it's time to run the app. + * Other reset causes (notably poweron) should run the app directly. + * If a user app wants to utilize and detect watchdog resets, it + * must make sure that the other reset causes are cleared. */ - if ((ch & (RSTCTRL_WDRF_bm | RSTCTRL_EXTRF_bm)) != RSTCTRL_EXTRF_bm) { - if (ch & RSTCTRL_EXTRF_bm) { + if (ch & RSTCTRL_WDRF_bm) { + if (ch & RESET_EXTERNAL) { /* - * Clear WDRF because it was most probably set by wdr in bootloader. - * It's also needed to avoid loop by broken application which could - * prevent entering bootloader. - * '&' operation is skipped to spare few bytes as bits in MCUSR - * can only be cleared. + * Clear WDRF because it was most probably set by wdr in + * bootloader. It's also needed to avoid loop by broken + * application which could prevent entering bootloader. */ RSTCTRL.RSTFR = RSTCTRL_WDRF_bm; } + } + if (!(ch & RESET_EXTERNAL)) { /* - * save the reset flags in the designated register - * This can be saved in a main program by putting code in .init0 (which - * executes before normal c init code) to save R2 to a global variable. + * save the reset flags in the designated register. + * This can be saved in a main program by putting code in + * .init0 (which executes before normal c init code) to save R2 + * to a global variable. */ __asm__ __volatile__ ("mov r2, %0\n" :: "r" (ch)); @@ -336,7 +347,9 @@ int main (void) { ); } } +#endif // Fancy reset cause stuff + watchdogReset(); _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0); // full speed clock MYUART_TXPORT.DIR |= MYUART_TXPIN; // set TX pin to output @@ -351,7 +364,7 @@ int main (void) { MYUART.CTRLB = USART_RXEN_bm | USART_TXEN_bm; // Set up watchdog to trigger after 1s - watchdogConfig(WDT_PERIOD_1KCLK_gc); + watchdogConfig(WDT_PERIOD_8KCLK_gc); #if (LED_START_FLASHES > 0) || defined(LED_DATA_FLASH) || defined(LED_START_ON) /* Set LED pin as output */ @@ -360,11 +373,17 @@ int main (void) { #if LED_START_FLASHES > 0 /* Flash onboard LED to signal entering of bootloader */ +# ifdef LED_INVERT + flash_led(LED_START_FLASHES * 2+1); +# else flash_led(LED_START_FLASHES * 2); +# endif #else #if defined(LED_START_ON) +# ifndef LED_INVERT /* Turn on LED to indicate starting bootloader (less code!) */ LED_PORT.OUT |= LED; +# endif #endif #endif @@ -405,7 +424,9 @@ int main (void) { address.bytes[0] = getch(); address.bytes[1] = getch(); // ToDo: will there be mega-0 chips with >128k of RAM? +/* UPDI chips apparently have byte-addressable FLASH ? address.word *= 2; // Convert from word address to byte address +*/ verifySpace(); } else if(ch == STK_UNIVERSAL) { @@ -540,6 +561,8 @@ void flash_led (uint8_t count) { #endif void watchdogConfig (uint8_t x) { + while(WDT.STATUS & WDT_SYNCBUSY_bm) + ; _PROTECTED_WRITE(WDT.CTRLA, x); }