avr/fuse.h: fuse support(3)
NAME
- <avr/fuse.h>: Fuse Support - Introduction.RS 4
- 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.
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:
- #define FUSE_EESAVE ~_BV(3)
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:
- (FUSE_BOOTSZ0 & FUSE_BOOTSZ1 & FUSE_EESAVE & FUSE_SPIEN & FUSE_JTAGEN)
- 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 ....
API Usage Example
Putting all of this together is easy. Using C99's designated initializers:
#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;
- }
- Or, using the variable directly instead of the FUSES macro,
- #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;
- }
- If you are compiling in C++, you cannot use the designated intializers so you
- must do:
- #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;
- }
- 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=device 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:
- avr-objdump -s -j .fuse <ELF file>
- The section contents shows the address on the left, then the data going from
- lower address to a higher address, left to right.
Author
- Generated automatically by Doxygen for avr-libc from the source code.