I was trying to change the value of DDRB by its memory address with the following code:

*(volatile byte*) 0x04 = 0b00100000;

It did not work.

I got the value 0x04 from a post on the Arduino forum, and they claim to have gotten it from the datasheet that looks like this:

enter image description here

It says 0x04 next to it, but my code only started working when I switched to 0x24, the value inside the parentheses. This is the same for PORTB and I assume all the other port related registers.

What does 0x04 point to, how does it relate to DDRB, and why is 0x24 in parenthesis if that is the actual address?


2 Answers 2


For the lower 64 IO registers, there are two addresses. The first (0x04 in this example) is used for access using certain I/O instructions such as out (write to IO register) and sbi (set bit in register). The larger value address (0x24 here) address, or only address for higher registers is used for memory access instructions such as sts (store to SRAM).

The latter address is higher because the AVR uses a unified memory address range, where the lower 0x00-0x1F are the 32 registers in the register map (r0-r31), so for memory access (your pointer dereference) you have to use the true address of the register.

For example, this is the address map for the ATMega328p taken from its datasheet:

Atmega328p Address Map

This is noted in the device datasheet in the register map section:

Notes from datasheet about address usage

Better yet, if using avr-gcc, #include <avr/io.h> and use the defines for each register (e.g. PORTB) which already take care of working out which is the correct address to use. These defines will properly optimise to use the in/out instructions where possible.

  • \$\begingroup\$ Where is figure 7.2 from? It should be 2048 x 8 RAM. \$\endgroup\$ Commented Feb 11, 2023 at 14:20
  • 1
    \$\begingroup\$ @thebusybee Page 18 of the datasheet. Seems there is a typo in the size, as you say should be '2'048 not '1'048. The actual addresses are correct (0x0100-0x08FF is 2048 bytes). \$\endgroup\$ Commented Feb 11, 2023 at 14:28

AVR has a Harvard architecture. The I/O registers of these devices are mapped into two of the memory spaces.

In I/O addressing (e.g. IN and OUT opcodes), use the addresses 0x00 - 0x3F.

When using the data address space (e.g. LD/ST opcodes, which is what C generates), you must add 0x20 to access these I/O registers.

See section 8.5 I/O Memory of the datasheet for more information.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.