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.

505 lines
11KB

  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. }