bootloader.c 14 KB

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