avr_sfr_notes(3)
π NAME π
avr_sfr_notes β the whole vibe behind those magical special-function-register macros, bestie π
β¨ SYNOPSIS β¨
Detailed Description
okay so first things first: <avr/sfr_defs.h> gets included by every single one of the <avr/ioXXXX.h> files π«Ά and those files use the macros defined in here to make the special function register definitions look like either C variables or plain simple constants β it literally depends on the _SFR_ASM_COMPAT define. no cap.
here are some examples straight out of <avr/iocanxx.h> showing how you'd define macros like this:
#define PORTA _SFR_IO8(0x02)
#define EEAR _SFR_IO16(0x21)
#define UDR0 _SFR_MEM8(0xC6)
#define TCNT3 _SFR_MEM16(0x94)
#define CANIDT _SFR_MEM32(0xF0)
so if _SFR_ASM_COMPAT is not defined, C programs can just use names like PORTA directly in C expressions (yes, even on the left side of assignment operators, she's versatile πββοΈ) and GCC will do the right thing β it'll use short I/O instructions if possible. and in this case the __SFR_OFFSET definition is not used in any way at all. it's just sitting there. not invited. π
now define _SFR_ASM_COMPAT as 1 and those same names work as simple constants (the addresses of the I/O registers). this is necessary when the file gets included in preprocessed assembler (*.S) source files, so it happens automatically if __ASSEMBLER__ is defined. by default, all addresses are defined as if they were memory addresses (the kind you'd use in lds/sts instructions). but to use these addresses in in/out instructions, you must subtract 0x20 from them. yes really. do the math. β¨
for more backwards compatibility, you can insert this at the start of your old assembler source file:
#define __SFR_OFFSET 0
this automatically subtracts 0x20 from I/O space addresses β but lowkey it's a hack π© so the recommendation is to actually change your source: wrap such addresses in the macros defined here, as shown below. once you've done that, the __SFR_OFFSET definition is no longer necessary and can be removed. glow up achieved. π
real example β this code could be used in a boot loader that is portable between devices with SPMCR at different addresses:
<avr/iom163.h>: #define SPMCR _SFR_IO8(0x37)
<avr/iom128.h>: #define SPMCR _SFR_MEM8(0x68)
#if _SFR_IO_REG_P(SPMCR)
out _SFR_IO_ADDR(SPMCR), r24
#else
sts _SFR_MEM_ADDR(SPMCR), r24
#endif
you can use the in/out/cbi/sbi/sbic/sbis instructions, without the _SFR_IO_REG_P test, if you know that the register is in the I/O space (as with SREG, for example β she's an icon, she knows her place π). if it isn't, the assembler will complain (I/O address out of range 0...0x3f), so this should be fairly safe. fairly. π
and if you do not define __SFR_OFFSET (so it will be 0x20 by default), all special register addresses are defined as memory addresses (so SREG is 0x5f), and β if code size and speed are not important, and you don't like the ugly #if above β you can always use lds/sts to access them. but heads up bestie, this will not work if __SFR_OFFSET != 0x20, so use a different macro (defined only if __SFR_OFFSET == 0x20) for safety:
sts _SFR_ADDR(SPMCR), r24
and in C programs? all 3 combinations of _SFR_ASM_COMPAT and __SFR_OFFSET are supported β the _SFR_ADDR(SPMCR) macro can be used to get the address of the SPMCR register (0x57 or 0x68 depending on device). every combination ate, no crumbs. π₯
π AUTHOR π
Generated automatically by Doxygen for avr-libc from the source code. (not me writing it by hand, the robots did that part π€β¨)
and that's the whole page, babe π this was Version 2.1.0, dated Sat Jan 29 2022, and honestly? iconic behavior from the avr-libc girlies. go forth and <avr/sfr_defs.h> responsibly ππ¦πΈ
π¦ where this page comes from
- fedora 43: avr-libc 2.2.1-3.fc43 Β· BSD-3-Clause
- fedora 44: avr-libc 2.2.1-5.fc44 Β· BSD-3-Clause
- opensuse-leap 16.0: avr-libc 2.1.0-bp160.1.33 Β· BSD-3-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms