MPM bootloader for AVR
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.

534 lines
14 KiB

  1. /***************************************************************************
  2. * Copyright (C) 01/2012 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. /*
  24. * atmega32:
  25. * Fuse H: 0xda (1024 words bootloader)
  26. * Fuse L: 0xd4 (8Mhz internal RC-Osz.)
  27. */
  28. #if defined (__AVR_ATmega32__)
  29. #define F_CPU 8000000
  30. #define VERSION_STRING "MPMBOOT m32v1.0"
  31. #define SIGNATURE_BYTES 0x1E, 0x95, 0x02
  32. #else
  33. #error MCU not supported
  34. #endif
  35. /* 25ms @8MHz */
  36. #define TIMER_RELOAD (0xFF - 195)
  37. /* 40 * 25ms = 1s */
  38. #define TIMEOUT 40
  39. #define RXTX_DDR DDRD
  40. #define RXTX_PORT PORTD
  41. #define RXTX_NUM PORTD2
  42. #define LED_INIT() DDRD |= (1<<PORTD3)
  43. #define LED_OFF() PORTD |= (1<<PORTD3)
  44. #define LED_ON() PORTD &= ~(1<<PORTD3)
  45. #define LED_TOGGLE() PORTD ^= (1<<PORTD3)
  46. #define BAUDRATE 115200
  47. #ifndef MPM_ADDRESS
  48. #define MPM_ADDRESS 0x11
  49. #endif /* MPM_ADDRESS */
  50. #define EEPROM_SUPPORT 1
  51. #define UART_CALC_BAUDRATE(baudRate) (((uint32_t)F_CPU) / (((uint32_t)baudRate)*16) -1)
  52. /*
  53. * LED blinks with 20Hz (while bootloader is running)
  54. *
  55. * general protocol:
  56. * =================
  57. * req: <device> <cmd> <length> <data>*
  58. * rsp: <cmd> <cause> <length> <data>*
  59. *
  60. * device is MPM device address and has 9th bit set, all other
  61. * bytes in request & response have 9th bit NOT set
  62. *
  63. * length is 16bit, MSB first
  64. *
  65. * rsp-cause codes:
  66. * 0x00 - ok
  67. * 0xF0 - command not supported (unknown to bootloader)
  68. * 0xF1 - parameter error (invalid memtype/address)
  69. * 0xFF - unspecified error
  70. *
  71. * CMD switch mode:
  72. * ================
  73. * req: <cmd:0x01>,<length:0x0001>,<mode>
  74. * rsp: <cmd:0x01>,<cause:0x00>,<length:0x0000>
  75. *
  76. * mode codes:
  77. * 0x00 - bootloader
  78. * 0x80 - application
  79. *
  80. * CMD get bootloader version:
  81. * ===========================
  82. * req: <cmd:0x02>,<length:0x0000>
  83. * rsp: <cmd:0x02>,<cause:0x00>,<length[2]>,<data[x]>
  84. *
  85. * response data is bootloader version string with implementation specific length
  86. *
  87. * CMD get chip info:
  88. * ==================
  89. * req: <cmd:0x03>,<length:0x0000>
  90. * rsp: <cmd:0x03>,<cause:0x00>,<length:0x0008>,<signature[3]><pagesize[1]><flashsize[2]><eepromsize[2]>
  91. *
  92. * CMD read memory:
  93. * ================
  94. * req: <cmd:0x11>,<length:0x0004>,<memtype>,<address[2]>,<size[2]>
  95. * rsp: <cmd:0x11>,<cause:0x00>,<length[2]>,<data[x]>
  96. *
  97. * memtype codes:
  98. * 0x01 - flash memory
  99. * 0x02 - eeprom memory
  100. *
  101. * CMD write memory:
  102. * =================
  103. * req: <cmd:0x12>,<length[2]>,<memtype>,<address[2]>,<size[2]>,<data[x]>
  104. * rsp: <cmd:0x12>,<cause:0x00>,<length:0x0000>
  105. *
  106. * memtype codes:
  107. * 0x01 - flash memory
  108. * 0x02 - eeprom memory
  109. *
  110. */
  111. #define CMD_WAIT 0x00
  112. #define CMD_SWITCH_MODE 0x01
  113. #define CMD_GET_VERSION 0x02
  114. #define CMD_GET_CHIPINFO 0x03
  115. #define CMD_READ_MEMORY 0x11
  116. #define CMD_WRITE_MEMORY 0x12
  117. #define CAUSE_SUCCESS 0x00
  118. #define CAUSE_NOT_SUPPORTED 0xF0
  119. #define CAUSE_INVALID_PARAMETER 0xF1
  120. #define CAUSE_UNSPECIFIED_ERROR 0xFF
  121. #define BOOTMODE_BOOTLOADER 0x00
  122. #define BOOTMODE_APPLICATION 0x80
  123. #define MEMTYPE_FLASH 0x01
  124. #define MEMTYPE_EEPROM 0x02
  125. #define BOOTWAIT_EXPIRED 0x00
  126. #define BOOTWAIT_INTERRUPTED 0xFF
  127. const static uint8_t info[16] = VERSION_STRING;
  128. const static uint8_t chipinfo[8] = {
  129. SIGNATURE_BYTES,
  130. SPM_PAGESIZE,
  131. ((BOOTLOADER_START) >> 8) & 0xFF,
  132. (BOOTLOADER_START) & 0xFF,
  133. ((E2END +1) >> 8 & 0xFF),
  134. (E2END +1) & 0xFF
  135. };
  136. volatile static uint8_t boot_timeout = TIMEOUT;
  137. static uint8_t rx_addressed;
  138. static uint16_t rx_bcnt;
  139. static uint8_t rx_cmd;
  140. static uint16_t rx_length;
  141. static uint16_t tx_bcnt;
  142. static uint8_t tx_cmd;
  143. static uint8_t tx_cause;
  144. static uint16_t tx_length;
  145. static uint8_t para_mode;
  146. static uint8_t para_memtype;
  147. static uint16_t para_address;
  148. static uint16_t para_size;
  149. /* write buffer */
  150. static uint16_t mem_address;
  151. static uint8_t pagebuf[SPM_PAGESIZE];
  152. static void write_flash_page(void)
  153. {
  154. uint16_t pagestart = para_address;
  155. uint8_t pagesize = SPM_PAGESIZE;
  156. uint8_t *data = pagebuf;
  157. boot_page_erase(pagestart);
  158. boot_spm_busy_wait();
  159. do {
  160. uint16_t dataword;
  161. dataword = (*data++);
  162. dataword |= (*data++) << 8;
  163. boot_page_fill(para_address, dataword);
  164. para_address += 2;
  165. pagesize -= 2;
  166. } while (pagesize);
  167. boot_page_write(pagestart);
  168. boot_spm_busy_wait();
  169. boot_rww_enable();
  170. }
  171. #if (EEPROM_SUPPORT)
  172. static uint8_t read_eeprom_byte(void)
  173. {
  174. EEARL = para_address;
  175. EEARH = (para_address >> 8);
  176. EECR |= (1<<EERE);
  177. return EEDR;
  178. }
  179. static void write_eeprom_page(uint16_t size)
  180. {
  181. uint8_t *data = pagebuf;
  182. while (size--) {
  183. EEARL = para_address;
  184. EEARH = (para_address >> 8);
  185. para_address++;
  186. EEDR = *data++;
  187. #if defined (__AVR_ATmega32__)
  188. EECR |= (1<<EEMWE);
  189. EECR |= (1<<EEWE);
  190. #else
  191. #error write_eeprom_page(): access not defined
  192. #endif
  193. eeprom_busy_wait();
  194. }
  195. }
  196. #endif /* (EEPROM_SUPPORT) */
  197. ISR(USART_RXC_vect)
  198. {
  199. uint8_t data = UDR;
  200. if (rx_addressed == 0) {
  201. /* own address, disable MPM mode and receive following bytes */
  202. if (data == MPM_ADDRESS) {
  203. #if 0
  204. /* stay in bootloader */
  205. boot_timeout = BOOTWAIT_INTERRUPTED;
  206. #else
  207. /* restart timeout */
  208. boot_timeout = TIMEOUT;
  209. #endif
  210. /* enable LED */
  211. LED_ON();
  212. UCSRA &= ~(1<<MPCM);
  213. rx_addressed = 1;
  214. rx_bcnt = 0;
  215. }
  216. } else {
  217. /* byte 0 is command */
  218. if (rx_bcnt == 0) {
  219. rx_cmd = data;
  220. /* byte 1/2 is payload length */
  221. } else if (rx_bcnt == 1 || rx_bcnt == 2) {
  222. rx_length = (rx_length << 8) | data;
  223. /* byte >= 3 is payload */
  224. } else if ((rx_bcnt -3) < rx_length) {
  225. uint16_t pos = rx_bcnt -3;
  226. if ((rx_cmd == CMD_SWITCH_MODE) && (pos == 0)) {
  227. para_mode = data;
  228. } else if ((rx_cmd == CMD_READ_MEMORY) || (rx_cmd == CMD_WRITE_MEMORY)) {
  229. switch (pos) {
  230. case 0:
  231. para_memtype = data;
  232. break;
  233. case 1:
  234. case 2:
  235. mem_address = (mem_address << 8) | data;
  236. break;
  237. case 3:
  238. case 4:
  239. para_size = (para_size << 8) | data;
  240. break;
  241. default:
  242. pos -= 5;
  243. if ((rx_cmd == CMD_WRITE_MEMORY) && (pos < sizeof(pagebuf))) {
  244. pagebuf[pos] = data;
  245. }
  246. break;
  247. }
  248. }
  249. }
  250. /* last byte received */
  251. if ((rx_bcnt -2) == rx_length) {
  252. /* setup response */
  253. tx_bcnt = 0;
  254. tx_cmd = rx_cmd;
  255. tx_cause = CAUSE_SUCCESS;
  256. tx_length = 0;
  257. switch (tx_cmd) {
  258. case CMD_SWITCH_MODE:
  259. if ((para_mode != BOOTMODE_APPLICATION) && (para_mode != BOOTMODE_BOOTLOADER)) {
  260. tx_cause = CAUSE_INVALID_PARAMETER;
  261. }
  262. break;
  263. case CMD_GET_VERSION:
  264. tx_length = sizeof(info);
  265. break;
  266. case CMD_GET_CHIPINFO:
  267. tx_length = sizeof(chipinfo);
  268. break;
  269. case CMD_READ_MEMORY:
  270. tx_length = para_size;
  271. /* no break */
  272. case CMD_WRITE_MEMORY:
  273. if (para_memtype == MEMTYPE_FLASH) {
  274. /* only access application area */
  275. if (mem_address > (BOOTLOADER_START - SPM_PAGESIZE)) {
  276. tx_length = 0;
  277. tx_cause = CAUSE_INVALID_PARAMETER;
  278. /* writes must pagesize aligned */
  279. } else if (tx_cmd == CMD_WRITE_MEMORY) {
  280. if (((mem_address & (SPM_PAGESIZE -1)) == 0x00) &&
  281. (para_size <= SPM_PAGESIZE)
  282. ) {
  283. while (para_size < SPM_PAGESIZE) {
  284. pagebuf[para_size] = 0xFF;
  285. }
  286. write_flash_page();
  287. } else {
  288. tx_cause = CAUSE_INVALID_PARAMETER;
  289. }
  290. }
  291. #if (EEPROM_SUPPORT)
  292. } else if (para_memtype == MEMTYPE_EEPROM) {
  293. if ((mem_address > (E2END +1)) || ((mem_address + para_size) > (E2END +1))) {
  294. tx_cause = CAUSE_INVALID_PARAMETER;
  295. } else if (tx_cmd == CMD_WRITE_MEMORY) {
  296. write_eeprom_page(para_size);
  297. }
  298. #endif /*(EEPROM_SUPPORT) */
  299. } else {
  300. tx_length = 0;
  301. tx_cause = CAUSE_INVALID_PARAMETER;
  302. }
  303. break;
  304. default:
  305. tx_cause = CAUSE_NOT_SUPPORTED;
  306. break;
  307. }
  308. /* kickoff transmit */
  309. UCSRB |= (1<<UDRIE);
  310. }
  311. rx_bcnt++;
  312. }
  313. }
  314. ISR(USART_UDRE_vect)
  315. {
  316. if (tx_bcnt == 0) {
  317. /* enable RS485 transmitter */
  318. RXTX_PORT |= (1<<RXTX_NUM);
  319. UCSRB &= ~(1<<TXB8);
  320. UDR = tx_cmd;
  321. } else if (tx_bcnt == 1) {
  322. UDR = tx_cause;
  323. } else if (tx_bcnt == 2) {
  324. UDR = (tx_length >> 8);
  325. } else if (tx_bcnt == 3) {
  326. UDR = (tx_length & 0xFF);
  327. } else if ((tx_bcnt -4) < tx_length) {
  328. uint16_t pos = tx_bcnt -4;
  329. uint8_t data = 0xFF;
  330. if (tx_cmd == CMD_GET_VERSION) {
  331. data = info[pos];
  332. } else if (tx_cmd == CMD_GET_CHIPINFO) {
  333. data = chipinfo[pos];
  334. } else if (tx_cmd == CMD_READ_MEMORY) {
  335. if (para_memtype == MEMTYPE_FLASH) {
  336. data = pgm_read_byte_near(mem_address++);
  337. #if (EEPROM_SUPPORT)
  338. } else if (para_memtype == MEMTYPE_EEPROM) {
  339. data = read_eeprom_byte();
  340. mem_address++;
  341. #endif /* (EEPROM_SUPPORT) */
  342. }
  343. }
  344. UDR = data;
  345. } else {
  346. /* stop transmit */
  347. UCSRB &= ~(1<<UDRIE);
  348. }
  349. tx_bcnt++;
  350. }
  351. ISR(USART_TXC_vect)
  352. {
  353. /* disable LED */
  354. LED_OFF();
  355. /* disable RS485 transmitter */
  356. RXTX_PORT &= ~(1<<RXTX_NUM);
  357. /* enable MP mode again */
  358. UCSRA |= (1<<MPCM);
  359. rx_addressed = 0;
  360. /* switch to application after everything is transmitted */
  361. if ((tx_cmd == CMD_SWITCH_MODE) && (para_mode == BOOTMODE_APPLICATION)) {
  362. boot_timeout = BOOTWAIT_EXPIRED;
  363. }
  364. }
  365. ISR(TIMER0_OVF_vect)
  366. {
  367. /* restart timer */
  368. TCNT0 = TIMER_RELOAD;
  369. switch (boot_timeout) {
  370. default:
  371. boot_timeout--;
  372. /* fall-through */
  373. case BOOTWAIT_INTERRUPTED:
  374. LED_TOGGLE();
  375. /* fall-through */
  376. case BOOTWAIT_EXPIRED:
  377. break;
  378. }
  379. }
  380. #if (OSCCAL_CHECK)
  381. static void uart_send(char *p)
  382. {
  383. while (*p) {
  384. while (!(UCSRA & (1<<UDRE)));
  385. UDR = *p++;
  386. }
  387. }
  388. #endif /* (OSCCAL_CHECK) */
  389. static void (*jump_to_app)(void) __attribute__ ((noreturn)) = 0x0000;
  390. int main(void) __attribute__ ((noreturn));
  391. int main(void)
  392. {
  393. /* LED and TXEN are outputs */
  394. LED_INIT();
  395. RXTX_DDR |= (1<<RXTX_NUM);
  396. #if defined(OSCCAL_VALUE)
  397. OSCCAL = OSCCAL_VALUE;
  398. #endif
  399. /* move interrupt-vectors to bootloader */
  400. /* timer0: running with F_CPU/1024, OVF interrupt */
  401. #if defined (__AVR_ATmega32__)
  402. GICR = (1<<IVCE);
  403. GICR = (1<<IVSEL);
  404. TCCR0 = (1<<CS02) | (1<<CS00);
  405. TIMSK = (1<<TOIE0);
  406. #endif
  407. /* USART config */
  408. /* Multi Drop Mode, 9n1 */
  409. UCSRA = (1<<MPCM);
  410. UCSRB = (1<<RXEN) | (1<<TXEN) | (1<<RXCIE) | (1<<TXCIE) | (1<<UCSZ2);
  411. UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
  412. UBRRH = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF;
  413. UBRRL = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF);
  414. /* store MPM address in TWI register for application */
  415. TWAR = MPM_ADDRESS;
  416. #if (OSCCAL_CHECK)
  417. /* 11.354ms for 109 bits @9600 */
  418. /* 946.18us for 109 bits @115200 */
  419. uart_send("1234567890");
  420. #endif /* (OSCCAL_CHECK) */
  421. sei();
  422. while (boot_timeout != BOOTWAIT_EXPIRED);
  423. cli();
  424. /* disable timer0 */
  425. /* move interrupt vectors back to application */
  426. #if defined (__AVR_ATmega32__)
  427. TCCR0 = 0x00;
  428. TIMSK = 0x00;
  429. GICR = (1<<IVCE);
  430. GICR = (0<<IVSEL);
  431. #endif
  432. /* disable LED */
  433. LED_OFF();
  434. uint16_t wait = 0x0000;
  435. do {
  436. __asm volatile ("nop");
  437. } while (--wait);
  438. jump_to_app();
  439. }