A TWI / I2C bootloader for AVR MCUs
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
9 years ago
9 years ago
9 years ago
5 years ago
5 years ago
12 years ago
5 years ago
5 years ago
12 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
12 years ago
12 years ago
9 years ago
12 years ago
9 years ago
12 years ago
9 years ago
12 years ago
12 years ago
9 years ago
12 years ago
9 years ago
12 years ago
9 years ago
12 years ago
12 years ago
9 years ago
12 years ago
9 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
9 years ago
9 years ago
9 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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. /***************************************************************************
  2. * Copyright (C) 11/2019 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. #define VERSION_STRING "TWIBOOT v2.1"
  24. #define EEPROM_SUPPORT 1
  25. #define LED_SUPPORT 1
  26. /* 25ms @8MHz */
  27. #define TIMER_RELOAD (0xFF - 195)
  28. /* 40 * 25ms */
  29. #define TIMEOUT 40
  30. #if LED_SUPPORT
  31. #define LED_INIT() DDRB = ((1<<PORTB4) | (1<<PORTB5))
  32. #define LED_RT_ON() PORTB |= (1<<PORTB4)
  33. #define LED_RT_OFF() PORTB &= ~(1<<PORTB4)
  34. #define LED_GN_ON() PORTB |= (1<<PORTB5)
  35. #define LED_GN_OFF() PORTB &= ~(1<<PORTB5)
  36. #define LED_GN_TOGGLE() PORTB ^= (1<<PORTB5)
  37. #define LED_OFF() PORTB = 0x00
  38. #else
  39. #define LED_INIT()
  40. #define LED_RT_ON()
  41. #define LED_RT_OFF()
  42. #define LED_GN_ON()
  43. #define LED_GN_OFF()
  44. #define LED_GN_TOGGLE()
  45. #define LED_OFF()
  46. #endif
  47. #ifndef TWI_ADDRESS
  48. #define TWI_ADDRESS 0x29
  49. #endif
  50. /* SLA+R */
  51. #define CMD_WAIT 0x00
  52. #define CMD_READ_VERSION 0x01
  53. #define CMD_READ_MEMORY 0x02
  54. /* internal mappings */
  55. #define CMD_READ_CHIPINFO (0x10 | CMD_READ_MEMORY)
  56. #define CMD_READ_FLASH (0x20 | CMD_READ_MEMORY)
  57. #define CMD_READ_EEPROM (0x30 | CMD_READ_MEMORY)
  58. #define CMD_READ_PARAMETERS (0x40 | CMD_READ_MEMORY) /* only in APP */
  59. /* SLA+W */
  60. #define CMD_SWITCH_APPLICATION CMD_READ_VERSION
  61. #define CMD_WRITE_MEMORY CMD_READ_MEMORY
  62. /* internal mappings */
  63. #define CMD_BOOT_BOOTLOADER (0x10 | CMD_SWITCH_APPLICATION) /* only in APP */
  64. #define CMD_BOOT_APPLICATION (0x20 | CMD_SWITCH_APPLICATION)
  65. #define CMD_WRITE_CHIPINFO (0x10 | CMD_WRITE_MEMORY) /* invalid */
  66. #define CMD_WRITE_FLASH (0x20 | CMD_WRITE_MEMORY)
  67. #define CMD_WRITE_EEPROM (0x30 | CMD_WRITE_MEMORY)
  68. #define CMD_WRITE_PARAMETERS (0x40 | CMD_WRITE_MEMORY) /* only in APP */
  69. /* CMD_SWITCH_APPLICATION parameter */
  70. #define BOOTTYPE_BOOTLOADER 0x00 /* only in APP */
  71. #define BOOTTYPE_APPLICATION 0x80
  72. /* CMD_{READ|WRITE}_* parameter */
  73. #define MEMTYPE_CHIPINFO 0x00
  74. #define MEMTYPE_FLASH 0x01
  75. #define MEMTYPE_EEPROM 0x02
  76. #define MEMTYPE_PARAMETERS 0x03 /* only in APP */
  77. /*
  78. * LED_GN flashes with 20Hz (while bootloader is running)
  79. * LED_RT flashes on TWI activity
  80. *
  81. * bootloader twi-protocol:
  82. * - abort boot timeout:
  83. * SLA+W, 0x00, STO
  84. *
  85. * - show bootloader version
  86. * SLA+W, 0x01, SLA+R, {16 bytes}, STO
  87. *
  88. * - start application
  89. * SLA+W, 0x01, 0x80, STO
  90. *
  91. * - read chip info: 3byte signature, 1byte page size, 2byte flash size, 2byte eeprom size
  92. * SLA+W, 0x02, 0x00, 0x00, 0x00, SLA+R, {8 bytes}, STO
  93. *
  94. * - read one (or more) flash bytes
  95. * SLA+W, 0x02, 0x01, addrh, addrl, SLA+R, {* bytes}, STO
  96. *
  97. * - read one (or more) eeprom bytes
  98. * SLA+W, 0x02, 0x02, addrh, addrl, SLA+R, {* bytes}, STO
  99. *
  100. * - write one flash page
  101. * SLA+W, 0x02, 0x01, addrh, addrl, {* bytes}, STO
  102. *
  103. * - write one (or more) eeprom bytes
  104. * SLA+W, 0x02, 0x02, addrh, addrl, {* bytes}, STO
  105. */
  106. const static uint8_t info[16] = VERSION_STRING;
  107. const static uint8_t chipinfo[8] = {
  108. SIGNATURE_0, SIGNATURE_1, SIGNATURE_2,
  109. SPM_PAGESIZE,
  110. (BOOTLOADER_START >> 8) & 0xFF,
  111. BOOTLOADER_START & 0xFF,
  112. #if (EEPROM_SUPPORT)
  113. ((E2END +1) >> 8 & 0xFF),
  114. (E2END +1) & 0xFF
  115. #else
  116. 0x00, 0x00
  117. #endif
  118. };
  119. /* wait 40 * 25ms = 1s */
  120. static uint8_t boot_timeout = TIMEOUT;
  121. static uint8_t cmd = CMD_WAIT;
  122. /* flash buffer */
  123. static uint8_t buf[SPM_PAGESIZE];
  124. static uint16_t addr;
  125. /* *************************************************************************
  126. * write_flash_page
  127. * ************************************************************************* */
  128. static void write_flash_page(void)
  129. {
  130. uint16_t pagestart = addr;
  131. uint8_t size = SPM_PAGESIZE;
  132. uint8_t *p = buf;
  133. if (pagestart >= BOOTLOADER_START)
  134. {
  135. return;
  136. }
  137. boot_page_erase(pagestart);
  138. boot_spm_busy_wait();
  139. do {
  140. uint16_t data = *p++;
  141. data |= *p++ << 8;
  142. boot_page_fill(addr, data);
  143. addr += 2;
  144. size -= 2;
  145. } while (size);
  146. boot_page_write(pagestart);
  147. boot_spm_busy_wait();
  148. boot_rww_enable();
  149. } /* write_flash_page */
  150. #if (EEPROM_SUPPORT)
  151. /* *************************************************************************
  152. * read_eeprom_byte
  153. * ************************************************************************* */
  154. static uint8_t read_eeprom_byte(void)
  155. {
  156. EEARL = addr;
  157. EEARH = (addr >> 8);
  158. EECR |= (1<<EERE);
  159. addr++;
  160. return EEDR;
  161. } /* read_eeprom_byte */
  162. /* *************************************************************************
  163. * write_eeprom_byte
  164. * ************************************************************************* */
  165. static void write_eeprom_byte(uint8_t val)
  166. {
  167. EEARL = addr;
  168. EEARH = (addr >> 8);
  169. EEDR = val;
  170. addr++;
  171. #if defined (__AVR_ATmega8__)
  172. EECR |= (1<<EEMWE);
  173. EECR |= (1<<EEWE);
  174. #elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__) || \
  175. defined (__AVR_ATmega328P__)
  176. EECR |= (1<<EEMPE);
  177. EECR |= (1<<EEPE);
  178. #endif
  179. eeprom_busy_wait();
  180. } /* write_eeprom_byte */
  181. #endif /* EEPROM_SUPPORT */
  182. /* *************************************************************************
  183. * TWI_data_write
  184. * ************************************************************************* */
  185. static uint8_t TWI_data_write(uint8_t bcnt, uint8_t data)
  186. {
  187. uint8_t ack = 0x01;
  188. switch (bcnt)
  189. {
  190. case 0:
  191. switch (data)
  192. {
  193. case CMD_SWITCH_APPLICATION:
  194. case CMD_WRITE_MEMORY:
  195. /* no break */
  196. case CMD_WAIT:
  197. /* abort countdown */
  198. boot_timeout = 0;
  199. break;
  200. default:
  201. /* boot app now */
  202. cmd = CMD_BOOT_APPLICATION;
  203. ack = 0x00;
  204. break;
  205. }
  206. cmd = data;
  207. break;
  208. case 1:
  209. switch (cmd)
  210. {
  211. case CMD_SWITCH_APPLICATION:
  212. if (data == BOOTTYPE_APPLICATION)
  213. {
  214. cmd = CMD_BOOT_APPLICATION;
  215. }
  216. ack = 0x00;
  217. break;
  218. case CMD_WRITE_MEMORY:
  219. if (data == MEMTYPE_CHIPINFO)
  220. {
  221. cmd = CMD_WRITE_CHIPINFO;
  222. }
  223. else if (data == MEMTYPE_FLASH)
  224. {
  225. cmd = CMD_WRITE_FLASH;
  226. }
  227. #if (EEPROM_SUPPORT)
  228. else if (data == MEMTYPE_EEPROM)
  229. {
  230. cmd = CMD_WRITE_EEPROM;
  231. }
  232. #endif /* (EEPROM_SUPPORT) */
  233. else
  234. {
  235. ack = 0x00;
  236. }
  237. break;
  238. default:
  239. ack = 0x00;
  240. break;
  241. }
  242. break;
  243. case 2:
  244. case 3:
  245. addr <<= 8;
  246. addr |= data;
  247. break;
  248. default:
  249. switch (cmd)
  250. {
  251. case CMD_WRITE_FLASH:
  252. buf[bcnt -4] = data;
  253. if (bcnt >= sizeof(buf) +3)
  254. {
  255. write_flash_page();
  256. ack = 0x00;
  257. }
  258. break;
  259. #if (EEPROM_SUPPORT)
  260. case CMD_WRITE_EEPROM:
  261. write_eeprom_byte(data);
  262. break;
  263. #endif /* (EEPROM_SUPPORT) */
  264. default:
  265. ack = 0x00;
  266. break;
  267. }
  268. break;
  269. }
  270. return ack;
  271. } /* TWI_data_write */
  272. /* *************************************************************************
  273. * TWI_data_read
  274. * ************************************************************************* */
  275. static uint8_t TWI_data_read(uint8_t bcnt)
  276. {
  277. uint8_t data;
  278. switch (cmd)
  279. {
  280. case CMD_READ_VERSION:
  281. bcnt %= sizeof(info);
  282. data = info[bcnt];
  283. break;
  284. case CMD_READ_CHIPINFO:
  285. bcnt %= sizeof(chipinfo);
  286. data = chipinfo[bcnt];
  287. break;
  288. case CMD_READ_FLASH:
  289. data = pgm_read_byte_near(addr++);
  290. break;
  291. #if (EEPROM_SUPPORT)
  292. case CMD_READ_EEPROM:
  293. data = read_eeprom_byte();
  294. break;
  295. #endif /* (EEPROM_SUPPORT) */
  296. default:
  297. data = 0xFF;
  298. break;
  299. }
  300. return data;
  301. } /* TWI_data_read */
  302. /* *************************************************************************
  303. * TWI_vect
  304. * ************************************************************************* */
  305. static void TWI_vect(void)
  306. {
  307. static uint8_t bcnt;
  308. uint8_t control = TWCR;
  309. switch (TWSR & 0xF8)
  310. {
  311. /* SLA+W received, ACK returned -> receive data and ACK */
  312. case 0x60:
  313. bcnt = 0;
  314. LED_RT_ON();
  315. break;
  316. /* prev. SLA+W, data received, ACK returned -> receive data and ACK */
  317. case 0x80:
  318. if (TWI_data_write(bcnt++, TWDR) == 0x00)
  319. {
  320. control &= ~(1<<TWEA);
  321. bcnt = 0;
  322. }
  323. break;
  324. /* SLA+R received, ACK returned -> send data */
  325. case 0xA8:
  326. bcnt = 0;
  327. LED_RT_ON();
  328. /* prev. SLA+R, data sent, ACK returned -> send data */
  329. case 0xB8:
  330. TWDR = TWI_data_read(bcnt++);
  331. break;
  332. /* prev. SLA+W, data received, NACK returned -> IDLE */
  333. case 0x88:
  334. /* STOP or repeated START -> IDLE */
  335. case 0xA0:
  336. /* prev. SLA+R, data sent, NACK returned -> IDLE */
  337. case 0xC0:
  338. LED_RT_OFF();
  339. control |= (1<<TWEA);
  340. break;
  341. /* illegal state(s) -> reset hardware */
  342. default:
  343. control |= (1<<TWSTO);
  344. break;
  345. }
  346. TWCR = (1<<TWINT) | control;
  347. } /* TWI_vect */
  348. /* *************************************************************************
  349. * TIMER0_OVF_vect
  350. * ************************************************************************* */
  351. static void TIMER0_OVF_vect(void)
  352. {
  353. /* restart timer */
  354. TCNT0 = TIMER_RELOAD;
  355. /* blink LED while running */
  356. LED_GN_TOGGLE();
  357. /* count down for app-boot */
  358. if (boot_timeout > 1)
  359. {
  360. boot_timeout--;
  361. }
  362. else if (boot_timeout == 1)
  363. {
  364. /* trigger app-boot */
  365. cmd = CMD_BOOT_APPLICATION;
  366. }
  367. } /* TIMER0_OVF_vect */
  368. static void (*jump_to_app)(void) __attribute__ ((noreturn)) = 0x0000;
  369. /* *************************************************************************
  370. * init1
  371. * ************************************************************************* */
  372. void init1(void) __attribute__((naked, section(".init1")));
  373. void init1(void)
  374. {
  375. /* make sure r1 is 0x00 */
  376. asm volatile ("clr __zero_reg__");
  377. /* on some MCUs the stack pointer defaults NOT to RAMEND */
  378. #if defined(__AVR_ATmega8__) || defined(__AVR_ATmega8515__) || \
  379. defined(__AVR_ATmega8535__) || defined (__AVR_ATmega16__) || \
  380. defined (__AVR_ATmega32__) || defined (__AVR_ATmega64__) || \
  381. defined (__AVR_ATmega128__) || defined (__AVR_ATmega162__)
  382. SP = RAMEND;
  383. #endif
  384. } /* init1 */
  385. /*
  386. * For newer devices the watchdog timer remains active even after a
  387. * system reset. So disable it as soon as possible.
  388. * automagically called on startup
  389. */
  390. #if defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__) || \
  391. defined (__AVR_ATmega328P__)
  392. /* *************************************************************************
  393. * disable_wdt_timer
  394. * ************************************************************************* */
  395. void disable_wdt_timer(void) __attribute__((naked, section(".init3")));
  396. void disable_wdt_timer(void)
  397. {
  398. MCUSR = 0;
  399. WDTCSR = (1<<WDCE) | (1<<WDE);
  400. WDTCSR = (0<<WDE);
  401. } /* disable_wdt_timer */
  402. #endif
  403. /* *************************************************************************
  404. * main
  405. * ************************************************************************* */
  406. int main(void) __attribute__ ((OS_main, section (".init9")));
  407. int main(void)
  408. {
  409. LED_INIT();
  410. LED_GN_ON();
  411. /* timer0: running with F_CPU/1024 */
  412. #if defined (__AVR_ATmega8__)
  413. TCCR0 = (1<<CS02) | (1<<CS00);
  414. #elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__) || \
  415. defined (__AVR_ATmega328P__)
  416. TCCR0B = (1<<CS02) | (1<<CS00);
  417. #endif
  418. /* TWI init: set address, auto ACKs */
  419. TWAR = (TWI_ADDRESS<<1);
  420. TWCR = (1<<TWEA) | (1<<TWEN);
  421. while (cmd != CMD_BOOT_APPLICATION)
  422. {
  423. if (TWCR & (1<<TWINT))
  424. {
  425. TWI_vect();
  426. }
  427. #if defined (__AVR_ATmega8__)
  428. if (TIFR & (1<<TOV0))
  429. {
  430. TIMER0_OVF_vect();
  431. TIFR = (1<<TOV0);
  432. }
  433. #elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__) || \
  434. defined (__AVR_ATmega328P__)
  435. if (TIFR0 & (1<<TOV0))
  436. {
  437. TIMER0_OVF_vect();
  438. TIFR0 = (1<<TOV0);
  439. }
  440. #endif
  441. }
  442. /* Disable TWI but keep address! */
  443. TWCR = 0x00;
  444. /* disable timer0 */
  445. #if defined (__AVR_ATmega8__)
  446. TCCR0 = 0x00;
  447. #elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__) || \
  448. defined (__AVR_ATmega328P__)
  449. TCCR0B = 0x00;
  450. #endif
  451. LED_OFF();
  452. uint16_t wait = 0x0000;
  453. do {
  454. __asm volatile ("nop");
  455. } while (--wait);
  456. jump_to_app();
  457. } /* main */