AVR Libc Home Page AVRs AVR Libc Development Pages
Main Page User Manual Library Reference FAQ Alphabetical Index Example Projects

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

Automatically generated by Doxygen 1.8.7 on Tue Aug 12 2014.