You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

293 lines
9.0 KiB

  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. #include <avr/boot.h>
  10. #ifdef PROTOCOL_LUFA
  11. # include <LUFA/Drivers/USB/USB.h>
  12. #endif
  13. /** \brief Bootloader Size in *bytes*
  14. *
  15. * AVR Boot section size are defined by setting BOOTSZ fuse in fact. Consult with your MCU datasheet.
  16. * Note that 'Word'(2 bytes) size and address are used in datasheet while TMK uses 'Byte'.
  17. *
  18. * Size of Bootloaders in bytes:
  19. * Atmel DFU loader(ATmega32U4) 4096
  20. * Atmel DFU loader(AT90USB128) 8192
  21. * LUFA bootloader(ATmega32U4) 4096
  22. * Arduino Caterina(ATmega32U4) 4096
  23. * USBaspLoader(ATmega***) 2048
  24. * Teensy halfKay(ATmega32U4) 512
  25. * Teensy++ halfKay(AT90USB128) 1024
  26. *
  27. * AVR Boot section is located at the end of Flash memory like the followings.
  28. *
  29. * byte Atmel/LUFA(ATMega32u4) byte Atmel(AT90SUB128)
  30. * 0x0000 +---------------+ 0x00000 +---------------+
  31. * | | | |
  32. * | | | |
  33. * | Application | | Application |
  34. * | | | |
  35. * = = = =
  36. * | | 32KB-4KB | | 128KB-8KB
  37. * 0x7000 +---------------+ 0x1E000 +---------------+
  38. * | Bootloader | 4KB | Bootloader | 8KB
  39. * 0x7FFF +---------------+ 0x1FFFF +---------------+
  40. *
  41. *
  42. * byte Teensy(ATMega32u4) byte Teensy++(AT90SUB128)
  43. * 0x0000 +---------------+ 0x00000 +---------------+
  44. * | | | |
  45. * | | | |
  46. * | Application | | Application |
  47. * | | | |
  48. * = = = =
  49. * | | 32KB-512B | | 128KB-1KB
  50. * 0x7E00 +---------------+ 0x1FC00 +---------------+
  51. * | Bootloader | 512B | Bootloader | 1KB
  52. * 0x7FFF +---------------+ 0x1FFFF +---------------+
  53. */
  54. #define FLASH_SIZE (FLASHEND + 1L)
  55. #if !defined(BOOTLOADER_SIZE)
  56. uint16_t bootloader_start;
  57. #endif
  58. // compatibility between ATMega8 and ATMega88
  59. #if !defined(MCUCSR)
  60. # if defined(MCUSR)
  61. # define MCUCSR MCUSR
  62. # endif
  63. #endif
  64. /** \brief Entering the Bootloader via Software
  65. *
  66. * http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html
  67. */
  68. #define BOOTLOADER_RESET_KEY 0xB007B007
  69. uint32_t reset_key __attribute__((section(".noinit,\"aw\",@nobits;")));
  70. /** \brief initialize MCU status by watchdog reset
  71. *
  72. * FIXME: needs doc
  73. */
  74. __attribute__((weak)) void bootloader_jump(void) {
  75. #if !defined(BOOTLOADER_SIZE)
  76. uint8_t high_fuse = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS);
  77. if (high_fuse & ~(FUSE_BOOTSZ0 & FUSE_BOOTSZ1)) {
  78. bootloader_start = (FLASH_SIZE - 512) >> 1;
  79. } else if (high_fuse & ~(FUSE_BOOTSZ1)) {
  80. bootloader_start = (FLASH_SIZE - 1024) >> 1;
  81. } else if (high_fuse & ~(FUSE_BOOTSZ0)) {
  82. bootloader_start = (FLASH_SIZE - 2048) >> 1;
  83. } else {
  84. bootloader_start = (FLASH_SIZE - 4096) >> 1;
  85. }
  86. #endif
  87. // Something like this might work, but it compiled larger than the block above
  88. // bootloader_start = FLASH_SIZE - (256 << (~high_fuse & 0b110 >> 1));
  89. #if defined(BOOTLOADER_HALFKAY)
  90. // http://www.pjrc.com/teensy/jump_to_bootloader.html
  91. cli();
  92. // disable watchdog, if enabled (it's not)
  93. // disable all peripherals
  94. // a shutdown call might make sense here
  95. UDCON = 1;
  96. USBCON = (1 << FRZCLK); // disable USB
  97. UCSR1B = 0;
  98. _delay_ms(5);
  99. # if defined(__AVR_AT90USB162__) // Teensy 1.0
  100. EIMSK = 0;
  101. PCICR = 0;
  102. SPCR = 0;
  103. ACSR = 0;
  104. EECR = 0;
  105. TIMSK0 = 0;
  106. TIMSK1 = 0;
  107. UCSR1B = 0;
  108. DDRB = 0;
  109. DDRC = 0;
  110. DDRD = 0;
  111. PORTB = 0;
  112. PORTC = 0;
  113. PORTD = 0;
  114. asm volatile("jmp 0x3E00");
  115. # elif defined(__AVR_ATmega32U4__) // Teensy 2.0
  116. EIMSK = 0;
  117. PCICR = 0;
  118. SPCR = 0;
  119. ACSR = 0;
  120. EECR = 0;
  121. ADCSRA = 0;
  122. TIMSK0 = 0;
  123. TIMSK1 = 0;
  124. TIMSK3 = 0;
  125. TIMSK4 = 0;
  126. UCSR1B = 0;
  127. TWCR = 0;
  128. DDRB = 0;
  129. DDRC = 0;
  130. DDRD = 0;
  131. DDRE = 0;
  132. DDRF = 0;
  133. TWCR = 0;
  134. PORTB = 0;
  135. PORTC = 0;
  136. PORTD = 0;
  137. PORTE = 0;
  138. PORTF = 0;
  139. asm volatile("jmp 0x7E00");
  140. # elif defined(__AVR_AT90USB646__) // Teensy++ 1.0
  141. EIMSK = 0;
  142. PCICR = 0;
  143. SPCR = 0;
  144. ACSR = 0;
  145. EECR = 0;
  146. ADCSRA = 0;
  147. TIMSK0 = 0;
  148. TIMSK1 = 0;
  149. TIMSK2 = 0;
  150. TIMSK3 = 0;
  151. UCSR1B = 0;
  152. TWCR = 0;
  153. DDRA = 0;
  154. DDRB = 0;
  155. DDRC = 0;
  156. DDRD = 0;
  157. DDRE = 0;
  158. DDRF = 0;
  159. PORTA = 0;
  160. PORTB = 0;
  161. PORTC = 0;
  162. PORTD = 0;
  163. PORTE = 0;
  164. PORTF = 0;
  165. asm volatile("jmp 0xFC00");
  166. # elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0
  167. EIMSK = 0;
  168. PCICR = 0;
  169. SPCR = 0;
  170. ACSR = 0;
  171. EECR = 0;
  172. ADCSRA = 0;
  173. TIMSK0 = 0;
  174. TIMSK1 = 0;
  175. TIMSK2 = 0;
  176. TIMSK3 = 0;
  177. UCSR1B = 0;
  178. TWCR = 0;
  179. DDRA = 0;
  180. DDRB = 0;
  181. DDRC = 0;
  182. DDRD = 0;
  183. DDRE = 0;
  184. DDRF = 0;
  185. PORTA = 0;
  186. PORTB = 0;
  187. PORTC = 0;
  188. PORTD = 0;
  189. PORTE = 0;
  190. PORTF = 0;
  191. asm volatile("jmp 0x1FC00");
  192. # endif
  193. #elif defined(BOOTLOADER_CATERINA)
  194. // this block may be optional
  195. // TODO: figure it out
  196. uint16_t *const bootKeyPtr = (uint16_t *)0x0800;
  197. // Value used by Caterina bootloader use to determine whether to run the
  198. // sketch or the bootloader programmer.
  199. uint16_t bootKey = 0x7777;
  200. *bootKeyPtr = bootKey;
  201. // setup watchdog timeout
  202. wdt_enable(WDTO_60MS);
  203. while (1) {
  204. } // wait for watchdog timer to trigger
  205. #elif defined(BOOTLOADER_USBASP)
  206. // Taken with permission of Stephan Baerwolf from https://github.com/tinyusbboard/API/blob/master/apipage.c
  207. wdt_enable(WDTO_15MS);
  208. wdt_reset();
  209. asm volatile("cli \n\t"
  210. "ldi r29 , %[ramendhi] \n\t"
  211. "ldi r28 , %[ramendlo] \n\t"
  212. # if (FLASHEND > 131071)
  213. "ldi r18 , %[bootaddrhi] \n\t"
  214. "st Y+, r18 \n\t"
  215. # endif
  216. "ldi r18 , %[bootaddrme] \n\t"
  217. "st Y+, r18 \n\t"
  218. "ldi r18 , %[bootaddrlo] \n\t"
  219. "st Y+, r18 \n\t"
  220. "out %[mcucsrio], __zero_reg__ \n\t"
  221. "bootloader_startup_loop%=: \n\t"
  222. "rjmp bootloader_startup_loop%= \n\t"
  223. :
  224. : [mcucsrio] "I"(_SFR_IO_ADDR(MCUCSR)),
  225. # if (FLASHEND > 131071)
  226. [ramendhi] "M"(((RAMEND - 2) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 2) >> 0) & 0xff), [bootaddrhi] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 16) & 0xff),
  227. # else
  228. [ramendhi] "M"(((RAMEND - 1) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 1) >> 0) & 0xff),
  229. # endif
  230. [bootaddrme] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 8) & 0xff), [bootaddrlo] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 0) & 0xff));
  231. #else // Assume remaining boards are DFU, even if the flag isn't set
  232. # if !(defined(__AVR_ATmega32A__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATtiny85__)) // no USB - maybe BOOTLOADER_BOOTLOADHID instead though?
  233. UDCON = 1;
  234. USBCON = (1 << FRZCLK); // disable USB
  235. UCSR1B = 0;
  236. _delay_ms(5); // 5 seems to work fine
  237. # endif
  238. # ifdef BOOTLOADER_BOOTLOADHID
  239. // force bootloadHID to stay in bootloader mode, so that it waits
  240. // for a new firmware to be flashed
  241. eeprom_write_byte((uint8_t *)1, 0x00);
  242. # endif
  243. // watchdog reset
  244. reset_key = BOOTLOADER_RESET_KEY;
  245. wdt_enable(WDTO_250MS);
  246. for (;;)
  247. ;
  248. #endif
  249. }
  250. /* this runs before main() */
  251. void bootloader_jump_after_watchdog_reset(void) __attribute__((used, naked, section(".init3")));
  252. void bootloader_jump_after_watchdog_reset(void) {
  253. #ifndef BOOTLOADER_HALFKAY
  254. if ((MCUCSR & (1 << WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
  255. reset_key = 0;
  256. // My custom USBasploader requires this to come up.
  257. MCUCSR = 0;
  258. // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog.
  259. MCUCSR &= ~(1 << WDRF);
  260. wdt_disable();
  261. // This is compled into 'icall', address should be in word unit, not byte.
  262. # ifdef BOOTLOADER_SIZE
  263. ((void (*)(void))((FLASH_SIZE - BOOTLOADER_SIZE) >> 1))();
  264. # else
  265. asm("ijmp" ::"z"(bootloader_start));
  266. # endif
  267. }
  268. #endif
  269. }