AVR Bootloader for MK-FlightCtrl
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.

12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. /***************************************************************************
  2. * Copyright (C) 09/2007 by Olaf Rempel *
  3. * razzor@kopf-tisch.de *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; version 2 of the License, *
  8. * *
  9. * This program is distributed in the hope that it will be useful, *
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  12. * GNU General Public License for more details. *
  13. * *
  14. * You should have received a copy of the GNU General Public License *
  15. * along with this program; if not, write to the *
  16. * Free Software Foundation, Inc., *
  17. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  18. ***************************************************************************/
  19. #include <avr/io.h>
  20. #include <avr/interrupt.h>
  21. #include <avr/boot.h>
  22. #include <avr/pgmspace.h>
  23. #include <avr/wdt.h>
  24. /*
  25. * ATMega 644P:
  26. * Fuse E: 0xFD (2.7V BOD)
  27. * Fuse H: 0xDC (1024 words bootloader)
  28. * Fuse L: 0xFF (ext. Crystal)
  29. */
  30. #define F_CPU 20000000
  31. #include <util/delay.h>
  32. #define BAUDRATE 57600
  33. #define UART_CALC_BAUDRATE(baudRate) ((uint32_t)(F_CPU) / ((uint32_t)(baudRate)*16) -1)
  34. #define APP_END 0xF7FF
  35. #define LED_RT (1<<PORTB0) /* low active */
  36. #define LED_GN (1<<PORTB1) /* high active */
  37. #define TWI_CLK 100000
  38. #define TWI_ADDRESS_BASE 0x28 /* 0x29 - 0x2C */
  39. #define TWI_DEVCODE 0x76 /* Mega8 */
  40. #define OWN_DEVCODE 0x74 /* Mega644 */
  41. #define OWN_SIGNATURE { 0x1E, 0x96, 0x0A } /* Mega644P */
  42. /* SLA+R */
  43. #define CMD_WAIT 0x00
  44. #define CMD_READ_VERSION 0x01
  45. #define CMD_READ_MEMORY 0x02
  46. /* SLA+W */
  47. #define CMD_SWITCH_APPLICATION CMD_READ_VERSION
  48. #define CMD_WRITE_MEMORY CMD_READ_MEMORY
  49. /* CMD_SWITCH_APPLICATION parameter */
  50. #define BOOTTYPE_BOOTLOADER 0x00
  51. #define BOOTTYPE_APPLICATION 0x80
  52. /* CMD_{READ|WRITE}_* parameter */
  53. #define MEMTYPE_CHIPINFO 0x00
  54. #define MEMTYPE_FLASH 0x01
  55. #define MEMTYPE_EEPROM 0x02
  56. #define MEMTYPE_PARAMETERS 0x03
  57. static void sendchar(uint8_t data)
  58. {
  59. loop_until_bit_is_set(UCSR0A, UDRE0);
  60. UDR0 = data;
  61. }
  62. static uint8_t recvchar(void)
  63. {
  64. loop_until_bit_is_set(UCSR0A, RXC0);
  65. return UDR0;
  66. }
  67. static void i2c_master_tx(uint8_t val)
  68. {
  69. TWDR = val;
  70. TWCR = (1<<TWINT) | (1<<TWEN);
  71. loop_until_bit_is_set(TWCR, TWINT);
  72. }
  73. static uint8_t i2c_master_rx(uint8_t ack)
  74. {
  75. if (ack)
  76. TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
  77. else
  78. TWCR = (1<<TWINT) | (1<<TWEN);
  79. loop_until_bit_is_set(TWCR, TWINT);
  80. return TWDR;
  81. }
  82. static void i2c_stop(void)
  83. {
  84. PORTB |= LED_RT;
  85. TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
  86. }
  87. static void i2c_start_address(uint8_t addr)
  88. {
  89. while (1) {
  90. PORTB &= ~LED_RT;
  91. TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
  92. loop_until_bit_is_set(TWCR, TWINT);
  93. i2c_master_tx(addr);
  94. uint8_t status = (TWSR & 0xF8);
  95. if (status == 0x18 || status == 0x40)
  96. break;
  97. i2c_stop();
  98. _delay_ms(1);
  99. }
  100. }
  101. static void i2c_switch_app(uint8_t i2c_dev, uint8_t app, uint8_t show_version)
  102. {
  103. i2c_start_address(i2c_dev);
  104. i2c_master_tx(CMD_SWITCH_APPLICATION);
  105. i2c_master_tx(app);
  106. i2c_stop();
  107. _delay_ms(100);
  108. if (show_version) {
  109. i2c_start_address(i2c_dev);
  110. i2c_master_tx(CMD_READ_VERSION);
  111. i2c_start_address(i2c_dev | 0x01);
  112. uint8_t cnt = 16;
  113. while (cnt--) {
  114. sendchar(i2c_master_rx(cnt));
  115. }
  116. i2c_stop();
  117. }
  118. }
  119. static uint8_t page_buf[SPM_PAGESIZE];
  120. static void eraseFlash(void)
  121. {
  122. uint16_t address = 0;
  123. while (APP_END > address) {
  124. boot_page_erase(address);
  125. boot_spm_busy_wait();
  126. address += SPM_PAGESIZE;
  127. }
  128. boot_rww_enable();
  129. }
  130. static void writeFlashPage(uint16_t address, uint16_t size)
  131. {
  132. uint16_t pagestart = address;
  133. uint16_t data;
  134. uint8_t *tmp = page_buf;
  135. do {
  136. data = *tmp++;
  137. data |= *tmp++ << 8;
  138. boot_page_fill(address, data);
  139. address += 2;
  140. size -= 2;
  141. } while (size);
  142. boot_page_write(pagestart);
  143. boot_spm_busy_wait();
  144. boot_rww_enable();
  145. }
  146. static void writeEEpromPage(uint16_t address, uint16_t size)
  147. {
  148. uint8_t *tmp = page_buf;
  149. do {
  150. EEARL = address;
  151. EEARH = (address >> 8);
  152. EEDR = *tmp++;
  153. address++;
  154. EECR |= (1<<EEMPE);
  155. EECR |= (1<<EEPE);
  156. eeprom_busy_wait();
  157. size--;
  158. } while (size);
  159. }
  160. static void readFlashPage(uint16_t address, uint16_t size)
  161. {
  162. uint16_t data;
  163. do {
  164. data = pgm_read_word_near(address);
  165. sendchar(data);
  166. sendchar((data >> 8));
  167. address += 2;
  168. size -= 2;
  169. } while (size);
  170. }
  171. static void readEEpromPage(uint16_t address, uint16_t size)
  172. {
  173. do {
  174. EEARL = address;
  175. EEARH = (address >> 8);
  176. EECR |= (1<<EERE);
  177. address++;
  178. sendchar(EEDR);
  179. size--;
  180. } while (size);
  181. }
  182. /* 0-2: signature, 3: pagesize, 4-5: flash size, 6-7: eeprom size */
  183. static uint8_t chipinfo[8];
  184. void cmd_loop(uint8_t val)
  185. {
  186. uint16_t address = 0;
  187. uint16_t page_size = 0;
  188. uint8_t i2c_dev = 0;
  189. while (1) {
  190. uint8_t response = 0xFF;
  191. // Autoincrement?
  192. if (val == 'a') {
  193. response = 'Y';
  194. // write address
  195. } else if (val == 'A') {
  196. address = recvchar();
  197. address = (address << 8) | recvchar();
  198. response = '\r';
  199. // Buffer load support
  200. } else if (val == 'b') {
  201. sendchar('Y');
  202. page_size = (i2c_dev == 0) ? sizeof(page_buf) : chipinfo[3];
  203. sendchar((page_size >> 8) & 0xFF);
  204. response = page_size & 0Xff;
  205. // Start buffer load
  206. } else if (val == 'B') {
  207. uint16_t size;
  208. uint16_t cnt;
  209. uint8_t *tmp = page_buf;
  210. size = recvchar() << 8;
  211. size |= recvchar();
  212. val = recvchar();
  213. for (cnt = 0; cnt < page_size; cnt++)
  214. *tmp++ = (cnt < size) ? recvchar() : 0xFF;
  215. if (i2c_dev != 0) {
  216. i2c_start_address(i2c_dev);
  217. i2c_master_tx(CMD_WRITE_MEMORY);
  218. i2c_master_tx((val == 'F') ? MEMTYPE_FLASH : MEMTYPE_EEPROM);
  219. i2c_master_tx(address >> 8);
  220. i2c_master_tx(address & 0xFF);
  221. address += page_size;
  222. tmp = page_buf;
  223. while (cnt--)
  224. i2c_master_tx(*tmp++);
  225. i2c_stop();
  226. } else {
  227. if (val == 'F' && address < APP_END) {
  228. writeFlashPage(address, size);
  229. } else if (val == 'E' && address < E2END) {
  230. writeEEpromPage(address, size);
  231. }
  232. address += size;
  233. }
  234. response = '\r';
  235. // Block read
  236. } else if (val == 'g') {
  237. uint16_t size = recvchar() << 8;
  238. size |= recvchar();
  239. val = recvchar();
  240. if (i2c_dev != 0) {
  241. i2c_start_address(i2c_dev);
  242. i2c_master_tx(CMD_READ_MEMORY);
  243. i2c_master_tx((val == 'F') ? MEMTYPE_FLASH : MEMTYPE_EEPROM);
  244. i2c_master_tx(address >> 8);
  245. i2c_master_tx(address & 0xFF);
  246. i2c_start_address(i2c_dev | 0x01);
  247. while (size--) {
  248. sendchar(i2c_master_rx(size > 0));
  249. address++;
  250. }
  251. i2c_stop();
  252. } else {
  253. if (val == 'F') {
  254. readFlashPage(address, size);
  255. } else if (val == 'E') {
  256. readEEpromPage(address, size);
  257. }
  258. address += size;
  259. }
  260. // Chip erase
  261. } else if (val == 'e') {
  262. if (i2c_dev == 0) {
  263. eraseFlash();
  264. }
  265. response = '\r';
  266. // Exit upgrade
  267. } else if (val == 'E') {
  268. sendchar('\r');
  269. if (i2c_dev == 0) {
  270. return;
  271. }
  272. // Enter / Leave programming mode
  273. } else if (val == 'P' || val == 'L') {
  274. if (i2c_dev != 0) {
  275. val = (val == 'P') ? BOOTTYPE_BOOTLOADER : BOOTTYPE_APPLICATION;
  276. i2c_switch_app(i2c_dev, val, 0);
  277. }
  278. response = '\r';
  279. // return programmer type
  280. } else if (val == 'p') {
  281. response = 'S';
  282. // Return device type
  283. } else if (val == 't') {
  284. sendchar((i2c_dev == 0) ? OWN_DEVCODE : TWI_DEVCODE);
  285. response = '\0';
  286. // clear and set LED ignored
  287. } else if ((val == 'x') || (val == 'y') || (val == 'T')) {
  288. recvchar();
  289. response = '\r';
  290. // Return software identifier
  291. } else if (val == 'S') {
  292. sendchar('F');
  293. sendchar('C');
  294. sendchar('_');
  295. sendchar('B');
  296. sendchar('O');
  297. sendchar('O');
  298. response = 'T';
  299. // Return Software Version
  300. } else if (val == 'V' || val == 'v') {
  301. sendchar('0');
  302. response = '8';
  303. // Return Signature Bytes
  304. } else if (val == 's') {
  305. if (i2c_dev != 0) {
  306. sendchar(chipinfo[2]);
  307. sendchar(chipinfo[1]);
  308. response = chipinfo[0];
  309. } else {
  310. uint8_t sig[3] = OWN_SIGNATURE;
  311. sendchar(sig[2]);
  312. sendchar(sig[1]);
  313. response = sig[0];
  314. }
  315. // set i2c target
  316. } else if (val == '0') {
  317. i2c_dev = 0;
  318. } else if (val >= '1' && val <= '4') {
  319. i2c_dev = (val - '0' + TWI_ADDRESS_BASE) << 1;
  320. i2c_switch_app(i2c_dev, BOOTTYPE_BOOTLOADER, 1);
  321. i2c_start_address(i2c_dev);
  322. i2c_master_tx(CMD_READ_MEMORY);
  323. i2c_master_tx(MEMTYPE_CHIPINFO);
  324. i2c_master_tx(0x00);
  325. i2c_master_tx(0x00);
  326. i2c_start_address(i2c_dev | 0x01);
  327. uint8_t i;
  328. for (i = 0; i < sizeof(chipinfo); i++) {
  329. uint8_t more = (i < (sizeof(chipinfo) -1));
  330. chipinfo[i] = i2c_master_rx(more);
  331. }
  332. i2c_stop();
  333. // test props
  334. } else if (val == 'k' || val == 'l') {
  335. if (i2c_dev != 0) {
  336. i2c_start_address(i2c_dev);
  337. i2c_master_tx(0x00 + (val - 'k') * 0x10);
  338. i2c_stop();
  339. response = val;
  340. }
  341. // get Version
  342. } else if (val == 'I') {
  343. if (i2c_dev != 0) {
  344. i2c_switch_app(i2c_dev, BOOTTYPE_APPLICATION, 1);
  345. }
  346. // fake MK-TOOL specific stuff
  347. } else if (val == 0xAA) {
  348. sendchar('M');
  349. sendchar('K');
  350. sendchar('B');
  351. response = 'L';
  352. /* ESC */
  353. } else if (val != 0x1b) {
  354. response = '?';
  355. }
  356. if (response != 0xFF) {
  357. sendchar(response);
  358. }
  359. val = recvchar();
  360. }
  361. }
  362. static void (*jump_to_app)(void) __attribute__ ((noreturn)) = 0x0000;
  363. /*
  364. * For newer devices the watchdog timer remains active even after a
  365. * system reset. So disable it as soon as possible.
  366. * automagically called on startup
  367. */
  368. void disable_wdt_timer(void) __attribute__((naked, section(".init3")));
  369. void disable_wdt_timer(void)
  370. {
  371. MCUSR = 0;
  372. WDTCSR = (1<<WDCE) | (1<<WDE);
  373. WDTCSR = (0<<WDE);
  374. }
  375. /* linking without vectors, still need __vector_default */
  376. void __vector_default(void) {}
  377. int main(void) __attribute__ ((noreturn));
  378. int main(void)
  379. {
  380. DDRB = LED_GN | LED_RT;
  381. PORTB = LED_RT;
  382. /* Set baudrate */
  383. UBRR0H = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF;
  384. UBRR0L = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF);
  385. /* USART: rx/tx enable, 8n1 */
  386. UCSR0B = (1<<TXEN0) | (1<<RXEN0);
  387. UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
  388. /* enable TWI interface */
  389. TWBR = ((F_CPU/TWI_CLK)-16)/2;
  390. TWCR = (1<<TWSTO) | (1<<TWEN);
  391. uint8_t prev = 0x00;
  392. uint8_t boot_timeout = 100;
  393. while (boot_timeout-- > 0) {
  394. if (UCSR0A & (1<<RXC0)) {
  395. uint8_t val = recvchar();
  396. if (prev == 0x1B && (val == 0xAA || val == 'S')) {
  397. PORTB |= LED_GN;
  398. cmd_loop(val);
  399. boot_timeout = 0;
  400. }
  401. prev = val;
  402. }
  403. _delay_ms(10);
  404. if (!(boot_timeout & 0x03))
  405. PORTB ^= LED_GN;
  406. }
  407. PORTB = LED_RT;
  408. jump_to_app();
  409. }