]> git.friedersdorff.com Git - max/tmk_keyboard.git/blobdiff - tmk_core/common/avr/bootloader.c
core: Update comments in keycode.h
[max/tmk_keyboard.git] / tmk_core / common / avr / bootloader.c
index cda295b1811e92f90baea342084b37a07139bcc1..8abce9d818aa38bbf2c7d89ba0f4f270efc2f2c4 100644 (file)
@@ -3,6 +3,7 @@
 #include <avr/io.h>
 #include <avr/interrupt.h>
 #include <avr/wdt.h>
+#include <avr/boot.h>
 #include <util/delay.h>
 #include "bootloader.h"
 
 #endif
 
 
-/* Boot Section Size in *BYTEs*
- *   Teensy   halfKay    512
- *   Teensy++ halfKay    1024
- *   Atmel DFU loader    4096
- *   LUFA bootloader     4096
- *   USBaspLoader        2048
+/* Bootloader Size in *bytes*
+ *
+ * AVR Boot section size are defined by setting BOOTSZ fuse in fact. Consult with your MCU datasheet.
+ * Note that 'Word'(2 bytes) size and address are used in datasheet while TMK uses 'Byte'.
+ *
+ * Size of Bootloaders in bytes:
+ *   Atmel DFU loader(ATmega32U2)   4096
+ *   Atmel DFU loader(ATmega32U4)   4096
+ *   Atmel DFU loader(AT90USB128)   8192
+ *   LUFA bootloader(ATmega32U4)    4096
+ *   Arduino Caterina(ATmega32U4)   4096
+ *   USBaspLoader(ATmega***)        2048
+ *   Teensy   halfKay(ATmega32U4)   512
+ *   Teensy++ halfKay(AT90USB128)   1024
+ *
+ *
+ * AVR Boot section is located at the end of Flash memory.
+ *
+ * byte     ATMega32u4 with 4096-byte Boot section
+ * 0x0000   +---------------+
+ *          |               |
+ *          |               |
+ *          |  Application  | 28KB
+ *          |               |
+ *          =               =
+ *          |               |
+ * 0x7000   +---------------+ <---- BOOTLOADER_START
+ *          |  Bootloader   | 4KB   BOOTLOADER_SIZE
+ * 0x7FFF   +---------------+ <---- FLASHEND
  */
-#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)
+/* bootloader start address in byte */
+#define BOOTLOADER_START      (FLASHEND - bootloader_size() + 1)
+
+/* boot section size in byte */
+static inline uint16_t bootloader_size(void)
+{
+#if defined(BOOTLOADER_SIZE)
+    return BOOTLOADER_SIZE;
+#else
+    #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega32U2__) || \
+            defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega16U2__) || \
+            defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
+        uint8_t hfuse = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS);
+        switch ((hfuse >> 1) & 3) {
+            case 0: return 4096;
+            case 1: return 2048;
+            case 2: return 1024;
+            case 3: return 512;
+        }
+        return 4096;
+    #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || \
+            defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
+        uint8_t hfuse = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS);
+        switch ((hfuse >> 1) & 3) {
+            case 0: return 8192;
+            case 1: return 4096;
+            case 2: return 2048;
+            case 3: return 1024;
+        }
+        return 8192;
+    #else
+        #error Set Boot section size to BOOTLOADER_SIZE in config.h
+    #endif
+#endif
+}
 
 
-/* 
- * Entering the Bootloader via Software 
+/*
+ * Entering the Bootloader via Software
  * http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html
  */
 #define BOOTLOADER_RESET_KEY 0xB007B007
@@ -39,7 +92,6 @@ void bootloader_jump(void) {
 #ifdef PROTOCOL_LUFA
     USB_Disable();
     cli();
-    _delay_ms(2000);
 #endif
 
 #ifdef PROTOCOL_PJRC
@@ -50,6 +102,14 @@ void bootloader_jump(void) {
     _delay_ms(5);
 #endif
 
+#ifndef NO_BOOTLOADER_CATERINA_BOOTKEY
+    // Set bootkey for Arduino Leonardo and Pro Micro bootloader
+    // Watchdog reset with bootkey causes the bootloader to enter program mode instead of starting application.
+    // https://github.com/arduino/ArduinoCore-avr/blob/master/bootloaders/caterina/Caterina.c#L68-L69
+    // https://github.com/sparkfun/SF32u4_boards/blob/master/sparkfun/avr/bootloaders/caterina/Caterina.c#L88-L89
+    *(volatile uint16_t *)0x0800 = 0x7777;
+#endif
+
     // watchdog reset
     reset_key = BOOTLOADER_RESET_KEY;
     wdt_enable(WDTO_250MS);
@@ -64,85 +124,20 @@ void bootloader_jump_after_watchdog_reset(void)
     if ((MCUSR & (1<<WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
         reset_key = 0;
 
-        // My custom USBasploader requires this to come up.
+        // some of bootloaders may need to preseve?
         MCUSR = 0;
 
-        // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog.
-        MCUSR &= ~(1<<WDRF);
+        // disable watchdog timer
         wdt_disable();
 
-        // This is compled into 'icall', address should be in word unit, not byte.
-        ((void (*)(void))(BOOTLOADER_START/2))();
-    }
-}
-
-
-#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
-     */
-#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__)
-    // This makes custom USBasploader come up.
-    MCUSR = 0;
-
-    // initialize ports
-    PORTB = 0; PORTC= 0; PORTD = 0;
-    DDRB = 0; DDRC= 0; DDRD = 0;
-
-    // disable interrupts
-    EIMSK = 0; EECR = 0; SPCR = 0;
-    ACSR = 0; SPMCSR = 0; WDTCSR = 0; PCICR = 0;
-    TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0;
-    ADCSRA = 0; TWCR = 0; UCSR0B = 0;
+#ifndef NO_BOOTLOADER_CATERINA_BOOTKEY
+        // Clear bootkey of Caterina bootloader for other bootloaders
+        // Leonardo and Pro Micro with Arduino default fuse setting don't reach here
+        // because bootloader section are executed before application everytime.
+        *(volatile uint16_t *)0x0800 = 0;
 #endif
 
-    // 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.
+        ((void (*)(void))( (uint16_t)(BOOTLOADER_START / 2) ))();
+    }
 }
-#endif