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.

510 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)
  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(20);
  108. }
  109. static void i2c_print_version(uint8_t i2c_dev)
  110. {
  111. i2c_start_address(i2c_dev);
  112. i2c_master_tx(CMD_READ_VERSION);
  113. i2c_start_address(i2c_dev | 0x01);
  114. uint8_t cnt = 16;
  115. while (cnt--) {
  116. sendchar(i2c_master_rx(cnt));
  117. }
  118. i2c_stop();
  119. }
  120. static uint8_t page_buf[SPM_PAGESIZE];
  121. static void eraseFlash(void)
  122. {
  123. uint16_t address = 0;
  124. while (APP_END < address) {
  125. boot_page_erase(address);
  126. boot_spm_busy_wait();
  127. address += SPM_PAGESIZE;
  128. }
  129. boot_rww_enable();
  130. }
  131. static void writeFlashPage(uint16_t address, uint16_t size)
  132. {
  133. uint16_t pagestart = address;
  134. uint16_t data;
  135. uint8_t *tmp = page_buf;
  136. do {
  137. data = *tmp++;
  138. data |= *tmp++ << 8;
  139. boot_page_fill(address, data);
  140. address += 2;
  141. size -= 2;
  142. } while (size);
  143. boot_page_write(pagestart);
  144. boot_spm_busy_wait();
  145. boot_rww_enable();
  146. }
  147. static void writeEEpromPage(uint16_t address, uint16_t size)
  148. {
  149. uint8_t *tmp = page_buf;
  150. do {
  151. EEARL = address;
  152. EEARH = (address >> 8);
  153. EEDR = *tmp++;
  154. address++;
  155. EECR |= (1<<EEMPE);
  156. EECR |= (1<<EEPE);
  157. eeprom_busy_wait();
  158. size--;
  159. } while (size);
  160. }
  161. static void readFlashPage(uint16_t address, uint16_t size)
  162. {
  163. uint16_t data;
  164. do {
  165. data = pgm_read_word_near(address);
  166. sendchar(data);
  167. sendchar((data >> 8));
  168. address += 2;
  169. size -= 2;
  170. } while (size);
  171. }
  172. static void readEEpromPage(uint16_t address, uint16_t size)
  173. {
  174. do {
  175. EEARL = address;
  176. EEARH = (address >> 8);
  177. EECR |= (1<<EERE);
  178. address++;
  179. sendchar(EEDR);
  180. size--;
  181. } while (size);
  182. }
  183. /* 0-2: signature, 3: pagesize, 4-5: flash size, 6-7: eeprom size */
  184. static uint8_t chipinfo[8];
  185. void cmd_loop(uint8_t val)
  186. {
  187. uint16_t address = 0;
  188. uint16_t page_size = 0;
  189. uint8_t i2c_dev = 0;
  190. while (1) {
  191. uint8_t response = 0xFF;
  192. // Autoincrement?
  193. if (val == 'a') {
  194. response = 'Y';
  195. // write address
  196. } else if (val == 'A') {
  197. address = recvchar();
  198. address = (address << 8) | recvchar();
  199. response = '\r';
  200. // Buffer load support
  201. } else if (val == 'b') {
  202. sendchar('Y');
  203. page_size = (i2c_dev == 0) ? sizeof(page_buf) : chipinfo[3];
  204. sendchar((page_size >> 8) & 0xFF);
  205. response = page_size & 0Xff;
  206. // Start buffer load
  207. } else if (val == 'B') {
  208. uint16_t size;
  209. uint16_t cnt;
  210. uint8_t *tmp = page_buf;
  211. size = recvchar() << 8;
  212. size |= recvchar();
  213. val = recvchar();
  214. for (cnt = 0; cnt < page_size; cnt++)
  215. *tmp++ = (cnt < size) ? recvchar() : 0xFF;
  216. if (i2c_dev != 0) {
  217. i2c_start_address(i2c_dev);
  218. i2c_master_tx(CMD_WRITE_MEMORY);
  219. i2c_master_tx((val == 'F') ? MEMTYPE_FLASH : MEMTYPE_EEPROM);
  220. i2c_master_tx(address >> 8);
  221. i2c_master_tx(address & 0xFF);
  222. address += page_size;
  223. tmp = page_buf;
  224. while (cnt--)
  225. i2c_master_tx(*tmp++);
  226. i2c_stop();
  227. } else {
  228. if (val == 'F') {
  229. writeFlashPage(address, size);
  230. } else if (val == 'E') {
  231. writeEEpromPage(address, size);
  232. }
  233. address += size;
  234. }
  235. response = '\r';
  236. // Block read
  237. } else if (val == 'g') {
  238. uint16_t size = recvchar() << 8;
  239. size |= recvchar();
  240. val = recvchar();
  241. if (i2c_dev != 0) {
  242. i2c_start_address(i2c_dev);
  243. i2c_master_tx(CMD_READ_MEMORY);
  244. i2c_master_tx((val == 'F') ? MEMTYPE_FLASH : MEMTYPE_EEPROM);
  245. i2c_master_tx(address >> 8);
  246. i2c_master_tx(address & 0xFF);
  247. i2c_start_address(i2c_dev | 0x01);
  248. while (size--) {
  249. sendchar(i2c_master_rx(size > 0));
  250. address++;
  251. }
  252. i2c_stop();
  253. } else {
  254. if (val == 'F') {
  255. readFlashPage(address, size);
  256. } else if (val == 'E') {
  257. readEEpromPage(address, size);
  258. }
  259. address += size;
  260. }
  261. // Chip erase
  262. } else if (val == 'e') {
  263. if (i2c_dev == 0) {
  264. eraseFlash();
  265. }
  266. response = '\r';
  267. // Exit upgrade
  268. } else if (val == 'E') {
  269. sendchar('\r');
  270. if (i2c_dev == 0) {
  271. return;
  272. }
  273. // Enter / Leave programming mode
  274. } else if (val == 'P' || val == 'L') {
  275. if (i2c_dev != 0) {
  276. val = (val == 'P') ? BOOTTYPE_BOOTLOADER : BOOTTYPE_APPLICATION;
  277. i2c_switch_app(i2c_dev, val);
  278. }
  279. response = '\r';
  280. // return programmer type
  281. } else if (val == 'p') {
  282. response = 'S';
  283. // Return device type
  284. } else if (val == 't') {
  285. sendchar((i2c_dev == 0) ? OWN_DEVCODE : TWI_DEVCODE);
  286. response = '\0';
  287. // clear and set LED ignored
  288. } else if ((val == 'x') || (val == 'y') || (val == 'T')) {
  289. recvchar();
  290. response = '\r';
  291. // Return software identifier
  292. } else if (val == 'S') {
  293. sendchar('F');
  294. sendchar('C');
  295. sendchar('_');
  296. sendchar('B');
  297. sendchar('O');
  298. sendchar('O');
  299. response = 'T';
  300. // Return Software Version
  301. } else if (val == 'V' || val == 'v') {
  302. sendchar('0');
  303. response = '8';
  304. // Return Signature Bytes
  305. } else if (val == 's') {
  306. if (i2c_dev != 0) {
  307. sendchar(chipinfo[2]);
  308. sendchar(chipinfo[1]);
  309. response = chipinfo[0];
  310. } else {
  311. uint8_t sig[3] = OWN_SIGNATURE;
  312. sendchar(sig[2]);
  313. sendchar(sig[1]);
  314. response = sig[0];
  315. }
  316. // set i2c target
  317. } else if (val == '0') {
  318. i2c_dev = 0;
  319. } else if (val >= '1' && val <= '4') {
  320. i2c_dev = (val - '0' + TWI_ADDRESS_BASE) << 1;
  321. i2c_switch_app(i2c_dev, BOOTTYPE_BOOTLOADER);
  322. _delay_ms(100);
  323. i2c_print_version(i2c_dev);
  324. i2c_start_address(i2c_dev);
  325. i2c_master_tx(CMD_READ_MEMORY);
  326. i2c_master_tx(MEMTYPE_CHIPINFO);
  327. i2c_master_tx(0x00);
  328. i2c_master_tx(0x00);
  329. i2c_start_address(i2c_dev | 0x01);
  330. uint8_t i;
  331. for (i = 0; i < sizeof(chipinfo); i++) {
  332. uint8_t more = (i < (sizeof(chipinfo) -1));
  333. chipinfo[i] = i2c_master_rx(more);
  334. }
  335. i2c_stop();
  336. // test props
  337. } else if (val == 'k' || val == 'l') {
  338. if (i2c_dev != 0) {
  339. i2c_start_address(i2c_dev);
  340. i2c_master_tx(0x00 + (val - 'k') * 0x10);
  341. i2c_stop();
  342. response = val;
  343. }
  344. // get Version
  345. } else if (val == 'I') {
  346. if (i2c_dev != 0) {
  347. i2c_switch_app(i2c_dev, BOOTTYPE_APPLICATION);
  348. _delay_ms(100);
  349. i2c_print_version(i2c_dev);
  350. }
  351. // fake MK-TOOL specific stuff
  352. } else if (val == 0xAA) {
  353. sendchar('M');
  354. sendchar('K');
  355. sendchar('B');
  356. response = 'L';
  357. /* ESC */
  358. } else if (val != 0x1b) {
  359. response = '?';
  360. }
  361. if (response != 0xFF) {
  362. sendchar(response);
  363. }
  364. val = recvchar();
  365. }
  366. }
  367. static void (*jump_to_app)(void) __attribute__ ((noreturn)) = 0x0000;
  368. /*
  369. * For newer devices the watchdog timer remains active even after a
  370. * system reset. So disable it as soon as possible.
  371. * automagically called on startup
  372. */
  373. void disable_wdt_timer(void) __attribute__((naked, section(".init3")));
  374. void disable_wdt_timer(void)
  375. {
  376. MCUSR = 0;
  377. WDTCSR = (1<<WDCE) | (1<<WDE);
  378. WDTCSR = (0<<WDE);
  379. }
  380. /* linking without vectors, still need __vector_default */
  381. void __vector_default(void) {}
  382. int main(void) __attribute__ ((noreturn));
  383. int main(void)
  384. {
  385. DDRB = LED_GN | LED_RT;
  386. PORTB = LED_RT;
  387. /* Set baudrate */
  388. UBRR0H = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF;
  389. UBRR0L = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF);
  390. /* USART: rx/tx enable, 8n1 */
  391. UCSR0B = (1<<TXEN0) | (1<<RXEN0);
  392. UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
  393. /* enable TWI interface */
  394. TWBR = ((F_CPU/TWI_CLK)-16)/2;
  395. TWCR = (1<<TWSTO) | (1<<TWEN);
  396. uint8_t prev = 0x00;
  397. uint8_t boot_timeout = 100;
  398. while (boot_timeout-- > 0) {
  399. if (UCSR0A & (1<<RXC0)) {
  400. uint8_t val = recvchar();
  401. if (prev == 0x1B && (val == 0xAA || val == 'S')) {
  402. PORTB |= LED_GN;
  403. cmd_loop(val);
  404. boot_timeout = 0;
  405. }
  406. prev = val;
  407. }
  408. _delay_ms(10);
  409. if (!(boot_timeout & 0x03))
  410. PORTB ^= LED_GN;
  411. }
  412. PORTB = LED_RT;
  413. jump_to_app();
  414. }