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.
 
 
 
 
 

540 lines
13 KiB

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