AVR Bootloader (avrboot cleanup)
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.

583 lines
14KB

  1. /*****************************************************************************
  2. *
  3. * AVRPROG compatible boot-loader
  4. * Version : 0.85 (Dec. 2008)
  5. * Compiler : avr-gcc 4.1.2 / avr-libc 1.4.6
  6. * size : depends on features and startup ( minmal features < 512 words)
  7. * by : Martin Thomas, Kaiserslautern, Germany
  8. * eversmith@heizung-thomas.de
  9. * Additional code and improvements contributed by:
  10. * - Uwe Bonnes
  11. * - Bjoern Riemer
  12. * - Olaf Rempel
  13. *
  14. * License : Copyright (c) 2006-2008 M. Thomas, U. Bonnes, O. Rempel
  15. * Free to use. You have to mention the copyright
  16. * owners in source-code and documentation of derived
  17. * work. No warranty! (Yes, you can insert the BSD
  18. * license here)
  19. *
  20. * Tested with ATmega8, ATmega16, ATmega162, ATmega32, ATmega324P,
  21. * ATmega644, ATmega644P, ATmega128, AT90CAN128
  22. *
  23. * - Initial versions have been based on the Butterfly bootloader-code
  24. * by Atmel Corporation (Authors: BBrandal, PKastnes, ARodland, LHM)
  25. *
  26. ****************************************************************************
  27. *
  28. * See the makefile and readme.txt for information on how to adapt
  29. * the linker-settings to the selected Boot Size (BOOTSIZE=xxxx) and
  30. * the MCU-type. Other configurations futher down in this file.
  31. *
  32. * With BOOT_SIMPLE, minimal features and discarded int-vectors
  33. * this bootloader has should fit into a a 512 word (1024, 0x400 bytes)
  34. * bootloader-section.
  35. *
  36. ****************************************************************************/
  37. /*
  38. TODOs:
  39. - check lock-bits set
  40. - __bad_interrupt still linked even with modified
  41. linker-scripts which needs a default-handler,
  42. "wasted": 3 words for AVR5 (>8kB), 2 words for AVR4
  43. - Check watchdog-disable-function in avr-libc.
  44. */
  45. // tabsize: 4
  46. /* MCU frequency */
  47. #ifndef F_CPU
  48. // #define F_CPU 7372800
  49. #define F_CPU (7372800/2)
  50. #endif
  51. /* UART Baudrate */
  52. // #define BAUDRATE 9600
  53. // #define BAUDRATE 19200
  54. #define BAUDRATE 115200
  55. /* use "Double Speed Operation" */
  56. //#define UART_DOUBLESPEED
  57. /* use second UART on mega128 / can128 / mega162 / mega324p / mega644p */
  58. //#define UART_USE_SECOND
  59. /* Device-Type:
  60. For AVRProg the BOOT-option is prefered
  61. which is the "correct" value for a bootloader.
  62. avrdude may only detect the part-code for ISP */
  63. #define DEVTYPE DEVTYPE_BOOT
  64. // #define DEVTYPE DEVTYPE_ISP
  65. /*
  66. * Pin "STARTPIN" on port "STARTPORT" in this port has to grounded
  67. * (active low) to start the bootloader
  68. */
  69. #define BLPORT PORTC
  70. #define BLDDR DDRC
  71. #define BLPIN PINC
  72. #define BLPNUM PINC7
  73. /*
  74. * Define if Watchdog-Timer should be disable at startup
  75. */
  76. #define DISABLE_WDT_AT_STARTUP
  77. /*
  78. * Watchdog-reset is issued at exit
  79. * define the timeout-value here (see avr-libc manual)
  80. */
  81. #define EXIT_WDT_TIME WDTO_250MS
  82. /*
  83. * Select startup-mode
  84. * SIMPLE-Mode - Jump to bootloader main BL-loop if key is
  85. * pressed (Pin grounded) "during" reset or jump to the
  86. * application if the pin is not grounded. The internal
  87. * pull-up resistor is enabled during the startup and
  88. * gets disabled before the application is started.
  89. * POWERSAVE-Mode - Startup is separated in two loops
  90. * which makes power-saving a little easier if no firmware
  91. * is on the chip. Needs more memory
  92. * BOOTICE-Mode - to flash the JTAGICE upgrade.ebn file.
  93. * No startup-sequence in this mode. Jump directly to the
  94. * parser-loop on reset
  95. * F_CPU in BOOTICEMODE must be 7372800 Hz to be compatible
  96. * with the org. JTAGICE-Firmware
  97. * WAIT-mode waits 1 sec for the defined character if nothing
  98. * is recived then the user prog is started.
  99. */
  100. #define START_SIMPLE
  101. //#define START_WAIT
  102. //#define START_POWERSAVE
  103. //#define START_BOOTICE
  104. /* character to start the bootloader in mode START_WAIT */
  105. #define START_WAIT_UARTCHAR 'S'
  106. /* wait-time for START_WAIT mode ( t = WAIT_TIME * 10ms ) */
  107. #define WAIT_VALUE 100 /* here: 100*10ms = 1000ms = 1sec */
  108. /*
  109. * enable/disable readout of fuse and lock-bits
  110. * (AVRPROG has to detect the AVR correctly by device-code
  111. * to show the correct information).
  112. */
  113. //#define ENABLEREADFUSELOCK
  114. /* enable/disable write of lock-bits
  115. * WARNING: lock-bits can not be reseted by bootloader (as far as I know)
  116. * Only protection no unprotection, "chip erase" from bootloader only
  117. * clears the flash but does no real "chip erase" (this is not possible
  118. * with a bootloader as far as I know)
  119. * Keep this undefined!
  120. */
  121. //#define WRITELOCKBITS
  122. /*
  123. * define the following if the bootloader should not output
  124. * itself at flash read (will fake an empty boot-section)
  125. */
  126. #define READ_PROTECT_BOOTLOADER
  127. #define VERSION_HIGH '0'
  128. #define VERSION_LOW '8'
  129. #define GET_LOCK_BITS 0x0001
  130. #define GET_LOW_FUSE_BITS 0x0000
  131. #define GET_HIGH_FUSE_BITS 0x0003
  132. #define GET_EXTENDED_FUSE_BITS 0x0002
  133. #ifdef UART_DOUBLESPEED
  134. // #define UART_CALC_BAUDRATE(baudRate) (((F_CPU*10UL) / ((baudRate) *8UL) +5)/10 -1)
  135. #define UART_CALC_BAUDRATE(baudRate) ((uint32_t)((F_CPU) + ((uint32_t)baudRate * 4UL)) / ((uint32_t)(baudRate) * 8UL) - 1)
  136. #else
  137. // #define UART_CALC_BAUDRATE(baudRate) (((F_CPU*10UL) / ((baudRate)*16UL) +5)/10 -1)
  138. #define UART_CALC_BAUDRATE(baudRate) ((uint32_t)((F_CPU) + ((uint32_t)baudRate * 8UL)) / ((uint32_t)(baudRate) * 16UL) - 1)
  139. #endif
  140. #include <stdint.h>
  141. #include <avr/io.h>
  142. #include <avr/wdt.h>
  143. #include <avr/boot.h>
  144. #include <avr/pgmspace.h>
  145. #include <avr/eeprom.h>
  146. #include <avr/interrupt.h>
  147. #include <util/delay.h>
  148. #include "chipdef.h"
  149. uint8_t gBuffer[SPM_PAGESIZE];
  150. #if defined(BOOTLOADERHASNOVECTORS)
  151. #warning "This Bootloader does not link interrupt vectors - see makefile"
  152. /* make the linker happy - it wants to see __vector_default */
  153. // void __vector_default(void) { ; }
  154. void __vector_default(void) { ; }
  155. #endif
  156. static void sendchar(uint8_t data)
  157. {
  158. while (!(UART_STATUS & (1<<UART_TXREADY)));
  159. UART_DATA = data;
  160. }
  161. static uint8_t recvchar(void)
  162. {
  163. while (!(UART_STATUS & (1<<UART_RXREADY)));
  164. return UART_DATA;
  165. }
  166. static inline void eraseFlash(void)
  167. {
  168. // erase only main section (bootloader protection)
  169. uint32_t addr = 0;
  170. while (APP_END > addr) {
  171. boot_page_erase(addr); // Perform page erase
  172. boot_spm_busy_wait(); // Wait until the memory is erased.
  173. addr += SPM_PAGESIZE;
  174. }
  175. boot_rww_enable();
  176. }
  177. static inline void recvBuffer(pagebuf_t size)
  178. {
  179. pagebuf_t cnt;
  180. uint8_t *tmp = gBuffer;
  181. for (cnt = 0; cnt < sizeof(gBuffer); cnt++) {
  182. *tmp++ = (cnt < size) ? recvchar() : 0xFF;
  183. }
  184. }
  185. static inline uint16_t writeFlashPage(uint16_t waddr, pagebuf_t size)
  186. {
  187. uint32_t pagestart = (uint32_t)waddr<<1;
  188. uint32_t baddr = pagestart;
  189. uint16_t data;
  190. uint8_t *tmp = gBuffer;
  191. do {
  192. data = *tmp++;
  193. data |= *tmp++ << 8;
  194. boot_page_fill(baddr, data); // call asm routine.
  195. baddr += 2; // Select next word in memory
  196. size -= 2; // Reduce number of bytes to write by two
  197. } while (size); // Loop until all bytes written
  198. boot_page_write(pagestart);
  199. boot_spm_busy_wait();
  200. boot_rww_enable(); // Re-enable the RWW section
  201. return baddr>>1;
  202. }
  203. static inline uint16_t writeEEpromPage(uint16_t address, pagebuf_t size)
  204. {
  205. uint8_t *tmp = gBuffer;
  206. do {
  207. eeprom_write_byte( (uint8_t*)address, *tmp++ );
  208. address++; // Select next byte
  209. size--; // Decreas number of bytes to write
  210. } while (size); // Loop until all bytes written
  211. // eeprom_busy_wait();
  212. return address;
  213. }
  214. static inline uint16_t readFlashPage(uint16_t waddr, pagebuf_t size)
  215. {
  216. uint32_t baddr = (uint32_t)waddr<<1;
  217. uint16_t data;
  218. do {
  219. #ifndef READ_PROTECT_BOOTLOADER
  220. #warning "Bootloader not read-protected"
  221. #if defined(RAMPZ)
  222. data = pgm_read_word_far(baddr);
  223. #else
  224. data = pgm_read_word_near(baddr);
  225. #endif
  226. #else
  227. // don't read bootloader
  228. if ( baddr < APP_END ) {
  229. #if defined(RAMPZ)
  230. data = pgm_read_word_far(baddr);
  231. #else
  232. data = pgm_read_word_near(baddr);
  233. #endif
  234. }
  235. else {
  236. data = 0xFFFF; // fake empty
  237. }
  238. #endif
  239. sendchar(data); // send LSB
  240. sendchar((data >> 8)); // send MSB
  241. baddr += 2; // Select next word in memory
  242. size -= 2; // Subtract two bytes from number of bytes to read
  243. } while (size); // Repeat until block has been read
  244. return baddr>>1;
  245. }
  246. static inline uint16_t readEEpromPage(uint16_t address, pagebuf_t size)
  247. {
  248. do {
  249. sendchar( eeprom_read_byte( (uint8_t*)address ) );
  250. address++;
  251. size--; // Decrease number of bytes to read
  252. } while (size); // Repeat until block has been read
  253. return address;
  254. }
  255. #if defined(ENABLEREADFUSELOCK)
  256. static uint8_t read_fuse_lock(uint16_t addr)
  257. {
  258. uint8_t mode = (1<<BLBSET) | (1<<SPMEN);
  259. uint8_t retval;
  260. asm volatile
  261. (
  262. "movw r30, %3\n\t" /* Z to addr */ \
  263. "sts %0, %2\n\t" /* set mode in SPM_REG */ \
  264. "lpm\n\t" /* load fuse/lock value into r0 */ \
  265. "mov %1,r0\n\t" /* save return value */ \
  266. : "=m" (SPM_REG),
  267. "=r" (retval)
  268. : "r" (mode),
  269. "r" (addr)
  270. : "r30", "r31", "r0"
  271. );
  272. return retval;
  273. }
  274. #endif
  275. static void send_boot(void)
  276. {
  277. sendchar('A');
  278. sendchar('V');
  279. sendchar('R');
  280. sendchar('B');
  281. sendchar('O');
  282. sendchar('O');
  283. sendchar('T');
  284. }
  285. static void (*jump_to_app)(void) = 0x0000;
  286. int main(void)
  287. {
  288. uint16_t address = 0;
  289. uint8_t device = 0, val;
  290. #ifdef DISABLE_WDT_AT_STARTUP
  291. #ifdef WDT_OFF_SPECIAL
  292. #warning "using target specific watchdog_off"
  293. bootloader_wdt_off();
  294. #else
  295. cli();
  296. wdt_reset();
  297. wdt_disable();
  298. #endif
  299. #endif
  300. #ifdef START_POWERSAVE
  301. uint8_t OK = 1;
  302. #endif
  303. BLDDR &= ~(1<<BLPNUM); // set as Input
  304. BLPORT |= (1<<BLPNUM); // Enable pullup
  305. // Set baud rate
  306. UART_BAUD_HIGH = (UART_CALC_BAUDRATE(BAUDRATE)>>8) & 0xFF;
  307. UART_BAUD_LOW = (UART_CALC_BAUDRATE(BAUDRATE) & 0xFF);
  308. #ifdef UART_DOUBLESPEED
  309. UART_STATUS = ( 1<<UART_DOUBLE );
  310. #endif
  311. UART_CTRL = UART_CTRL_DATA;
  312. UART_CTRL2 = UART_CTRL2_DATA;
  313. #if defined(START_POWERSAVE)
  314. /*
  315. This is an adoption of the Butterfly Bootloader startup-sequence.
  316. It may look a little strange but separating the login-loop from
  317. the main parser-loop gives a lot a possibilities (timeout, sleep-modes
  318. etc.).
  319. */
  320. for(;OK;) {
  321. if ((BLPIN & (1<<BLPNUM))) {
  322. // jump to main app if pin is not grounded
  323. BLPORT &= ~(1<<BLPNUM); // set to default
  324. #ifdef UART_DOUBLESPEED
  325. UART_STATUS &= ~( 1<<UART_DOUBLE );
  326. #endif
  327. jump_to_app(); // Jump to application sector
  328. } else {
  329. val = recvchar();
  330. /* ESC */
  331. if (val == 0x1B) {
  332. // AVRPROG connection
  333. // Wait for signon
  334. while (val != 'S')
  335. val = recvchar();
  336. send_boot(); // Report signon
  337. OK = 0;
  338. } else {
  339. sendchar('?');
  340. }
  341. }
  342. // Power-Save code here
  343. }
  344. #elif defined(START_SIMPLE)
  345. if ((BLPIN & (1<<BLPNUM))) {
  346. // jump to main app if pin is not grounded
  347. BLPORT &= ~(1<<BLPNUM); // set to default
  348. #ifdef UART_DOUBLESPEED
  349. UART_STATUS &= ~( 1<<UART_DOUBLE );
  350. #endif
  351. jump_to_app(); // Jump to application sector
  352. }
  353. #elif defined(START_WAIT)
  354. uint16_t cnt = 0;
  355. while (1) {
  356. if (UART_STATUS & (1<<UART_RXREADY))
  357. if (UART_DATA == START_WAIT_UARTCHAR)
  358. break;
  359. if (cnt++ >= WAIT_VALUE) {
  360. BLPORT &= ~(1<<BLPNUM); // set to default
  361. jump_to_app(); // Jump to application sector
  362. }
  363. _delay_ms(10);
  364. }
  365. send_boot();
  366. #elif defined(START_BOOTICE)
  367. #warning "BOOTICE mode - no startup-condition"
  368. #else
  369. #error "Select START_ condition for bootloader in main.c"
  370. #endif
  371. for(;;) {
  372. val = recvchar();
  373. // Autoincrement?
  374. if (val == 'a') {
  375. sendchar('Y'); // Autoincrement is quicker
  376. //write address
  377. } else if (val == 'A') {
  378. address = recvchar(); //read address 8 MSB
  379. address = (address<<8) | recvchar();
  380. sendchar('\r');
  381. // Buffer load support
  382. } else if (val == 'b') {
  383. sendchar('Y'); // Report buffer load supported
  384. sendchar((sizeof(gBuffer) >> 8) & 0xFF); // Report buffer size in bytes
  385. sendchar(sizeof(gBuffer) & 0xFF);
  386. // Start buffer load
  387. } else if (val == 'B') {
  388. pagebuf_t size;
  389. size = recvchar() << 8; // Load high byte of buffersize
  390. size |= recvchar(); // Load low byte of buffersize
  391. val = recvchar(); // Load memory type ('E' or 'F')
  392. recvBuffer(size);
  393. if (device == DEVTYPE) {
  394. if (val == 'F') {
  395. address = writeFlashPage(address, size);
  396. } else if (val == 'E') {
  397. address = writeEEpromPage(address, size);
  398. }
  399. sendchar('\r');
  400. } else {
  401. sendchar(0);
  402. }
  403. // Block read
  404. } else if (val == 'g') {
  405. pagebuf_t size;
  406. size = recvchar() << 8; // Load high byte of buffersize
  407. size |= recvchar(); // Load low byte of buffersize
  408. val = recvchar(); // Get memtype
  409. if (val == 'F') {
  410. address = readFlashPage(address, size);
  411. } else if (val == 'E') {
  412. address = readEEpromPage(address, size);
  413. }
  414. // Chip erase
  415. } else if (val == 'e') {
  416. if (device == DEVTYPE) {
  417. eraseFlash();
  418. }
  419. sendchar('\r');
  420. // Exit upgrade
  421. } else if (val == 'E') {
  422. wdt_enable(EXIT_WDT_TIME); // Enable Watchdog Timer to give reset
  423. sendchar('\r');
  424. #ifdef WRITELOCKBITS
  425. #warning "Extension 'WriteLockBits' enabled"
  426. // TODO: does not work reliably
  427. // write lockbits
  428. } else if (val == 'l') {
  429. if (device == DEVTYPE) {
  430. // write_lock_bits(recvchar());
  431. boot_lock_bits_set(recvchar()); // boot.h takes care of mask
  432. boot_spm_busy_wait();
  433. }
  434. sendchar('\r');
  435. #endif
  436. // Enter programming mode
  437. } else if (val == 'P') {
  438. sendchar('\r');
  439. // Leave programming mode
  440. } else if (val == 'L') {
  441. sendchar('\r');
  442. // return programmer type
  443. } else if (val == 'p') {
  444. sendchar('S'); // always serial programmer
  445. #ifdef ENABLEREADFUSELOCK
  446. #warning "Extension 'ReadFuseLock' enabled"
  447. // read "low" fuse bits
  448. } else if (val == 'F') {
  449. sendchar(read_fuse_lock(GET_LOW_FUSE_BITS));
  450. // read lock bits
  451. } else if (val == 'r') {
  452. sendchar(read_fuse_lock(GET_LOCK_BITS));
  453. // read high fuse bits
  454. } else if (val == 'N') {
  455. sendchar(read_fuse_lock(GET_HIGH_FUSE_BITS));
  456. // read extended fuse bits
  457. } else if (val == 'Q') {
  458. sendchar(read_fuse_lock(GET_EXTENDED_FUSE_BITS));
  459. #endif
  460. // Return device type
  461. } else if (val == 't') {
  462. sendchar(DEVTYPE);
  463. sendchar(0);
  464. // clear and set LED ignored
  465. } else if ((val == 'x') || (val == 'y')) {
  466. recvchar();
  467. sendchar('\r');
  468. // set device
  469. } else if (val == 'T') {
  470. device = recvchar();
  471. sendchar('\r');
  472. // Return software identifier
  473. } else if (val == 'S') {
  474. send_boot();
  475. // Return Software Version
  476. } else if (val == 'V') {
  477. sendchar(VERSION_HIGH);
  478. sendchar(VERSION_LOW);
  479. // Return Signature Bytes (it seems that
  480. // AVRProg expects the "Atmel-byte" 0x1E last
  481. // but shows it first in the dialog-window)
  482. } else if (val == 's') {
  483. sendchar(SIG_BYTE3);
  484. sendchar(SIG_BYTE2);
  485. sendchar(SIG_BYTE1);
  486. /* ESC */
  487. } else if(val != 0x1b) {
  488. sendchar('?');
  489. }
  490. }
  491. return 0;
  492. }