bootloader.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /*
  2. * =====================================================================================
  3. *
  4. * ________ .__ __ ________ ____ ________
  5. * \_____ \ __ __|__| ____ | | __\______ \ _______ _/_ |/ _____/
  6. * / / \ \| | \ |/ ___\| |/ / | | \_/ __ \ \/ /| / __ \
  7. * / \_/. \ | / \ \___| < | ` \ ___/\ / | \ |__\ \
  8. * \_____\ \_/____/|__|\___ >__|_ \/_______ /\___ >\_/ |___|\_____ /
  9. * \__> \/ \/ \/ \/ \/
  10. *
  11. * www.optixx.org
  12. *
  13. *
  14. * Version: 1.0
  15. * Created: 07/21/2009 03:32:16 PM
  16. * Author: david@optixx.org
  17. *
  18. * simple USBasp compatible bootloader by
  19. * Alexander Neumann <alexander@lochraster.org>
  20. * inspired by USBasploader by Christian Starkjohann,
  21. * =====================================================================================
  22. */
  23. #include <avr/io.h>
  24. #include <avr/interrupt.h>
  25. #include <avr/pgmspace.h>
  26. #include <avr/boot.h>
  27. #include <avr/eeprom.h>
  28. #include <util/delay.h>
  29. #include <string.h>
  30. #include <avr/wdt.h>
  31. #include "config.h"
  32. #include "usbdrv/usbdrv.c"
  33. /*
  34. * USBasp requests, taken from the original USBasp sourcecode
  35. */
  36. #define USBASP_FUNC_CONNECT 1
  37. #define USBASP_FUNC_DISCONNECT 2
  38. #define USBASP_FUNC_TRANSMIT 3
  39. #define USBASP_FUNC_READFLASH 4
  40. #define USBASP_FUNC_ENABLEPROG 5
  41. #define USBASP_FUNC_WRITEFLASH 6
  42. #define USBASP_FUNC_READEEPROM 7
  43. #define USBASP_FUNC_WRITEEEPROM 8
  44. #define USBASP_FUNC_SETLONGADDRESS 9
  45. /*
  46. * additional functions
  47. */
  48. #define FUNC_ECHO 0x17
  49. /*
  50. * atmel isp commands
  51. */
  52. #define ISP_CHIP_ERASE1 0xAC
  53. #define ISP_CHIP_ERASE2 0x80
  54. #define ISP_READ_SIGNATURE 0x30
  55. #define ISP_READ_EEPROM 0xa0
  56. #define ISP_WRITE_EEPROM 0xc0
  57. #define LED_PORT PORTC
  58. #define LED_DIR DDRC
  59. #define LED_PIN PC7
  60. #define DLED_ON {((LED_PORT &=~ (1 << LED_PIN)),\
  61. (LED_DIR &=~ (1 << LED_PIN))); }
  62. #define DLED_OFF {((LED_PORT &=~ (1 << LED_PIN)),\
  63. (LED_DIR |= (1 << LED_PIN))); }
  64. #define DLED_TGL {((LED_PORT &=~ (1 << LED_PIN)),\
  65. (LED_DIR ^= (1 << LED_PIN)));}
  66. /*
  67. * some predefined signatures, taken from the original USBasp sourcecode
  68. */
  69. static const uint8_t signature[4] = {
  70. #ifdef SIGNATURE_BYTES
  71. SIGNATURE_BYTES
  72. #elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega8HVA__)
  73. 0x1e, 0x93, 0x07, 0
  74. #elif defined (__AVR_ATmega48__) || defined (__AVR_ATmega48P__)
  75. 0x1e, 0x92, 0x05, 0
  76. #elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega88P__)
  77. 0x1e, 0x93, 0x0a, 0
  78. #elif defined (__AVR_ATmega168__) || defined (__AVR_ATmega168P__)
  79. 0x1e, 0x94, 0x06, 0
  80. #elif defined (__AVR_ATmega328P__)
  81. 0x1e, 0x95, 0x0f, 0
  82. #elif defined (__AVR_ATmega644__)
  83. 0x1e, 0x96, 0x09, 0
  84. #else
  85. # error "Device signature is not known, please edit config.h!"
  86. #endif
  87. };
  88. #ifndef BOOT_SECTION_START
  89. # error "BOOT_SECTION_START undefined!"
  90. #endif
  91. #if defined (__AVR_ATmega644__)
  92. /*
  93. * Due arvdude limitations we can't erase the whole progmem without running into an usb timeount on cleint side. So we we limit the
  94. * erase section by 0x1000
  95. */
  96. #define ERASE_SECTION 0xe000
  97. #else
  98. #define ERASE_SECTION BOOT_SECTION_START
  99. #endif
  100. #ifdef DEBUG_UART
  101. static __attribute__ ((__noinline__))
  102. void uart_putc(uint8_t data)
  103. {
  104. while (!(UCSR0A & _BV(UDRE0)));
  105. UDR0 = data;
  106. }
  107. #else
  108. #define uart_putc(x)
  109. #endif
  110. #ifdef DEBUG_UART
  111. static __attribute__ ((__noinline__))
  112. void uart_puts(uint8_t * data)
  113. {
  114. while (*data) {
  115. uart_putc(*data);
  116. data++;
  117. }
  118. }
  119. #else
  120. #define uart_puts(x)
  121. #endif
  122. /*
  123. * supply custom usbDeviceConnect() and usbDeviceDisconnect() macros which turn the interrupt on and off at the right times, and prevent
  124. * the execution of an interrupt while the pullup resistor is switched off
  125. */
  126. #ifdef USB_CFG_PULLUP_IOPORTNAME
  127. #undef usbDeviceConnect
  128. #define usbDeviceConnect() do { \
  129. USB_PULLUP_DDR |= (1<<USB_CFG_PULLUP_BIT); \
  130. USB_PULLUP_OUT |= (1<<USB_CFG_PULLUP_BIT); \
  131. USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT); \
  132. } while(0);
  133. #undef usbDeviceDisconnect
  134. #define usbDeviceDisconnect() do { \
  135. USB_INTR_ENABLE &= ~(1 << USB_INTR_ENABLE_BIT); \
  136. USB_PULLUP_DDR &= ~(1<<USB_CFG_PULLUP_BIT); \
  137. USB_PULLUP_OUT &= ~(1<<USB_CFG_PULLUP_BIT); \
  138. } while(0);
  139. #endif
  140. /*
  141. * prototypes
  142. */
  143. void __attribute__ ((__noreturn__, __noinline__,
  144. __naked__)) leave_bootloader(void);
  145. /*
  146. * we just support flash sizes <= 64kb, for code size reasons if you need to program bigger devices, have a look at USBasploader:
  147. * http://www.obdev.at/products/avrusb/usbasploader.html
  148. */
  149. #if FLASHEND > 0xffff
  150. # error "usbload only supports up to 64kb of flash!"
  151. #endif
  152. /*
  153. * we are just checking the lower byte of flash_address, so make sure SPM_PAGESIZE is <= 256
  154. */
  155. #if SPM_PAGESIZE > 256
  156. # error "SPM_PAGESIZE is too big (just checking lower byte)"
  157. #endif
  158. /*
  159. * start flash (byte address) read/write at this address
  160. */
  161. usbWord_t flash_address;
  162. uint8_t bytes_remaining;
  163. uint8_t request;
  164. uint8_t request_exit;
  165. uint8_t timeout;
  166. usbMsgLen_t usbFunctionSetup(uchar data[8])
  167. {
  168. usbRequest_t *req = (void *) data;
  169. uint8_t len = 0;
  170. static uint8_t buf[4];
  171. /*
  172. * set global data pointer to local buffer
  173. */
  174. usbMsgPtr = buf;
  175. /*
  176. * on enableprog just return one zero, which means success
  177. */
  178. if (req->bRequest == USBASP_FUNC_ENABLEPROG) {
  179. buf[0] = 0;
  180. len = 1;
  181. timeout = 255;
  182. } else if (req->bRequest == USBASP_FUNC_CONNECT) {
  183. /*
  184. * turn on led
  185. */
  186. DLED_ON;
  187. } else if (req->bRequest == USBASP_FUNC_DISCONNECT) {
  188. /*
  189. * turn off led
  190. */
  191. DLED_OFF;
  192. request_exit = 1;
  193. /*
  194. * catch query for the devicecode, chip erase and eeprom byte requests
  195. */
  196. } else if (req->bRequest == USBASP_FUNC_TRANSMIT) {
  197. /*
  198. * reset buffer with zeroes
  199. */
  200. memset(buf, '\0', sizeof(buf));
  201. /*
  202. * read the address for eeprom operations
  203. */
  204. usbWord_t address;
  205. address.bytes[0] = data[4]; /* low byte is data[4] */
  206. address.bytes[1] = data[3]; /* high byte is data[3] */
  207. /*
  208. * if this is a request to read the device signature, answer with the appropiate signature byte
  209. */
  210. if (data[2] == ISP_READ_SIGNATURE) {
  211. /*
  212. * the complete isp data is reported back to avrdude, but we just need byte 4 bits 0 and 1 of byte 3 determine the signature
  213. * byte address
  214. */
  215. buf[3] = signature[data[4] & 0x03];
  216. #ifdef ENABLE_CATCH_EEPROM_ISP
  217. /*
  218. * catch eeprom read
  219. */
  220. } else if (data[2] == ISP_READ_EEPROM) {
  221. buf[3] = eeprom_read_byte((uint8_t *) address.word);
  222. /*
  223. * catch eeprom write
  224. */
  225. } else if (data[2] == ISP_WRITE_EEPROM) {
  226. /*
  227. * address is in data[4], data[3], and databyte is in data[5]
  228. */
  229. eeprom_write_byte((uint8_t *) address.word, data[5]);
  230. #endif
  231. /*
  232. * catch a chip erase
  233. */
  234. } else if (data[2] == ISP_CHIP_ERASE1 && data[3] == ISP_CHIP_ERASE2) {
  235. uart_puts("\n\rErase Flash");
  236. for (flash_address.word = 0;
  237. flash_address.word < ERASE_SECTION;
  238. flash_address.word += SPM_PAGESIZE) {
  239. /*
  240. * wait and erase page
  241. */
  242. boot_spm_busy_wait();
  243. if (flash_address.word && flash_address.word % 1024 == 0)
  244. uart_putc('.');
  245. cli();
  246. boot_page_erase(flash_address.word);
  247. sei();
  248. }
  249. uart_puts("\n\r");
  250. }
  251. /*
  252. * in case no data has been filled in by the if's above, just return zeroes
  253. */
  254. len = 4;
  255. #ifdef ENABLE_ECHO_FUNC
  256. /*
  257. * implement a simple echo function, for testing the usb connectivity
  258. */
  259. } else if (req->bRequest == FUNC_ECHO) {
  260. buf[0] = req->wValue.bytes[0];
  261. buf[1] = req->wValue.bytes[1];
  262. len = 2;
  263. #endif
  264. } else if (req->bRequest >= USBASP_FUNC_READFLASH) {
  265. /*
  266. * && req->bRequest <= USBASP_FUNC_SETLONGADDRESS
  267. */
  268. /*
  269. * extract address and length
  270. */
  271. flash_address.word = req->wValue.word;
  272. bytes_remaining = req->wLength.bytes[0];
  273. request = req->bRequest;
  274. /*
  275. * hand control over to usbFunctionRead()/usbFunctionWrite()
  276. */
  277. len = 0xff;
  278. }
  279. return len;
  280. }
  281. uchar usbFunctionWrite(uchar * data, uchar len)
  282. {
  283. if (len > bytes_remaining)
  284. len = bytes_remaining;
  285. bytes_remaining -= len;
  286. if (request == USBASP_FUNC_WRITEEEPROM) {
  287. for (uint8_t i = 0; i < len; i++)
  288. eeprom_write_byte((uint8_t *) flash_address.word++, *data++);
  289. } else {
  290. /*
  291. * data is handled wordwise, adjust len
  292. */
  293. len /= 2;
  294. len -= 1;
  295. for (uint8_t i = 0; i <= len; i++) {
  296. uint16_t *w = (uint16_t *) data;
  297. cli();
  298. boot_page_fill(flash_address.word, *w);
  299. sei();
  300. usbWord_t next_address;
  301. next_address.word = flash_address.word;
  302. next_address.word += 2;
  303. data += 2;
  304. /*
  305. * write page if page boundary is crossed or this is the last page
  306. */
  307. if (next_address.bytes[0] % SPM_PAGESIZE == 0 ||
  308. (bytes_remaining == 0 && i == len)) {
  309. cli();
  310. boot_page_write(flash_address.word);
  311. sei();
  312. boot_spm_busy_wait();
  313. cli();
  314. boot_rww_enable();
  315. sei();
  316. }
  317. flash_address.word = next_address.word;
  318. }
  319. }
  320. /*
  321. * flash led on activity
  322. */
  323. DLED_TGL;
  324. return (bytes_remaining == 0);
  325. }
  326. uchar usbFunctionRead(uchar * data, uchar len)
  327. {
  328. if (len > bytes_remaining)
  329. len = bytes_remaining;
  330. bytes_remaining -= len;
  331. for (uint8_t i = 0; i < len; i++) {
  332. if (request == USBASP_FUNC_READEEPROM)
  333. *data = eeprom_read_byte((void *) flash_address.word);
  334. else
  335. *data = pgm_read_byte_near((void *) flash_address.word);
  336. data++;
  337. flash_address.word++;
  338. }
  339. /*
  340. * flash led on activity
  341. */
  342. DLED_TGL;
  343. return len;
  344. }
  345. void (*jump_to_app) (void) = 0x0000;
  346. void leave_bootloader(void)
  347. {
  348. cli();
  349. /*
  350. * disconnect usb
  351. */
  352. usbDeviceDisconnect();
  353. for (uint8_t i = 0; i < 50; i++)
  354. _delay_ms(10); /* 0 means 0x10000, 38*1/f*0x10000 =~ 498ms */
  355. /*
  356. * enable watchdog to soft-reset the uC for clean startup of new application
  357. */
  358. wdt_enable(WDTO_15MS);
  359. /*
  360. * let watchdog kick in and reset uC
  361. */
  362. while (1);
  363. }
  364. int __attribute__ ((noreturn, OS_main)) main(void)
  365. {
  366. /*
  367. * start bootloader
  368. */
  369. #ifdef DEBUG_UART
  370. /*
  371. * init uart (115200 baud, at 20mhz)
  372. */
  373. UBRR0L = 10;
  374. UCSR0C = _BV(UCSZ00) | _BV(UCSZ01);
  375. UCSR0B = _BV(TXEN0);
  376. #endif
  377. uint8_t reset = MCUSR;
  378. uint16_t delay = 0;
  379. timeout = TIMEOUT;
  380. uart_puts("Snesram Bootloader v0.1\n\r");
  381. /*
  382. * if power-on reset, quit bootloader via watchdog reset
  383. */
  384. if (reset & _BV(PORF)) {
  385. uart_puts("Found power on reset\n\r");
  386. MCUSR = 0;
  387. leave_bootloader();
  388. }
  389. /*
  390. * if watchdog reset, disable watchdog and jump to app
  391. */
  392. else if (reset & _BV(WDRF)) {
  393. uart_puts("Found watchdog reset\n\r");
  394. MCUSR = 0;
  395. wdt_disable();
  396. DLED_TGL;
  397. _delay_ms(500);
  398. DLED_TGL;
  399. _delay_ms(500);
  400. uart_puts("Jump to main\n\r");
  401. jump_to_app();
  402. }
  403. uart_puts("Enter programming mode\n\r");
  404. /*
  405. * else: enter programming mode
  406. */
  407. /*
  408. * clear external reset flags
  409. */
  410. MCUSR = 0;
  411. /*
  412. * init exit request state
  413. */
  414. request_exit = 0;
  415. /*
  416. * move interrupts to boot section
  417. */
  418. MCUCR = (1 << IVCE);
  419. MCUCR = (1 << IVSEL);
  420. /*
  421. * enable interrupts
  422. */
  423. sei();
  424. /*
  425. * initialize usb pins
  426. */
  427. usbInit();
  428. /*
  429. * disconnect for ~500ms, so that the host re-enumerates this device
  430. */
  431. usbDeviceDisconnect();
  432. for (uint8_t i = 0; i < 50; i++)
  433. _delay_ms(10); /* 0 means 0x10000, 38*1/f*0x10000 =~ 498ms */
  434. usbDeviceConnect();
  435. uart_puts("Wait for firmware");
  436. while (1) {
  437. usbPoll();
  438. delay++;
  439. /*
  440. * do some led blinking, so that it is visible that the bootloader is still running
  441. */
  442. if (delay == 0) {
  443. uart_putc('.');
  444. DLED_TGL;
  445. if (timeout < 255)
  446. timeout--;
  447. }
  448. if (request_exit || timeout == 0) {
  449. uart_puts("\n\rExit\n\r");
  450. _delay_ms(10);
  451. leave_bootloader();
  452. }
  453. }
  454. }