RTEMS CPU Kit with SuperCore  4.11.3
boot.h
Go to the documentation of this file.
1 
70 /*
71  * Copyright (c) 2002,2003,2004,2005,2006,2007,2008,2009 Eric B. Weddington
72  * All rights reserved.
73  *
74  * Redistribution and use in source and binary forms, with or without
75  * modification, are permitted provided that the following conditions are met:
76  *
77  * * Redistributions of source code must retain the above copyright
78  * notice, this list of conditions and the following disclaimer.
79  *
80  * * Redistributions in binary form must reproduce the above copyright
81  * notice, this list of conditions and the following disclaimer in
82  * the documentation and/or other materials provided with the
83  * distribution.
84  *
85  * * Neither the name of the copyright holders nor the names of
86  * contributors may be used to endorse or promote products derived
87  * from this software without specific prior written permission.
88  *
89  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
90  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
91  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
92  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
93  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
94  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
95  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
96  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
97  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
98  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
99  * POSSIBILITY OF SUCH DAMAGE.
100  */
101 
102 
103 #ifndef _AVR_BOOT_H_
104 #define _AVR_BOOT_H_ 1
105 
113 #include <avr/eeprom.h>
114 #include <avr/io.h>
115 #include <inttypes.h>
116 #include <limits.h>
117 
118 /* Check for SPM Control Register in processor. */
119 #if defined (SPMCSR)
120 # define __SPM_REG SPMCSR
121 #elif defined (SPMCR)
122 # define __SPM_REG SPMCR
123 #else
124 # error AVR processor does not provide bootloader support!
125 #endif
126 
127 
128 /* Check for SPM Enable bit. */
129 #if defined(SPMEN)
130 # define __SPM_ENABLE SPMEN
131 #elif defined(SELFPRGEN)
132 # define __SPM_ENABLE SELFPRGEN
133 #else
134 # error Cannot find SPM Enable bit definition!
135 #endif
136 
145 #define BOOTLOADER_SECTION __attribute__ ((section (".bootloader")))
146 
147 /* Create common bit definitions. */
148 #ifdef ASB
149 #define __COMMON_ASB ASB
150 #else
151 #define __COMMON_ASB RWWSB
152 #endif
153 
154 #ifdef ASRE
155 #define __COMMON_ASRE ASRE
156 #else
157 #define __COMMON_ASRE RWWSRE
158 #endif
159 
160 /* Define the bit positions of the Boot Lock Bits. */
161 
162 #define BLB12 5
163 #define BLB11 4
164 #define BLB02 3
165 #define BLB01 2
166 
171 #define boot_spm_interrupt_enable() (__SPM_REG |= (uint8_t)_BV(SPMIE))
172 
177 #define boot_spm_interrupt_disable() (__SPM_REG &= (uint8_t)~_BV(SPMIE))
178 
183 #define boot_is_spm_interrupt() (__SPM_REG & (uint8_t)_BV(SPMIE))
184 
189 #define boot_rww_busy() (__SPM_REG & (uint8_t)_BV(__COMMON_ASB))
190 
195 #define boot_spm_busy() (__SPM_REG & (uint8_t)_BV(__SPM_ENABLE))
196 
201 #define boot_spm_busy_wait() do{}while(boot_spm_busy())
202 
203 #define __BOOT_PAGE_ERASE (_BV(__SPM_ENABLE) | _BV(PGERS))
204 #define __BOOT_PAGE_WRITE (_BV(__SPM_ENABLE) | _BV(PGWRT))
205 #define __BOOT_PAGE_FILL _BV(__SPM_ENABLE)
206 #define __BOOT_RWW_ENABLE (_BV(__SPM_ENABLE) | _BV(__COMMON_ASRE))
207 #if defined(BLBSET)
208 #define __BOOT_LOCK_BITS_SET (_BV(__SPM_ENABLE) | _BV(BLBSET))
209 #elif defined(RFLB) /* Some devices have RFLB defined instead of BLBSET. */
210 #define __BOOT_LOCK_BITS_SET (_BV(__SPM_ENABLE) | _BV(RFLB))
211 #endif
212 
213 #define __boot_page_fill_normal(address, data) \
214 (__extension__({ \
215  __asm__ __volatile__ \
216  ( \
217  "movw r0, %3\n\t" \
218  "sts %0, %1\n\t" \
219  "spm\n\t" \
220  "clr r1\n\t" \
221  : \
222  : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
223  "r" ((uint8_t)(__BOOT_PAGE_FILL)), \
224  "z" ((uint16_t)(address)), \
225  "r" ((uint16_t)(data)) \
226  : "r0" \
227  ); \
228 }))
229 
230 #define __boot_page_fill_alternate(address, data)\
231 (__extension__({ \
232  __asm__ __volatile__ \
233  ( \
234  "movw r0, %3\n\t" \
235  "sts %0, %1\n\t" \
236  "spm\n\t" \
237  ".word 0xffff\n\t" \
238  "nop\n\t" \
239  "clr r1\n\t" \
240  : \
241  : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
242  "r" ((uint8_t)(__BOOT_PAGE_FILL)), \
243  "z" ((uint16_t)(address)), \
244  "r" ((uint16_t)(data)) \
245  : "r0" \
246  ); \
247 }))
248 
249 #define __boot_page_fill_extended(address, data) \
250 (__extension__({ \
251  __asm__ __volatile__ \
252  ( \
253  "movw r0, %4\n\t" \
254  "movw r30, %A3\n\t" \
255  "sts %1, %C3\n\t" \
256  "sts %0, %2\n\t" \
257  "spm\n\t" \
258  "clr r1\n\t" \
259  : \
260  : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
261  "i" (_SFR_MEM_ADDR(RAMPZ)), \
262  "r" ((uint8_t)(__BOOT_PAGE_FILL)), \
263  "r" ((uint32_t)(address)), \
264  "r" ((uint16_t)(data)) \
265  : "r0", "r30", "r31" \
266  ); \
267 }))
268 
269 #define __boot_page_erase_normal(address) \
270 (__extension__({ \
271  __asm__ __volatile__ \
272  ( \
273  "sts %0, %1\n\t" \
274  "spm\n\t" \
275  : \
276  : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
277  "r" ((uint8_t)(__BOOT_PAGE_ERASE)), \
278  "z" ((uint16_t)(address)) \
279  ); \
280 }))
281 
282 #define __boot_page_erase_alternate(address) \
283 (__extension__({ \
284  __asm__ __volatile__ \
285  ( \
286  "sts %0, %1\n\t" \
287  "spm\n\t" \
288  ".word 0xffff\n\t" \
289  "nop\n\t" \
290  : \
291  : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
292  "r" ((uint8_t)(__BOOT_PAGE_ERASE)), \
293  "z" ((uint16_t)(address)) \
294  ); \
295 }))
296 
297 #define __boot_page_erase_extended(address) \
298 (__extension__({ \
299  __asm__ __volatile__ \
300  ( \
301  "movw r30, %A3\n\t" \
302  "sts %1, %C3\n\t" \
303  "sts %0, %2\n\t" \
304  "spm\n\t" \
305  : \
306  : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
307  "i" (_SFR_MEM_ADDR(RAMPZ)), \
308  "r" ((uint8_t)(__BOOT_PAGE_ERASE)), \
309  "r" ((uint32_t)(address)) \
310  : "r30", "r31" \
311  ); \
312 }))
313 
314 #define __boot_page_write_normal(address) \
315 (__extension__({ \
316  __asm__ __volatile__ \
317  ( \
318  "sts %0, %1\n\t" \
319  "spm\n\t" \
320  : \
321  : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
322  "r" ((uint8_t)(__BOOT_PAGE_WRITE)), \
323  "z" ((uint16_t)(address)) \
324  ); \
325 }))
326 
327 #define __boot_page_write_alternate(address) \
328 (__extension__({ \
329  __asm__ __volatile__ \
330  ( \
331  "sts %0, %1\n\t" \
332  "spm\n\t" \
333  ".word 0xffff\n\t" \
334  "nop\n\t" \
335  : \
336  : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
337  "r" ((uint8_t)(__BOOT_PAGE_WRITE)), \
338  "z" ((uint16_t)(address)) \
339  ); \
340 }))
341 
342 #define __boot_page_write_extended(address) \
343 (__extension__({ \
344  __asm__ __volatile__ \
345  ( \
346  "movw r30, %A3\n\t" \
347  "sts %1, %C3\n\t" \
348  "sts %0, %2\n\t" \
349  "spm\n\t" \
350  : \
351  : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
352  "i" (_SFR_MEM_ADDR(RAMPZ)), \
353  "r" ((uint8_t)(__BOOT_PAGE_WRITE)), \
354  "r" ((uint32_t)(address)) \
355  : "r30", "r31" \
356  ); \
357 }))
358 
359 #define __boot_rww_enable() \
360 (__extension__({ \
361  __asm__ __volatile__ \
362  ( \
363  "sts %0, %1\n\t" \
364  "spm\n\t" \
365  : \
366  : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
367  "r" ((uint8_t)(__BOOT_RWW_ENABLE)) \
368  ); \
369 }))
370 
371 #define __boot_rww_enable_alternate() \
372 (__extension__({ \
373  __asm__ __volatile__ \
374  ( \
375  "sts %0, %1\n\t" \
376  "spm\n\t" \
377  ".word 0xffff\n\t" \
378  "nop\n\t" \
379  : \
380  : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
381  "r" ((uint8_t)(__BOOT_RWW_ENABLE)) \
382  ); \
383 }))
384 
385 /* From the mega16/mega128 data sheets (maybe others):
386 
387  Bits by SPM To set the Boot Loader Lock bits, write the desired data to
388  R0, write "X0001001" to SPMCR and execute SPM within four clock cycles
389  after writing SPMCR. The only accessible Lock bits are the Boot Lock bits
390  that may prevent the Application and Boot Loader section from any
391  software update by the MCU.
392 
393  If bits 5..2 in R0 are cleared (zero), the corresponding Boot Lock bit
394  will be programmed if an SPM instruction is executed within four cycles
395  after BLBSET and SPMEN (or SELFPRGEN) are set in SPMCR. The Z-pointer is
396  don't care during this operation, but for future compatibility it is
397  recommended to load the Z-pointer with $0001 (same as used for reading the
398  Lock bits). For future compatibility It is also recommended to set bits 7,
399  6, 1, and 0 in R0 to 1 when writing the Lock bits. When programming the
400  Lock bits the entire Flash can be read during the operation. */
401 
402 #define __boot_lock_bits_set(lock_bits) \
403 (__extension__({ \
404  uint8_t value = (uint8_t)(~(lock_bits)); \
405  __asm__ __volatile__ \
406  ( \
407  "ldi r30, 1\n\t" \
408  "ldi r31, 0\n\t" \
409  "mov r0, %2\n\t" \
410  "sts %0, %1\n\t" \
411  "spm\n\t" \
412  : \
413  : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
414  "r" ((uint8_t)(__BOOT_LOCK_BITS_SET)), \
415  "r" (value) \
416  : "r0", "r30", "r31" \
417  ); \
418 }))
419 
420 #define __boot_lock_bits_set_alternate(lock_bits) \
421 (__extension__({ \
422  uint8_t value = (uint8_t)(~(lock_bits)); \
423  __asm__ __volatile__ \
424  ( \
425  "ldi r30, 1\n\t" \
426  "ldi r31, 0\n\t" \
427  "mov r0, %2\n\t" \
428  "sts %0, %1\n\t" \
429  "spm\n\t" \
430  ".word 0xffff\n\t" \
431  "nop\n\t" \
432  : \
433  : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
434  "r" ((uint8_t)(__BOOT_LOCK_BITS_SET)), \
435  "r" (value) \
436  : "r0", "r30", "r31" \
437  ); \
438 }))
439 
440 /*
441  Reading lock and fuse bits:
442 
443  Similarly to writing the lock bits above, set BLBSET and SPMEN (or
444  SELFPRGEN) bits in __SPMREG, and then (within four clock cycles) issue an
445  LPM instruction.
446 
447  Z address: contents:
448  0x0000 low fuse bits
449  0x0001 lock bits
450  0x0002 extended fuse bits
451  0x0003 high fuse bits
452 
453  Sounds confusing, doesn't it?
454 
455  Unlike the macros in pgmspace.h, no need to care for non-enhanced
456  cores here as these old cores do not provide SPM support anyway.
457  */
458 
463 #define GET_LOW_FUSE_BITS (0x0000)
464 
468 #define GET_LOCK_BITS (0x0001)
469 
473 #define GET_EXTENDED_FUSE_BITS (0x0002)
474 
478 #define GET_HIGH_FUSE_BITS (0x0003)
479 
492 #define boot_lock_fuse_bits_get(address) \
493 (__extension__({ \
494  uint8_t __result; \
495  __asm__ __volatile__ \
496  ( \
497  "sts %1, %2\n\t" \
498  "lpm %0, Z\n\t" \
499  : "=r" (__result) \
500  : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
501  "r" ((uint8_t)(__BOOT_LOCK_BITS_SET)), \
502  "z" ((uint16_t)(address)) \
503  ); \
504  __result; \
505 }))
506 
518 #define __BOOT_SIGROW_READ (_BV(__SPM_ENABLE) | _BV(SIGRD))
519 
520 #define boot_signature_byte_get(addr) \
521 (__extension__({ \
522  uint8_t __result; \
523  __asm__ __volatile__ \
524  ( \
525  "sts %1, %2\n\t" \
526  "lpm %0, Z" "\n\t" \
527  : "=r" (__result) \
528  : "i" (_SFR_MEM_ADDR(__SPM_REG)), \
529  "r" ((uint8_t)(__BOOT_SIGROW_READ)), \
530  "z" ((uint16_t)(addr)) \
531  ); \
532  __result; \
533 }))
534 
588 /* Normal versions of the macros use 16-bit addresses.
589  Extended versions of the macros use 32-bit addresses.
590  Alternate versions of the macros use 16-bit addresses and require special
591  instruction sequences after LPM.
592 
593  FLASHEND is defined in the ioXXXX.h file.
594  USHRT_MAX is defined in <limits.h>. */
595 
596 #if defined(__AVR_ATmega161__) || defined(__AVR_ATmega163__) \
597  || defined(__AVR_ATmega323__)
598 
599 /* Alternate: ATmega161/163/323 and 16 bit address */
600 #define boot_page_fill(address, data) __boot_page_fill_alternate(address, data)
601 #define boot_page_erase(address) __boot_page_erase_alternate(address)
602 #define boot_page_write(address) __boot_page_write_alternate(address)
603 #define boot_rww_enable() __boot_rww_enable_alternate()
604 #define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_alternate(lock_bits)
605 
606 #elif (FLASHEND > USHRT_MAX)
607 
608 /* Extended: >16 bit address */
609 #define boot_page_fill(address, data) __boot_page_fill_extended(address, data)
610 #define boot_page_erase(address) __boot_page_erase_extended(address)
611 #define boot_page_write(address) __boot_page_write_extended(address)
612 #define boot_rww_enable() __boot_rww_enable()
613 #define boot_lock_bits_set(lock_bits) __boot_lock_bits_set(lock_bits)
614 
615 #else
616 
617 /* Normal: 16 bit address */
618 #define boot_page_fill(address, data) __boot_page_fill_normal(address, data)
619 #define boot_page_erase(address) __boot_page_erase_normal(address)
620 #define boot_page_write(address) __boot_page_write_normal(address)
621 #define boot_rww_enable() __boot_rww_enable()
622 #define boot_lock_bits_set(lock_bits) __boot_lock_bits_set(lock_bits)
623 
624 #endif
625 
631 #define boot_page_fill_safe(address, data) \
632 do { \
633  boot_spm_busy_wait(); \
634  eeprom_busy_wait(); \
635  boot_page_fill(address, data); \
636 } while (0)
637 
643 #define boot_page_erase_safe(address) \
644 do { \
645  boot_spm_busy_wait(); \
646  eeprom_busy_wait(); \
647  boot_page_erase (address); \
648 } while (0)
649 
655 #define boot_page_write_safe(address) \
656 do { \
657  boot_spm_busy_wait(); \
658  eeprom_busy_wait(); \
659  boot_page_write (address); \
660 } while (0)
661 
667 #define boot_rww_enable_safe() \
668 do { \
669  boot_spm_busy_wait(); \
670  eeprom_busy_wait(); \
671  boot_rww_enable(); \
672 } while (0)
673 
679 #define boot_lock_bits_set_safe(lock_bits) \
680 do { \
681  boot_spm_busy_wait(); \
682  eeprom_busy_wait(); \
683  boot_lock_bits_set (lock_bits); \
684 } while (0)
685 
687 #endif /* _AVR_BOOT_H_ */
Data EEPROM Contained in the AVR Microcontrollers.
AVR device-specific IO Definitions.