AVR Libc Home Page AVRs AVR Libc Development Pages
Main Page User Manual Library Reference FAQ Alphabetical Index Example Projects

pgmspace.h

Go to the documentation of this file.
00001 /* Copyright (c) 2002-2007  Marek Michalkiewicz
00002    Copyright (c) 2006, Carlos Lamas
00003    Copyright (c) 2009-2010, Jan Waclawek
00004    All rights reserved.
00005 
00006    Redistribution and use in source and binary forms, with or without
00007    modification, are permitted provided that the following conditions are met:
00008 
00009    * Redistributions of source code must retain the above copyright
00010      notice, this list of conditions and the following disclaimer.
00011    * Redistributions in binary form must reproduce the above copyright
00012      notice, this list of conditions and the following disclaimer in
00013      the documentation and/or other materials provided with the
00014      distribution.
00015    * Neither the name of the copyright holders nor the names of
00016      contributors may be used to endorse or promote products derived
00017      from this software without specific prior written permission.
00018 
00019   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00020   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00021   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00022   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00023   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00024   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00025   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00026   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00027   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00028   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00029   POSSIBILITY OF SUCH DAMAGE. */
00030 
00031 /* $Id: pgmspace.h 2169 2010-06-14 06:28:23Z arcanum $ */
00032 
00033 /*
00034    pgmspace.h
00035 
00036    Contributors:
00037      Created by Marek Michalkiewicz <marekm@linux.org.pl>
00038      Eric B. Weddington <eric@ecentral.com>
00039      Wolfgang Haidinger <wh@vmars.tuwien.ac.at> (pgm_read_dword())
00040      Ivanov Anton <anton@arc.com.ru> (pgm_read_float())
00041  */
00042 
00043 /** \file */
00044 /** \defgroup avr_pgmspace <avr/pgmspace.h>: Program Space Utilities
00045     \code
00046     #include <avr/io.h>
00047     #include <avr/pgmspace.h>
00048     \endcode
00049 
00050     The functions in this module provide interfaces for a program to access
00051     data stored in program space (flash memory) of the device.  In order to
00052     use these functions, the target device must support either the \c LPM or
00053     \c ELPM instructions.
00054 
00055     \note These functions are an attempt to provide some compatibility with
00056     header files that come with IAR C, to make porting applications between
00057     different compilers easier.  This is not 100% compatibility though (GCC
00058     does not have full support for multiple address spaces yet).
00059 
00060     \note If you are working with strings which are completely based in ram,
00061     use the standard string functions described in \ref avr_string.
00062 
00063     \note If possible, put your constant tables in the lower 64 KB and use
00064     pgm_read_byte_near() or pgm_read_word_near() instead of
00065     pgm_read_byte_far() or pgm_read_word_far() since it is more efficient that
00066     way, and you can still use the upper 64K for executable code.
00067     All functions that are suffixed with a \c _P \e require their
00068     arguments to be in the lower 64 KB of the flash ROM, as they do
00069     not use ELPM instructions.  This is normally not a big concern as
00070     the linker setup arranges any program space constants declared
00071     using the macros from this header file so they are placed right after
00072     the interrupt vectors, and in front of any executable code.  However,
00073     it can become a problem if there are too many of these constants, or
00074     for bootloaders on devices with more than 64 KB of ROM.
00075     <em>All these functions will not work in that situation.</em>
00076 
00077     \note For <b>Xmega</b> devices, make sure the NVM controller
00078     command register (\c NVM.CMD or \c NVM_CMD) is set to 0x00 (NOP)
00079     before using any of these functions.
00080 */
00081 
00082 #ifndef __PGMSPACE_H_
00083 #define __PGMSPACE_H_ 1
00084 
00085 #define __need_size_t
00086 #include <inttypes.h>
00087 #include <stddef.h>
00088 #include <avr/io.h>
00089 
00090 #ifndef __ATTR_CONST__
00091 #define __ATTR_CONST__ __attribute__((__const__))
00092 #endif
00093 
00094 #ifndef __ATTR_PROGMEM__
00095 #define __ATTR_PROGMEM__ __attribute__((__progmem__))
00096 #endif
00097 
00098 #ifndef __ATTR_PURE__
00099 #define __ATTR_PURE__ __attribute__((__pure__))
00100 #endif
00101 
00102 /**
00103    \ingroup avr_pgmspace
00104    \def PROGMEM
00105 
00106    Attribute to use in order to declare an object being located in
00107    flash ROM.
00108  */
00109 #define PROGMEM __ATTR_PROGMEM__
00110 
00111 #ifdef __cplusplus
00112 extern "C" {
00113 #endif
00114 
00115 #if defined(__DOXYGEN__)
00116 /*
00117  * Doxygen doesn't grok the appended attribute syntax of
00118  * GCC, and confuses the typedefs with function decls, so
00119  * supply a doxygen-friendly view.
00120  */
00121 /**
00122    \ingroup avr_pgmspace
00123    \typedef prog_void
00124 
00125    Type of a "void" object located in flash ROM.  Does not make much
00126    sense by itself, but can be used to declare a "void *" object in
00127    flash ROM.
00128 */
00129 typedef void PROGMEM prog_void;
00130 /**
00131    \ingroup avr_pgmspace
00132    \typedef prog_char
00133 
00134    Type of a "char" object located in flash ROM.
00135 */
00136 typedef char PROGMEM prog_char;
00137 
00138 /**
00139    \ingroup avr_pgmspace
00140    \typedef prog_uchar
00141 
00142    Type of an "unsigned char" object located in flash ROM.
00143 */
00144 typedef unsigned char PROGMEM prog_uchar;
00145 
00146 
00147 /**
00148    \ingroup avr_pgmspace
00149    \typedef prog_int8_t
00150 
00151    Type of an "int8_t" object located in flash ROM.
00152 */
00153 typedef int8_t PROGMEM prog_int8_t;
00154 
00155 /**
00156    \ingroup avr_pgmspace
00157    \typedef prog_uint8_t
00158 
00159    Type of an "uint8_t" object located in flash ROM.
00160 */
00161 typedef uint8_t PROGMEM prog_uint8_t;
00162 
00163 /**
00164    \ingroup avr_pgmspace
00165    \typedef prog_int16_t
00166 
00167    Type of an "int16_t" object located in flash ROM.
00168 */
00169 typedef int16_t PROGMEM prog_int16_t;
00170 
00171 /**
00172    \ingroup avr_pgmspace
00173    \typedef prog_uint16_t
00174 
00175    Type of an "uint16_t" object located in flash ROM.
00176 */
00177 typedef uint16_t PROGMEM prog_uint16_t;
00178 
00179 /**
00180    \ingroup avr_pgmspace
00181    \typedef prog_int32_t
00182 
00183    Type of an "int32_t" object located in flash ROM.
00184 */
00185 typedef int32_t PROGMEM prog_int32_t;
00186 
00187 /**
00188    \ingroup avr_pgmspace
00189    \typedef prog_uint32_t
00190 
00191    Type of an "uint32_t" object located in flash ROM.
00192 */
00193 typedef uint32_t PROGMEM prog_uint32_t;
00194 
00195 /**
00196    \ingroup avr_pgmspace
00197    \typedef prog_int64_t
00198 
00199    Type of an "int64_t" object located in flash ROM.
00200 
00201    \note This type is not available when the compiler
00202    option -mint8 is in effect.
00203 */
00204 typedef int64_t PROGMEM prog_int64_t;
00205 
00206 /**
00207    \ingroup avr_pgmspace
00208    \typedef prog_uint64_t
00209 
00210    Type of an "uint64_t" object located in flash ROM.
00211 
00212    \note This type is not available when the compiler
00213    option -mint8 is in effect.
00214 */
00215 typedef uint64_t PROGMEM prog_uint64_t;
00216 #else  /* !DOXYGEN */
00217 typedef void prog_void PROGMEM;
00218 typedef char prog_char PROGMEM;
00219 typedef unsigned char prog_uchar PROGMEM;
00220 
00221 typedef int8_t    prog_int8_t   PROGMEM;
00222 typedef uint8_t   prog_uint8_t  PROGMEM;
00223 typedef int16_t   prog_int16_t  PROGMEM;
00224 typedef uint16_t  prog_uint16_t PROGMEM;
00225 typedef int32_t   prog_int32_t  PROGMEM;
00226 typedef uint32_t  prog_uint32_t PROGMEM;
00227 #if !__USING_MINT8
00228 typedef int64_t   prog_int64_t  PROGMEM;
00229 typedef uint64_t  prog_uint64_t PROGMEM;
00230 #endif
00231 #endif /* defined(__DOXYGEN__) */
00232 
00233 /* Although in C, we can get away with just using __c, it does not work in
00234    C++. We need to use &__c[0] to avoid the compiler puking. Dave Hylands
00235    explaned it thusly,
00236 
00237      Let's suppose that we use PSTR("Test"). In this case, the type returned
00238      by __c is a prog_char[5] and not a prog_char *. While these are
00239      compatible, they aren't the same thing (especially in C++). The type
00240      returned by &__c[0] is a prog_char *, which explains why it works
00241      fine. */
00242 
00243 #if defined(__DOXYGEN__)
00244 /*
00245  * The #define below is just a dummy that serves documentation
00246  * purposes only.
00247  */
00248 /** \ingroup avr_pgmspace
00249     \def PSTR(s)
00250 
00251     Used to declare a static pointer to a string in program space. */
00252 # define PSTR(s) ((const PROGMEM char *)(s))
00253 #else  /* !DOXYGEN */
00254 /* The real thing. */
00255 # define PSTR(s) (__extension__({static char __c[] PROGMEM = (s); &__c[0];}))
00256 #endif /* DOXYGEN */
00257 
00258 #define __LPM_classic__(addr)   \
00259 (__extension__({                \
00260     uint16_t __addr16 = (uint16_t)(addr); \
00261     uint8_t __result;           \
00262     __asm__                     \
00263     (                           \
00264         "lpm" "\n\t"            \
00265         "mov %0, r0" "\n\t"     \
00266         : "=r" (__result)       \
00267         : "z" (__addr16)        \
00268         : "r0"                  \
00269     );                          \
00270     __result;                   \
00271 }))
00272 
00273 #define __LPM_enhanced__(addr)  \
00274 (__extension__({                \
00275     uint16_t __addr16 = (uint16_t)(addr); \
00276     uint8_t __result;           \
00277     __asm__                     \
00278     (                           \
00279         "lpm %0, Z" "\n\t"      \
00280         : "=r" (__result)       \
00281         : "z" (__addr16)        \
00282     );                          \
00283     __result;                   \
00284 }))
00285 
00286 #define __LPM_word_classic__(addr)          \
00287 (__extension__({                            \
00288     uint16_t __addr16 = (uint16_t)(addr);   \
00289     uint16_t __result;                      \
00290     __asm__                                 \
00291     (                                       \
00292         "lpm"           "\n\t"              \
00293         "mov %A0, r0"   "\n\t"              \
00294         "adiw r30, 1"   "\n\t"              \
00295         "lpm"           "\n\t"              \
00296         "mov %B0, r0"   "\n\t"              \
00297         : "=r" (__result), "=z" (__addr16)  \
00298         : "1" (__addr16)                    \
00299         : "r0"                              \
00300     );                                      \
00301     __result;                               \
00302 }))
00303 
00304 #define __LPM_word_enhanced__(addr)         \
00305 (__extension__({                            \
00306     uint16_t __addr16 = (uint16_t)(addr);   \
00307     uint16_t __result;                      \
00308     __asm__                                 \
00309     (                                       \
00310         "lpm %A0, Z+"   "\n\t"              \
00311         "lpm %B0, Z"    "\n\t"              \
00312         : "=r" (__result), "=z" (__addr16)  \
00313         : "1" (__addr16)                    \
00314     );                                      \
00315     __result;                               \
00316 }))
00317 
00318 #define __LPM_dword_classic__(addr)         \
00319 (__extension__({                            \
00320     uint16_t __addr16 = (uint16_t)(addr);   \
00321     uint32_t __result;                      \
00322     __asm__                                 \
00323     (                                       \
00324         "lpm"           "\n\t"              \
00325         "mov %A0, r0"   "\n\t"              \
00326         "adiw r30, 1"   "\n\t"              \
00327         "lpm"           "\n\t"              \
00328         "mov %B0, r0"   "\n\t"              \
00329         "adiw r30, 1"   "\n\t"              \
00330         "lpm"           "\n\t"              \
00331         "mov %C0, r0"   "\n\t"              \
00332         "adiw r30, 1"   "\n\t"              \
00333         "lpm"           "\n\t"              \
00334         "mov %D0, r0"   "\n\t"              \
00335         : "=r" (__result), "=z" (__addr16)  \
00336         : "1" (__addr16)                    \
00337         : "r0"                              \
00338     );                                      \
00339     __result;                               \
00340 }))
00341 
00342 #define __LPM_dword_enhanced__(addr)        \
00343 (__extension__({                            \
00344     uint16_t __addr16 = (uint16_t)(addr);   \
00345     uint32_t __result;                      \
00346     __asm__                                 \
00347     (                                       \
00348         "lpm %A0, Z+"   "\n\t"              \
00349         "lpm %B0, Z+"   "\n\t"              \
00350         "lpm %C0, Z+"   "\n\t"              \
00351         "lpm %D0, Z"    "\n\t"              \
00352         : "=r" (__result), "=z" (__addr16)  \
00353         : "1" (__addr16)                    \
00354     );                                      \
00355     __result;                               \
00356 }))
00357 
00358 #define __LPM_float_classic__(addr)         \
00359 (__extension__({                            \
00360     uint16_t __addr16 = (uint16_t)(addr);   \
00361     float __result;                         \
00362     __asm__                                 \
00363     (                                       \
00364         "lpm"           "\n\t"              \
00365         "mov %A0, r0"   "\n\t"              \
00366         "adiw r30, 1"   "\n\t"              \
00367         "lpm"           "\n\t"              \
00368         "mov %B0, r0"   "\n\t"              \
00369         "adiw r30, 1"   "\n\t"              \
00370         "lpm"           "\n\t"              \
00371         "mov %C0, r0"   "\n\t"              \
00372         "adiw r30, 1"   "\n\t"              \
00373         "lpm"           "\n\t"              \
00374         "mov %D0, r0"   "\n\t"              \
00375         : "=r" (__result), "=z" (__addr16)  \
00376         : "1" (__addr16)                    \
00377         : "r0"                              \
00378     );                                      \
00379     __result;                               \
00380 }))
00381 
00382 #define __LPM_float_enhanced__(addr)        \
00383 (__extension__({                            \
00384     uint16_t __addr16 = (uint16_t)(addr);   \
00385     float __result;                         \
00386     __asm__                                 \
00387     (                                       \
00388         "lpm %A0, Z+"   "\n\t"              \
00389         "lpm %B0, Z+"   "\n\t"              \
00390         "lpm %C0, Z+"   "\n\t"              \
00391         "lpm %D0, Z"    "\n\t"              \
00392         : "=r" (__result), "=z" (__addr16)  \
00393         : "1" (__addr16)                    \
00394     );                                      \
00395     __result;                               \
00396 }))
00397 
00398 #if defined (__AVR_HAVE_LPMX__)
00399 #define __LPM(addr)         __LPM_enhanced__(addr)
00400 #define __LPM_word(addr)    __LPM_word_enhanced__(addr)
00401 #define __LPM_dword(addr)   __LPM_dword_enhanced__(addr)
00402 #define __LPM_float(addr)   __LPM_float_enhanced__(addr)
00403 #else
00404 #define __LPM(addr)         __LPM_classic__(addr)
00405 #define __LPM_word(addr)    __LPM_word_classic__(addr)
00406 #define __LPM_dword(addr)   __LPM_dword_classic__(addr)
00407 #define __LPM_float(addr)   __LPM_float_classic__(addr)
00408 #endif
00409 
00410 /** \ingroup avr_pgmspace
00411     \def pgm_read_byte_near(address_short)
00412     Read a byte from the program space with a 16-bit (near) address. 
00413     \note The address is a byte address.
00414     The address is in the program space. */
00415 
00416 #define pgm_read_byte_near(address_short) __LPM((uint16_t)(address_short))
00417 
00418 /** \ingroup avr_pgmspace
00419     \def pgm_read_word_near(address_short)
00420     Read a word from the program space with a 16-bit (near) address. 
00421     \note The address is a byte address. 
00422     The address is in the program space. */
00423 
00424 #define pgm_read_word_near(address_short) __LPM_word((uint16_t)(address_short))
00425 
00426 /** \ingroup avr_pgmspace
00427     \def pgm_read_dword_near(address_short)
00428     Read a double word from the program space with a 16-bit (near) address. 
00429     \note The address is a byte address. 
00430     The address is in the program space. */
00431 
00432 #define pgm_read_dword_near(address_short) \
00433     __LPM_dword((uint16_t)(address_short))
00434 
00435 /** \ingroup avr_pgmspace
00436     \def pgm_read_float_near(address_short)
00437     Read a float from the program space with a 16-bit (near) address. 
00438     \note The address is a byte address. 
00439     The address is in the program space. */
00440 
00441 #define pgm_read_float_near(address_short) \
00442     __LPM_float((uint16_t)(address_short))
00443 
00444 #if defined(RAMPZ) || defined(__DOXYGEN__)
00445 
00446 /* Only for devices with more than 64K of program memory.
00447    RAMPZ must be defined (see iom103.h, iom128.h).
00448 */
00449 
00450 /* The classic functions are needed for ATmega103. */
00451 
00452 #define __ELPM_classic__(addr)      \
00453 (__extension__({                    \
00454     uint32_t __addr32 = (uint32_t)(addr); \
00455     uint8_t __result;               \
00456     __asm__                         \
00457     (                               \
00458         "out %2, %C1" "\n\t"        \
00459         "mov r31, %B1" "\n\t"       \
00460         "mov r30, %A1" "\n\t"       \
00461         "elpm" "\n\t"               \
00462         "mov %0, r0" "\n\t"         \
00463         : "=r" (__result)           \
00464         : "r" (__addr32),           \
00465           "I" (_SFR_IO_ADDR(RAMPZ)) \
00466         : "r0", "r30", "r31"        \
00467     );                              \
00468     __result;                       \
00469 }))
00470 
00471 #define __ELPM_enhanced__(addr)     \
00472 (__extension__({                    \
00473     uint32_t __addr32 = (uint32_t)(addr); \
00474     uint8_t __result;               \
00475     __asm__                         \
00476     (                               \
00477         "out %2, %C1" "\n\t"        \
00478         "movw r30, %1" "\n\t"       \
00479         "elpm %0, Z+" "\n\t"        \
00480         : "=r" (__result)           \
00481         : "r" (__addr32),           \
00482           "I" (_SFR_IO_ADDR(RAMPZ)) \
00483         : "r30", "r31"              \
00484     );                              \
00485     __result;                       \
00486 }))
00487 
00488 #define __ELPM_xmega__(addr)        \
00489 (__extension__({                    \
00490     uint32_t __addr32 = (uint32_t)(addr); \
00491     uint8_t __result;               \
00492     __asm__                         \
00493     (                               \
00494         "in __tmp_reg__, %2" "\n\t" \
00495         "out %2, %C1" "\n\t"        \
00496         "movw r30, %1" "\n\t"       \
00497         "elpm %0, Z+" "\n\t"        \
00498         "out %2, __tmp_reg__"       \
00499         : "=r" (__result)           \
00500         : "r" (__addr32),           \
00501           "I" (_SFR_IO_ADDR(RAMPZ)) \
00502         : "r30", "r31"              \
00503     );                              \
00504     __result;                       \
00505 }))
00506 
00507 #define __ELPM_word_classic__(addr)     \
00508 (__extension__({                        \
00509     uint32_t __addr32 = (uint32_t)(addr); \
00510     uint16_t __result;                  \
00511     __asm__                             \
00512     (                                   \
00513         "out %2, %C1"   "\n\t"          \
00514         "mov r31, %B1"  "\n\t"          \
00515         "mov r30, %A1"  "\n\t"          \
00516         "elpm"          "\n\t"          \
00517         "mov %A0, r0"   "\n\t"          \
00518         "in r0, %2"     "\n\t"          \
00519         "adiw r30, 1"   "\n\t"          \
00520         "adc r0, __zero_reg__" "\n\t"   \
00521         "out %2, r0"    "\n\t"          \
00522         "elpm"          "\n\t"          \
00523         "mov %B0, r0"   "\n\t"          \
00524         : "=r" (__result)               \
00525         : "r" (__addr32),               \
00526           "I" (_SFR_IO_ADDR(RAMPZ))     \
00527         : "r0", "r30", "r31"            \
00528     );                                  \
00529     __result;                           \
00530 }))
00531 
00532 #define __ELPM_word_enhanced__(addr)    \
00533 (__extension__({                        \
00534     uint32_t __addr32 = (uint32_t)(addr); \
00535     uint16_t __result;                  \
00536     __asm__                             \
00537     (                                   \
00538         "out %2, %C1"   "\n\t"          \
00539         "movw r30, %1"  "\n\t"          \
00540         "elpm %A0, Z+"  "\n\t"          \
00541         "elpm %B0, Z"   "\n\t"          \
00542         : "=r" (__result)               \
00543         : "r" (__addr32),               \
00544           "I" (_SFR_IO_ADDR(RAMPZ))     \
00545         : "r30", "r31"                  \
00546     );                                  \
00547     __result;                           \
00548 }))
00549 
00550 #define __ELPM_word_xmega__(addr)       \
00551 (__extension__({                        \
00552     uint32_t __addr32 = (uint32_t)(addr); \
00553     uint16_t __result;                  \
00554     __asm__                             \
00555     (                                   \
00556         "in __tmp_reg__, %2" "\n\t"     \
00557         "out %2, %C1"   "\n\t"          \
00558         "movw r30, %1"  "\n\t"          \
00559         "elpm %A0, Z+"  "\n\t"          \
00560         "elpm %B0, Z"   "\n\t"          \
00561         "out %2, __tmp_reg__"           \
00562         : "=r" (__result)               \
00563         : "r" (__addr32),               \
00564           "I" (_SFR_IO_ADDR(RAMPZ))     \
00565         : "r30", "r31"                  \
00566     );                                  \
00567     __result;                           \
00568 }))
00569 
00570 #define __ELPM_dword_classic__(addr)      \
00571 (__extension__({                          \
00572     uint32_t __addr32 = (uint32_t)(addr); \
00573     uint32_t __result;                    \
00574     __asm__                               \
00575     (                                     \
00576         "out %2, %C1"          "\n\t"     \
00577         "mov r31, %B1"         "\n\t"     \
00578         "mov r30, %A1"         "\n\t"     \
00579         "elpm"                 "\n\t"     \
00580         "mov %A0, r0"          "\n\t"     \
00581         "in r0, %2"            "\n\t"     \
00582         "adiw r30, 1"          "\n\t"     \
00583         "adc r0, __zero_reg__" "\n\t"     \
00584         "out %2, r0"           "\n\t"     \
00585         "elpm"                 "\n\t"     \
00586         "mov %B0, r0"          "\n\t"     \
00587         "in r0, %2"            "\n\t"     \
00588         "adiw r30, 1"          "\n\t"     \
00589         "adc r0, __zero_reg__" "\n\t"     \
00590         "out %2, r0"           "\n\t"     \
00591         "elpm"                 "\n\t"     \
00592         "mov %C0, r0"          "\n\t"     \
00593         "in r0, %2"            "\n\t"     \
00594         "adiw r30, 1"          "\n\t"     \
00595         "adc r0, __zero_reg__" "\n\t"     \
00596         "out %2, r0"           "\n\t"     \
00597         "elpm"                 "\n\t"     \
00598         "mov %D0, r0"          "\n\t"     \
00599         : "=r" (__result)                 \
00600         : "r" (__addr32),                 \
00601           "I" (_SFR_IO_ADDR(RAMPZ))       \
00602         : "r0", "r30", "r31"              \
00603     );                                    \
00604     __result;                             \
00605 }))
00606 
00607 #define __ELPM_dword_enhanced__(addr)     \
00608 (__extension__({                          \
00609     uint32_t __addr32 = (uint32_t)(addr); \
00610     uint32_t __result;                    \
00611     __asm__                               \
00612     (                                     \
00613         "out %2, %C1"   "\n\t"            \
00614         "movw r30, %1"  "\n\t"            \
00615         "elpm %A0, Z+"  "\n\t"            \
00616         "elpm %B0, Z+"  "\n\t"            \
00617         "elpm %C0, Z+"  "\n\t"            \
00618         "elpm %D0, Z"   "\n\t"            \
00619         : "=r" (__result)                 \
00620         : "r" (__addr32),                 \
00621           "I" (_SFR_IO_ADDR(RAMPZ))       \
00622         : "r30", "r31"                    \
00623     );                                    \
00624     __result;                             \
00625 }))
00626 
00627 #define __ELPM_dword_xmega__(addr)        \
00628 (__extension__({                          \
00629     uint32_t __addr32 = (uint32_t)(addr); \
00630     uint32_t __result;                    \
00631     __asm__                               \
00632     (                                     \
00633         "in __tmp_reg__, %2" "\n\t"       \
00634         "out %2, %C1"   "\n\t"            \
00635         "movw r30, %1"  "\n\t"            \
00636         "elpm %A0, Z+"  "\n\t"            \
00637         "elpm %B0, Z+"  "\n\t"            \
00638         "elpm %C0, Z+"  "\n\t"            \
00639         "elpm %D0, Z"   "\n\t"            \
00640         "out %2, __tmp_reg__"             \
00641         : "=r" (__result)                 \
00642         : "r" (__addr32),                 \
00643           "I" (_SFR_IO_ADDR(RAMPZ))       \
00644         : "r30", "r31"                    \
00645     );                                    \
00646     __result;                             \
00647 }))
00648 
00649 #define __ELPM_float_classic__(addr)      \
00650 (__extension__({                          \
00651     uint32_t __addr32 = (uint32_t)(addr); \
00652     float __result;                       \
00653     __asm__                               \
00654     (                                     \
00655         "out %2, %C1"          "\n\t"     \
00656         "mov r31, %B1"         "\n\t"     \
00657         "mov r30, %A1"         "\n\t"     \
00658         "elpm"                 "\n\t"     \
00659         "mov %A0, r0"          "\n\t"     \
00660         "in r0, %2"            "\n\t"     \
00661         "adiw r30, 1"          "\n\t"     \
00662         "adc r0, __zero_reg__" "\n\t"     \
00663         "out %2, r0"           "\n\t"     \
00664         "elpm"                 "\n\t"     \
00665         "mov %B0, r0"          "\n\t"     \
00666         "in r0, %2"            "\n\t"     \
00667         "adiw r30, 1"          "\n\t"     \
00668         "adc r0, __zero_reg__" "\n\t"     \
00669         "out %2, r0"           "\n\t"     \
00670         "elpm"                 "\n\t"     \
00671         "mov %C0, r0"          "\n\t"     \
00672         "in r0, %2"            "\n\t"     \
00673         "adiw r30, 1"          "\n\t"     \
00674         "adc r0, __zero_reg__" "\n\t"     \
00675         "out %2, r0"           "\n\t"     \
00676         "elpm"                 "\n\t"     \
00677         "mov %D0, r0"          "\n\t"     \
00678         : "=r" (__result)                 \
00679         : "r" (__addr32),                 \
00680           "I" (_SFR_IO_ADDR(RAMPZ))       \
00681         : "r0", "r30", "r31"              \
00682     );                                    \
00683     __result;                             \
00684 }))
00685 
00686 #define __ELPM_float_enhanced__(addr)     \
00687 (__extension__({                          \
00688     uint32_t __addr32 = (uint32_t)(addr); \
00689     float __result;                       \
00690     __asm__                               \
00691     (                                     \
00692         "out %2, %C1"   "\n\t"            \
00693         "movw r30, %1"  "\n\t"            \
00694         "elpm %A0, Z+"  "\n\t"            \
00695         "elpm %B0, Z+"  "\n\t"            \
00696         "elpm %C0, Z+"  "\n\t"            \
00697         "elpm %D0, Z"   "\n\t"            \
00698         : "=r" (__result)                 \
00699         : "r" (__addr32),                 \
00700           "I" (_SFR_IO_ADDR(RAMPZ))       \
00701         : "r30", "r31"                    \
00702     );                                    \
00703     __result;                             \
00704 }))
00705 
00706 #define __ELPM_float_xmega__(addr)        \
00707 (__extension__({                          \
00708     uint32_t __addr32 = (uint32_t)(addr); \
00709     float __result;                       \
00710     __asm__                               \
00711     (                                     \
00712         "in __tmp_reg__, %2" "\n\t"       \
00713         "out %2, %C1"   "\n\t"            \
00714         "movw r30, %1"  "\n\t"            \
00715         "elpm %A0, Z+"  "\n\t"            \
00716         "elpm %B0, Z+"  "\n\t"            \
00717         "elpm %C0, Z+"  "\n\t"            \
00718         "elpm %D0, Z"   "\n\t"            \
00719         "out %2, __tmp_reg__"             \
00720         : "=r" (__result)                 \
00721         : "r" (__addr32),                 \
00722           "I" (_SFR_IO_ADDR(RAMPZ))       \
00723         : "r30", "r31"                    \
00724     );                                    \
00725     __result;                             \
00726 }))
00727 
00728 /* 
00729 Check for architectures that implement RAMPD (avrxmega3, avrxmega5, 
00730 avrxmega7) as they need to save/restore RAMPZ for ELPM macros so it does
00731 not interfere with data accesses. 
00732 */
00733 #if defined (__AVR_HAVE_RAMPD__)
00734 
00735 #define __ELPM(addr)        __ELPM_xmega__(addr)
00736 #define __ELPM_word(addr)   __ELPM_word_xmega__(addr)
00737 #define __ELPM_dword(addr)  __ELPM_dword_xmega__(addr)
00738 #define __ELPM_float(addr)  __ELPM_float_xmega__(addr)
00739 
00740 #else
00741 
00742 #if defined (__AVR_HAVE_LPMX__)
00743 
00744 #define __ELPM(addr)        __ELPM_enhanced__(addr)
00745 #define __ELPM_word(addr)   __ELPM_word_enhanced__(addr)
00746 #define __ELPM_dword(addr)  __ELPM_dword_enhanced__(addr)
00747 #define __ELPM_float(addr)  __ELPM_float_enhanced__(addr)
00748 
00749 #else
00750 
00751 #define __ELPM(addr)        __ELPM_classic__(addr)
00752 #define __ELPM_word(addr)   __ELPM_word_classic__(addr)
00753 #define __ELPM_dword(addr)  __ELPM_dword_classic__(addr)
00754 #define __ELPM_float(addr)  __ELPM_float_classic__(addr)
00755 
00756 #endif  /* __AVR_HAVE_LPMX__ */
00757 
00758 #endif  /* __AVR_HAVE_RAMPD__ */
00759 
00760 
00761 /** \ingroup avr_pgmspace
00762     \def pgm_read_byte_far(address_long)
00763     Read a byte from the program space with a 32-bit (far) address. 
00764 
00765     \note The address is a byte address. 
00766     The address is in the program space. */
00767 
00768 #define pgm_read_byte_far(address_long)  __ELPM((uint32_t)(address_long))
00769 
00770 /** \ingroup avr_pgmspace
00771     \def pgm_read_word_far(address_long)
00772     Read a word from the program space with a 32-bit (far) address. 
00773 
00774     \note The address is a byte address.
00775     The address is in the program space. */
00776 
00777 #define pgm_read_word_far(address_long)  __ELPM_word((uint32_t)(address_long))
00778 
00779 /** \ingroup avr_pgmspace
00780     \def pgm_read_dword_far(address_long)
00781     Read a double word from the program space with a 32-bit (far) address. 
00782 
00783     \note The address is a byte address.
00784     The address is in the program space. */
00785 
00786 #define pgm_read_dword_far(address_long) __ELPM_dword((uint32_t)(address_long))
00787 
00788 /** \ingroup avr_pgmspace
00789     \def pgm_read_float_far(address_long)
00790     Read a float from the program space with a 32-bit (far) address. 
00791 
00792     \note The address is a byte address.
00793     The address is in the program space. */
00794 
00795 #define pgm_read_float_far(address_long) __ELPM_float((uint32_t)(address_long))
00796 
00797 #endif /* RAMPZ or __DOXYGEN__ */
00798 
00799 /** \ingroup avr_pgmspace
00800     \def pgm_read_byte(address_short)
00801     Read a byte from the program space with a 16-bit (near) address. 
00802 
00803     \note The address is a byte address. 
00804     The address is in the program space. */
00805 
00806 #define pgm_read_byte(address_short)    pgm_read_byte_near(address_short)
00807 
00808 /** \ingroup avr_pgmspace
00809     \def pgm_read_word(address_short)
00810     Read a word from the program space with a 16-bit (near) address. 
00811 
00812     \note The address is a byte address. 
00813     The address is in the program space. */
00814 
00815 #define pgm_read_word(address_short)    pgm_read_word_near(address_short)
00816 
00817 /** \ingroup avr_pgmspace
00818     \def pgm_read_dword(address_short)
00819     Read a double word from the program space with a 16-bit (near) address. 
00820 
00821     \note The address is a byte address. 
00822     The address is in the program space. */
00823 
00824 #define pgm_read_dword(address_short)   pgm_read_dword_near(address_short)
00825 
00826 /** \ingroup avr_pgmspace
00827     \def pgm_read_float(address_short)
00828     Read a float from the program space with a 16-bit (near) address. 
00829 
00830     \note The address is a byte address. 
00831     The address is in the program space. */
00832 
00833 #define pgm_read_float(address_short)   pgm_read_float_near(address_short)
00834 
00835 /** \ingroup avr_pgmspace
00836     \def PGM_P
00837 
00838     Used to declare a variable that is a pointer to a string in program
00839     space. */
00840 
00841 #ifndef PGM_P
00842 #define PGM_P const prog_char *
00843 #endif
00844 
00845 /** \ingroup avr_pgmspace
00846     \def PGM_VOID_P
00847 
00848     Used to declare a generic pointer to an object in program space. */
00849 
00850 #ifndef PGM_VOID_P
00851 #define PGM_VOID_P const prog_void *
00852 #endif
00853 
00854 
00855 /* pgm_get_far_address() macro
00856 
00857    This macro facilitates the obtention of a 32 bit "far" pointer (only 24 bits
00858    used) to data even passed the 64KB limit for the 16 bit ordinary pointer. It
00859    is similar to the '&' operator, with some limitations.
00860 
00861    Comments:
00862 
00863    - The overhead is minimal and it's mainly due to the 32 bit size operation.
00864 
00865    - 24 bit sizes guarantees the code compatibility for use in future devices.
00866 
00867    - hh8() is an undocumented feature but seems to give the third significant byte
00868      of a 32 bit data and accepts symbols, complementing the functionality of hi8()
00869      and lo8(). There is not an equivalent assembler function to get the high
00870      significant byte.
00871 
00872    - 'var' has to be resolved at linking time as an existing symbol, i.e, a simple
00873      type variable name, an array name (not an indexed element of the array, if the
00874      index is a constant the compiler does not complain but fails to get the address
00875      if optimization is enabled), a struct name or a struct field name, a function
00876      identifier, a linker defined identifier,...
00877 
00878    - The returned value is the identifier's VMA (virtual memory address) determined
00879      by the linker and falls in the corresponding memory region. The AVR Harvard
00880      architecture requires non overlapping VMA areas for the multiple address spaces
00881      in the processor: Flash ROM, RAM, and EEPROM. Typical offset for this are
00882      0x00000000, 0x00800xx0, and 0x00810000 respectively, derived from the linker
00883          script used and linker options. The value returned can be seen then as a
00884      universal pointer.
00885 
00886 */
00887 
00888 #define pgm_get_far_address(var)                          \
00889 ({                                                    \
00890         uint_farptr_t tmp;                                \
00891                                                       \
00892         __asm__ __volatile__(                             \
00893                                                       \
00894                         "ldi    %A0, lo8(%1)"           "\n\t"    \
00895                         "ldi    %B0, hi8(%1)"           "\n\t"    \
00896                         "ldi    %C0, hh8(%1)"           "\n\t"    \
00897                         "clr    %D0"                    "\n\t"    \
00898                 :                                             \
00899                         "=d" (tmp)                                \
00900                 :                                             \
00901                         "p"  (&(var))                             \
00902         );                                                \
00903         tmp;                                              \
00904 })
00905 
00906 
00907 extern PGM_VOID_P memchr_P(PGM_VOID_P, int __val, size_t __len) __ATTR_CONST__;
00908 extern int memcmp_P(const void *, PGM_VOID_P, size_t) __ATTR_PURE__;
00909 extern void *memccpy_P(void *, PGM_VOID_P, int __val, size_t);
00910 extern void *memcpy_P(void *, PGM_VOID_P, size_t);
00911 extern void *memmem_P(const void *, size_t, PGM_VOID_P, size_t) __ATTR_PURE__;
00912 extern PGM_VOID_P memrchr_P(PGM_VOID_P, int __val, size_t __len) __ATTR_CONST__;
00913 extern char *strcat_P(char *, PGM_P);
00914 extern PGM_P strchr_P(PGM_P, int __val) __ATTR_CONST__;
00915 extern PGM_P strchrnul_P(PGM_P, int __val) __ATTR_CONST__;
00916 extern int strcmp_P(const char *, PGM_P) __ATTR_PURE__;
00917 extern char *strcpy_P(char *, PGM_P);
00918 extern int strcasecmp_P(const char *, PGM_P) __ATTR_PURE__;
00919 extern char *strcasestr_P(const char *, PGM_P) __ATTR_PURE__;
00920 extern size_t strcspn_P(const char *__s, PGM_P __reject) __ATTR_PURE__;
00921 extern size_t strlcat_P (char *, PGM_P, size_t );
00922 extern size_t strlcpy_P (char *, PGM_P, size_t );
00923 extern size_t strlen_P(PGM_P) __ATTR_CONST__; /* program memory can't change */
00924 extern size_t strnlen_P(PGM_P, size_t) __ATTR_CONST__; /* program memory can't change */
00925 extern int strncmp_P(const char *, PGM_P, size_t) __ATTR_PURE__;
00926 extern int strncasecmp_P(const char *, PGM_P, size_t) __ATTR_PURE__;
00927 extern char *strncat_P(char *, PGM_P, size_t);
00928 extern char *strncpy_P(char *, PGM_P, size_t);
00929 extern char *strpbrk_P(const char *__s, PGM_P __accept) __ATTR_PURE__;
00930 extern PGM_P strrchr_P(PGM_P, int __val) __ATTR_CONST__;
00931 extern char *strsep_P(char **__sp, PGM_P __delim);
00932 extern size_t strspn_P(const char *__s, PGM_P __accept) __ATTR_PURE__;
00933 extern char *strstr_P(const char *, PGM_P) __ATTR_PURE__;
00934 extern char *strtok_P(char *__s, PGM_P __delim);
00935 extern char *strtok_rP(char *__s, PGM_P __delim, char **__last);
00936 
00937 extern size_t strlen_PF (uint_farptr_t src) __ATTR_CONST__; /* program memory can't change */
00938 extern size_t strnlen_PF (uint_farptr_t src, size_t len) __ATTR_CONST__; /* program memory can't change */
00939 extern void *memcpy_PF (void *dest, uint_farptr_t src, size_t len);
00940 extern char *strcpy_PF (char *dest, uint_farptr_t src);
00941 extern char *strncpy_PF (char *dest, uint_farptr_t src, size_t len);
00942 extern char *strcat_PF (char *dest, uint_farptr_t src);
00943 extern size_t strlcat_PF (char *dst, uint_farptr_t src, size_t siz);
00944 extern char *strncat_PF (char *dest, uint_farptr_t src, size_t len);
00945 extern int strcmp_PF (const char *s1, uint_farptr_t s2) __ATTR_PURE__;
00946 extern int strncmp_PF (const char *s1, uint_farptr_t s2, size_t n) __ATTR_PURE__;
00947 extern int strcasecmp_PF (const char *s1, uint_farptr_t s2) __ATTR_PURE__;
00948 extern int strncasecmp_PF (const char *s1, uint_farptr_t s2, size_t n) __ATTR_PURE__;
00949 extern char *strstr_PF (const char *s1, uint_farptr_t s2);
00950 extern size_t strlcpy_PF (char *dst, uint_farptr_t src, size_t siz);
00951 extern int memcmp_PF(const void *, uint_farptr_t, size_t) __ATTR_PURE__;
00952 
00953 
00954 #ifdef __cplusplus
00955 }
00956 #endif
00957 
00958 #endif /* __PGMSPACE_H_ */

Automatically generated by Doxygen 1.7.3 on Thu May 19 2011.