diff options
author | Jack Humbert <jack.humb@gmail.com> | 2017-11-27 23:08:21 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-11-27 23:08:21 -0500 |
commit | 9fdc27626097ae03b767a09427efc90475d90955 (patch) | |
tree | a555c38f1b714af6e2c2c96187552757d08224b9 /tmk_core | |
parent | 9113f3387a670373919fe62899b0ab27e9d89eba (diff) |
Updates bootloader settings, adds file size check (#2029)
* pull fuse settings for bootloader jump
* fix 32a chips
* make automatic bootloader selection optional
* quantify bootloaders
* fixs #164, speeds up dfu reset
* fix for chips w/o usb
* missing an n
* fix bootloader sizes, use words for addresses
* fix bmini, pearl, and [[ issue, make things quiet
* ignore avr errors on arm for now
* update settings for the light
* document bootloader stuff
* add bootloader title
Diffstat (limited to 'tmk_core')
-rw-r--r-- | tmk_core/avr.mk | 10 | ||||
-rw-r--r-- | tmk_core/common/avr/bootloader.c | 196 | ||||
-rw-r--r-- | tmk_core/common/avr/bootloader_size.c | 20 | ||||
-rw-r--r-- | tmk_core/rules.mk | 23 |
4 files changed, 145 insertions, 104 deletions
diff --git a/tmk_core/avr.mk b/tmk_core/avr.mk index 94e9a7bdbb..c083f6b72d 100644 --- a/tmk_core/avr.mk +++ b/tmk_core/avr.mk @@ -121,22 +121,22 @@ qmk: $(BUILD_DIR)/$(TARGET).hex printf "@ $(TARGET).json\n@=info.json\n" | zipnote -w $(TARGET).qmk # Program the device. -program: $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).eep +program: $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).eep check-size $(PROGRAM_CMD) -teensy: $(BUILD_DIR)/$(TARGET).hex +teensy: $(BUILD_DIR)/$(TARGET).hex check-size $(TEENSY_LOADER_CLI) -mmcu=$(MCU) -w -v $(BUILD_DIR)/$(TARGET).hex BATCHISP ?= batchisp -flip: $(BUILD_DIR)/$(TARGET).hex +flip: $(BUILD_DIR)/$(TARGET).hex check-size $(BATCHISP) -hardware usb -device $(MCU) -operation erase f $(BATCHISP) -hardware usb -device $(MCU) -operation loadbuffer $(BUILD_DIR)/$(TARGET).hex program $(BATCHISP) -hardware usb -device $(MCU) -operation start reset 0 DFU_PROGRAMMER ?= dfu-programmer -dfu: $(BUILD_DIR)/$(TARGET).hex sizeafter +dfu: $(BUILD_DIR)/$(TARGET).hex check-size until $(DFU_PROGRAMMER) $(MCU) get bootloader-version; do\ echo "Error: Bootloader not found. Trying again in 5s." ;\ sleep 5 ;\ @@ -168,7 +168,7 @@ dfu-ee: $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).eep fi $(DFU_PROGRAMMER) $(MCU) reset -avrdude: $(BUILD_DIR)/$(TARGET).hex +avrdude: $(BUILD_DIR)/$(TARGET).hex check-size if grep -q -s Microsoft /proc/version; then \ echo 'ERROR: AVR flashing cannot be automated within the Windows Subsystem for Linux (WSL) currently. Instead, take the .hex file generated and flash it using AVRDUDE, AVRDUDESS, or XLoader.'; \ else \ diff --git a/tmk_core/common/avr/bootloader.c b/tmk_core/common/avr/bootloader.c index 34db8d0b0a..ee150817c3 100644 --- a/tmk_core/common/avr/bootloader.c +++ b/tmk_core/common/avr/bootloader.c @@ -6,6 +6,7 @@ #include <avr/wdt.h> #include <util/delay.h> #include "bootloader.h" +#include <avr/boot.h> #ifdef PROTOCOL_LUFA #include <LUFA/Drivers/USB/USB.h> @@ -56,14 +57,17 @@ * | Bootloader | 512B | Bootloader | 1KB * 0x7FFF +---------------+ 0x1FFFF +---------------+ */ -#ifndef BOOTLOADER_SIZE -#warning To use bootloader_jump() you need to define BOOTLOADER_SIZE in config.h. -#define BOOTLOADER_SIZE 4096 -#endif -#define FLASH_SIZE (FLASHEND + 1L) -#define BOOTLOADER_START (FLASH_SIZE - BOOTLOADER_SIZE) +#define FLASH_SIZE (FLASHEND + 1L) + +#if !defined(BOOTLOADER_SIZE) + uint16_t bootloader_start; +#endif +#define BOOT_SIZE_256 0b110 +#define BOOT_SIZE_512 0b100 +#define BOOT_SIZE_1024 0b010 +#define BOOT_SIZE_2048 0b000 /* * Entering the Bootloader via Software @@ -74,34 +78,62 @@ uint32_t reset_key __attribute__ ((section (".noinit"))); /* initialize MCU status by watchdog reset */ void bootloader_jump(void) { - #ifndef CATERINA_BOOTLOADER - - #ifdef PROTOCOL_LUFA - USB_Disable(); - cli(); - _delay_ms(2000); - #endif - - #ifdef PROTOCOL_PJRC - cli(); - UDCON = 1; - USBCON = (1<<FRZCLK); - UCSR1B = 0; - _delay_ms(5); - #endif - - #ifdef BOOTLOADHID_BOOTLOADER - // force bootloadHID to stay in bootloader mode, so that it waits - // for a new firmware to be flashed - eeprom_write_byte((uint8_t *)1, 0x00); - #endif - // watchdog reset - reset_key = BOOTLOADER_RESET_KEY; - wdt_enable(WDTO_250MS); - for (;;); + #if !defined(BOOTLOADER_SIZE) + uint8_t high_fuse = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS); + + if (high_fuse & BOOT_SIZE_256) { + bootloader_start = (FLASH_SIZE - 512) >> 1; + } else if (high_fuse & BOOT_SIZE_512) { + bootloader_start = (FLASH_SIZE - 1024) >> 1; + } else if (high_fuse & BOOT_SIZE_1024) { + bootloader_start = (FLASH_SIZE - 2048) >> 1; + } else { + bootloader_start = (FLASH_SIZE - 4096) >> 1; + } + #endif - #else + // Something like this might work, but it compiled larger than the block above + // bootloader_start = FLASH_SIZE - (256 << (~high_fuse & 0b110 >> 1)); + + + #if defined(BOOTLOADER_HALFKAY) + // http://www.pjrc.com/teensy/jump_to_bootloader.html + cli(); + // disable watchdog, if enabled (it's not) + // disable all peripherals + // a shutdown call might make sense here + UDCON = 1; + USBCON = (1<<FRZCLK); // disable USB + UCSR1B = 0; + _delay_ms(5); + #if defined(__AVR_AT90USB162__) // Teensy 1.0 + EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; + TIMSK0 = 0; TIMSK1 = 0; UCSR1B = 0; + DDRB = 0; DDRC = 0; DDRD = 0; + PORTB = 0; PORTC = 0; PORTD = 0; + asm volatile("jmp 0x3E00"); + #elif defined(__AVR_ATmega32U4__) // Teensy 2.0 + EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; + TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0; + DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0; + PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; + asm volatile("jmp 0x7E00"); + #elif defined(__AVR_AT90USB646__) // Teensy++ 1.0 + EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; + TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0; + DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; + PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; + asm volatile("jmp 0xFC00"); + #elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0 + EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; + TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0; + DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; + PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; + asm volatile("jmp 0x1FC00"); + #endif + + #elif defined(BOOTLOADER_CATERINA) // this block may be optional // TODO: figure it out @@ -118,83 +150,65 @@ void bootloader_jump(void) { while(1) {} // wait for watchdog timer to trigger + #else // Assume remaining boards are DFU, even if the flag isn't set + + #ifndef __AVR_ATmega32A__ // no USB - maybe BOOTLOADER_BOOTLOADHID instead though? + UDCON = 1; + USBCON = (1<<FRZCLK); // disable USB + UCSR1B = 0; + _delay_ms(5); // 5 seems to work fine + #endif + + #ifdef BOOTLOADER_BOOTLOADHID + // force bootloadHID to stay in bootloader mode, so that it waits + // for a new firmware to be flashed + eeprom_write_byte((uint8_t *)1, 0x00); + #endif + + // watchdog reset + reset_key = BOOTLOADER_RESET_KEY; + wdt_enable(WDTO_250MS); + for (;;); #endif + } #ifdef __AVR_ATmega32A__ -// MCUSR is actually called MCUCSR in ATmega32A -#define MCUSR MCUCSR + // MCUSR is actually called MCUCSR in ATmega32A + #define MCUSR MCUCSR #endif /* this runs before main() */ void bootloader_jump_after_watchdog_reset(void) __attribute__ ((used, naked, section (".init3"))); void bootloader_jump_after_watchdog_reset(void) { - if ((MCUSR & (1<<WDRF)) && reset_key == BOOTLOADER_RESET_KEY) { - reset_key = 0; + #ifndef BOOTLOADER_HALFKAY + if ((MCUSR & (1<<WDRF)) && reset_key == BOOTLOADER_RESET_KEY) { + reset_key = 0; + + // My custom USBasploader requires this to come up. + MCUSR = 0; - // My custom USBasploader requires this to come up. - MCUSR = 0; + // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog. + MCUSR &= ~(1<<WDRF); + wdt_disable(); - // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog. - MCUSR &= ~(1<<WDRF); - wdt_disable(); - // This is compled into 'icall', address should be in word unit, not byte. - ((void (*)(void))(BOOTLOADER_START/2))(); - } + // This is compled into 'icall', address should be in word unit, not byte. + #ifdef BOOTLOADER_SIZE + ((void (*)(void))( (FLASH_SIZE - BOOTLOADER_SIZE) >> 1))(); + #else + asm("ijmp" :: "z" (bootloader_start)); + #endif + } + #endif } #if 0 -/* Jumping To The Bootloader - * http://www.pjrc.com/teensy/jump_to_bootloader.html - * - * This method doen't work when using LUFA. idk why. - * - needs to initialize more regisers or interrupt setting? - */ -void bootloader_jump(void) { -#ifdef PROTOCOL_LUFA - USB_Disable(); - cli(); - _delay_ms(2000); -#endif - -#ifdef PROTOCOL_PJRC - cli(); - UDCON = 1; - USBCON = (1<<FRZCLK); - UCSR1B = 0; - _delay_ms(5); -#endif - - /* - * Initialize - */ -#if defined(__AVR_AT90USB162__) - EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; - TIMSK0 = 0; TIMSK1 = 0; UCSR1B = 0; - DDRB = 0; DDRC = 0; DDRD = 0; - PORTB = 0; PORTC = 0; PORTD = 0; -#elif defined(__AVR_ATmega32U4__) - EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; - TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0; - DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0; - PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; -#elif defined(__AVR_AT90USB646__) - EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; - TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0; - DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; - PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; -#elif defined(__AVR_AT90USB1286__) - EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; - TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0; - DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; - PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; -#endif - /* - * USBaspLoader + * USBaspLoader - I'm not sure if this is used at all in any projects + * would love to support it if it is -Jack */ #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) // This makes custom USBasploader come up. diff --git a/tmk_core/common/avr/bootloader_size.c b/tmk_core/common/avr/bootloader_size.c new file mode 100644 index 0000000000..0d8d534f84 --- /dev/null +++ b/tmk_core/common/avr/bootloader_size.c @@ -0,0 +1,20 @@ +// Copyright 2017 Jack Humbert +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +#include <avr/io.h> +#include <avr/boot.h> + +// this is not valid C - it's for computing the size available on the chip +AVR_SIZE: FLASHEND + 1 - BOOTLOADER_SIZE
\ No newline at end of file diff --git a/tmk_core/rules.mk b/tmk_core/rules.mk index 53e79ef47a..920a7f6add 100644 --- a/tmk_core/rules.mk +++ b/tmk_core/rules.mk @@ -216,6 +216,9 @@ MOVE_DEP = mv -f $(patsubst %.o,%.td,$@) $(patsubst %.o,%.d,$@) elf: $(BUILD_DIR)/$(TARGET).elf hex: $(BUILD_DIR)/$(TARGET).hex +cphex: hex + $(SILENT) || printf "Copying $(TARGET).hex to qmk_firmware folder" | $(AWK_CMD) + $(COPY) $(BUILD_DIR)/$(TARGET).hex $(TARGET).hex && $(PRINT_OK) eep: $(BUILD_DIR)/$(TARGET).eep lss: $(BUILD_DIR)/$(TARGET).lss sym: $(BUILD_DIR)/$(TARGET).sym @@ -223,19 +226,17 @@ LIBNAME=lib$(TARGET).a lib: $(LIBNAME) # Display size of file. -HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex +HEXSIZE = $(SIZE) --target=$(FORMAT) $(BUILD_DIR)/$(TARGET).hex #ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf ELFSIZE = $(SIZE) $(BUILD_DIR)/$(TARGET).elf sizebefore: - @if test -f $(TARGET).hex; then $(SECHO) $(MSG_SIZE_BEFORE); $(SILENT) || $(HEXSIZE); \ + @if test -f $(BUILD_DIR)/$(TARGET).hex; then $(SECHO) $(MSG_SIZE_BEFORE); $(SILENT) || $(HEXSIZE); \ 2>/dev/null; $(SECHO); fi sizeafter: $(BUILD_DIR)/$(TARGET).hex - @if test -f $(TARGET).hex; then $(SECHO); $(SECHO) $(MSG_SIZE_AFTER); $(SILENT) || $(HEXSIZE); \ + @if test -f $(BUILD_DIR)/$(TARGET).hex; then $(SECHO); $(SECHO) $(MSG_SIZE_AFTER); $(SILENT) || $(HEXSIZE); \ 2>/dev/null; $(SECHO); fi - # test file sizes eventually - # @if [[ $($(SIZE) --target=$(FORMAT) $(TARGET).hex | $(AWK) 'NR==2 {print "0x"$5}') -gt 0x200 ]]; then $(SECHO) "File is too big!"; fi # Display compiler version information. gccversion : @@ -249,8 +250,6 @@ gccversion : @if $(AUTOGEN); then \ $(SILENT) || printf "Copying $(TARGET).hex to keymaps/$(KEYMAP)/$(TARGET).hex\n"; \ $(COPY) $@ $(KEYMAP_PATH)/$(TARGET).hex; \ - else \ - $(COPY) $@ $(TARGET).hex; \ fi %.eep: %.elf @@ -371,6 +370,14 @@ show_path: @echo SRC=$(SRC) @echo OBJ=$(OBJ) +check-size: + $(eval MAX_SIZE=$(shell n=`avr-gcc -E -mmcu=$(MCU) $(CFLAGS) $(OPT_DEFS) tmk_core/common/avr/bootloader_size.c 2> /dev/null | grep -oP "(?<=AVR_SIZE: ).+"`; echo $$(($$n)) || echo 0)) + $(eval CURRENT_SIZE=$(shell if [ -f $(BUILD_DIR)/$(TARGET).hex ]; then $(SIZE) --target=$(FORMAT) $(BUILD_DIR)/$(TARGET).hex | $(AWK) 'NR==2 {print $$4}'; else printf 0; fi)) + if [ $(MAX_SIZE) -gt 0 ] && [ $(CURRENT_SIZE) -gt 0 ]; then \ + $(SILENT) || printf "$(MSG_CHECK_FILESIZE)" | $(AWK_CMD); \ + if [ $(CURRENT_SIZE) -gt $(MAX_SIZE) ]; then $(PRINT_WARNING_PLAIN); $(SILENT) || printf " * $(MSG_FILE_TOO_BIG)" ; else $(PRINT_OK); $(SILENT) || printf " * $(MSG_FILE_JUST_RIGHT)"; fi \ + fi + # Create build directory $(shell mkdir -p $(BUILD_DIR) 2>/dev/null) @@ -385,4 +392,4 @@ $(eval $(foreach OUTPUT,$(OUTPUTS),$(shell mkdir -p $(OUTPUT) 2>/dev/null))) .PHONY : all finish sizebefore sizeafter qmkversion \ gccversion build elf hex eep lss sym coff extcoff \ clean clean_list debug gdb-config show_path \ -program teensy dfu flip dfu-ee flip-ee dfu-start +program teensy dfu flip dfu-ee flip-ee dfu-start
\ No newline at end of file |