]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/common/avr/bootloader.c
Add 'quantum/visualizer/' from commit 'bde869aa7ec8601459bc63b9636081d21108d1be'
[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  * 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     // watchdog reset
91     reset_key = BOOTLOADER_RESET_KEY;
92     wdt_enable(WDTO_250MS);
93     for (;;);
94 }
95
96
97 /* this runs before main() */
98 void bootloader_jump_after_watchdog_reset(void) __attribute__ ((used, naked, section (".init3")));
99 void bootloader_jump_after_watchdog_reset(void)
100 {
101     if ((MCUSR & (1<<WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
102         reset_key = 0;
103
104         // My custom USBasploader requires this to come up.
105         MCUSR = 0;
106
107         // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog.
108         MCUSR &= ~(1<<WDRF);
109         wdt_disable();
110
111         // This is compled into 'icall', address should be in word unit, not byte.
112         ((void (*)(void))(BOOTLOADER_START/2))();
113     }
114 }
115
116
117 #if 0
118 /* Jumping To The Bootloader
119  * http://www.pjrc.com/teensy/jump_to_bootloader.html
120  * 
121  * This method doen't work when using LUFA. idk why.
122  * - needs to initialize more regisers or interrupt setting?
123  */
124 void bootloader_jump(void) {
125 #ifdef PROTOCOL_LUFA
126     USB_Disable();
127     cli();
128     _delay_ms(2000);
129 #endif
130
131 #ifdef PROTOCOL_PJRC
132     cli();
133     UDCON = 1;
134     USBCON = (1<<FRZCLK);
135     UCSR1B = 0;
136     _delay_ms(5);
137 #endif
138
139     /*
140      * Initialize
141      */
142 #if defined(__AVR_AT90USB162__)
143     EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0;
144     TIMSK0 = 0; TIMSK1 = 0; UCSR1B = 0;
145     DDRB = 0; DDRC = 0; DDRD = 0;
146     PORTB = 0; PORTC = 0; PORTD = 0;
147 #elif defined(__AVR_ATmega32U4__)
148     EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
149     TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0;
150     DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0;
151     PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
152 #elif defined(__AVR_AT90USB646__)
153     EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
154     TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0;
155     DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
156     PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
157 #elif defined(__AVR_AT90USB1286__)
158     EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
159     TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0;
160     DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
161     PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
162 #endif
163
164     /*
165      * USBaspLoader
166      */
167 #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__)
168     // This makes custom USBasploader come up.
169     MCUSR = 0;
170
171     // initialize ports
172     PORTB = 0; PORTC= 0; PORTD = 0;
173     DDRB = 0; DDRC= 0; DDRD = 0;
174
175     // disable interrupts
176     EIMSK = 0; EECR = 0; SPCR = 0;
177     ACSR = 0; SPMCSR = 0; WDTCSR = 0; PCICR = 0;
178     TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0;
179     ADCSRA = 0; TWCR = 0; UCSR0B = 0;
180 #endif
181
182     // This is compled into 'icall', address should be in word unit, not byte.
183     ((void (*)(void))(BOOTLOADER_START/2))();
184 }
185 #endif