avr_fuse(3avr)
π NAME π
avr_fuse β bestie, this is the whole vibe of <avr/fuse.h>: Fuse Support, no cap π
β¨ SYNOPSIS β¨
okay so buckle up because this one is all about the ~Detailed Description~ and it's giving very much "read the whole thing or your chip gets the wrong fuses" energy π«Ά
πΈ Detailed Description πΈ
π¦ Introduction π¦
The Fuse API is literally how you tell the compiler which fuse settings you want for the specific AVR device you're building for. Those settings get parked in a special section inside the ELF output file β and that happens after linking, just so you know the timeline bestie β¨
Programming tools can eat this up: they pull the fuse info out of the ELF file and figure out whether the fuses even need to be programmed before the Flash and EEPROM memories get programmed. Which is iconic, because it means one single ELF file can hold every single thing you need to program an AVR ππ
To actually use the Fuse API, you include <avr/io.h>, and that header is a girlboss and automatically includes both the individual I/O header file and the <avr/fuse.h> file. Those two other files? They provide everything you need to set the AVR fuses. obsessed. π
π Fuse API π
Every I/O header file must define the FUSE_MEMORY_SIZE macro, and it's set to the number of fuse bytes that exist in that AVR device. simple as that β¨
There's a new type, __fuse_t, defined as a structure. How many fields it has? Depends entirely on how many fuse bytes FUSE_MEMORY_SIZE says there are:
- If
FUSE_MEMORY_SIZE == 1, there's only a single field:byte, of typeunsigned char. - If
FUSE_MEMORY_SIZE == 2, there are two fields:lowandhigh, of typeunsigned char. - If
FUSE_MEMORY_SIZE == 3, there are three fields:low,high, andextended, of typeunsigned char. - If
FUSE_MEMORY_SIZE > 3, there's a single field:byte, which is an array ofunsigned char, and the size of that array isFUSE_MEMORY_SIZE.
Then there's a convenience macro, FUSEMEM β it's defined as a GCC attribute for a custom-named section of ".fuse". π
And another convenience macro, FUSES β it declares a variable, __fuse, of type __fuse_t with the attribute that FUSEMEM defines. This variable is the whole point: it lets the end user set the fuse data without breaking a sweat π§
Note π If a device-specific I/O header file has previously definedFUSEMEM, thenFUSEMEMis not redefined. Same deal withFUSES: if a device-specific I/O header file already defined it,FUSESis not redefined.
Every AVR device I/O header file has a whole set of defined macros that spell out the actual fuse bits available on that device. And here's the twist, bestie β AVR fuses have inverted values: logical 1 means an unprogrammed (disabled) bit, and logical 0 means a programmed (enabled) bit. The macros for each individual fuse bit show this by doing 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. Then it gets inverted to represent logical values for a fuse memory byte.
To combine those fuse bit macros into one whole fuse byte, you 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 giving default values for each fuse byte that exists. 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 providing 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, fr fr. 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're compiling in C++, you cannot use the designated initializers, 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 β and listen, this part is important β there are a number of caveats 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. TheFUSESmacro 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
.fusesection in the ELF file gets its values from the initial variable assignment ONLY. This means you can NOT assign values to this variable inside functions β and the new values will not be put into the ELF.fusesection. π - The global variable declared in the
FUSESmacro has two leading underscores, which means it's 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_tstructure. Why? Because the fuse bits in all bytes default to a logical1β that means unprogrammed β while normal uninitialized data defaults to all logical zeros. So it is vital that all fuse bytes are initialized, even with default data. If they aren't, then the fuse bits may not be programmed to the desired settings. π this is the one that gets people, don't be that girl. - Be sure to have the
-mmcu=deviceflag in your compile command line and your linker command line, so the correct device is selected and the correct I/O header file is included when you include<avr/io.h>. - You can print out the contents of the
.fusesection 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 a lower address to a higher address, left to right. simple π
π Author π
Generated automatically by Doxygen for AVR-LibC from the source code. (not a human author bestie, the robots did it π€β¨)
okay that's the whole page π«Ά this one came straight from AVR-LibC, Version 2.2.1, and it's filed under avr_fuse(3avr). go set your fuses correctly, ily, periodt π
ππ
π¦ where this page comes from
- ubuntu resolute: avr-libc 1:2.2.1-1build1 Β· BSD-3-Clause
- ubuntu stonking: avr-libc 1:2.2.1-1build1 Β· BSD-3-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms