]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - tmk_core/common/avr/bootloader.c
core: Add bootkey of Caterina bootloader
[max/tmk_keyboard.git] / tmk_core / common / avr / bootloader.c
1 #include <stdint.h>
2 #include <stdbool.h>
3 #include <avr/io.h>
4 #include <avr/interrupt.h>
5 #include <avr/wdt.h>
6 #include <util/delay.h>
7 #include "bootloader.h"
8
9 #ifdef PROTOCOL_LUFA
10 #include <LUFA/Drivers/USB/USB.h>
11 #endif
12
13
14 /* Bootloader Size in *bytes*
15  *
16  * AVR Boot section size are defined by setting BOOTSZ fuse in fact. Consult with your MCU datasheet.
17  * Note that 'Word'(2 bytes) size and address are used in datasheet while TMK uses 'Byte'.
18  *
19  *
20  * Size of Bootloaders in bytes:
21  *   Atmel DFU loader(ATmega32U4)   4096
22  *   Atmel DFU loader(AT90USB128)   8192
23  *   LUFA bootloader(ATmega32U4)    4096
24  *   Arduino Caterina(ATmega32U4)   4096
25  *   USBaspLoader(ATmega***)        2048
26  *   Teensy   halfKay(ATmega32U4)   512
27  *   Teensy++ halfKay(AT90USB128)   1024
28  *
29  *
30  * AVR Boot section is located at the end of Flash memory like the followings.
31  *
32  *
33  * byte     Atmel/LUFA(ATMega32u4)          byte     Atmel(AT90SUB128)
34  * 0x0000   +---------------+               0x00000  +---------------+
35  *          |               |                        |               |
36  *          |               |                        |               |
37  *          |  Application  |                        |  Application  |
38  *          |               |                        |               |
39  *          =               =                        =               =
40  *          |               | 32KB-4KB               |               | 128KB-8KB
41  * 0x6000   +---------------+               0x1FC00  +---------------+
42  *          |  Bootloader   | 4KB                    |  Bootloader   | 8KB
43  * 0x7FFF   +---------------+               0x1FFFF  +---------------+
44  *
45  *
46  * byte     Teensy(ATMega32u4)              byte     Teensy++(AT90SUB128)
47  * 0x0000   +---------------+               0x00000  +---------------+
48  *          |               |                        |               |
49  *          |               |                        |               |
50  *          |  Application  |                        |  Application  |
51  *          |               |                        |               |
52  *          =               =                        =               =
53  *          |               | 32KB-512B              |               | 128KB-1KB
54  * 0x7E00   +---------------+               0x1FC00  +---------------+
55  *          |  Bootloader   | 512B                   |  Bootloader   | 1KB
56  * 0x7FFF   +---------------+               0x1FFFF  +---------------+
57  */
58 #ifndef BOOTLOADER_SIZE
59 #warning To use bootloader_jump() you need to define BOOTLOADER_SIZE in config.h.
60 #define BOOTLOADER_SIZE     4096
61 #endif
62
63 #define FLASH_SIZE          (FLASHEND + 1L)
64 #define BOOTLOADER_START    (FLASH_SIZE - BOOTLOADER_SIZE)
65
66
67 /* 
68  * Entering the Bootloader via Software 
69  * http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html
70  */
71 #define BOOTLOADER_RESET_KEY 0xB007B007
72 uint32_t reset_key  __attribute__ ((section (".noinit")));
73
74 /* initialize MCU status by watchdog reset */
75 void bootloader_jump(void) {
76 #ifdef PROTOCOL_LUFA
77     USB_Disable();
78     cli();
79     _delay_ms(2000);
80 #endif
81
82 #ifdef PROTOCOL_PJRC
83     cli();
84     UDCON = 1;
85     USBCON = (1<<FRZCLK);
86     UCSR1B = 0;
87     _delay_ms(5);
88 #endif
89
90 #ifndef NO_BOOTLOADER_CATERINA_BOOTKEY
91     // Set bootkey for Arduino Leonardo and Pro Micro bootloader
92     // Watchdog reset with bootkey causes the bootloader to enter program mode instead of starting application.
93     // https://github.com/arduino/ArduinoCore-avr/blob/master/bootloaders/caterina/Caterina.c#L68-L69
94     // https://github.com/sparkfun/SF32u4_boards/blob/master/sparkfun/avr/bootloaders/caterina/Caterina.c#L88-L89
95     *(volatile uint16_t *)0x0800 = 0x7777;
96 #endif
97
98     // watchdog reset
99     reset_key = BOOTLOADER_RESET_KEY;
100     wdt_enable(WDTO_250MS);
101     for (;;);
102 }
103
104
105 /* this runs before main() */
106 void bootloader_jump_after_watchdog_reset(void) __attribute__ ((used, naked, section (".init3")));
107 void bootloader_jump_after_watchdog_reset(void)
108 {
109     if ((MCUSR & (1<<WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
110         reset_key = 0;
111
112         // My custom USBasploader requires this to come up.
113         MCUSR = 0;
114
115         // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog.
116         MCUSR &= ~(1<<WDRF);
117         wdt_disable();
118
119 #ifndef NO_BOOTLOADER_CATERINA_BOOTKEY
120         // Clear bootkey of Caterina bootloader for other bootloaders
121         // Leonardo and Pro Micro with Arduino default fuse setting don't reach here
122         // because bootloader section are executed before application everytime.
123         *(volatile uint16_t *)0x0800 = 0;
124 #endif
125
126         // This is compled into 'icall', address should be in word unit, not byte.
127         ((void (*)(void))(BOOTLOADER_START/2))();
128     }
129 }
130
131
132 #if 0
133 /* Jumping To The Bootloader
134  * http://www.pjrc.com/teensy/jump_to_bootloader.html
135  * 
136  * This method doen't work when using LUFA. idk why.
137  * - needs to initialize more regisers or interrupt setting?
138  */
139 void bootloader_jump(void) {
140 #ifdef PROTOCOL_LUFA
141     USB_Disable();
142     cli();
143     _delay_ms(2000);
144 #endif
145
146 #ifdef PROTOCOL_PJRC
147     cli();
148     UDCON = 1;
149     USBCON = (1<<FRZCLK);
150     UCSR1B = 0;
151     _delay_ms(5);
152 #endif
153
154     /*
155      * Initialize
156      */
157 #if defined(__AVR_AT90USB162__)
158     EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0;
159     TIMSK0 = 0; TIMSK1 = 0; UCSR1B = 0;
160     DDRB = 0; DDRC = 0; DDRD = 0;
161     PORTB = 0; PORTC = 0; PORTD = 0;
162 #elif defined(__AVR_ATmega32U4__)
163     EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
164     TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0;
165     DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0;
166     PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
167 #elif defined(__AVR_AT90USB646__)
168     EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
169     TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0;
170     DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
171     PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
172 #elif defined(__AVR_AT90USB1286__)
173     EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
174     TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0;
175     DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
176     PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
177 #endif
178
179     /*
180      * USBaspLoader
181      */
182 #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__)
183     // This makes custom USBasploader come up.
184     MCUSR = 0;
185
186     // initialize ports
187     PORTB = 0; PORTC= 0; PORTD = 0;
188     DDRB = 0; DDRC= 0; DDRD = 0;
189
190     // disable interrupts
191     EIMSK = 0; EECR = 0; SPCR = 0;
192     ACSR = 0; SPMCSR = 0; WDTCSR = 0; PCICR = 0;
193     TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0;
194     ADCSRA = 0; TWCR = 0; UCSR0B = 0;
195 #endif
196
197     // This is compled into 'icall', address should be in word unit, not byte.
198     ((void (*)(void))(BOOTLOADER_START/2))();
199 }
200 #endif