]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/common/avr/bootloader.c
Merge remote-tracking branch 'jackhumbert/master'
[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/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  * 0x7000   +---------------+               0x1E000  +---------------+
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     #ifndef CATERINA_BOOTLOADER
77
78         #ifdef PROTOCOL_LUFA
79             USB_Disable();
80             cli();
81             _delay_ms(2000);
82         #endif
83
84         #ifdef PROTOCOL_PJRC
85             cli();
86             UDCON = 1;
87             USBCON = (1<<FRZCLK);
88             UCSR1B = 0;
89             _delay_ms(5);
90         #endif
91
92         // watchdog reset
93         reset_key = BOOTLOADER_RESET_KEY;
94         wdt_enable(WDTO_250MS);
95         for (;;);
96
97     #else
98         // this block may be optional
99         // TODO: figure it out
100
101         uint16_t *const bootKeyPtr = (uint16_t *)0x0800;
102
103         // Value used by Caterina bootloader use to determine whether to run the
104         // sketch or the bootloader programmer.
105         uint16_t bootKey = 0x7777;
106
107         *bootKeyPtr = bootKey;
108
109         // setup watchdog timeout
110         wdt_enable(WDTO_60MS);
111
112         while(1) {} // wait for watchdog timer to trigger
113
114     #endif
115 }
116
117 /* this runs before main() */
118 void bootloader_jump_after_watchdog_reset(void) __attribute__ ((used, naked, section (".init3")));
119 void bootloader_jump_after_watchdog_reset(void)
120 {
121     if ((MCUSR & (1<<WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
122         reset_key = 0;
123
124         // My custom USBasploader requires this to come up.
125         MCUSR = 0;
126
127         // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog.
128         MCUSR &= ~(1<<WDRF);
129         wdt_disable();
130
131         // This is compled into 'icall', address should be in word unit, not byte.
132         ((void (*)(void))(BOOTLOADER_START/2))();
133     }
134 }
135
136
137 #if 0
138 /* Jumping To The Bootloader
139  * http://www.pjrc.com/teensy/jump_to_bootloader.html
140  *
141  * This method doen't work when using LUFA. idk why.
142  * - needs to initialize more regisers or interrupt setting?
143  */
144 void bootloader_jump(void) {
145 #ifdef PROTOCOL_LUFA
146     USB_Disable();
147     cli();
148     _delay_ms(2000);
149 #endif
150
151 #ifdef PROTOCOL_PJRC
152     cli();
153     UDCON = 1;
154     USBCON = (1<<FRZCLK);
155     UCSR1B = 0;
156     _delay_ms(5);
157 #endif
158
159     /*
160      * Initialize
161      */
162 #if defined(__AVR_AT90USB162__)
163     EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0;
164     TIMSK0 = 0; TIMSK1 = 0; UCSR1B = 0;
165     DDRB = 0; DDRC = 0; DDRD = 0;
166     PORTB = 0; PORTC = 0; PORTD = 0;
167 #elif defined(__AVR_ATmega32U4__)
168     EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
169     TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0;
170     DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0;
171     PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
172 #elif defined(__AVR_AT90USB646__)
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 #elif defined(__AVR_AT90USB1286__)
178     EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
179     TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0;
180     DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
181     PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
182 #endif
183
184     /*
185      * USBaspLoader
186      */
187 #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__)
188     // This makes custom USBasploader come up.
189     MCUSR = 0;
190
191     // initialize ports
192     PORTB = 0; PORTC= 0; PORTD = 0;
193     DDRB = 0; DDRC= 0; DDRD = 0;
194
195     // disable interrupts
196     EIMSK = 0; EECR = 0; SPCR = 0;
197     ACSR = 0; SPMCSR = 0; WDTCSR = 0; PCICR = 0;
198     TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0;
199     ADCSRA = 0; TWCR = 0; UCSR0B = 0;
200 #endif
201
202     // This is compled into 'icall', address should be in word unit, not byte.
203     ((void (*)(void))(BOOTLOADER_START/2))();
204 }
205 #endif