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.

448 lines
10.0KB

  1. /***************************************************************************
  2. * Copyright (C) 08/2010 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 F_CPU 8000000
  24. #include <util/delay.h>
  25. /*
  26. * atmega8:
  27. * Fuse H: 0xda (512 words bootloader)
  28. * Fuse L: 0x84 (8Mhz internal RC-Osz., 2.7V BOD)
  29. *
  30. * atmega88:
  31. * Fuse E: 0xfa (512 words bootloader)
  32. * Fuse H: 0xdd (2.7V BOD)
  33. * Fuse L: 0xc2 (8Mhz internal RC-Osz.)
  34. *
  35. * atmega168:
  36. * Fuse E: 0xfa (512 words bootloader)
  37. * Fuse H: 0xdd (2.7V BOD)
  38. * Fuse L: 0xc2 (8Mhz internal RC-Osz.)
  39. */
  40. #if defined (__AVR_ATmega8__)
  41. #define VERSION_STRING "TWIBOOT m8v2.0"
  42. #define SIGNATURE_BYTES 0x1E, 0x93, 0x07
  43. #elif defined (__AVR_ATmega88__)
  44. #define VERSION_STRING "TWIBOOT m88v2.0"
  45. #define SIGNATURE_BYTES 0x1E, 0x93, 0x0A
  46. #elif defined (__AVR_ATmega168__)
  47. #define VERSION_STRING "TWIBOOT m168v2.0"
  48. #define SIGNATURE_BYTES 0x1E, 0x94, 0x06
  49. #else
  50. #error MCU not supported
  51. #endif
  52. #define EEPROM_SUPPORT 1
  53. /* 25ms @8MHz */
  54. #define TIMER_RELOAD (0xFF - 195)
  55. /* 40 * 25ms */
  56. #define TIMEOUT 40
  57. #define LED_RT (1<<PORTB4)
  58. #define LED_GN (1<<PORTB5)
  59. #define TWI_ADDRESS 0x21
  60. /* SLA+R */
  61. #define CMD_WAIT 0x00
  62. #define CMD_READ_VERSION 0x01
  63. #define CMD_READ_MEMORY 0x02
  64. /* internal mappings */
  65. #define CMD_READ_CHIPINFO (0x10 | CMD_READ_MEMORY)
  66. #define CMD_READ_FLASH (0x20 | CMD_READ_MEMORY)
  67. #define CMD_READ_EEPROM (0x30 | CMD_READ_MEMORY)
  68. #define CMD_READ_PARAMETERS (0x40 | CMD_READ_MEMORY) /* only in APP */
  69. /* SLA+W */
  70. #define CMD_SWITCH_APPLICATION CMD_READ_VERSION
  71. #define CMD_WRITE_MEMORY CMD_READ_MEMORY
  72. /* internal mappings */
  73. #define CMD_BOOT_BOOTLOADER (0x10 | CMD_SWITCH_APPLICATION) /* only in APP */
  74. #define CMD_BOOT_APPLICATION (0x20 | CMD_SWITCH_APPLICATION)
  75. #define CMD_WRITE_CHIPINFO (0x10 | CMD_WRITE_MEMORY) /* invalid */
  76. #define CMD_WRITE_FLASH (0x20 | CMD_WRITE_MEMORY)
  77. #define CMD_WRITE_EEPROM (0x30 | CMD_WRITE_MEMORY)
  78. #define CMD_WRITE_PARAMETERS (0x40 | CMD_WRITE_MEMORY) /* only in APP */
  79. /* CMD_SWITCH_APPLICATION parameter */
  80. #define BOOTTYPE_BOOTLOADER 0x00 /* only in APP */
  81. #define BOOTTYPE_APPLICATION 0x80
  82. /* CMD_{READ|WRITE}_* parameter */
  83. #define MEMTYPE_CHIPINFO 0x00
  84. #define MEMTYPE_FLASH 0x01
  85. #define MEMTYPE_EEPROM 0x02
  86. #define MEMTYPE_PARAMETERS 0x03 /* only in APP */
  87. /*
  88. * LED_GN blinks with 20Hz (while bootloader is running)
  89. * LED_RT blinks on TWI activity
  90. *
  91. * bootloader twi-protocol:
  92. * - abort boot timeout:
  93. * SLA+W, 0x00, STO
  94. *
  95. * - show bootloader version
  96. * SLA+W, 0x01, SLA+R, {16 bytes}, STO
  97. *
  98. * - start application
  99. * SLA+W, 0x01, 0x80, STO
  100. *
  101. * - read chip info: 3byte signature, 1byte page size, 2byte flash size, 2byte eeprom size
  102. * SLA+W, 0x02, 0x00, 0x00, 0x00, SLA+R, {4 bytes}, STO
  103. *
  104. * - read one (or more) flash bytes
  105. * SLA+W, 0x02, 0x01, addrh, addrl, SLA+R, {* bytes}, STO
  106. *
  107. * - read one (or more) eeprom bytes
  108. * SLA+W, 0x02, 0x02, addrh, addrl, SLA+R, {* bytes}, STO
  109. *
  110. * - write one flash page (64bytes on mega8)
  111. * SLA+W, 0x02, 0x01, addrh, addrl, {64 bytes}, STO
  112. *
  113. * - write one (or more) eeprom bytes
  114. * SLA+W, 0x02, 0x02, addrh, addrl, {* bytes}, STO
  115. */
  116. const static uint8_t info[16] = VERSION_STRING;
  117. const static uint8_t chipinfo[8] = {
  118. SIGNATURE_BYTES,
  119. SPM_PAGESIZE,
  120. (APP_END >> 8) & 0xFF,
  121. APP_END & 0xFF,
  122. #if (EEPROM_SUPPORT)
  123. ((E2END +1) >> 8 & 0xFF),
  124. (E2END +1) & 0xFF
  125. #else
  126. 0x00, 0x00
  127. #endif
  128. };
  129. /* wait 40 * 25ms = 1s */
  130. static uint8_t boot_timeout = TIMEOUT;
  131. volatile static uint8_t cmd = CMD_WAIT;
  132. /* flash buffer */
  133. static uint8_t buf[SPM_PAGESIZE];
  134. static uint16_t addr;
  135. static void write_flash_page(void)
  136. {
  137. uint16_t pagestart = addr;
  138. uint8_t size = SPM_PAGESIZE;
  139. uint8_t *p = buf;
  140. if (pagestart >= APP_END)
  141. return;
  142. boot_page_erase(pagestart);
  143. boot_spm_busy_wait();
  144. do {
  145. uint16_t data = *p++;
  146. data |= *p++ << 8;
  147. boot_page_fill(addr, data);
  148. addr += 2;
  149. size -= 2;
  150. } while (size);
  151. boot_page_write(pagestart);
  152. boot_spm_busy_wait();
  153. boot_rww_enable();
  154. }
  155. #if (EEPROM_SUPPORT)
  156. static uint8_t read_eeprom_byte(void)
  157. {
  158. EEARL = addr;
  159. EEARH = (addr >> 8);
  160. EECR |= (1<<EERE);
  161. addr++;
  162. return EEDR;
  163. }
  164. static void write_eeprom_byte(uint8_t val)
  165. {
  166. EEARL = addr;
  167. EEARH = (addr >> 8);
  168. EEDR = val;
  169. addr++;
  170. #if defined (__AVR_ATmega8__)
  171. EECR |= (1<<EEMWE);
  172. EECR |= (1<<EEWE);
  173. #elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__)
  174. EECR |= (1<<EEMPE);
  175. EECR |= (1<<EEPE);
  176. #endif
  177. eeprom_busy_wait();
  178. }
  179. #endif /* EEPROM_SUPPORT */
  180. ISR(TWI_vect)
  181. {
  182. static uint8_t bcnt;
  183. uint8_t data;
  184. uint8_t ack = (1<<TWEA);
  185. switch (TWSR & 0xF8) {
  186. /* SLA+W received, ACK returned -> receive data and ACK */
  187. case 0x60:
  188. bcnt = 0;
  189. PORTB |= LED_RT;
  190. TWCR |= (1<<TWINT) | (1<<TWEA);
  191. break;
  192. /* prev. SLA+W, data received, ACK returned -> receive data and ACK */
  193. case 0x80:
  194. data = TWDR;
  195. switch (bcnt) {
  196. case 0:
  197. switch (data) {
  198. case CMD_SWITCH_APPLICATION:
  199. case CMD_WRITE_MEMORY:
  200. bcnt++;
  201. /* no break */
  202. case CMD_WAIT:
  203. /* abort countdown */
  204. boot_timeout = 0;
  205. break;
  206. default:
  207. /* boot app now */
  208. cmd = CMD_BOOT_APPLICATION;
  209. ack = (0<<TWEA);
  210. break;
  211. }
  212. cmd = data;
  213. break;
  214. case 1:
  215. switch (cmd) {
  216. case CMD_SWITCH_APPLICATION:
  217. if (data == BOOTTYPE_APPLICATION) {
  218. cmd = CMD_BOOT_APPLICATION;
  219. }
  220. ack = (0<<TWEA);
  221. break;
  222. case CMD_WRITE_MEMORY:
  223. bcnt++;
  224. if (data == MEMTYPE_CHIPINFO) {
  225. cmd = CMD_WRITE_CHIPINFO;
  226. } else if (data == MEMTYPE_FLASH) {
  227. cmd = CMD_WRITE_FLASH;
  228. #if (EEPROM_SUPPORT)
  229. } else if (data == MEMTYPE_EEPROM) {
  230. cmd = CMD_WRITE_EEPROM;
  231. #endif
  232. } else {
  233. ack = (0<<TWEA);
  234. }
  235. break;
  236. default:
  237. ack = (0<<TWEA);
  238. break;
  239. }
  240. break;
  241. case 2:
  242. case 3:
  243. addr <<= 8;
  244. addr |= data;
  245. bcnt++;
  246. break;
  247. default:
  248. switch (cmd) {
  249. case CMD_WRITE_FLASH:
  250. buf[bcnt -4] = data;
  251. if (bcnt < sizeof(buf) +3) {
  252. bcnt++;
  253. } else {
  254. write_flash_page();
  255. ack = (0<<TWEA);
  256. }
  257. break;
  258. #if (EEPROM_SUPPORT)
  259. case CMD_WRITE_EEPROM:
  260. write_eeprom_byte(data);
  261. bcnt++;
  262. break;
  263. #endif
  264. default:
  265. ack = (0<<TWEA);
  266. break;
  267. }
  268. break;
  269. }
  270. if (ack == 0x00)
  271. bcnt = 0;
  272. TWCR |= (1<<TWINT) | ack;
  273. break;
  274. /* SLA+R received, ACK returned -> send data */
  275. case 0xA8:
  276. bcnt = 0;
  277. PORTB |= LED_RT;
  278. /* prev. SLA+R, data sent, ACK returned -> send data */
  279. case 0xB8:
  280. switch (cmd) {
  281. case CMD_READ_VERSION:
  282. data = info[bcnt++];
  283. bcnt %= sizeof(info);
  284. break;
  285. case CMD_READ_CHIPINFO:
  286. data = chipinfo[bcnt++];
  287. bcnt %= sizeof(chipinfo);
  288. break;
  289. case CMD_READ_FLASH:
  290. data = pgm_read_byte_near(addr++);
  291. break;
  292. #if (EEPROM_SUPPORT)
  293. case CMD_READ_EEPROM:
  294. data = read_eeprom_byte();
  295. break;
  296. #endif
  297. default:
  298. data = 0xFF;
  299. break;
  300. }
  301. TWDR = data;
  302. TWCR |= (1<<TWINT) | (1<<TWEA);
  303. break;
  304. /* STOP or repeated START */
  305. case 0xA0:
  306. /* data sent, NACK returned */
  307. case 0xC0:
  308. PORTB &= ~LED_RT;
  309. TWCR |= (1<<TWINT) | (1<<TWEA);
  310. break;
  311. /* illegal state -> reset hardware */
  312. case 0xF8:
  313. TWCR |= (1<<TWINT) | (1<<TWSTO) | (1<<TWEA);
  314. break;
  315. }
  316. }
  317. ISR(TIMER0_OVF_vect)
  318. {
  319. /* restart timer */
  320. TCNT0 = TIMER_RELOAD;
  321. /* blink LED while running */
  322. PORTB ^= LED_GN;
  323. /* count down for app-boot */
  324. if (boot_timeout > 1)
  325. boot_timeout--;
  326. /* trigger app-boot */
  327. else if (boot_timeout == 1)
  328. cmd = CMD_BOOT_APPLICATION;
  329. }
  330. static void (*jump_to_app)(void) __attribute__ ((noreturn)) = 0x0000;
  331. /*
  332. * For newer devices (mega88) the watchdog timer remains active even after a
  333. * system reset. So disable it as soon as possible.
  334. * automagically called on startup
  335. */
  336. #if defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__)
  337. void disable_wdt_timer(void) __attribute__((naked, section(".init3")));
  338. void disable_wdt_timer(void)
  339. {
  340. MCUSR = 0;
  341. WDTCSR = (1<<WDCE) | (1<<WDE);
  342. WDTCSR = (0<<WDE);
  343. }
  344. #endif
  345. int main(void) __attribute__ ((noreturn));
  346. int main(void)
  347. {
  348. DDRB = LED_GN | LED_RT;
  349. PORTB = LED_GN;
  350. /* move interrupt-vectors to bootloader */
  351. MCUCR = (1<<IVCE);
  352. MCUCR = (1<<IVSEL);
  353. /* timer0: running with F_CPU/1024, OVF interrupt */
  354. #if defined (__AVR_ATmega8__)
  355. TCCR0 = (1<<CS02) | (1<<CS00);
  356. TIMSK = (1<<TOIE0);
  357. #elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__)
  358. TCCR0B = (1<<CS02) | (1<<CS00);
  359. TIMSK0 = (1<<TOIE0);
  360. #endif
  361. /* TWI init: set address, auto ACKs with interrupts */
  362. TWAR = (TWI_ADDRESS<<1);
  363. TWCR = (1<<TWEA) | (1<<TWEN) | (1<<TWIE);
  364. sei();
  365. while (cmd != CMD_BOOT_APPLICATION);
  366. cli();
  367. /* Disable TWI but keep address! */
  368. TWCR = 0x00;
  369. /* disable timer0 */
  370. #if defined (__AVR_ATmega8__)
  371. TCCR0 = 0x00;
  372. TIMSK = 0x00;
  373. #elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega168__)
  374. TIMSK0 = 0x00;
  375. TCCR0B = 0x00;
  376. #endif
  377. /* move interrupt vectors back to application */
  378. MCUCR = (1<<IVCE);
  379. MCUCR = (0<<IVSEL);
  380. PORTB = 0x00;
  381. jump_to_app();
  382. }