boot.h
1 /* Modified to use out for SPM access 2 ** Peter Knight, Optiboot project http://optiboot.googlecode.com 3 ** 4 ** Todo: Tidy up 5 ** 6 ** "_short" routines execute 1 cycle faster and use 1 less word of flash 7 ** by using "out" instruction instead of "sts". 8 ** 9 ** Additional elpm variants that trust the value of RAMPZ 10 */ 11 12 /* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Eric B. Weddington 13 All rights reserved. 14 15 Redistribution and use in source and binary forms, with or without 16 modification, are permitted provided that the following conditions are met: 17 18 * Redistributions of source code must retain the above copyright 19 notice, this list of conditions and the following disclaimer. 20 * Redistributions in binary form must reproduce the above copyright 21 notice, this list of conditions and the following disclaimer in 22 the documentation and/or other materials provided with the 23 distribution. 24 * Neither the name of the copyright holders nor the names of 25 contributors may be used to endorse or promote products derived 26 from this software without specific prior written permission. 27 28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 29 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 32 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 POSSIBILITY OF SUCH DAMAGE. */ 39 40 /* $Id: boot.h,v 1.27.2.3 2008/09/30 13:58:48 arcanum Exp $ */ 41 42 #ifndef _AVR_BOOT_H_ 43 #define _AVR_BOOT_H_ 1 44 45 /** \file */ 46 /** \defgroup avr_boot <avr/boot.h>: Bootloader Support Utilities 47 \code 48 #include <avr/io.h> 49 #include <avr/boot.h> 50 \endcode 51 52 The macros in this module provide a C language interface to the 53 bootloader support functionality of certain AVR processors. These 54 macros are designed to work with all sizes of flash memory. 55 56 Global interrupts are not automatically disabled for these macros. It 57 is left up to the programmer to do this. See the code example below. 58 Also see the processor datasheet for caveats on having global interrupts 59 enabled during writing of the Flash. 60 61 \note Not all AVR processors provide bootloader support. See your 62 processor datasheet to see if it provides bootloader support. 63 64 \todo From email with Marek: On smaller devices (all except ATmega64/128), 65 __SPM_REG is in the I/O space, accessible with the shorter "in" and "out" 66 instructions - since the boot loader has a limited size, this could be an 67 important optimization. 68 69 \par API Usage Example 70 The following code shows typical usage of the boot API. 71 72 \code 73 #include <inttypes.h> 74 #include <avr/interrupt.h> 75 #include <avr/pgmspace.h> 76 77 void boot_program_page (uint32_t page, uint8_t *buf) 78 { 79 uint16_t i; 80 uint8_t sreg; 81 82 // Disable interrupts. 83 84 sreg = SREG; 85 cli(); 86 87 eeprom_busy_wait (); 88 89 boot_page_erase (page); 90 boot_spm_busy_wait (); // Wait until the memory is erased. 91 92 for (i=0; i<SPM_PAGESIZE; i+=2) 93 { 94 // Set up little-endian word. 95 96 uint16_t w = *buf++; 97 w += (*buf++) << 8; 98 99 boot_page_fill (page + i, w); 100 } 101 102 boot_page_write (page); // Store buffer in flash page. 103 boot_spm_busy_wait(); // Wait until the memory is written. 104 105 // Reenable RWW-section again. We need this if we want to jump back 106 // to the application after bootloading. 107 108 boot_rww_enable (); 109 110 // Re-enable interrupts (if they were ever enabled). 111 112 SREG = sreg; 113 }\endcode */ 114 115 #include <avr/eeprom.h> 116 #include <avr/io.h> 117 #include <inttypes.h> 118 #include <limits.h> 119 120 /* Check for SPM Control Register in processor. */ 121 #if defined (SPMCSR) 122 # define __SPM_REG SPMCSR 123 #elif defined (SPMCR) 124 # define __SPM_REG SPMCR 125 #else 126 # error AVR processor does not provide bootloader support! 127 #endif 128 129 130 /* Check for SPM Enable bit. */ 131 #if defined(SPMEN) 132 # define __SPM_ENABLE SPMEN 133 #elif defined(SELFPRGEN) 134 # define __SPM_ENABLE SELFPRGEN 135 #else 136 # error Cannot find SPM Enable bit definition! 137 #endif 138 139 /** \ingroup avr_boot 140 \def BOOTLOADER_SECTION 141 142 Used to declare a function or variable to be placed into a 143 new section called .bootloader. This section and its contents 144 can then be relocated to any address (such as the bootloader 145 NRWW area) at link-time. */ 146 147 #define BOOTLOADER_SECTION __attribute__ ((section (".bootloader"))) 148 149 /* Create common bit definitions. */ 150 #ifdef ASB 151 #define __COMMON_ASB ASB 152 #else 153 #define __COMMON_ASB RWWSB 154 #endif 155 156 #ifdef ASRE 157 #define __COMMON_ASRE ASRE 158 #else 159 #define __COMMON_ASRE RWWSRE 160 #endif 161 162 /* Define the bit positions of the Boot Lock Bits. */ 163 164 #define BLB12 5 165 #define BLB11 4 166 #define BLB02 3 167 #define BLB01 2 168 169 /** \ingroup avr_boot 170 \def boot_spm_interrupt_enable() 171 Enable the SPM interrupt. */ 172 173 #define boot_spm_interrupt_enable() (__SPM_REG |= (uint8_t)_BV(SPMIE)) 174 175 /** \ingroup avr_boot 176 \def boot_spm_interrupt_disable() 177 Disable the SPM interrupt. */ 178 179 #define boot_spm_interrupt_disable() (__SPM_REG &= (uint8_t)~_BV(SPMIE)) 180 181 /** \ingroup avr_boot 182 \def boot_is_spm_interrupt() 183 Check if the SPM interrupt is enabled. */ 184 185 #define boot_is_spm_interrupt() (__SPM_REG & (uint8_t)_BV(SPMIE)) 186 187 /** \ingroup avr_boot 188 \def boot_rww_busy() 189 Check if the RWW section is busy. */ 190 191 #define boot_rww_busy() (__SPM_REG & (uint8_t)_BV(__COMMON_ASB)) 192 193 /** \ingroup avr_boot 194 \def boot_spm_busy() 195 Check if the SPM instruction is busy. */ 196 197 #define boot_spm_busy() (__SPM_REG & (uint8_t)_BV(__SPM_ENABLE)) 198 199 /** \ingroup avr_boot 200 \def boot_spm_busy_wait() 201 Wait while the SPM instruction is busy. */ 202 203 #define boot_spm_busy_wait() do{}while(boot_spm_busy()) 204 205 #define __BOOT_PAGE_ERASE (_BV(__SPM_ENABLE) | _BV(PGERS)) 206 #define __BOOT_PAGE_WRITE (_BV(__SPM_ENABLE) | _BV(PGWRT)) 207 #define __BOOT_PAGE_FILL _BV(__SPM_ENABLE) 208 #define __BOOT_RWW_ENABLE (_BV(__SPM_ENABLE) | _BV(__COMMON_ASRE)) 209 #define __BOOT_LOCK_BITS_SET (_BV(__SPM_ENABLE) | _BV(BLBSET)) 210 211 #define __boot_page_fill_short(address, data) \ 212 (__extension__({ \ 213 __asm__ __volatile__ \ 214 ( \ 215 "movw r0, %3\n\t" \ 216 "out %0, %1\n\t" \ 217 "spm\n\t" \ 218 "clr r1\n\t" \ 219 : \ 220 : "i" (_SFR_IO_ADDR(__SPM_REG)), \ 221 "r" ((uint8_t)__BOOT_PAGE_FILL), \ 222 "z" ((uint16_t)address), \ 223 "r" ((uint16_t)data) \ 224 : "r0" \ 225 ); \ 226 })) 227 228 #define __boot_page_fill_normal(address, data) \ 229 (__extension__({ \ 230 __asm__ __volatile__ \ 231 ( \ 232 "movw r0, %3\n\t" \ 233 "sts %0, %1\n\t" \ 234 "spm\n\t" \ 235 "clr r1\n\t" \ 236 : \ 237 : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ 238 "r" ((uint8_t)__BOOT_PAGE_FILL), \ 239 "z" ((uint16_t)address), \ 240 "r" ((uint16_t)data) \ 241 : "r0" \ 242 ); \ 243 })) 244 245 #define __boot_page_fill_alternate(address, data)\ 246 (__extension__({ \ 247 __asm__ __volatile__ \ 248 ( \ 249 "movw r0, %3\n\t" \ 250 "sts %0, %1\n\t" \ 251 "spm\n\t" \ 252 ".word 0xffff\n\t" \ 253 "nop\n\t" \ 254 "clr r1\n\t" \ 255 : \ 256 : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ 257 "r" ((uint8_t)__BOOT_PAGE_FILL), \ 258 "z" ((uint16_t)address), \ 259 "r" ((uint16_t)data) \ 260 : "r0" \ 261 ); \ 262 })) 263 264 #define __boot_page_fill_extended(address, data) \ 265 (__extension__({ \ 266 __asm__ __volatile__ \ 267 ( \ 268 "movw r0, %4\n\t" \ 269 "movw r30, %A3\n\t" \ 270 "sts %1, %C3\n\t" \ 271 "sts %0, %2\n\t" \ 272 "spm\n\t" \ 273 "clr r1\n\t" \ 274 : \ 275 : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ 276 "i" (_SFR_MEM_ADDR(RAMPZ)), \ 277 "r" ((uint8_t)__BOOT_PAGE_FILL), \ 278 "r" ((uint32_t)address), \ 279 "r" ((uint16_t)data) \ 280 : "r0", "r30", "r31" \ 281 ); \ 282 })) 283 284 #define __boot_page_fill_extended_short(address, data) \ 285 (__extension__({ \ 286 __asm__ __volatile__ \ 287 ( \ 288 "movw r0, %4\n\t" \ 289 "movw r30, %A3\n\t" \ 290 "out %1, %C3\n\t" \ 291 "out %0, %2\n\t" \ 292 "spm\n\t" \ 293 "clr r1\n\t" \ 294 : \ 295 : "i" (_SFR_IO_ADDR(__SPM_REG)), \ 296 "i" (_SFR_IO_ADDR(RAMPZ)), \ 297 "r" ((uint8_t)__BOOT_PAGE_FILL), \ 298 "r" ((uint32_t)address), \ 299 "r" ((uint16_t)data) \ 300 : "r0", "r30", "r31" \ 301 ); \ 302 })) 303 304 #define __boot_page_erase_short(address) \ 305 (__extension__({ \ 306 __asm__ __volatile__ \ 307 ( \ 308 "out %0, %1\n\t" \ 309 "spm\n\t" \ 310 : \ 311 : "i" (_SFR_IO_ADDR(__SPM_REG)), \ 312 "r" ((uint8_t)__BOOT_PAGE_ERASE), \ 313 "z" ((uint16_t)address) \ 314 ); \ 315 })) 316 317 318 #define __boot_page_erase_normal(address) \ 319 (__extension__({ \ 320 __asm__ __volatile__ \ 321 ( \ 322 "sts %0, %1\n\t" \ 323 "spm\n\t" \ 324 : \ 325 : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ 326 "r" ((uint8_t)__BOOT_PAGE_ERASE), \ 327 "z" ((uint16_t)address) \ 328 ); \ 329 })) 330 331 #define __boot_page_erase_alternate(address) \ 332 (__extension__({ \ 333 __asm__ __volatile__ \ 334 ( \ 335 "sts %0, %1\n\t" \ 336 "spm\n\t" \ 337 ".word 0xffff\n\t" \ 338 "nop\n\t" \ 339 : \ 340 : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ 341 "r" ((uint8_t)__BOOT_PAGE_ERASE), \ 342 "z" ((uint16_t)address) \ 343 ); \ 344 })) 345 346 #define __boot_page_erase_extended(address) \ 347 (__extension__({ \ 348 __asm__ __volatile__ \ 349 ( \ 350 "movw r30, %A3\n\t" \ 351 "sts %1, %C3\n\t" \ 352 "sts %0, %2\n\t" \ 353 "spm\n\t" \ 354 : \ 355 : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ 356 "i" (_SFR_MEM_ADDR(RAMPZ)), \ 357 "r" ((uint8_t)__BOOT_PAGE_ERASE), \ 358 "r" ((uint32_t)address) \ 359 : "r30", "r31" \ 360 ); \ 361 })) 362 #define __boot_page_erase_extended_short(address) \ 363 (__extension__({ \ 364 __asm__ __volatile__ \ 365 ( \ 366 "movw r30, %A3\n\t" \ 367 "out %1, %C3\n\t" \ 368 "out %0, %2\n\t" \ 369 "spm\n\t" \ 370 : \ 371 : "i" (_SFR_IO_ADDR(__SPM_REG)), \ 372 "i" (_SFR_IO_ADDR(RAMPZ)), \ 373 "r" ((uint8_t)__BOOT_PAGE_ERASE), \ 374 "r" ((uint32_t)address) \ 375 : "r30", "r31" \ 376 ); \ 377 })) 378 379 #define __boot_page_write_short(address) \ 380 (__extension__({ \ 381 __asm__ __volatile__ \ 382 ( \ 383 "out %0, %1\n\t" \ 384 "spm\n\t" \ 385 : \ 386 : "i" (_SFR_IO_ADDR(__SPM_REG)), \ 387 "r" ((uint8_t)__BOOT_PAGE_WRITE), \ 388 "z" ((uint16_t)address) \ 389 ); \ 390 })) 391 392 #define __boot_page_write_normal(address) \ 393 (__extension__({ \ 394 __asm__ __volatile__ \ 395 ( \ 396 "sts %0, %1\n\t" \ 397 "spm\n\t" \ 398 : \ 399 : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ 400 "r" ((uint8_t)__BOOT_PAGE_WRITE), \ 401 "z" ((uint16_t)address) \ 402 ); \ 403 })) 404 405 #define __boot_page_write_alternate(address) \ 406 (__extension__({ \ 407 __asm__ __volatile__ \ 408 ( \ 409 "sts %0, %1\n\t" \ 410 "spm\n\t" \ 411 ".word 0xffff\n\t" \ 412 "nop\n\t" \ 413 : \ 414 : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ 415 "r" ((uint8_t)__BOOT_PAGE_WRITE), \ 416 "z" ((uint16_t)address) \ 417 ); \ 418 })) 419 420 #define __boot_page_write_extended(address) \ 421 (__extension__({ \ 422 __asm__ __volatile__ \ 423 ( \ 424 "movw r30, %A3\n\t" \ 425 "sts %1, %C3\n\t" \ 426 "sts %0, %2\n\t" \ 427 "spm\n\t" \ 428 : \ 429 : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ 430 "i" (_SFR_MEM_ADDR(RAMPZ)), \ 431 "r" ((uint8_t)__BOOT_PAGE_WRITE), \ 432 "r" ((uint32_t)address) \ 433 : "r30", "r31" \ 434 ); \ 435 })) 436 #define __boot_page_write_extended_short(address) \ 437 (__extension__({ \ 438 __asm__ __volatile__ \ 439 ( \ 440 "movw r30, %A3\n\t" \ 441 "out %1, %C3\n\t" \ 442 "out %0, %2\n\t" \ 443 "spm\n\t" \ 444 : \ 445 : "i" (_SFR_IO_ADDR(__SPM_REG)), \ 446 "i" (_SFR_IO_ADDR(RAMPZ)), \ 447 "r" ((uint8_t)__BOOT_PAGE_WRITE), \ 448 "r" ((uint32_t)address) \ 449 : "r30", "r31" \ 450 ); \ 451 })) 452 453 #define __boot_rww_enable_short() \ 454 (__extension__({ \ 455 __asm__ __volatile__ \ 456 ( \ 457 "out %0, %1\n\t" \ 458 "spm\n\t" \ 459 : \ 460 : "i" (_SFR_IO_ADDR(__SPM_REG)), \ 461 "r" ((uint8_t)__BOOT_RWW_ENABLE) \ 462 ); \ 463 })) 464 465 #define __boot_rww_enable() \ 466 (__extension__({ \ 467 __asm__ __volatile__ \ 468 ( \ 469 "sts %0, %1\n\t" \ 470 "spm\n\t" \ 471 : \ 472 : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ 473 "r" ((uint8_t)__BOOT_RWW_ENABLE) \ 474 ); \ 475 })) 476 477 #define __boot_rww_enable_alternate() \ 478 (__extension__({ \ 479 __asm__ __volatile__ \ 480 ( \ 481 "sts %0, %1\n\t" \ 482 "spm\n\t" \ 483 ".word 0xffff\n\t" \ 484 "nop\n\t" \ 485 : \ 486 : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ 487 "r" ((uint8_t)__BOOT_RWW_ENABLE) \ 488 ); \ 489 })) 490 491 /* From the mega16/mega128 data sheets (maybe others): 492 493 Bits by SPM To set the Boot Loader Lock bits, write the desired data to 494 R0, write "X0001001" to SPMCR and execute SPM within four clock cycles 495 after writing SPMCR. The only accessible Lock bits are the Boot Lock bits 496 that may prevent the Application and Boot Loader section from any 497 software update by the MCU. 498 499 If bits 5..2 in R0 are cleared (zero), the corresponding Boot Lock bit 500 will be programmed if an SPM instruction is executed within four cycles 501 after BLBSET and SPMEN (or SELFPRGEN) are set in SPMCR. The Z-pointer is 502 don't care during this operation, but for future compatibility it is 503 recommended to load the Z-pointer with $0001 (same as used for reading the 504 Lock bits). For future compatibility It is also recommended to set bits 7, 505 6, 1, and 0 in R0 to 1 when writing the Lock bits. When programming the 506 Lock bits the entire Flash can be read during the operation. */ 507 508 #define __boot_lock_bits_set_short(lock_bits) \ 509 (__extension__({ \ 510 uint8_t value = (uint8_t)(~(lock_bits)); \ 511 __asm__ __volatile__ \ 512 ( \ 513 "ldi r30, 1\n\t" \ 514 "ldi r31, 0\n\t" \ 515 "mov r0, %2\n\t" \ 516 "out %0, %1\n\t" \ 517 "spm\n\t" \ 518 : \ 519 : "i" (_SFR_IO_ADDR(__SPM_REG)), \ 520 "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \ 521 "r" (value) \ 522 : "r0", "r30", "r31" \ 523 ); \ 524 })) 525 526 #define __boot_lock_bits_set(lock_bits) \ 527 (__extension__({ \ 528 uint8_t value = (uint8_t)(~(lock_bits)); \ 529 __asm__ __volatile__ \ 530 ( \ 531 "ldi r30, 1\n\t" \ 532 "ldi r31, 0\n\t" \ 533 "mov r0, %2\n\t" \ 534 "sts %0, %1\n\t" \ 535 "spm\n\t" \ 536 : \ 537 : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ 538 "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \ 539 "r" (value) \ 540 : "r0", "r30", "r31" \ 541 ); \ 542 })) 543 544 #define __boot_lock_bits_set_alternate(lock_bits) \ 545 (__extension__({ \ 546 uint8_t value = (uint8_t)(~(lock_bits)); \ 547 __asm__ __volatile__ \ 548 ( \ 549 "ldi r30, 1\n\t" \ 550 "ldi r31, 0\n\t" \ 551 "mov r0, %2\n\t" \ 552 "sts %0, %1\n\t" \ 553 "spm\n\t" \ 554 ".word 0xffff\n\t" \ 555 "nop\n\t" \ 556 : \ 557 : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ 558 "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \ 559 "r" (value) \ 560 : "r0", "r30", "r31" \ 561 ); \ 562 })) 563 564 /* 565 Reading lock and fuse bits: 566 567 Similarly to writing the lock bits above, set BLBSET and SPMEN (or 568 SELFPRGEN) bits in __SPMREG, and then (within four clock cycles) issue an 569 LPM instruction. 570 571 Z address: contents: 572 0x0000 low fuse bits 573 0x0001 lock bits 574 0x0002 extended fuse bits 575 0x0003 high fuse bits 576 577 Sounds confusing, doesn't it? 578 579 Unlike the macros in pgmspace.h, no need to care for non-enhanced 580 cores here as these old cores do not provide SPM support anyway. 581 */ 582 583 /** \ingroup avr_boot 584 \def GET_LOW_FUSE_BITS 585 address to read the low fuse bits, using boot_lock_fuse_bits_get 586 */ 587 #define GET_LOW_FUSE_BITS (0x0000) 588 /** \ingroup avr_boot 589 \def GET_LOCK_BITS 590 address to read the lock bits, using boot_lock_fuse_bits_get 591 */ 592 #define GET_LOCK_BITS (0x0001) 593 /** \ingroup avr_boot 594 \def GET_EXTENDED_FUSE_BITS 595 address to read the extended fuse bits, using boot_lock_fuse_bits_get 596 */ 597 #define GET_EXTENDED_FUSE_BITS (0x0002) 598 /** \ingroup avr_boot 599 \def GET_HIGH_FUSE_BITS 600 address to read the high fuse bits, using boot_lock_fuse_bits_get 601 */ 602 #define GET_HIGH_FUSE_BITS (0x0003) 603 604 /** \ingroup avr_boot 605 \def boot_lock_fuse_bits_get(address) 606 607 Read the lock or fuse bits at \c address. 608 609 Parameter \c address can be any of GET_LOW_FUSE_BITS, 610 GET_LOCK_BITS, GET_EXTENDED_FUSE_BITS, or GET_HIGH_FUSE_BITS. 611 612 \note The lock and fuse bits returned are the physical values, 613 i.e. a bit returned as 0 means the corresponding fuse or lock bit 614 is programmed. 615 */ 616 #define boot_lock_fuse_bits_get_short(address) \ 617 (__extension__({ \ 618 uint8_t __result; \ 619 __asm__ __volatile__ \ 620 ( \ 621 "ldi r30, %3\n\t" \ 622 "ldi r31, 0\n\t" \ 623 "out %1, %2\n\t" \ 624 "lpm %0, Z\n\t" \ 625 : "=r" (__result) \ 626 : "i" (_SFR_IO_ADDR(__SPM_REG)), \ 627 "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \ 628 "M" (address) \ 629 : "r0", "r30", "r31" \ 630 ); \ 631 __result; \ 632 })) 633 634 #define boot_lock_fuse_bits_get(address) \ 635 (__extension__({ \ 636 uint8_t __result; \ 637 __asm__ __volatile__ \ 638 ( \ 639 "ldi r30, %3\n\t" \ 640 "ldi r31, 0\n\t" \ 641 "sts %1, %2\n\t" \ 642 "lpm %0, Z\n\t" \ 643 : "=r" (__result) \ 644 : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ 645 "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \ 646 "M" (address) \ 647 : "r0", "r30", "r31" \ 648 ); \ 649 __result; \ 650 })) 651 652 /** \ingroup avr_boot 653 \def boot_signature_byte_get(address) 654 655 Read the Signature Row byte at \c address. For some MCU types, 656 this function can also retrieve the factory-stored oscillator 657 calibration bytes. 658 659 Parameter \c address can be 0-0x1f as documented by the datasheet. 660 \note The values are MCU type dependent. 661 */ 662 663 #define __BOOT_SIGROW_READ (_BV(__SPM_ENABLE) | _BV(SIGRD)) 664 665 #define boot_signature_byte_get_short(addr) \ 666 (__extension__({ \ 667 uint16_t __addr16 = (uint16_t)(addr); \ 668 uint8_t __result; \ 669 __asm__ __volatile__ \ 670 ( \ 671 "out %1, %2\n\t" \ 672 "lpm %0, Z" "\n\t" \ 673 : "=r" (__result) \ 674 : "i" (_SFR_IO_ADDR(__SPM_REG)), \ 675 "r" ((uint8_t) __BOOT_SIGROW_READ), \ 676 "z" (__addr16) \ 677 ); \ 678 __result; \ 679 })) 680 681 #define boot_signature_byte_get(addr) \ 682 (__extension__({ \ 683 uint16_t __addr16 = (uint16_t)(addr); \ 684 uint8_t __result; \ 685 __asm__ __volatile__ \ 686 ( \ 687 "sts %1, %2\n\t" \ 688 "lpm %0, Z" "\n\t" \ 689 : "=r" (__result) \ 690 : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ 691 "r" ((uint8_t) __BOOT_SIGROW_READ), \ 692 "z" (__addr16) \ 693 ); \ 694 __result; \ 695 })) 696 697 /** \ingroup avr_boot 698 \def boot_page_fill(address, data) 699 700 Fill the bootloader temporary page buffer for flash 701 address with data word. 702 703 \note The address is a byte address. The data is a word. The AVR 704 writes data to the buffer a word at a time, but addresses the buffer 705 per byte! So, increment your address by 2 between calls, and send 2 706 data bytes in a word format! The LSB of the data is written to the lower 707 address; the MSB of the data is written to the higher address.*/ 708 709 /** \ingroup avr_boot 710 \def boot_page_erase(address) 711 712 Erase the flash page that contains address. 713 714 \note address is a byte address in flash, not a word address. */ 715 716 /** \ingroup avr_boot 717 \def boot_page_write(address) 718 719 Write the bootloader temporary page buffer 720 to flash page that contains address. 721 722 \note address is a byte address in flash, not a word address. */ 723 724 /** \ingroup avr_boot 725 \def boot_rww_enable() 726 727 Enable the Read-While-Write memory section. */ 728 729 /** \ingroup avr_boot 730 \def boot_lock_bits_set(lock_bits) 731 732 Set the bootloader lock bits. 733 734 \param lock_bits A mask of which Boot Loader Lock Bits to set. 735 736 \note In this context, a 'set bit' will be written to a zero value. 737 Note also that only BLBxx bits can be programmed by this command. 738 739 For example, to disallow the SPM instruction from writing to the Boot 740 Loader memory section of flash, you would use this macro as such: 741 742 \code 743 boot_lock_bits_set (_BV (BLB11)); 744 \endcode 745 746 \note Like any lock bits, the Boot Loader Lock Bits, once set, 747 cannot be cleared again except by a chip erase which will in turn 748 also erase the boot loader itself. */ 749 750 /* Normal versions of the macros use 16-bit addresses. 751 Extended versions of the macros use 32-bit addresses. 752 Alternate versions of the macros use 16-bit addresses and require special 753 instruction sequences after LPM. 754 755 FLASHEND is defined in the ioXXXX.h file. 756 USHRT_MAX is defined in <limits.h>. */ 757 758 #if defined(__AVR_ATmega161__) || defined(__AVR_ATmega163__) \ 759 || defined(__AVR_ATmega323__) 760 761 /* Alternate: ATmega161/163/323 and 16 bit address */ 762 #define boot_page_fill(address, data) __boot_page_fill_alternate(address, data) 763 #define boot_page_erase(address) __boot_page_erase_alternate(address) 764 #define boot_page_write(address) __boot_page_write_alternate(address) 765 #define boot_rww_enable() __boot_rww_enable_alternate() 766 #define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_alternate(lock_bits) 767 768 #elif (FLASHEND > USHRT_MAX) 769 770 /* Extended: >16 bit address */ 771 #define boot_page_fill(address, data) __boot_page_fill_extended_short(address, data) 772 #define boot_page_erase(address) __boot_page_erase_extended_short(address) 773 #define boot_page_write(address) __boot_page_write_extended_short(address) 774 #define boot_rww_enable() __boot_rww_enable_short() 775 #define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits) 776 777 #else 778 779 /* Normal: 16 bit address */ 780 #define boot_page_fill(address, data) __boot_page_fill_short(address, data) 781 #define boot_page_erase(address) __boot_page_erase_short(address) 782 #define boot_page_write(address) __boot_page_write_short(address) 783 #define boot_rww_enable() __boot_rww_enable_short() 784 #define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits) 785 786 #endif 787 788 /** \ingroup avr_boot 789 790 Same as boot_page_fill() except it waits for eeprom and spm operations to 791 complete before filling the page. */ 792 793 #define boot_page_fill_safe(address, data) \ 794 do { \ 795 boot_spm_busy_wait(); \ 796 eeprom_busy_wait(); \ 797 boot_page_fill(address, data); \ 798 } while (0) 799 800 /** \ingroup avr_boot 801 802 Same as boot_page_erase() except it waits for eeprom and spm operations to 803 complete before erasing the page. */ 804 805 #define boot_page_erase_safe(address) \ 806 do { \ 807 boot_spm_busy_wait(); \ 808 eeprom_busy_wait(); \ 809 boot_page_erase (address); \ 810 } while (0) 811 812 /** \ingroup avr_boot 813 814 Same as boot_page_write() except it waits for eeprom and spm operations to 815 complete before writing the page. */ 816 817 #define boot_page_write_safe(address) \ 818 do { \ 819 boot_spm_busy_wait(); \ 820 eeprom_busy_wait(); \ 821 boot_page_write (address); \ 822 } while (0) 823 824 /** \ingroup avr_boot 825 826 Same as boot_rww_enable() except waits for eeprom and spm operations to 827 complete before enabling the RWW mameory. */ 828 829 #define boot_rww_enable_safe() \ 830 do { \ 831 boot_spm_busy_wait(); \ 832 eeprom_busy_wait(); \ 833 boot_rww_enable(); \ 834 } while (0) 835 836 /** \ingroup avr_boot 837 838 Same as boot_lock_bits_set() except waits for eeprom and spm operations to 839 complete before setting the lock bits. */ 840 841 #define boot_lock_bits_set_safe(lock_bits) \ 842 do { \ 843 boot_spm_busy_wait(); \ 844 eeprom_busy_wait(); \ 845 boot_lock_bits_set (lock_bits); \ 846 } while (0) 847 848 #endif /* _AVR_BOOT_H_ */