bootloader.c 14 KB

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