Addressing ATmega registers by number

I am aware I can address eg. DDRB register by name, but I want to access the registers by number, essentially reading /writing directly to an I/O register (eg. port 0x04 for DDRB).

I want to do this in a loop (and I want to be able to initiate it from the attached PC).

How can I read or write directly from/to an AVR's I/O register by number?

DDRB is a defined value that evaluates to 0x04. So just use the number in place of the name.

DDRB is a number, it’s just been defined as a human-readable mnemonic.

port 0x04 for DDRB

Doesn’t make sense, DDRB is one of the PORTB regs, there is no “port 0x04 for DDRB”. Do you mean “pin 0x04”?

If you want to address ports using a number you could have an array of port addresses

byte ports [] = {DDRB, DDRA, PINx, PORTy...};

for (int i = 0, i < n; i++) {
    ports [i] = somevalue;

I think you should explain what you want to do not how you think it should be done.


@Grumpy_Mike: How would I rewrite this:

  byte maskAnd = 0x07;
  byte maskEor = 0x73;
  DDRB = ( DDRB & maskAnd ) ^ maskEor;
  0x04 = ( 0x04 & maskAnd ) ^ maskEor;

Line 3 compiles just fine; Line 4 will not compile and would mean something entirely different than to manipulate controller registers.

@Graynomad: I want to be able to send an instruction from my PC to Arduino, saying "what is the current value of DDRB?" If I have to program all registers in an 'if' or 'case' statement, I will probably make many errors and the program will grow really quick in size.

If you check the datasheet of ATmega1280, you'll see DDRB is a register at I/O port 0x04. If you examine the disassembled machine code that is sent to the controller while programming it, you'll see writing to IO ports is simply reading an IO register. I do not mean pin 0x04.

Line 4 will not compile

I think that’s because the lower registers (< 0x60) are addressed with a 0x20 offset for memory instructions and directly for IO instructions.

so DDRB = x actually writes to 0x24. You could try that address to see if it works.

The DDRx macro organises this for you.

If I have to program all registers in an ‘if’ or ‘case’ statement, I will probably make many errors and the program will grow really quick in size.

Try the above address adjustment, if it works just add 0x20 to all regs below 0x60.


Point taken about the + 0x20, but a line like:

0x24 = ....

will never compile. I need some way to tell the compiler to access the AVR's register, not the number. Any idea where I can find the DDRx macro? Maybe I can figure it out from the source codes.

On my system it’s in C:\arduino-1.0\hardware\tools\avr

from iom328p.h
#define DDRB _SFR_IO8(0x04)

from sfr_defs.h
#define _SFR_IO8(io_addr) ((io_addr) + __SFR_OFFSET)


void testje() {
  byte maskAnd = 0x00;
  byte maskEor = 0x73;
  byte regNum = 0x04;
  _SFR_IO8( regNum ) = ( _SFR_IO8( regNum ) & maskAnd ) ^ maskEor;

Compiles, I can test a bit with it :)


Try using:-

  *(unsigned short *)0x04 = 0;

or what ever.

@Grumpy_Mike: Compiles too! I was searching the source codes for what _SFR_IO8 exactly does, possibly it just does your little trick.


To find out what exactly what code a bunch of macros generate, I like to just run the compiler with the -E switch 1. Turn on verbose mode (in preferences(1.0) or hold shift(0022)) 2. Compile 3. Copy first line (from where is says blahbalh/avr-g++ to the next time it says it) into a command prompt/terminal 4. there should be a word "-c" in it. Change that to "-E" 5. After -o, there's a path to a file. Change the name to some thing like sketch.preprocessed (optional) 6. hit enter 7. read sketch.preprocessed, and scroll all the way to the bottom, where your sketch is 8. ??? 9. PROFIT

_SFR_IO8( regNum ) = ( _SFR_IO8( regNum ) & maskAnd ) ^ maskEor;
(*(volatile uint8_t *)((regNum) + 0x20)) = ( (*(volatile uint8_t *)((regNum) + 0x20)) & maskAnd ) ^ maskEor;

Cool! This little work instruction is useful information for troubleshooting and future reference :)