---
name: "avr_sfr_notes"
section: "3avr"
platform: "linux"
package: "avr-libc"
version: "1:2.2.1-1"
release: "Debian 13 (Trixie)"
platforms: ["linux"]
url: "https://new.carta.tech/avr_sfr_notes"
---

# avr\_sfr\_notes(3avr)

Additional notes from \<avr/sfr\_defs.h\>

## NAME

avr\_sfr\_notes - Additional notes from \<avr/sfr\_defs.h\>

## SYNOPSIS

## Detailed Description

The `<`**avr/sfr\_defs.h**`>` **file is included by all of the** `<avr/ioXXXX.h>` **files, which use macros defined here to make the special function register definitions look like C variables or simple constants, depending on the** `_SFR_ASM_COMPAT` **define. Some examples from** `<avr/iocanxx.h>` **to show how to define such macros:**

```
#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)
```

**If** `_SFR_ASM_COMPAT` **is not defined, C programs can use names like** `PORTA` **directly in C expressions (also on the left side of assignment operators) and GCC will do the right thing (use short I/O instructions if possible). The** `__SFR_OFFSET` **definition is not used in any way in this case.**

**Define** `_SFR_ASM_COMPAT` **as 1 to make these names work as simple constants (addresses of the I/O registers). This is necessary when included in preprocessed assembler (\*.S) source files, so it is done automatically if** `__ASSEMBLER__` **is defined. By default, all addresses are defined as if they were memory addresses (used in** `lds/sts` **instructions). To use these addresses in** `in/out` **instructions, you must subtract 0x20 from them.**

**For more backwards compatibility, insert the following at the start of your old assembler source file:**

```
#define __SFR_OFFSET 0
```

**This automatically subtracts 0x20 from I/O space addresses, but it's a hack, so it is recommended to change your source: wrap such addresses in macros defined here, as shown below. After this is done, the** `__SFR_OFFSET` **definition is no longer necessary and can be removed.**

**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). If it isn't, the assembler will complain (I/O address out of range 0...0x3f), so this should be fairly safe.**

**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, 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
```

**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).**

## Author

**Generated automatically by Doxygen for AVR-LibC from the source code.**
