diff options
Diffstat (limited to 'include/avr/fuse.h')
-rw-r--r-- | include/avr/fuse.h | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/include/avr/fuse.h b/include/avr/fuse.h new file mode 100644 index 0000000000..ba968ba853 --- /dev/null +++ b/include/avr/fuse.h @@ -0,0 +1,268 @@ +/* Copyright (c) 2007, Atmel Corporation + 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. */ + + +/* avr/fuse.h - Fuse API */ + +#ifndef _AVR_FUSE_H_ +#define _AVR_FUSE_H_ 1 + +/* This file must be explicitly included by <avr/io.h>. */ +#if !defined(_AVR_IO_H_) +#error "You must #include <avr/io.h> and not <avr/fuse.h> by itself." +#endif + + +/** \file */ +/** \defgroup avr_fuse <avr/fuse.h>: Fuse Support + + \par Introduction + + The Fuse API allows a user to specify the fuse settings for the specific + AVR device they are compiling for. These fuse settings will be placed + in a special section in the ELF output file, after linking. + + Programming tools can take advantage of the fuse information embedded in + the ELF file, by extracting this information and determining if the fuses + need to be programmed before programming the Flash and EEPROM memories. + This also allows a single ELF file to contain all the + information needed to program an AVR. + + To use the Fuse API, include the <avr/io.h> header file, which in turn + automatically includes the individual I/O header file and the <avr/fuse.h> + file. These other two files provides everything necessary to set the AVR + fuses. + + \par Fuse API + + Each I/O header file must define the FUSE_MEMORY_SIZE macro which is + defined to the number of fuse bytes that exist in the AVR device. + + A new type, __fuse_t, is defined as a structure. The number of fields in + this structure are determined by the number of fuse bytes in the + FUSE_MEMORY_SIZE macro. + + If FUSE_MEMORY_SIZE == 1, there is only a single field: byte, of type + unsigned char. + + If FUSE_MEMORY_SIZE == 2, there are two fields: low, and high, of type + unsigned char. + + If FUSE_MEMORY_SIZE == 3, there are three fields: low, high, and extended, + of type unsigned char. + + If FUSE_MEMORY_SIZE > 3, there is a single field: byte, which is an array + of unsigned char with the size of the array being FUSE_MEMORY_SIZE. + + A convenience macro, FUSEMEM, is defined as a GCC attribute for a + custom-named section of ".fuse". + + A convenience macro, FUSES, is defined that declares a variable, __fuse, of + type __fuse_t with the attribute defined by FUSEMEM. This variable + allows the end user to easily set the fuse data. + + \note If a device-specific I/O header file has previously defined FUSEMEM, + then FUSEMEM is not redefined. If a device-specific I/O header file has + previously defined FUSES, then FUSES is not redefined. + + Each AVR device I/O header file has a set of defined macros which specify the + actual fuse bits available on that device. The AVR fuses have inverted + values, logical 1 for an unprogrammed (disabled) bit and logical 0 for a + programmed (enabled) bit. The defined macros for each individual fuse + bit represent this in their definition by a bit-wise inversion of a mask. + For example, the FUSE_EESAVE fuse in the ATmega128 is defined as: + \code + #define FUSE_EESAVE ~_BV(3) + \endcode + \note The _BV macro creates a bit mask from a bit number. It is then + inverted to represent logical values for a fuse memory byte. + + To combine the fuse bits macros together to represent a whole fuse byte, + use the bitwise AND operator, like so: + \code + (FUSE_BOOTSZ0 & FUSE_BOOTSZ1 & FUSE_EESAVE & FUSE_SPIEN & FUSE_JTAGEN) + \endcode + + Each device I/O header file also defines macros that provide default values + for each fuse byte that is available. LFUSE_DEFAULT is defined for a Low + Fuse byte. HFUSE_DEFAULT is defined for a High Fuse byte. EFUSE_DEFAULT + is defined for an Extended Fuse byte. + + If FUSE_MEMORY_SIZE > 3, then the I/O header file defines macros that + provide default values for each fuse byte like so: + FUSE0_DEFAULT + FUSE1_DEFAULT + FUSE2_DEFAULT + FUSE3_DEFAULT + FUSE4_DEFAULT + .... + + \par API Usage Example + + Putting all of this together is easy. Using C99's designated initializers: + + \code + #include <avr/io.h> + + FUSES = + { + .low = LFUSE_DEFAULT, + .high = (FUSE_BOOTSZ0 & FUSE_BOOTSZ1 & FUSE_EESAVE & FUSE_SPIEN & FUSE_JTAGEN), + .extended = EFUSE_DEFAULT, + }; + + int main(void) + { + return 0; + } + \endcode + + Or, using the variable directly instead of the FUSES macro, + + \code + #include <avr/io.h> + + __fuse_t __fuse __attribute__((section (".fuse"))) = + { + .low = LFUSE_DEFAULT, + .high = (FUSE_BOOTSZ0 & FUSE_BOOTSZ1 & FUSE_EESAVE & FUSE_SPIEN & FUSE_JTAGEN), + .extended = EFUSE_DEFAULT, + }; + + int main(void) + { + return 0; + } + \endcode + + If you are compiling in C++, you cannot use the designated intializers so + you must do: + + \code + #include <avr/io.h> + + FUSES = + { + LFUSE_DEFAULT, // .low + (FUSE_BOOTSZ0 & FUSE_BOOTSZ1 & FUSE_EESAVE & FUSE_SPIEN & FUSE_JTAGEN), // .high + EFUSE_DEFAULT, // .extended + }; + + int main(void) + { + return 0; + } + \endcode + + + However there are a number of caveats that you need to be aware of to + use this API properly. + + Be sure to include <avr/io.h> to get all of the definitions for the API. + The FUSES macro defines a global variable to store the fuse data. This + variable is assigned to its own linker section. Assign the desired fuse + values immediately in the variable initialization. + + The .fuse section in the ELF file will get its values from the initial + variable assignment ONLY. This means that you can NOT assign values to + this variable in functions and the new values will not be put into the + ELF .fuse section. + + The global variable is declared in the FUSES macro has two leading + underscores, which means that it is reserved for the "implementation", + meaning the library, so it will not conflict with a user-named variable. + + You must initialize ALL fields in the __fuse_t structure. This is because + the fuse bits in all bytes default to a logical 1, meaning unprogrammed. + Normal uninitialized data defaults to all locgial zeros. So it is vital that + all fuse bytes are initialized, even with default data. If they are not, + then the fuse bits may not programmed to the desired settings. + + Be sure to have the -mmcu=<em>device</em> flag in your compile command line and + your linker command line to have the correct device selected and to have + the correct I/O header file included when you include <avr/io.h>. + + You can print out the contents of the .fuse section in the ELF file by + using this command line: + \code + avr-objdump -s -j .fuse <ELF file> + \endcode + The section contents shows the address on the left, then the data going from + lower address to a higher address, left to right. + +*/ + +#ifndef __ASSEMBLER__ + +#ifndef FUSEMEM +#define FUSEMEM __attribute__((section (".fuse"))) +#endif + +#if FUSE_MEMORY_SIZE > 3 + +typedef struct +{ + unsigned char byte[FUSE_MEMORY_SIZE]; +} __fuse_t; + + +#elif FUSE_MEMORY_SIZE == 3 + +typedef struct +{ + unsigned char low; + unsigned char high; + unsigned char extended; +} __fuse_t; + +#elif FUSE_MEMORY_SIZE == 2 + +typedef struct +{ + unsigned char low; + unsigned char high; +} __fuse_t; + +#elif FUSE_MEMORY_SIZE == 1 + +typedef struct +{ + unsigned char byte; +} __fuse_t; + +#endif + +#ifndef FUSES +#define FUSES __fuse_t __fuse FUSEMEM +#endif + +#endif /* !__ASSEMBLER__ */ + +#endif /* _AVR_FUSE_H_ */ |