A question on avr macros

Hi,
I’m not sure if this is the right forum to ask this question, I teach a class on microcontrollers. We are working with the ATMEGA 2560 and programming in C. I was showing the students how to blink 3 LEDS using the I/O registers and a timer functionbuilt into the Arduino library. What I realized that in my code I had an error in specifying the data direction register, but the code still functioned properly.

I initialized 3 ports for output by initializing the Data Direction Register B, but used the wrong register macro names for the bits:

DDRB |= (1 << PORTB5) | (1 << PORTB6) | (1 << PORTB7);

It should have been stated:

DDRB |= (1 << DDB5) | (1 << DDB6) | (1 << DDB7);

The code still works even though it appears that the wrong macros were used. Did my compiler outsmart me?

My understanding is that the when you include avr/io.h, the macros give the preprocessor directives to associate the “Bitname” such as DB5 with the address in memory. It looks like that is not correct. Why does DDB5 = PORTB5?

Thanks!

The code is equivalent if the macros happen to have the same value. I have seen this incidentally happen more than once in AVR where people technically used the non-intended macros and still had the same result. Just Ctrl+Click on the macro name in VSCode to follow them to the source and inspect their value, and you shall find the truth.

Just to add my £0.02.

The three registers for the pins, DDRx, PORTx & PINx, use exactly the same bits for the same pins, so your code worked fine because the bit patterns were identical. I suffered from exactly this “problem” when I first delved into AVR programming and away from Arduino.

DDB5 = PINB5 = PORTB5 = (1 << 5).

Cheers,
Norm.

Thank you very much for your reply. I was thinking that each register bit location in a register has a unique address, but that was my mistake. I guess there is no such thing as a register bit number address!

Thanks so much for your reply.
I was overthinking it. I was under the impression that each bit in the register is somehow unique in the address.

So I could write
DDRB |= (1 >> ADATE); and get the same result as

DDRB |= (1 << DDB5);

because ADATE = 5. Do you agree?

You could indeed use ADATE like that. Or anything else that has the same value.

It would confuse people used to using the “correct” bit names though! :wink:

You can also use 32, 0x20, 0b0010000 etc without the shift of course.

Cheers,
Norm.

Yeah, I would never use ADATE like that. I was just realizing that all of the macros for bit names are just numbers. I originally thought that the macro for a bit name was a pointer that had to be referenced from its register address. But that wouldnt make sense since the address of the registers are 8 bits wide so it already accounts for the bit locations. Hope that makes sense what i was thinking.
Thanks!

if I remember correctly, the register names are volatile uint8_t * pointers but yes, the bit names are just the bit positions in the register. So you have this for PINB, for example:

#define PINB _SFR_IO8(0x03)
#define PINB0 0
#define PINB1 1
#define PINB2 2
#define PINB3 3
#define PINB4 4
#define PINB5 5
#define PINB6 6
#define PINB7 7

and:

#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)

and

#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))

So, I did remember correctly! :wink:

Have fun.

Cheers,
Norm.