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/common/avr/bootloader.c | |
| parent | 9113f3387a670373919fe62899b0ab27e9d89eba (diff) | |
| download | qmk_firmware-9fdc27626097ae03b767a09427efc90475d90955.tar.gz qmk_firmware-9fdc27626097ae03b767a09427efc90475d90955.zip | |
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/common/avr/bootloader.c')
| -rw-r--r-- | tmk_core/common/avr/bootloader.c | 196 |
1 files changed, 105 insertions, 91 deletions
diff --git a/tmk_core/common/avr/bootloader.c b/tmk_core/common/avr/bootloader.c index 34db8d0b0..ee150817c 100644 --- a/tmk_core/common/avr/bootloader.c +++ b/tmk_core/common/avr/bootloader.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <avr/wdt.h> | 6 | #include <avr/wdt.h> |
| 7 | #include <util/delay.h> | 7 | #include <util/delay.h> |
| 8 | #include "bootloader.h" | 8 | #include "bootloader.h" |
| 9 | #include <avr/boot.h> | ||
| 9 | 10 | ||
| 10 | #ifdef PROTOCOL_LUFA | 11 | #ifdef PROTOCOL_LUFA |
| 11 | #include <LUFA/Drivers/USB/USB.h> | 12 | #include <LUFA/Drivers/USB/USB.h> |
| @@ -56,14 +57,17 @@ | |||
| 56 | * | Bootloader | 512B | Bootloader | 1KB | 57 | * | Bootloader | 512B | Bootloader | 1KB |
| 57 | * 0x7FFF +---------------+ 0x1FFFF +---------------+ | 58 | * 0x7FFF +---------------+ 0x1FFFF +---------------+ |
| 58 | */ | 59 | */ |
| 59 | #ifndef BOOTLOADER_SIZE | ||
| 60 | #warning To use bootloader_jump() you need to define BOOTLOADER_SIZE in config.h. | ||
| 61 | #define BOOTLOADER_SIZE 4096 | ||
| 62 | #endif | ||
| 63 | 60 | ||
| 64 | #define FLASH_SIZE (FLASHEND + 1L) | 61 | #define FLASH_SIZE (FLASHEND + 1L) |
| 65 | #define BOOTLOADER_START (FLASH_SIZE - BOOTLOADER_SIZE) | 62 | |
| 63 | #if !defined(BOOTLOADER_SIZE) | ||
| 64 | uint16_t bootloader_start; | ||
| 65 | #endif | ||
| 66 | 66 | ||
| 67 | #define BOOT_SIZE_256 0b110 | ||
| 68 | #define BOOT_SIZE_512 0b100 | ||
| 69 | #define BOOT_SIZE_1024 0b010 | ||
| 70 | #define BOOT_SIZE_2048 0b000 | ||
| 67 | 71 | ||
| 68 | /* | 72 | /* |
| 69 | * Entering the Bootloader via Software | 73 | * Entering the Bootloader via Software |
| @@ -74,34 +78,62 @@ uint32_t reset_key __attribute__ ((section (".noinit"))); | |||
| 74 | 78 | ||
| 75 | /* initialize MCU status by watchdog reset */ | 79 | /* initialize MCU status by watchdog reset */ |
| 76 | void bootloader_jump(void) { | 80 | void bootloader_jump(void) { |
| 77 | #ifndef CATERINA_BOOTLOADER | ||
| 78 | |||
| 79 | #ifdef PROTOCOL_LUFA | ||
| 80 | USB_Disable(); | ||
| 81 | cli(); | ||
| 82 | _delay_ms(2000); | ||
| 83 | #endif | ||
| 84 | |||
| 85 | #ifdef PROTOCOL_PJRC | ||
| 86 | cli(); | ||
| 87 | UDCON = 1; | ||
| 88 | USBCON = (1<<FRZCLK); | ||
| 89 | UCSR1B = 0; | ||
| 90 | _delay_ms(5); | ||
| 91 | #endif | ||
| 92 | |||
| 93 | #ifdef BOOTLOADHID_BOOTLOADER | ||
| 94 | // force bootloadHID to stay in bootloader mode, so that it waits | ||
| 95 | // for a new firmware to be flashed | ||
| 96 | eeprom_write_byte((uint8_t *)1, 0x00); | ||
| 97 | #endif | ||
| 98 | 81 | ||
| 99 | // watchdog reset | 82 | #if !defined(BOOTLOADER_SIZE) |
| 100 | reset_key = BOOTLOADER_RESET_KEY; | 83 | uint8_t high_fuse = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS); |
| 101 | wdt_enable(WDTO_250MS); | 84 | |
| 102 | for (;;); | 85 | if (high_fuse & BOOT_SIZE_256) { |
| 86 | bootloader_start = (FLASH_SIZE - 512) >> 1; | ||
| 87 | } else if (high_fuse & BOOT_SIZE_512) { | ||
| 88 | bootloader_start = (FLASH_SIZE - 1024) >> 1; | ||
| 89 | } else if (high_fuse & BOOT_SIZE_1024) { | ||
| 90 | bootloader_start = (FLASH_SIZE - 2048) >> 1; | ||
| 91 | } else { | ||
| 92 | bootloader_start = (FLASH_SIZE - 4096) >> 1; | ||
| 93 | } | ||
| 94 | #endif | ||
| 103 | 95 | ||
| 104 | #else | 96 | // Something like this might work, but it compiled larger than the block above |
| 97 | // bootloader_start = FLASH_SIZE - (256 << (~high_fuse & 0b110 >> 1)); | ||
| 98 | |||
| 99 | |||
| 100 | #if defined(BOOTLOADER_HALFKAY) | ||
| 101 | // http://www.pjrc.com/teensy/jump_to_bootloader.html | ||
| 102 | cli(); | ||
| 103 | // disable watchdog, if enabled (it's not) | ||
| 104 | // disable all peripherals | ||
| 105 | // a shutdown call might make sense here | ||
| 106 | UDCON = 1; | ||
| 107 | USBCON = (1<<FRZCLK); // disable USB | ||
| 108 | UCSR1B = 0; | ||
| 109 | _delay_ms(5); | ||
| 110 | #if defined(__AVR_AT90USB162__) // Teensy 1.0 | ||
| 111 | EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; | ||
| 112 | TIMSK0 = 0; TIMSK1 = 0; UCSR1B = 0; | ||
| 113 | DDRB = 0; DDRC = 0; DDRD = 0; | ||
| 114 | PORTB = 0; PORTC = 0; PORTD = 0; | ||
| 115 | asm volatile("jmp 0x3E00"); | ||
| 116 | #elif defined(__AVR_ATmega32U4__) // Teensy 2.0 | ||
| 117 | EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; | ||
| 118 | TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0; | ||
| 119 | DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0; | ||
| 120 | PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; | ||
| 121 | asm volatile("jmp 0x7E00"); | ||
| 122 | #elif defined(__AVR_AT90USB646__) // Teensy++ 1.0 | ||
| 123 | EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; | ||
| 124 | TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0; | ||
| 125 | DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; | ||
| 126 | PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; | ||
| 127 | asm volatile("jmp 0xFC00"); | ||
| 128 | #elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0 | ||
| 129 | EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; | ||
| 130 | TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0; | ||
| 131 | DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; | ||
| 132 | PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; | ||
| 133 | asm volatile("jmp 0x1FC00"); | ||
| 134 | #endif | ||
| 135 | |||
| 136 | #elif defined(BOOTLOADER_CATERINA) | ||
| 105 | // this block may be optional | 137 | // this block may be optional |
| 106 | // TODO: figure it out | 138 | // TODO: figure it out |
| 107 | 139 | ||
| @@ -118,83 +150,65 @@ void bootloader_jump(void) { | |||
| 118 | 150 | ||
| 119 | while(1) {} // wait for watchdog timer to trigger | 151 | while(1) {} // wait for watchdog timer to trigger |
| 120 | 152 | ||
| 153 | #else // Assume remaining boards are DFU, even if the flag isn't set | ||
| 154 | |||
| 155 | #ifndef __AVR_ATmega32A__ // no USB - maybe BOOTLOADER_BOOTLOADHID instead though? | ||
| 156 | UDCON = 1; | ||
| 157 | USBCON = (1<<FRZCLK); // disable USB | ||
| 158 | UCSR1B = 0; | ||
| 159 | _delay_ms(5); // 5 seems to work fine | ||
| 160 | #endif | ||
| 161 | |||
| 162 | #ifdef BOOTLOADER_BOOTLOADHID | ||
| 163 | // force bootloadHID to stay in bootloader mode, so that it waits | ||
| 164 | // for a new firmware to be flashed | ||
| 165 | eeprom_write_byte((uint8_t *)1, 0x00); | ||
| 166 | #endif | ||
| 167 | |||
| 168 | // watchdog reset | ||
| 169 | reset_key = BOOTLOADER_RESET_KEY; | ||
| 170 | wdt_enable(WDTO_250MS); | ||
| 171 | for (;;); | ||
| 121 | #endif | 172 | #endif |
| 173 | |||
| 122 | } | 174 | } |
| 123 | 175 | ||
| 124 | #ifdef __AVR_ATmega32A__ | 176 | #ifdef __AVR_ATmega32A__ |
| 125 | // MCUSR is actually called MCUCSR in ATmega32A | 177 | // MCUSR is actually called MCUCSR in ATmega32A |
| 126 | #define MCUSR MCUCSR | 178 | #define MCUSR MCUCSR |
| 127 | #endif | 179 | #endif |
| 128 | 180 | ||
| 129 | /* this runs before main() */ | 181 | /* this runs before main() */ |
| 130 | void bootloader_jump_after_watchdog_reset(void) __attribute__ ((used, naked, section (".init3"))); | 182 | void bootloader_jump_after_watchdog_reset(void) __attribute__ ((used, naked, section (".init3"))); |
| 131 | void bootloader_jump_after_watchdog_reset(void) | 183 | void bootloader_jump_after_watchdog_reset(void) |
| 132 | { | 184 | { |
| 133 | if ((MCUSR & (1<<WDRF)) && reset_key == BOOTLOADER_RESET_KEY) { | 185 | #ifndef BOOTLOADER_HALFKAY |
| 134 | reset_key = 0; | 186 | if ((MCUSR & (1<<WDRF)) && reset_key == BOOTLOADER_RESET_KEY) { |
| 187 | reset_key = 0; | ||
| 188 | |||
| 189 | // My custom USBasploader requires this to come up. | ||
| 190 | MCUSR = 0; | ||
| 135 | 191 | ||
| 136 | // My custom USBasploader requires this to come up. | 192 | // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog. |
| 137 | MCUSR = 0; | 193 | MCUSR &= ~(1<<WDRF); |
| 194 | wdt_disable(); | ||
| 138 | 195 | ||
| 139 | // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog. | ||
| 140 | MCUSR &= ~(1<<WDRF); | ||
| 141 | wdt_disable(); | ||
| 142 | 196 | ||
| 143 | // This is compled into 'icall', address should be in word unit, not byte. | 197 | // This is compled into 'icall', address should be in word unit, not byte. |
| 144 | ((void (*)(void))(BOOTLOADER_START/2))(); | 198 | #ifdef BOOTLOADER_SIZE |
| 145 | } | 199 | ((void (*)(void))( (FLASH_SIZE - BOOTLOADER_SIZE) >> 1))(); |
| 200 | #else | ||
| 201 | asm("ijmp" :: "z" (bootloader_start)); | ||
| 202 | #endif | ||
| 203 | } | ||
| 204 | #endif | ||
| 146 | } | 205 | } |
| 147 | 206 | ||
| 148 | 207 | ||
| 149 | #if 0 | 208 | #if 0 |
| 150 | /* Jumping To The Bootloader | ||
| 151 | * http://www.pjrc.com/teensy/jump_to_bootloader.html | ||
| 152 | * | ||
| 153 | * This method doen't work when using LUFA. idk why. | ||
| 154 | * - needs to initialize more regisers or interrupt setting? | ||
| 155 | */ | ||
| 156 | void bootloader_jump(void) { | ||
| 157 | #ifdef PROTOCOL_LUFA | ||
| 158 | USB_Disable(); | ||
| 159 | cli(); | ||
| 160 | _delay_ms(2000); | ||
| 161 | #endif | ||
| 162 | |||
| 163 | #ifdef PROTOCOL_PJRC | ||
| 164 | cli(); | ||
| 165 | UDCON = 1; | ||
| 166 | USBCON = (1<<FRZCLK); | ||
| 167 | UCSR1B = 0; | ||
| 168 | _delay_ms(5); | ||
| 169 | #endif | ||
| 170 | |||
| 171 | /* | ||
| 172 | * Initialize | ||
| 173 | */ | ||
| 174 | #if defined(__AVR_AT90USB162__) | ||
| 175 | EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; | ||
| 176 | TIMSK0 = 0; TIMSK1 = 0; UCSR1B = 0; | ||
| 177 | DDRB = 0; DDRC = 0; DDRD = 0; | ||
| 178 | PORTB = 0; PORTC = 0; PORTD = 0; | ||
| 179 | #elif defined(__AVR_ATmega32U4__) | ||
| 180 | EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; | ||
| 181 | TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0; | ||
| 182 | DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0; | ||
| 183 | PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; | ||
| 184 | #elif defined(__AVR_AT90USB646__) | ||
| 185 | EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; | ||
| 186 | TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0; | ||
| 187 | DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; | ||
| 188 | PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; | ||
| 189 | #elif defined(__AVR_AT90USB1286__) | ||
| 190 | EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; | ||
| 191 | TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0; | ||
| 192 | DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; | ||
| 193 | PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; | ||
| 194 | #endif | ||
| 195 | |||
| 196 | /* | 209 | /* |
| 197 | * USBaspLoader | 210 | * USBaspLoader - I'm not sure if this is used at all in any projects |
| 211 | * would love to support it if it is -Jack | ||
| 198 | */ | 212 | */ |
| 199 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) | 213 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) |
| 200 | // This makes custom USBasploader come up. | 214 | // This makes custom USBasploader come up. |
