summaryrefslogtreecommitdiff
path: root/tmk_core
diff options
context:
space:
mode:
authorJack Humbert <jack.humb@gmail.com>2017-11-27 23:08:21 -0500
committerGitHub <noreply@github.com>2017-11-27 23:08:21 -0500
commit9fdc27626097ae03b767a09427efc90475d90955 (patch)
treea555c38f1b714af6e2c2c96187552757d08224b9 /tmk_core
parent9113f3387a670373919fe62899b0ab27e9d89eba (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.mk10
-rw-r--r--tmk_core/common/avr/bootloader.c196
-rw-r--r--tmk_core/common/avr/bootloader_size.c20
-rw-r--r--tmk_core/rules.mk23
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