AVR-LibC  2.3.0git
Standard C library for AVR-GCC
 

AVR-LibC Documen­tation

AVR-LibC Development Pages

Main Page

User Manual

Library Refe­rence

FAQ

Example Projects

File List

Index

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