diff options
Diffstat (limited to 'include/avr/pgmspace.h')
-rw-r--r-- | include/avr/pgmspace.h | 887 |
1 files changed, 887 insertions, 0 deletions
diff --git a/include/avr/pgmspace.h b/include/avr/pgmspace.h new file mode 100644 index 0000000000..42010168b1 --- /dev/null +++ b/include/avr/pgmspace.h @@ -0,0 +1,887 @@ +/** + * @file pgmspace.h + * + * @brief Definitions for ATmega640 + * + * The functions in this module provide interfaces for a program to access + * data stored in program space (flash memory) of the device. In order to + * use these functions, the target device must support either the \c LPM or + * \c ELPM instructions. + * + * @note These functions are an attempt to provide some compatibility with + * header files that come with IAR C, to make porting applications between + * different compilers easier. This is not 100% compatibility though (GCC + * does not have full support for multiple address spaces yet). + * + * @note If you are working with strings which are completely based in ram, + * use the standard string functions described in \ref avr_string. + * + * \note If possible, put your constant tables in the lower 64 KB and use + * pgm_read_byte_near() or pgm_read_word_near() instead of + * pgm_read_byte_far() or pgm_read_word_far() since it is more efficient that + * way, and you can still use the upper 64K for executable code. + * All functions that are suffixed with a \c _P \e require their + * arguments to be in the lower 64 KB of the flash ROM, as they do + * not use ELPM instructions. This is normally not a big concern as + * the linker setup arranges any program space constants declared + * using the macros from this header file so they are placed right after + * the interrupt vectors, and in front of any executable code. However, + * it can become a problem if there are too many of these constants, or + * for bootloaders on devices with more than 64 KB of ROM. + * <em>All these functions will not work in that situation.</em> + * + * Contributors: + * Created by Marek Michalkiewicz <marekm@linux.org.pl> + * Eric B. Weddington <eric@ecentral.com> + * Wolfgang Haidinger <wh@vmars.tuwien.ac.at> (pgm_read_dword()) + * Ivanov Anton <anton@arc.com.ru> (pgm_read_float()) + */ + +/* + * Copyright (c) 2002 - 2007 Marek Michalkiewicz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PGMSPACE_H_ +#define __PGMSPACE_H_ 1 + +/** + * @defgroup avr_pgmspace Program Space Utilities + * + * @ingroup avr + * + */ +/**@{**/ + +#define __need_size_t +#include <inttypes.h> +#include <stddef.h> +#include <avr/io.h> + +#ifndef __ATTR_CONST__ +#define __ATTR_CONST__ __attribute__((__const__)) +#endif + +#ifndef __ATTR_PROGMEM__ +#define __ATTR_PROGMEM__ __attribute__((__progmem__)) +#endif + +#ifndef __ATTR_PURE__ +#define __ATTR_PURE__ __attribute__((__pure__)) +#endif + +/** + \ingroup avr_pgmspace + \def PROGMEM + + Attribute to use in order to declare an object being located in + flash ROM. + */ +#define PROGMEM __ATTR_PROGMEM__ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__DOXYGEN__) +/* + * Doxygen doesn't grok the appended attribute syntax of + * GCC, and confuses the typedefs with function decls, so + * supply a doxygen-friendly view. + */ +/** + \ingroup avr_pgmspace + \typedef prog_void + + Type of a "void" object located in flash ROM. Does not make much + sense by itself, but can be used to declare a "void *" object in + flash ROM. +*/ +typedef void PROGMEM prog_void; +/** + \ingroup avr_pgmspace + \typedef prog_char + + Type of a "char" object located in flash ROM. +*/ +typedef char PROGMEM prog_char; + +/** + \ingroup avr_pgmspace + \typedef prog_uchar + + Type of an "unsigned char" object located in flash ROM. +*/ +typedef unsigned char PROGMEM prog_uchar; + + +/** + \ingroup avr_pgmspace + \typedef prog_int8_t + + Type of an "int8_t" object located in flash ROM. +*/ +typedef int8_t PROGMEM prog_int8_t; + +/** + \ingroup avr_pgmspace + \typedef prog_uint8_t + + Type of an "uint8_t" object located in flash ROM. +*/ +typedef uint8_t PROGMEM prog_uint8_t; + +/** + \ingroup avr_pgmspace + \typedef prog_int16_t + + Type of an "int16_t" object located in flash ROM. +*/ +typedef int16_t PROGMEM prog_int16_t; + +/** + \ingroup avr_pgmspace + \typedef prog_uint16_t + + Type of an "uint16_t" object located in flash ROM. +*/ +typedef uint16_t PROGMEM prog_uint16_t; + +/** + \ingroup avr_pgmspace + \typedef prog_int32_t + + Type of an "int32_t" object located in flash ROM. +*/ +typedef int32_t PROGMEM prog_int32_t; + +/** + \ingroup avr_pgmspace + \typedef prog_uint32_t + + Type of an "uint32_t" object located in flash ROM. +*/ +typedef uint32_t PROGMEM prog_uint32_t; + +/** + \ingroup avr_pgmspace + \typedef prog_int64_t + + Type of an "int64_t" object located in flash ROM. + + \note This type is not available when the compiler + option -mint8 is in effect. +*/ +typedef int64_t PROGMEM prog_int64_t; + +/** + \ingroup avr_pgmspace + \typedef prog_uint64_t + + Type of an "uint64_t" object located in flash ROM. + + \note This type is not available when the compiler + option -mint8 is in effect. +*/ +typedef uint64_t PROGMEM prog_uint64_t; +#else /* !DOXYGEN */ +typedef void prog_void PROGMEM; +typedef char prog_char PROGMEM; +typedef unsigned char prog_uchar PROGMEM; + +typedef int8_t prog_int8_t PROGMEM; +typedef uint8_t prog_uint8_t PROGMEM; +typedef int16_t prog_int16_t PROGMEM; +typedef uint16_t prog_uint16_t PROGMEM; +typedef int32_t prog_int32_t PROGMEM; +typedef uint32_t prog_uint32_t PROGMEM; +#if !__USING_MINT8 +typedef int64_t prog_int64_t PROGMEM; +typedef uint64_t prog_uint64_t PROGMEM; +#endif +#endif /* defined(__DOXYGEN__) */ + +/* Although in C, we can get away with just using __c, it does not work in + C++. We need to use &__c[0] to avoid the compiler puking. Dave Hylands + explaned it thusly, + + Let's suppose that we use PSTR("Test"). In this case, the type returned + by __c is a prog_char[5] and not a prog_char *. While these are + compatible, they aren't the same thing (especially in C++). The type + returned by &__c[0] is a prog_char *, which explains why it works + fine. */ + +#if defined(__DOXYGEN__) +/* + * The #define below is just a dummy that serves documentation + * purposes only. + */ +/** \ingroup avr_pgmspace + \def PSTR(s) + + Used to declare a static pointer to a string in program space. */ +# define PSTR(s) ((const PROGMEM char *)(s)) +#else /* !DOXYGEN */ +/* The real thing. */ +# define PSTR(s) (__extension__({static char __c[] PROGMEM = (s); &__c[0];})) +#endif /* DOXYGEN */ + +#define __LPM_classic__(addr) \ +(__extension__({ \ + uint16_t __addr16 = (uint16_t)(addr); \ + uint8_t __result; \ + __asm__ \ + ( \ + "lpm" "\n\t" \ + "mov %0, r0" "\n\t" \ + : "=r" (__result) \ + : "z" (__addr16) \ + : "r0" \ + ); \ + __result; \ +})) + +#define __LPM_enhanced__(addr) \ +(__extension__({ \ + uint16_t __addr16 = (uint16_t)(addr); \ + uint8_t __result; \ + __asm__ \ + ( \ + "lpm %0, Z" "\n\t" \ + : "=r" (__result) \ + : "z" (__addr16) \ + ); \ + __result; \ +})) + +#define __LPM_word_classic__(addr) \ +(__extension__({ \ + uint16_t __addr16 = (uint16_t)(addr); \ + uint16_t __result; \ + __asm__ \ + ( \ + "lpm" "\n\t" \ + "mov %A0, r0" "\n\t" \ + "adiw r30, 1" "\n\t" \ + "lpm" "\n\t" \ + "mov %B0, r0" "\n\t" \ + : "=r" (__result), "=z" (__addr16) \ + : "1" (__addr16) \ + : "r0" \ + ); \ + __result; \ +})) + +#define __LPM_word_enhanced__(addr) \ +(__extension__({ \ + uint16_t __addr16 = (uint16_t)(addr); \ + uint16_t __result; \ + __asm__ \ + ( \ + "lpm %A0, Z+" "\n\t" \ + "lpm %B0, Z" "\n\t" \ + : "=r" (__result), "=z" (__addr16) \ + : "1" (__addr16) \ + ); \ + __result; \ +})) + +#define __LPM_dword_classic__(addr) \ +(__extension__({ \ + uint16_t __addr16 = (uint16_t)(addr); \ + uint32_t __result; \ + __asm__ \ + ( \ + "lpm" "\n\t" \ + "mov %A0, r0" "\n\t" \ + "adiw r30, 1" "\n\t" \ + "lpm" "\n\t" \ + "mov %B0, r0" "\n\t" \ + "adiw r30, 1" "\n\t" \ + "lpm" "\n\t" \ + "mov %C0, r0" "\n\t" \ + "adiw r30, 1" "\n\t" \ + "lpm" "\n\t" \ + "mov %D0, r0" "\n\t" \ + : "=r" (__result), "=z" (__addr16) \ + : "1" (__addr16) \ + : "r0" \ + ); \ + __result; \ +})) + +#define __LPM_dword_enhanced__(addr) \ +(__extension__({ \ + uint16_t __addr16 = (uint16_t)(addr); \ + uint32_t __result; \ + __asm__ \ + ( \ + "lpm %A0, Z+" "\n\t" \ + "lpm %B0, Z+" "\n\t" \ + "lpm %C0, Z+" "\n\t" \ + "lpm %D0, Z" "\n\t" \ + : "=r" (__result), "=z" (__addr16) \ + : "1" (__addr16) \ + ); \ + __result; \ +})) + +#define __LPM_float_classic__(addr) \ +(__extension__({ \ + uint16_t __addr16 = (uint16_t)(addr); \ + float __result; \ + __asm__ \ + ( \ + "lpm" "\n\t" \ + "mov %A0, r0" "\n\t" \ + "adiw r30, 1" "\n\t" \ + "lpm" "\n\t" \ + "mov %B0, r0" "\n\t" \ + "adiw r30, 1" "\n\t" \ + "lpm" "\n\t" \ + "mov %C0, r0" "\n\t" \ + "adiw r30, 1" "\n\t" \ + "lpm" "\n\t" \ + "mov %D0, r0" "\n\t" \ + : "=r" (__result), "=z" (__addr16) \ + : "1" (__addr16) \ + : "r0" \ + ); \ + __result; \ +})) + +#define __LPM_float_enhanced__(addr) \ +(__extension__({ \ + uint16_t __addr16 = (uint16_t)(addr); \ + float __result; \ + __asm__ \ + ( \ + "lpm %A0, Z+" "\n\t" \ + "lpm %B0, Z+" "\n\t" \ + "lpm %C0, Z+" "\n\t" \ + "lpm %D0, Z" "\n\t" \ + : "=r" (__result), "=z" (__addr16) \ + : "1" (__addr16) \ + ); \ + __result; \ +})) + +#if defined (__AVR_HAVE_LPMX__) +#define __LPM(addr) __LPM_enhanced__(addr) +#define __LPM_word(addr) __LPM_word_enhanced__(addr) +#define __LPM_dword(addr) __LPM_dword_enhanced__(addr) +#define __LPM_float(addr) __LPM_float_enhanced__(addr) +#else +#define __LPM(addr) __LPM_classic__(addr) +#define __LPM_word(addr) __LPM_word_classic__(addr) +#define __LPM_dword(addr) __LPM_dword_classic__(addr) +#define __LPM_float(addr) __LPM_float_classic__(addr) +#endif + +/** \ingroup avr_pgmspace + \def pgm_read_byte_near(address_short) + Read a byte from the program space with a 16-bit (near) address. + \note The address is a byte address. + The address is in the program space. */ + +#define pgm_read_byte_near(address_short) __LPM((uint16_t)(address_short)) + +/** \ingroup avr_pgmspace + \def pgm_read_word_near(address_short) + Read a word from the program space with a 16-bit (near) address. + \note The address is a byte address. + The address is in the program space. */ + +#define pgm_read_word_near(address_short) __LPM_word((uint16_t)(address_short)) + +/** \ingroup avr_pgmspace + \def pgm_read_dword_near(address_short) + Read a double word from the program space with a 16-bit (near) address. + \note The address is a byte address. + The address is in the program space. */ + +#define pgm_read_dword_near(address_short) \ + __LPM_dword((uint16_t)(address_short)) + +/** \ingroup avr_pgmspace + \def pgm_read_float_near(address_short) + Read a float from the program space with a 16-bit (near) address. + \note The address is a byte address. + The address is in the program space. */ + +#define pgm_read_float_near(address_short) \ + __LPM_float((uint16_t)(address_short)) + +#if defined(RAMPZ) || defined(__DOXYGEN__) + +/* Only for devices with more than 64K of program memory. + RAMPZ must be defined (see iom103.h, iom128.h). +*/ + +/* The classic functions are needed for ATmega103. */ + +#define __ELPM_classic__(addr) \ +(__extension__({ \ + uint32_t __addr32 = (uint32_t)(addr); \ + uint8_t __result; \ + __asm__ \ + ( \ + "out %2, %C1" "\n\t" \ + "mov r31, %B1" "\n\t" \ + "mov r30, %A1" "\n\t" \ + "elpm" "\n\t" \ + "mov %0, r0" "\n\t" \ + : "=r" (__result) \ + : "r" (__addr32), \ + "I" (_SFR_IO_ADDR(RAMPZ)) \ + : "r0", "r30", "r31" \ + ); \ + __result; \ +})) + +#define __ELPM_enhanced__(addr) \ +(__extension__({ \ + uint32_t __addr32 = (uint32_t)(addr); \ + uint8_t __result; \ + __asm__ \ + ( \ + "out %2, %C1" "\n\t" \ + "movw r30, %1" "\n\t" \ + "elpm %0, Z+" "\n\t" \ + : "=r" (__result) \ + : "r" (__addr32), \ + "I" (_SFR_IO_ADDR(RAMPZ)) \ + : "r30", "r31" \ + ); \ + __result; \ +})) + +#define __ELPM_xmega__(addr) \ +(__extension__({ \ + uint32_t __addr32 = (uint32_t)(addr); \ + uint8_t __result; \ + __asm__ \ + ( \ + "in __tmp_reg__, %2" "\n\t" \ + "out %2, %C1" "\n\t" \ + "movw r30, %1" "\n\t" \ + "elpm %0, Z+" "\n\t" \ + "out %2, __tmp_reg__" \ + : "=r" (__result) \ + : "r" (__addr32), \ + "I" (_SFR_IO_ADDR(RAMPZ)) \ + : "r30", "r31" \ + ); \ + __result; \ +})) + +#define __ELPM_word_classic__(addr) \ +(__extension__({ \ + uint32_t __addr32 = (uint32_t)(addr); \ + uint16_t __result; \ + __asm__ \ + ( \ + "out %2, %C1" "\n\t" \ + "mov r31, %B1" "\n\t" \ + "mov r30, %A1" "\n\t" \ + "elpm" "\n\t" \ + "mov %A0, r0" "\n\t" \ + "in r0, %2" "\n\t" \ + "adiw r30, 1" "\n\t" \ + "adc r0, __zero_reg__" "\n\t" \ + "out %2, r0" "\n\t" \ + "elpm" "\n\t" \ + "mov %B0, r0" "\n\t" \ + : "=r" (__result) \ + : "r" (__addr32), \ + "I" (_SFR_IO_ADDR(RAMPZ)) \ + : "r0", "r30", "r31" \ + ); \ + __result; \ +})) + +#define __ELPM_word_enhanced__(addr) \ +(__extension__({ \ + uint32_t __addr32 = (uint32_t)(addr); \ + uint16_t __result; \ + __asm__ \ + ( \ + "out %2, %C1" "\n\t" \ + "movw r30, %1" "\n\t" \ + "elpm %A0, Z+" "\n\t" \ + "elpm %B0, Z" "\n\t" \ + : "=r" (__result) \ + : "r" (__addr32), \ + "I" (_SFR_IO_ADDR(RAMPZ)) \ + : "r30", "r31" \ + ); \ + __result; \ +})) + +#define __ELPM_word_xmega__(addr) \ +(__extension__({ \ + uint32_t __addr32 = (uint32_t)(addr); \ + uint16_t __result; \ + __asm__ \ + ( \ + "in __tmp_reg__, %2" "\n\t" \ + "out %2, %C1" "\n\t" \ + "movw r30, %1" "\n\t" \ + "elpm %A0, Z+" "\n\t" \ + "elpm %B0, Z" "\n\t" \ + "out %2, __tmp_reg__" \ + : "=r" (__result) \ + : "r" (__addr32), \ + "I" (_SFR_IO_ADDR(RAMPZ)) \ + : "r30", "r31" \ + ); \ + __result; \ +})) + +#define __ELPM_dword_classic__(addr) \ +(__extension__({ \ + uint32_t __addr32 = (uint32_t)(addr); \ + uint32_t __result; \ + __asm__ \ + ( \ + "out %2, %C1" "\n\t" \ + "mov r31, %B1" "\n\t" \ + "mov r30, %A1" "\n\t" \ + "elpm" "\n\t" \ + "mov %A0, r0" "\n\t" \ + "in r0, %2" "\n\t" \ + "adiw r30, 1" "\n\t" \ + "adc r0, __zero_reg__" "\n\t" \ + "out %2, r0" "\n\t" \ + "elpm" "\n\t" \ + "mov %B0, r0" "\n\t" \ + "in r0, %2" "\n\t" \ + "adiw r30, 1" "\n\t" \ + "adc r0, __zero_reg__" "\n\t" \ + "out %2, r0" "\n\t" \ + "elpm" "\n\t" \ + "mov %C0, r0" "\n\t" \ + "in r0, %2" "\n\t" \ + "adiw r30, 1" "\n\t" \ + "adc r0, __zero_reg__" "\n\t" \ + "out %2, r0" "\n\t" \ + "elpm" "\n\t" \ + "mov %D0, r0" "\n\t" \ + : "=r" (__result) \ + : "r" (__addr32), \ + "I" (_SFR_IO_ADDR(RAMPZ)) \ + : "r0", "r30", "r31" \ + ); \ + __result; \ +})) + +#define __ELPM_dword_enhanced__(addr) \ +(__extension__({ \ + uint32_t __addr32 = (uint32_t)(addr); \ + uint32_t __result; \ + __asm__ \ + ( \ + "out %2, %C1" "\n\t" \ + "movw r30, %1" "\n\t" \ + "elpm %A0, Z+" "\n\t" \ + "elpm %B0, Z+" "\n\t" \ + "elpm %C0, Z+" "\n\t" \ + "elpm %D0, Z" "\n\t" \ + : "=r" (__result) \ + : "r" (__addr32), \ + "I" (_SFR_IO_ADDR(RAMPZ)) \ + : "r30", "r31" \ + ); \ + __result; \ +})) + +#define __ELPM_dword_xmega__(addr) \ +(__extension__({ \ + uint32_t __addr32 = (uint32_t)(addr); \ + uint32_t __result; \ + __asm__ \ + ( \ + "in __tmp_reg__, %2" "\n\t" \ + "out %2, %C1" "\n\t" \ + "movw r30, %1" "\n\t" \ + "elpm %A0, Z+" "\n\t" \ + "elpm %B0, Z+" "\n\t" \ + "elpm %C0, Z+" "\n\t" \ + "elpm %D0, Z" "\n\t" \ + "out %2, __tmp_reg__" \ + : "=r" (__result) \ + : "r" (__addr32), \ + "I" (_SFR_IO_ADDR(RAMPZ)) \ + : "r30", "r31" \ + ); \ + __result; \ +})) + +#define __ELPM_float_classic__(addr) \ +(__extension__({ \ + uint32_t __addr32 = (uint32_t)(addr); \ + float __result; \ + __asm__ \ + ( \ + "out %2, %C1" "\n\t" \ + "mov r31, %B1" "\n\t" \ + "mov r30, %A1" "\n\t" \ + "elpm" "\n\t" \ + "mov %A0, r0" "\n\t" \ + "in r0, %2" "\n\t" \ + "adiw r30, 1" "\n\t" \ + "adc r0, __zero_reg__" "\n\t" \ + "out %2, r0" "\n\t" \ + "elpm" "\n\t" \ + "mov %B0, r0" "\n\t" \ + "in r0, %2" "\n\t" \ + "adiw r30, 1" "\n\t" \ + "adc r0, __zero_reg__" "\n\t" \ + "out %2, r0" "\n\t" \ + "elpm" "\n\t" \ + "mov %C0, r0" "\n\t" \ + "in r0, %2" "\n\t" \ + "adiw r30, 1" "\n\t" \ + "adc r0, __zero_reg__" "\n\t" \ + "out %2, r0" "\n\t" \ + "elpm" "\n\t" \ + "mov %D0, r0" "\n\t" \ + : "=r" (__result) \ + : "r" (__addr32), \ + "I" (_SFR_IO_ADDR(RAMPZ)) \ + : "r0", "r30", "r31" \ + ); \ + __result; \ +})) + +#define __ELPM_float_enhanced__(addr) \ +(__extension__({ \ + uint32_t __addr32 = (uint32_t)(addr); \ + float __result; \ + __asm__ \ + ( \ + "out %2, %C1" "\n\t" \ + "movw r30, %1" "\n\t" \ + "elpm %A0, Z+" "\n\t" \ + "elpm %B0, Z+" "\n\t" \ + "elpm %C0, Z+" "\n\t" \ + "elpm %D0, Z" "\n\t" \ + : "=r" (__result) \ + : "r" (__addr32), \ + "I" (_SFR_IO_ADDR(RAMPZ)) \ + : "r30", "r31" \ + ); \ + __result; \ +})) + +#define __ELPM_float_xmega__(addr) \ +(__extension__({ \ + uint32_t __addr32 = (uint32_t)(addr); \ + float __result; \ + __asm__ \ + ( \ + "in __tmp_reg__, %2" "\n\t" \ + "out %2, %C1" "\n\t" \ + "movw r30, %1" "\n\t" \ + "elpm %A0, Z+" "\n\t" \ + "elpm %B0, Z+" "\n\t" \ + "elpm %C0, Z+" "\n\t" \ + "elpm %D0, Z" "\n\t" \ + "out %2, __tmp_reg__" \ + : "=r" (__result) \ + : "r" (__addr32), \ + "I" (_SFR_IO_ADDR(RAMPZ)) \ + : "r30", "r31" \ + ); \ + __result; \ +})) + +/* +Check for architectures that implement RAMPD (avrxmega3, avrxmega5, +avrxmega7) as they need to save/restore RAMPZ for ELPM macros so it does +not interfere with data accesses. +*/ +#if defined (__AVR_HAVE_RAMPD__) + +#define __ELPM(addr) __ELPM_xmega__(addr) +#define __ELPM_word(addr) __ELPM_word_xmega__(addr) +#define __ELPM_dword(addr) __ELPM_dword_xmega__(addr) +#define __ELPM_float(addr) __ELPM_float_xmega__(addr) + +#else + +#if defined (__AVR_HAVE_LPMX__) + +#define __ELPM(addr) __ELPM_enhanced__(addr) +#define __ELPM_word(addr) __ELPM_word_enhanced__(addr) +#define __ELPM_dword(addr) __ELPM_dword_enhanced__(addr) +#define __ELPM_float(addr) __ELPM_float_enhanced__(addr) + +#else + +#define __ELPM(addr) __ELPM_classic__(addr) +#define __ELPM_word(addr) __ELPM_word_classic__(addr) +#define __ELPM_dword(addr) __ELPM_dword_classic__(addr) +#define __ELPM_float(addr) __ELPM_float_classic__(addr) + +#endif /* __AVR_HAVE_LPMX__ */ + +#endif /* __AVR_HAVE_RAMPD__ */ + + +/** \ingroup avr_pgmspace + \def pgm_read_byte_far(address_long) + Read a byte from the program space with a 32-bit (far) address. + + \note The address is a byte address. + The address is in the program space. */ + +#define pgm_read_byte_far(address_long) __ELPM((uint32_t)(address_long)) + +/** \ingroup avr_pgmspace + \def pgm_read_word_far(address_long) + Read a word from the program space with a 32-bit (far) address. + + \note The address is a byte address. + The address is in the program space. */ + +#define pgm_read_word_far(address_long) __ELPM_word((uint32_t)(address_long)) + +/** \ingroup avr_pgmspace + \def pgm_read_dword_far(address_long) + Read a double word from the program space with a 32-bit (far) address. + + \note The address is a byte address. + The address is in the program space. */ + +#define pgm_read_dword_far(address_long) __ELPM_dword((uint32_t)(address_long)) + +/** \ingroup avr_pgmspace + \def pgm_read_float_far(address_long) + Read a float from the program space with a 32-bit (far) address. + + \note The address is a byte address. + The address is in the program space. */ + +#define pgm_read_float_far(address_long) __ELPM_float((uint32_t)(address_long)) + +#endif /* RAMPZ or __DOXYGEN__ */ + +/** \ingroup avr_pgmspace + \def pgm_read_byte(address_short) + Read a byte from the program space with a 16-bit (near) address. + + \note The address is a byte address. + The address is in the program space. */ + +#define pgm_read_byte(address_short) pgm_read_byte_near(address_short) + +/** \ingroup avr_pgmspace + \def pgm_read_word(address_short) + Read a word from the program space with a 16-bit (near) address. + + \note The address is a byte address. + The address is in the program space. */ + +#define pgm_read_word(address_short) pgm_read_word_near(address_short) + +/** \ingroup avr_pgmspace + \def pgm_read_dword(address_short) + Read a double word from the program space with a 16-bit (near) address. + + \note The address is a byte address. + The address is in the program space. */ + +#define pgm_read_dword(address_short) pgm_read_dword_near(address_short) + +/** \ingroup avr_pgmspace + \def pgm_read_float(address_short) + Read a float from the program space with a 16-bit (near) address. + + \note The address is a byte address. + The address is in the program space. */ + +#define pgm_read_float(address_short) pgm_read_float_near(address_short) + +/** \ingroup avr_pgmspace + \def PGM_P + + Used to declare a variable that is a pointer to a string in program + space. */ + +#ifndef PGM_P +#define PGM_P const prog_char * +#endif + +/** \ingroup avr_pgmspace + \def PGM_VOID_P + + Used to declare a generic pointer to an object in program space. */ + +#ifndef PGM_VOID_P +#define PGM_VOID_P const prog_void * +#endif + +extern PGM_VOID_P memchr_P(PGM_VOID_P, int __val, size_t __len) __ATTR_CONST__; +extern int memcmp_P(const void *, PGM_VOID_P, size_t) __ATTR_PURE__; +extern void *memccpy_P(void *, PGM_VOID_P, int __val, size_t); +extern void *memcpy_P(void *, PGM_VOID_P, size_t); +extern void *memmem_P(const void *, size_t, PGM_VOID_P, size_t) __ATTR_PURE__; +extern PGM_VOID_P memrchr_P(PGM_VOID_P, int __val, size_t __len) __ATTR_CONST__; +extern char *strcat_P(char *, PGM_P); +extern PGM_P strchr_P(PGM_P, int __val) __ATTR_CONST__; +extern PGM_P strchrnul_P(PGM_P, int __val) __ATTR_CONST__; +extern int strcmp_P(const char *, PGM_P) __ATTR_PURE__; +extern char *strcpy_P(char *, PGM_P); +extern int strcasecmp_P(const char *, PGM_P) __ATTR_PURE__; +extern char *strcasestr_P(const char *, PGM_P) __ATTR_PURE__; +extern size_t strcspn_P(const char *__s, PGM_P __reject) __ATTR_PURE__; +extern size_t strlcat_P (char *, PGM_P, size_t ); +extern size_t strlcpy_P (char *, PGM_P, size_t ); +extern size_t strlen_P(PGM_P) __ATTR_CONST__; /* program memory can't change */ +extern size_t strnlen_P(PGM_P, size_t) __ATTR_CONST__; /* program memory can't change */ +extern int strncmp_P(const char *, PGM_P, size_t) __ATTR_PURE__; +extern int strncasecmp_P(const char *, PGM_P, size_t) __ATTR_PURE__; +extern char *strncat_P(char *, PGM_P, size_t); +extern char *strncpy_P(char *, PGM_P, size_t); +extern char *strpbrk_P(const char *__s, PGM_P __accept) __ATTR_PURE__; +extern PGM_P strrchr_P(PGM_P, int __val) __ATTR_CONST__; +extern char *strsep_P(char **__sp, PGM_P __delim); +extern size_t strspn_P(const char *__s, PGM_P __accept) __ATTR_PURE__; +extern char *strstr_P(const char *, PGM_P) __ATTR_PURE__; +extern char *strtok_P(char *__s, PGM_P __delim); +extern char *strtok_rP(char *__s, PGM_P __delim, char **__last); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif /* __PGMSPACE_H_ */ |