]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/common/avr/bootloader.c
34db8d0b0aa66c18538f978fac66e44f9938ed5c
[qmk_firmware.git] / tmk_core / common / avr / bootloader.c
1 #include <stdint.h>
2 #include <stdbool.h>
3 #include <avr/io.h>
4 #include <avr/eeprom.h>
5 #include <avr/interrupt.h>
6 #include <avr/wdt.h>
7 #include <util/delay.h>
8 #include "bootloader.h"
9
10 #ifdef PROTOCOL_LUFA
11 #include <LUFA/Drivers/USB/USB.h>
12 #endif
13
14
15 /* Bootloader Size in *bytes*
16  *
17  * AVR Boot section size are defined by setting BOOTSZ fuse in fact. Consult with your MCU datasheet.
18  * Note that 'Word'(2 bytes) size and address are used in datasheet while TMK uses 'Byte'.
19  *
20  *
21  * Size of Bootloaders in bytes:
22  *   Atmel DFU loader(ATmega32U4)   4096
23  *   Atmel DFU loader(AT90USB128)   8192
24  *   LUFA bootloader(ATmega32U4)    4096
25  *   Arduino Caterina(ATmega32U4)   4096
26  *   USBaspLoader(ATmega***)        2048
27  *   Teensy   halfKay(ATmega32U4)   512
28  *   Teensy++ halfKay(AT90USB128)   1024
29  *
30  *
31  * AVR Boot section is located at the end of Flash memory like the followings.
32  *
33  *
34  * byte     Atmel/LUFA(ATMega32u4)          byte     Atmel(AT90SUB128)
35  * 0x0000   +---------------+               0x00000  +---------------+
36  *          |               |                        |               |
37  *          |               |                        |               |
38  *          |  Application  |                        |  Application  |
39  *          |               |                        |               |
40  *          =               =                        =               =
41  *          |               | 32KB-4KB               |               | 128KB-8KB
42  * 0x7000   +---------------+               0x1E000  +---------------+
43  *          |  Bootloader   | 4KB                    |  Bootloader   | 8KB
44  * 0x7FFF   +---------------+               0x1FFFF  +---------------+
45  *
46  *
47  * byte     Teensy(ATMega32u4)              byte     Teensy++(AT90SUB128)
48  * 0x0000   +---------------+               0x00000  +---------------+
49  *          |               |                        |               |
50  *          |               |                        |               |
51  *          |  Application  |                        |  Application  |
52  *          |               |                        |               |
53  *          =               =                        =               =
54  *          |               | 32KB-512B              |               | 128KB-1KB
55  * 0x7E00   +---------------+               0x1FC00  +---------------+
56  *          |  Bootloader   | 512B                   |  Bootloader   | 1KB
57  * 0x7FFF   +---------------+               0x1FFFF  +---------------+
58  */
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
64 #define FLASH_SIZE          (FLASHEND + 1L)
65 #define BOOTLOADER_START    (FLASH_SIZE - BOOTLOADER_SIZE)
66
67
68 /*
69  * Entering the Bootloader via Software
70  * http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html
71  */
72 #define BOOTLOADER_RESET_KEY 0xB007B007
73 uint32_t reset_key  __attribute__ ((section (".noinit")));
74
75 /* initialize MCU status by watchdog reset */
76 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
99         // watchdog reset
100         reset_key = BOOTLOADER_RESET_KEY;
101         wdt_enable(WDTO_250MS);
102         for (;;);
103
104     #else
105         // this block may be optional
106         // TODO: figure it out
107
108         uint16_t *const bootKeyPtr = (uint16_t *)0x0800;
109
110         // Value used by Caterina bootloader use to determine whether to run the
111         // sketch or the bootloader programmer.
112         uint16_t bootKey = 0x7777;
113
114         *bootKeyPtr = bootKey;
115
116         // setup watchdog timeout
117         wdt_enable(WDTO_60MS);
118
119         while(1) {} // wait for watchdog timer to trigger
120
121     #endif
122 }
123
124 #ifdef __AVR_ATmega32A__
125 // MCUSR is actually called MCUCSR in ATmega32A
126 #define MCUSR MCUCSR
127 #endif
128
129 /* this runs before main() */
130 void bootloader_jump_after_watchdog_reset(void) __attribute__ ((used, naked, section (".init3")));
131 void bootloader_jump_after_watchdog_reset(void)
132 {
133     if ((MCUSR & (1<<WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
134         reset_key = 0;
135
136         // My custom USBasploader requires this to come up.
137         MCUSR = 0;
138
139         // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog.
140         MCUSR &= ~(1<<WDRF);
141         wdt_disable();
142
143         // This is compled into 'icall', address should be in word unit, not byte.
144         ((void (*)(void))(BOOTLOADER_START/2))();
145     }
146 }
147
148
149 #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     /*
197      * USBaspLoader
198      */
199 #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__)
200     // This makes custom USBasploader come up.
201     MCUSR = 0;
202
203     // initialize ports
204     PORTB = 0; PORTC= 0; PORTD = 0;
205     DDRB = 0; DDRC= 0; DDRD = 0;
206
207     // disable interrupts
208     EIMSK = 0; EECR = 0; SPCR = 0;
209     ACSR = 0; SPMCSR = 0; WDTCSR = 0; PCICR = 0;
210     TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0;
211     ADCSRA = 0; TWCR = 0; UCSR0B = 0;
212 #endif
213
214     // This is compled into 'icall', address should be in word unit, not byte.
215     ((void (*)(void))(BOOTLOADER_START/2))();
216 }
217 #endif