1 |
/* |
/* Copyright (c) 2002-2003, Eric B. Weddington |
|
Copyright (c) 2002-2003, Eric B. Weddington |
|
2 |
All rights reserved. |
All rights reserved. |
3 |
|
|
4 |
Redistribution and use in source and binary forms, with or without |
Redistribution and use in source and binary forms, with or without |
24 |
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
25 |
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
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 |
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
27 |
POSSIBILITY OF SUCH DAMAGE. |
POSSIBILITY OF SUCH DAMAGE. */ |
|
*/ |
|
|
|
|
28 |
|
|
29 |
/** \defgroup avr_boot Bootloader Support Utilities |
/** \defgroup avr_boot Bootloader Support Utilities |
30 |
\code |
\code |
48 |
important optimization. |
important optimization. |
49 |
*/ |
*/ |
50 |
|
|
|
|
|
|
|
|
51 |
#ifndef _AVR_BOOT_H_ |
#ifndef _AVR_BOOT_H_ |
52 |
#define _AVR_BOOT_H_ 1 |
#define _AVR_BOOT_H_ 1 |
53 |
|
|
|
|
|
54 |
#include <avr/eeprom.h> |
#include <avr/eeprom.h> |
55 |
#include <avr/io.h> |
#include <avr/io.h> |
56 |
#include <limits.h> |
#include <limits.h> |
57 |
|
|
|
|
|
|
|
|
58 |
/* Check for SPM Control Register in processor. */ |
/* Check for SPM Control Register in processor. */ |
59 |
#ifdef SPMCSR |
#ifdef SPMCSR |
60 |
#define __SPM_REG SPMCSR |
# define __SPM_REG SPMCSR |
|
#else |
|
|
#ifdef SPMCR |
|
|
#define __SPM_REG SPMCR |
|
61 |
#else |
#else |
62 |
#error AVR processor does not provide bootloader support! |
# ifdef SPMCR |
63 |
#endif |
# define __SPM_REG SPMCR |
64 |
|
# else |
65 |
|
# error AVR processor does not provide bootloader support! |
66 |
|
# endif |
67 |
#endif |
#endif |
68 |
|
|
69 |
/** \ingroup avr_boot |
/** \ingroup avr_boot |
76 |
|
|
77 |
#define BOOTLOADER_SECTION __attribute__ ((section (".bootloader"))) |
#define BOOTLOADER_SECTION __attribute__ ((section (".bootloader"))) |
78 |
|
|
|
|
|
79 |
/* Create common bit definitions. */ |
/* Create common bit definitions. */ |
80 |
#ifdef ASB |
#ifdef ASB |
81 |
#define __COMMON_ASB ASB |
#define __COMMON_ASB ASB |
89 |
#define __COMMON_ASRE RWWSRE |
#define __COMMON_ASRE RWWSRE |
90 |
#endif |
#endif |
91 |
|
|
|
|
|
|
|
|
92 |
/** \ingroup avr_boot |
/** \ingroup avr_boot |
93 |
\def boot_spm_interrupt_enable() |
\def boot_spm_interrupt_enable() |
94 |
Enable the SPM interrupt. */ |
Enable the SPM interrupt. */ |
95 |
|
|
96 |
#define boot_spm_interrupt_enable() (__SPM_REG |= (unsigned char)_BV(SPMIE)) |
#define boot_spm_interrupt_enable() (__SPM_REG |= (unsigned char)_BV(SPMIE)) |
97 |
|
|
98 |
/** \ingroup avr_boot |
/** \ingroup avr_boot |
99 |
\def boot_spm_interrupt_disable() |
\def boot_spm_interrupt_disable() |
100 |
Disable the SPM interrupt. */ |
Disable the SPM interrupt. */ |
101 |
|
|
102 |
#define boot_spm_interrupt_disable() (__SPM_REG &= (unsigned char)~_BV(SPMIE)) |
#define boot_spm_interrupt_disable() (__SPM_REG &= (unsigned char)~_BV(SPMIE)) |
103 |
|
|
104 |
/** \ingroup avr_boot |
/** \ingroup avr_boot |
105 |
\def boot_is_spm_interrupt() |
\def boot_is_spm_interrupt() |
106 |
Check if the SPM interrupt is enabled. */ |
Check if the SPM interrupt is enabled. */ |
107 |
|
|
108 |
#define boot_is_spm_interrupt() (__SPM_REG & (unsigned char)_BV(SPMIE)) |
#define boot_is_spm_interrupt() (__SPM_REG & (unsigned char)_BV(SPMIE)) |
109 |
|
|
110 |
/** \ingroup avr_boot |
/** \ingroup avr_boot |
111 |
\def boot_rww_busy() |
\def boot_rww_busy() |
112 |
Check if the RWW section is busy. */ |
Check if the RWW section is busy. */ |
113 |
|
|
114 |
#define boot_rww_busy() (__SPM_REG & (unsigned char)_BV(__COMMON_ASB)) |
#define boot_rww_busy() (__SPM_REG & (unsigned char)_BV(__COMMON_ASB)) |
115 |
|
|
116 |
/** \ingroup avr_boot |
/** \ingroup avr_boot |
117 |
\def boot_spm_busy() |
\def boot_spm_busy() |
118 |
Check if the SPM instruction is busy. */ |
Check if the SPM instruction is busy. */ |
119 |
|
|
120 |
#define boot_spm_busy() (__SPM_REG & (unsigned char)_BV(SPMEN)) |
#define boot_spm_busy() (__SPM_REG & (unsigned char)_BV(SPMEN)) |
121 |
|
|
122 |
/** \ingroup avr_boot |
/** \ingroup avr_boot |
123 |
\def boot_spm_busy_wait() |
\def boot_spm_busy_wait() |
124 |
Wait while the SPM instruction is busy. */ |
Wait while the SPM instruction is busy. */ |
125 |
|
|
126 |
#define boot_spm_busy_wait() do{}while(boot_spm_busy()) |
#define boot_spm_busy_wait() do{}while(boot_spm_busy()) |
|
|
|
|
|
|
127 |
|
|
128 |
#define __BOOT_PAGE_ERASE (_BV(SPMEN) | _BV(PGERS)) |
#define __BOOT_PAGE_ERASE (_BV(SPMEN) | _BV(PGERS)) |
129 |
#define __BOOT_PAGE_WRITE (_BV(SPMEN) | _BV(PGWRT)) |
#define __BOOT_PAGE_WRITE (_BV(SPMEN) | _BV(PGWRT)) |
131 |
#define __BOOT_RWW_ENABLE (_BV(SPMEN) | _BV(__COMMON_ASRE)) |
#define __BOOT_RWW_ENABLE (_BV(SPMEN) | _BV(__COMMON_ASRE)) |
132 |
#define __BOOT_LOCK_BITS_SET (_BV(SPMEN) | _BV(BLBSET)) |
#define __BOOT_LOCK_BITS_SET (_BV(SPMEN) | _BV(BLBSET)) |
133 |
|
|
134 |
#define __BOOT_LOCK_BITS_MASK (_BV(BLB01) | _BV(BLB02) | _BV(BLB11) | _BV(BLB12)) |
#define __BOOT_LOCK_BITS_MASK (_BV(BLB01) | _BV(BLB02) \ |
135 |
|
| _BV(BLB11) | _BV(BLB12)) |
|
|
|
136 |
|
|
137 |
#define __boot_page_fill_normal(address, data) \ |
#define __boot_page_fill_normal(address, data) \ |
138 |
({ \ |
({ \ |
153 |
); \ |
); \ |
154 |
}) |
}) |
155 |
|
|
156 |
|
#define __boot_page_fill_alternate(address, data)\ |
|
#define __boot_page_fill_alternate(address, data) \ |
|
157 |
({ \ |
({ \ |
158 |
boot_spm_busy_wait(); \ |
boot_spm_busy_wait(); \ |
159 |
while(!eeprom_is_ready()); \ |
while(!eeprom_is_ready()); \ |
211 |
); \ |
); \ |
212 |
}) |
}) |
213 |
|
|
|
|
|
214 |
#define __boot_page_erase_alternate(address) \ |
#define __boot_page_erase_alternate(address) \ |
215 |
({ \ |
({ \ |
216 |
boot_spm_busy_wait(); \ |
boot_spm_busy_wait(); \ |
229 |
); \ |
); \ |
230 |
}) |
}) |
231 |
|
|
|
|
|
|
|
|
232 |
#define __boot_page_erase_extended(address) \ |
#define __boot_page_erase_extended(address) \ |
233 |
({ \ |
({ \ |
234 |
boot_spm_busy_wait(); \ |
boot_spm_busy_wait(); \ |
247 |
); \ |
); \ |
248 |
}) |
}) |
249 |
|
|
|
|
|
250 |
#define __boot_page_write_normal(address) \ |
#define __boot_page_write_normal(address) \ |
251 |
({ \ |
({ \ |
252 |
boot_spm_busy_wait(); \ |
boot_spm_busy_wait(); \ |
263 |
); \ |
); \ |
264 |
}) |
}) |
265 |
|
|
|
|
|
266 |
#define __boot_page_write_alternate(address) \ |
#define __boot_page_write_alternate(address) \ |
267 |
({ \ |
({ \ |
268 |
boot_spm_busy_wait(); \ |
boot_spm_busy_wait(); \ |
281 |
); \ |
); \ |
282 |
}) |
}) |
283 |
|
|
|
|
|
|
|
|
284 |
#define __boot_page_write_extended(address) \ |
#define __boot_page_write_extended(address) \ |
285 |
({ \ |
({ \ |
286 |
boot_spm_busy_wait(); \ |
boot_spm_busy_wait(); \ |
299 |
); \ |
); \ |
300 |
}) |
}) |
301 |
|
|
|
|
|
302 |
#define __boot_rww_enable() \ |
#define __boot_rww_enable() \ |
303 |
({ \ |
({ \ |
304 |
boot_spm_busy_wait(); \ |
boot_spm_busy_wait(); \ |
312 |
); \ |
); \ |
313 |
}) |
}) |
314 |
|
|
|
|
|
315 |
#define __boot_rww_enable_alternate() \ |
#define __boot_rww_enable_alternate() \ |
316 |
({ \ |
({ \ |
317 |
boot_spm_busy_wait(); \ |
boot_spm_busy_wait(); \ |
327 |
); \ |
); \ |
328 |
}) |
}) |
329 |
|
|
|
|
|
330 |
#define __boot_lock_bits_set(lock_bits) \ |
#define __boot_lock_bits_set(lock_bits) \ |
331 |
({ \ |
({ \ |
332 |
unsigned char value = (unsigned char)(lock_bits | __BOOT_LOCK_BITS_MASK); \ |
unsigned char value = (unsigned char)(lock_bits | __BOOT_LOCK_BITS_MASK); \ |
346 |
); \ |
); \ |
347 |
}) |
}) |
348 |
|
|
|
|
|
349 |
#define __boot_lock_bits_set_alternate(lock_bits) \ |
#define __boot_lock_bits_set_alternate(lock_bits) \ |
350 |
({ \ |
({ \ |
351 |
unsigned char value = (unsigned char)(lock_bits | __BOOT_LOCK_BITS_MASK); \ |
unsigned char value = (unsigned char)(lock_bits | __BOOT_LOCK_BITS_MASK); \ |
367 |
); \ |
); \ |
368 |
}) |
}) |
369 |
|
|
|
|
|
370 |
/** \ingroup avr_boot |
/** \ingroup avr_boot |
371 |
\def boot_page_fill(address, data) |
\def boot_page_fill(address, data) |
372 |
|
|
386 |
|
|
387 |
\note address is a byte address in flash, not a word address. */ |
\note address is a byte address in flash, not a word address. */ |
388 |
|
|
|
|
|
389 |
/** \ingroup avr_boot |
/** \ingroup avr_boot |
390 |
\def boot_page_write(address) |
\def boot_page_write(address) |
391 |
|
|
394 |
|
|
395 |
\note address is a byte address in flash, not a word address. */ |
\note address is a byte address in flash, not a word address. */ |
396 |
|
|
|
|
|
397 |
/** \ingroup avr_boot |
/** \ingroup avr_boot |
398 |
\def boot_rww_enable() |
\def boot_rww_enable() |
399 |
|
|
400 |
Enable the Read-While-Write memory section. |
Enable the Read-While-Write memory section. */ |
|
|
|
|
*/ |
|
|
|
|
401 |
|
|
402 |
/** \ingroup avr_boot |
/** \ingroup avr_boot |
403 |
\def boot_lock_bits_set(lock_bits) |
\def boot_lock_bits_set(lock_bits) |
404 |
|
|
405 |
Set the bootloader lock bits. |
Set the bootloader lock bits. */ |
|
|
|
|
*/ |
|
406 |
|
|
407 |
|
/* Normal versions of the macros use 16-bit addresses. |
408 |
|
Extended versions of the macros use 32-bit addresses. |
409 |
|
Alternate versions of the macros use 16-bit addresses and require special |
410 |
|
instruction sequences after LPM. |
411 |
|
|
412 |
/* |
FLASHEND is defined in the ioXXXX.h file. |
413 |
Normal versions of the macros use 16-bit addresses. |
USHRT_MAX is defined in <limits.h>. */ |
|
Extended versions of the macros use 32-bit addresses. |
|
|
Alternate versions of the macros use 16-bit addresses and require special instruction |
|
|
sequences after LPM. |
|
|
|
|
|
FLASHEND is defined in the ioXXXX.h file. |
|
|
USHRT_MAX is defined in <limits.h>. |
|
|
*/ |
|
414 |
|
|
415 |
#if defined(__AVR_ATmega161__) || defined(__AVR_ATmega163__) || defined(__AVR_ATmega323__) |
#if defined(__AVR_ATmega161__) || defined(__AVR_ATmega163__) \ |
416 |
|
|| defined(__AVR_ATmega323__) |
417 |
|
|
418 |
/* Alternate: ATmega161/163/323 and 16 bit address */ |
/* Alternate: ATmega161/163/323 and 16 bit address */ |
419 |
#define boot_page_fill(address, data) __boot_page_fill_alternate(address, data) |
#define boot_page_fill(address, data) __boot_page_fill_alternate(address, data) |
420 |
#define boot_page_erase(address) __boot_page_erase_alternate(address) |
#define boot_page_erase(address) __boot_page_erase_alternate(address) |
421 |
#define boot_page_write(address) __boot_page_write_alternate(address) |
#define boot_page_write(address) __boot_page_write_alternate(address) |
422 |
#define boot_rww_enable() __boot_rww_enable_alternate() |
#define boot_rww_enable() __boot_rww_enable_alternate() |
423 |
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_alternate(lock_bits) |
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_alternate(lock_bits) |
424 |
|
|
425 |
#elif (FLASHEND > USHRT_MAX) |
#elif (FLASHEND > USHRT_MAX) |
426 |
|
|
427 |
/* Extended: >16 bit address */ |
/* Extended: >16 bit address */ |
428 |
#define boot_page_fill(address, data) __boot_page_fill_extended(address, data) |
#define boot_page_fill(address, data) __boot_page_fill_extended(address, data) |
429 |
#define boot_page_erase(address) __boot_page_erase_extended(address) |
#define boot_page_erase(address) __boot_page_erase_extended(address) |
430 |
#define boot_page_write(address) __boot_page_write_extended(address) |
#define boot_page_write(address) __boot_page_write_extended(address) |
431 |
#define boot_rww_enable() __boot_rww_enable() |
#define boot_rww_enable() __boot_rww_enable() |
432 |
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set(lock_bits) |
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set(lock_bits) |
433 |
|
|
434 |
#else |
#else |
435 |
|
|
436 |
/* Normal: 16 bit address */ |
/* Normal: 16 bit address */ |
437 |
#define boot_page_fill(address, data) __boot_page_fill_normal(address, data) |
#define boot_page_fill(address, data) __boot_page_fill_normal(address, data) |
438 |
#define boot_page_erase(address) __boot_page_erase_normal(address) |
#define boot_page_erase(address) __boot_page_erase_normal(address) |
439 |
#define boot_page_write(address) __boot_page_write_normal(address) |
#define boot_page_write(address) __boot_page_write_normal(address) |
440 |
#define boot_rww_enable() __boot_rww_enable() |
#define boot_rww_enable() __boot_rww_enable() |
441 |
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set(lock_bits) |
#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set(lock_bits) |
442 |
|
|
443 |
#endif |
#endif |
444 |
|
|
|
|
|
445 |
/** \ingroup avr_boot |
/** \ingroup avr_boot |
446 |
|
|
447 |
API Usage Example: |
API Usage Example: |
449 |
\code |
\code |
450 |
#include <avr/interrupt.h> |
#include <avr/interrupt.h> |
451 |
#include <avr/pgmspace.h> |
#include <avr/pgmspace.h> |
452 |
|
|
453 |
#define ADDRESS 0x1C000UL |
#define ADDRESS 0x1C000UL |
454 |
|
|
455 |
void boot_test(void) |
void boot_test(void) |
456 |
{ |
{ |
457 |
unsigned char buffer[8]; |
unsigned char buffer[8]; |
465 |
boot_rww_enable(); |
boot_rww_enable(); |
466 |
} |
} |
467 |
|
|
|
|
|
468 |
// Write data to buffer a word at a time. Note incrementing address by 2. |
// Write data to buffer a word at a time. Note incrementing address by 2. |
469 |
// SPM_PAGESIZE is defined in the microprocessor IO header file. |
// SPM_PAGESIZE is defined in the microprocessor IO header file. |
470 |
for(unsigned long i = ADDRESS; i < ADDRESS + SPM_PAGESIZE; i += 2) |
for(unsigned long i = ADDRESS; i < ADDRESS + SPM_PAGESIZE; i += 2) |
472 |
boot_page_fill(i, (i-ADDRESS) + ((i-ADDRESS+1) << 8)); |
boot_page_fill(i, (i-ADDRESS) + ((i-ADDRESS+1) << 8)); |
473 |
} |
} |
474 |
|
|
|
|
|
475 |
// Write page. |
// Write page. |
476 |
boot_page_write((unsigned long)ADDRESS); |
boot_page_write((unsigned long)ADDRESS); |
477 |
while(boot_rww_busy()) |
while(boot_rww_busy()) |
481 |
|
|
482 |
sei(); |
sei(); |
483 |
|
|
|
|
|
484 |
// Read back the values and display. |
// Read back the values and display. |
485 |
// (The show() function is undefined and is used here as an example only.) |
// (The show() function is undefined and is used here as an example only.) |
486 |
for(unsigned long i = ADDRESS; i < ADDRESS + 256; i++) |
for(unsigned long i = ADDRESS; i < ADDRESS + 256; i++) |
490 |
|
|
491 |
return; |
return; |
492 |
} |
} |
493 |
\endcode */ |
\endcode */ |
|
|
|
|
|
|
|
|
|
|
#endif |
|
|
|
|
494 |
|
|
495 |
|
#endif /* _AVR_BOOT_H_ */ |