]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/lib/TOSBoot/avr/boot.h
Changes so this checkout exactly matches CVS at -r release_tinyos_2_0_2_2.
[tinyos-2.x.git] / tos / lib / TOSBoot / avr / boot.h
diff --git a/tos/lib/TOSBoot/avr/boot.h b/tos/lib/TOSBoot/avr/boot.h
new file mode 100644 (file)
index 0000000..08c89ce
--- /dev/null
@@ -0,0 +1,498 @@
+/* Copyright (c) 2002, 2003, 2004  Eric B. Weddington\r
+   All rights reserved.\r
+\r
+   Redistribution and use in source and binary forms, with or without\r
+   modification, are permitted provided that the following conditions are met:\r
+\r
+   * Redistributions of source code must retain the above copyright\r
+     notice, this list of conditions and the following disclaimer.\r
+   * Redistributions in binary form must reproduce the above copyright\r
+     notice, this list of conditions and the following disclaimer in\r
+     the documentation and/or other materials provided with the\r
+     distribution.\r
+   * Neither the name of the copyright holders nor the names of\r
+     contributors may be used to endorse or promote products derived\r
+     from this software without specific prior written permission.\r
+\r
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\r
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+  POSSIBILITY OF SUCH DAMAGE. */\r
+\r
+#ifndef _AVR_BOOT_H_\r
+#define _AVR_BOOT_H_    1\r
+\r
+/** \defgroup avr_boot Bootloader Support Utilities\r
+    \code\r
+    #include <avr/io.h>\r
+    #include <avr/boot.h>\r
+    \endcode\r
+\r
+    The macros in this module provide a C language interface to the\r
+    bootloader support functionality of certain AVR processors. These\r
+    macros are designed to work with all sizes of flash memory.\r
+\r
+    \note Not all AVR processors provide bootloader support. See your\r
+    processor datasheet to see if it provides bootloader support.\r
+\r
+    \todo From email with Marek: On smaller devices (all except ATmega64/128),\r
+    __SPM_REG is in the I/O space, accessible with the shorter "in" and "out"\r
+    instructions - since the boot loader has a limited size, this could be an\r
+    important optimization.\r
+\r
+    \par API Usage Example\r
+    The following code shows typical usage of the boot API.\r
+\r
+    \code\r
+    #include <avr/interrupt.h>\r
+    #include <avr/pgmspace.h>\r
+    \r
+    #define ADDRESS     0x1C000UL\r
+    \r
+    void boot_test(void)\r
+    {\r
+        unsigned char buffer[8];\r
+    \r
+        cli();\r
+    \r
+        // Erase page.\r
+        boot_page_erase((unsigned long)ADDRESS);\r
+        while(boot_rww_busy())\r
+        {\r
+            boot_rww_enable();\r
+        }\r
+    \r
+        // Write data to buffer a word at a time. Note incrementing address\r
+        // by 2. SPM_PAGESIZE is defined in the microprocessor IO header file.\r
+        for(unsigned long i = ADDRESS; i < ADDRESS + SPM_PAGESIZE; i += 2)\r
+        {\r
+            boot_page_fill(i, (i-ADDRESS) + ((i-ADDRESS+1) << 8));\r
+        }\r
+    \r
+        // Write page.\r
+        boot_page_write((unsigned long)ADDRESS);\r
+        while(boot_rww_busy())\r
+        {\r
+            boot_rww_enable();\r
+        }\r
+    \r
+        sei();\r
+    \r
+        // Read back the values and display.\r
+        // (The show() function is undefined and is used here as an example\r
+        // only.)\r
+        for(unsigned long i = ADDRESS; i < ADDRESS + 256; i++)\r
+        {\r
+            show(utoa(pgm_read_byte(i), buffer, 16));\r
+        }\r
+    \r
+        return;\r
+    }\endcode */\r
+\r
+#include <avr/eeprom.h>\r
+#include <avr/io.h>\r
+#include <inttypes.h>\r
+#include <limits.h>\r
+\r
+/* Check for SPM Control Register in processor. */\r
+#if defined (SPMCSR)\r
+#  define __SPM_REG    SPMCSR\r
+#elif defined (SPMCR)\r
+#  define __SPM_REG    SPMCR\r
+#else\r
+#  error AVR processor does not provide bootloader support!\r
+#endif\r
+\r
+/** \ingroup avr_boot\r
+    \def BOOTLOADER_SECTION\r
+\r
+    Used to declare a function or variable to be placed into a\r
+    new section called .bootloader. This section and its contents\r
+    can then be relocated to any address (such as the bootloader\r
+    NRWW area) at link-time. */\r
+\r
+#define BOOTLOADER_SECTION    __attribute__ ((section (".bootloader")))\r
+\r
+/* Create common bit definitions. */\r
+#ifdef ASB\r
+#define __COMMON_ASB    ASB\r
+#else\r
+#define __COMMON_ASB    RWWSB\r
+#endif\r
+\r
+#ifdef ASRE\r
+#define __COMMON_ASRE   ASRE\r
+#else\r
+#define __COMMON_ASRE   RWWSRE\r
+#endif\r
+\r
+/* Define the bit positions of the Boot Lock Bits. */\r
+\r
+#define BLB12           5\r
+#define BLB11           4\r
+#define BLB02           3\r
+#define BLB01           2\r
+\r
+/** \ingroup avr_boot\r
+    \def boot_spm_interrupt_enable()\r
+    Enable the SPM interrupt. */\r
+\r
+#define boot_spm_interrupt_enable()   (__SPM_REG |= (uint8_t)_BV(SPMIE))\r
+\r
+/** \ingroup avr_boot\r
+    \def boot_spm_interrupt_disable()\r
+    Disable the SPM interrupt. */\r
+\r
+#define boot_spm_interrupt_disable()  (__SPM_REG &= (uint8_t)~_BV(SPMIE))\r
+\r
+/** \ingroup avr_boot\r
+    \def boot_is_spm_interrupt()\r
+    Check if the SPM interrupt is enabled. */\r
+\r
+#define boot_is_spm_interrupt()       (__SPM_REG & (uint8_t)_BV(SPMIE))\r
+\r
+/** \ingroup avr_boot\r
+    \def boot_rww_busy()\r
+    Check if the RWW section is busy. */\r
+\r
+#define boot_rww_busy()          (__SPM_REG & (uint8_t)_BV(__COMMON_ASB))\r
+\r
+/** \ingroup avr_boot\r
+    \def boot_spm_busy()\r
+    Check if the SPM instruction is busy. */\r
+\r
+#define boot_spm_busy()               (__SPM_REG & (uint8_t)_BV(SPMEN))\r
+\r
+/** \ingroup avr_boot\r
+    \def boot_spm_busy_wait()\r
+    Wait while the SPM instruction is busy. */\r
+\r
+#define boot_spm_busy_wait()          do{}while(boot_spm_busy())\r
+\r
+#define __BOOT_PAGE_ERASE         (_BV(SPMEN) | _BV(PGERS))\r
+#define __BOOT_PAGE_WRITE         (_BV(SPMEN) | _BV(PGWRT))\r
+#define __BOOT_PAGE_FILL          _BV(SPMEN)\r
+#define __BOOT_RWW_ENABLE         (_BV(SPMEN) | _BV(__COMMON_ASRE))\r
+#define __BOOT_LOCK_BITS_SET      (_BV(SPMEN) | _BV(BLBSET))\r
+\r
+#define __BOOT_LOCK_BITS_MASK     (_BV(BLB01) | _BV(BLB02) \\r
+                                   | _BV(BLB11) | _BV(BLB12))\r
+\r
+#define eeprom_busy_wait() do {} while (!eeprom_is_ready())\r
+\r
+#define __boot_page_fill_normal(address, data)   \\r
+({                                               \\r
+    boot_spm_busy_wait();                        \\r
+    eeprom_busy_wait();                          \\r
+    __asm__ __volatile__                         \\r
+    (                                            \\r
+        "movw  r0, %3\n\t"                       \\r
+        "movw r30, %2\n\t"                       \\r
+        "sts %0, %1\n\t"                         \\r
+        "spm\n\t"                                \\r
+        "clr  r1\n\t"                            \\r
+        : "=m" (__SPM_REG)                       \\r
+        : "r" ((uint8_t)__BOOT_PAGE_FILL),       \\r
+          "r" ((uint16_t)address),               \\r
+          "r" ((uint16_t)data)                   \\r
+        : "r0", "r30", "r31"                     \\r
+    );                                           \\r
+})\r
+\r
+#define __boot_page_fill_alternate(address, data)\\r
+({                                               \\r
+    boot_spm_busy_wait();                        \\r
+    eeprom_busy_wait();                          \\r
+    __asm__ __volatile__                         \\r
+    (                                            \\r
+        "movw  r0, %3\n\t"                       \\r
+        "movw r30, %2\n\t"                       \\r
+        "sts %0, %1\n\t"                         \\r
+        "spm\n\t"                                \\r
+        ".word 0xffff\n\t"                       \\r
+        "nop\n\t"                                \\r
+        "clr  r1\n\t"                            \\r
+        : "=m" (__SPM_REG)                       \\r
+        : "r" ((uint8_t)__BOOT_PAGE_FILL),       \\r
+          "r" ((uint16_t)address),               \\r
+          "r" ((uint16_t)data)                   \\r
+        : "r0", "r30", "r31"                     \\r
+    );                                           \\r
+})\r
+\r
+#define __boot_page_fill_extended(address, data) \\r
+({                                               \\r
+    boot_spm_busy_wait();                        \\r
+    eeprom_busy_wait();                          \\r
+    __asm__ __volatile__                         \\r
+    (                                            \\r
+        "movw  r0, %4\n\t"                       \\r
+        "movw r30, %A3\n\t"                      \\r
+        "sts %1, %C3\n\t"                        \\r
+        "sts %0, %2\n\t"                         \\r
+        "spm\n\t"                                \\r
+        "clr  r1\n\t"                            \\r
+        : "=m" (__SPM_REG),                      \\r
+          "=m" (RAMPZ)                           \\r
+        : "r" ((uint8_t)__BOOT_PAGE_FILL),       \\r
+          "r" ((uint32_t)address),               \\r
+          "r" ((uint16_t)data)                   \\r
+        : "r0", "r30", "r31"                     \\r
+    );                                           \\r
+})\r
+\r
+#define __boot_page_erase_normal(address)        \\r
+({                                               \\r
+    boot_spm_busy_wait();                        \\r
+    eeprom_busy_wait();                          \\r
+    __asm__ __volatile__                         \\r
+    (                                            \\r
+        "movw r30, %2\n\t"                       \\r
+        "sts %0, %1\n\t"                         \\r
+        "spm\n\t"                                \\r
+        : "=m" (__SPM_REG)                       \\r
+        : "r" ((uint8_t)__BOOT_PAGE_ERASE),      \\r
+          "r" ((uint16_t)address)                \\r
+        : "r30", "r31"                           \\r
+    );                                           \\r
+})\r
+\r
+#define __boot_page_erase_alternate(address)     \\r
+({                                               \\r
+    boot_spm_busy_wait();                        \\r
+    eeprom_busy_wait();                          \\r
+    __asm__ __volatile__                         \\r
+    (                                            \\r
+        "movw r30, %2\n\t"                       \\r
+        "sts %0, %1\n\t"                         \\r
+        "spm\n\t"                                \\r
+        ".word 0xffff\n\t"                       \\r
+        "nop\n\t"                                \\r
+        : "=m" (__SPM_REG)                       \\r
+        : "r" ((uint8_t)__BOOT_PAGE_ERASE),      \\r
+          "r" ((uint16_t)address)                \\r
+        : "r30", "r31"                           \\r
+    );                                           \\r
+})\r
+\r
+#define __boot_page_erase_extended(address)      \\r
+({                                               \\r
+    boot_spm_busy_wait();                        \\r
+    eeprom_busy_wait();                          \\r
+    __asm__ __volatile__                         \\r
+    (                                            \\r
+        "movw r30, %A3\n\t"                      \\r
+        "sts  %1, %C3\n\t"                       \\r
+        "sts %0, %2\n\t"                         \\r
+        "spm\n\t"                                \\r
+        : "=m" (__SPM_REG),                      \\r
+          "=m" (RAMPZ)                           \\r
+        : "r" ((uint8_t)__BOOT_PAGE_ERASE),      \\r
+          "r" ((uint32_t)address)                \\r
+        : "r30", "r31"                           \\r
+    );                                           \\r
+})\r
+\r
+#define __boot_page_write_normal(address)        \\r
+({                                               \\r
+    boot_spm_busy_wait();                        \\r
+    eeprom_busy_wait();                          \\r
+    __asm__ __volatile__                         \\r
+    (                                            \\r
+        "movw r30, %2\n\t"                       \\r
+        "sts %0, %1\n\t"                         \\r
+        "spm\n\t"                                \\r
+        : "=m" (__SPM_REG)                       \\r
+        : "r" ((uint8_t)__BOOT_PAGE_WRITE),      \\r
+          "r" ((uint16_t)address)                \\r
+        : "r30", "r31"                           \\r
+    );                                           \\r
+})\r
+\r
+#define __boot_page_write_alternate(address)     \\r
+({                                               \\r
+    boot_spm_busy_wait();                        \\r
+    eeprom_busy_wait();                          \\r
+    __asm__ __volatile__                         \\r
+    (                                            \\r
+        "movw r30, %2\n\t"                       \\r
+        "sts %0, %1\n\t"                         \\r
+        "spm\n\t"                                \\r
+        ".word 0xffff\n\t"                       \\r
+        "nop\n\t"                                \\r
+        : "=m" (__SPM_REG)                       \\r
+        : "r" ((uint8_t)__BOOT_PAGE_WRITE),      \\r
+          "r" ((uint16_t)address)                \\r
+        : "r30", "r31"                           \\r
+    );                                           \\r
+})\r
+\r
+#define __boot_page_write_extended(address)      \\r
+({                                               \\r
+    boot_spm_busy_wait();                        \\r
+    eeprom_busy_wait();                          \\r
+    __asm__ __volatile__                         \\r
+    (                                            \\r
+        "movw r30, %A3\n\t"                      \\r
+        "sts %1, %C3\n\t"                        \\r
+        "sts %0, %2\n\t"                         \\r
+        "spm\n\t"                                \\r
+        : "=m" (__SPM_REG),                      \\r
+          "=m" (RAMPZ)                           \\r
+        : "r" ((uint8_t)__BOOT_PAGE_WRITE),      \\r
+          "r" ((uint32_t)address)                \\r
+        : "r30", "r31"                           \\r
+    );                                           \\r
+})\r
+\r
+#define __boot_rww_enable()                      \\r
+({                                               \\r
+    boot_spm_busy_wait();                        \\r
+    eeprom_busy_wait();                          \\r
+    __asm__ __volatile__                         \\r
+    (                                            \\r
+        "sts %0, %1\n\t"                         \\r
+        "spm\n\t"                                \\r
+        : "=m" (__SPM_REG)                       \\r
+        : "r" ((uint8_t)__BOOT_RWW_ENABLE)       \\r
+    );                                           \\r
+})\r
+\r
+#define __boot_rww_enable_alternate()            \\r
+({                                               \\r
+    boot_spm_busy_wait();                        \\r
+    eeprom_busy_wait();                          \\r
+    __asm__ __volatile__                         \\r
+    (                                            \\r
+        "sts %0, %1\n\t"                         \\r
+        "spm\n\t"                                \\r
+        ".word 0xffff\n\t"                       \\r
+        "nop\n\t"                                \\r
+        : "=m" (__SPM_REG)                       \\r
+        : "r" ((uint8_t)__BOOT_RWW_ENABLE)       \\r
+    );                                           \\r
+})\r
+\r
+#define __boot_lock_bits_set(lock_bits)                    \\r
+({                                                         \\r
+    uint8_t value = (uint8_t)(lock_bits | __BOOT_LOCK_BITS_MASK); \\r
+    boot_spm_busy_wait();                                  \\r
+    eeprom_busy_wait();                                    \\r
+    __asm__ __volatile__                                   \\r
+    (                                                      \\r
+        "ldi r30, 1\n\t"                                   \\r
+        "ldi r31, 0\n\t"                                   \\r
+        "mov r0, %2\n\t"                                   \\r
+        "sts %0, %1\n\t"                                   \\r
+        "spm\n\t"                                          \\r
+        : "=m" (__SPM_REG)                                 \\r
+        : "r" ((uint8_t)__BOOT_LOCK_BITS_SET),             \\r
+          "r" (value)                                      \\r
+        : "r0", "r30", "r31"                               \\r
+    );                                                     \\r
+})\r
+\r
+#define __boot_lock_bits_set_alternate(lock_bits)          \\r
+({                                                         \\r
+    uint8_t value = (uint8_t)(lock_bits | __BOOT_LOCK_BITS_MASK); \\r
+    boot_spm_busy_wait();                                  \\r
+    eeprom_busy_wait();                                    \\r
+    __asm__ __volatile__                                   \\r
+    (                                                      \\r
+        "ldi r30, 1\n\t"                                   \\r
+        "ldi r31, 0\n\t"                                   \\r
+        "mov r0, %2\n\t"                                   \\r
+        "sts %0, %1\n\t"                                   \\r
+        "spm\n\t"                                          \\r
+        ".word 0xffff\n\t"                                 \\r
+        "nop\n\t"                                          \\r
+        : "=m" (__SPM_REG)                                 \\r
+        : "r" ((uint8_t)__BOOT_LOCK_BITS_SET),       \\r
+          "r" (value)                                      \\r
+        : "r0", "r30", "r31"                               \\r
+    );                                                     \\r
+})\r
+\r
+/** \ingroup avr_boot\r
+    \def boot_page_fill(address, data)\r
+\r
+    Fill the bootloader temporary page buffer for flash \r
+    address with data word. \r
+\r
+    \note The address is a byte address. The data is a word. The AVR \r
+    writes data to the buffer a word at a time, but addresses the buffer\r
+    per byte! So, increment your address by 2 between calls, and send 2\r
+    data bytes in a word format! The LSB of the data is written to the lower \r
+    address; the MSB of the data is written to the higher address.*/\r
+\r
+/** \ingroup avr_boot\r
+    \def boot_page_erase(address)\r
+\r
+    Erase the flash page that contains address.\r
+\r
+    \note address is a byte address in flash, not a word address. */\r
+\r
+/** \ingroup avr_boot\r
+    \def boot_page_write(address)\r
+\r
+    Write the bootloader temporary page buffer \r
+    to flash page that contains address.\r
+    \r
+    \note address is a byte address in flash, not a word address. */\r
+\r
+/** \ingroup avr_boot\r
+    \def boot_rww_enable()\r
+\r
+    Enable the Read-While-Write memory section. */\r
+\r
+/** \ingroup avr_boot\r
+    \def boot_lock_bits_set(lock_bits)\r
+\r
+    Set the bootloader lock bits. */\r
+\r
+/* Normal versions of the macros use 16-bit addresses.\r
+   Extended versions of the macros use 32-bit addresses.\r
+   Alternate versions of the macros use 16-bit addresses and require special\r
+   instruction sequences after LPM.\r
+\r
+   FLASHEND is defined in the ioXXXX.h file.\r
+   USHRT_MAX is defined in <limits.h>. */ \r
+\r
+#if defined(__AVR_ATmega161__) || defined(__AVR_ATmega163__) \\r
+    || defined(__AVR_ATmega323__)\r
+\r
+/* Alternate: ATmega161/163/323 and 16 bit address */\r
+#define boot_page_fill(address, data) __boot_page_fill_alternate(address, data)\r
+#define boot_page_erase(address)      __boot_page_erase_alternate(address)\r
+#define boot_page_write(address)      __boot_page_write_alternate(address)\r
+#define boot_rww_enable()             __boot_rww_enable_alternate()\r
+#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_alternate(lock_bits)\r
+\r
+#elif (FLASHEND > USHRT_MAX) && !defined(__USING_MINT8)\r
+\r
+/* Extended: >16 bit address */\r
+#define boot_page_fill(address, data) __boot_page_fill_extended(address, data)\r
+#define boot_page_erase(address)      __boot_page_erase_extended(address)\r
+#define boot_page_write(address)      __boot_page_write_extended(address)\r
+#define boot_rww_enable()             __boot_rww_enable()\r
+#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set(lock_bits)\r
+\r
+#else\r
+\r
+/* Normal: 16 bit address */\r
+#define boot_page_fill(address, data) __boot_page_fill_normal(address, data)\r
+#define boot_page_erase(address)      __boot_page_erase_normal(address)\r
+#define boot_page_write(address)      __boot_page_write_normal(address)\r
+#define boot_rww_enable()             __boot_rww_enable()\r
+#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set(lock_bits)\r
+\r
+#endif\r
+\r
+#endif /* _AVR_BOOT_H_ */\r