Search code examples
cpointersavratmegaavr-gcc

Why use 2 pointers to point to register address in atmega microcontroller?


This Line defines address for DDRD register in avr microcontroller

#define myDDRD *((volatile unsigned char* const) 0x31)

Can you please clarify how pointers is used in the above line? Why do we need the first asterisk? shouldn't the second one be enough to point to the address 0x31?


Solution

  • You can separate *((volatile unsigned char* const) 0x31) into 2 parts:
    one inner part: (volatile unsigned char* const) 0x31
    and one outer part: *( inner part ).

    The inner part casts the integer 0x31 to a volatile unsigned char pointer which is constant.
    A pointer type consist of the type name and an asterisk after the type name: type*. To cast an expression parenthesis are uses (type)expression.

    The outer part dereferences the address the pointer contains as the asterisk is in front of it: *pointer in order to access it's value.

    If we take the inner part only why it isn't enough to read and write from the address?

    Imagine a pointer int* intPtr pointing to a valid integer already. If you now want to change that integer you have to do it by *intPtr = 42;. If you would do instead intPtr = 42; you would write 42 to the pointers value and not to the address it points to, so that 42 would be the new address the pointer contains.

    In short:
    The macro reads one byte (unsigned char) from address 0x31 if it's on the right hand side of an assigment and writes one byte to it if it's on the left hand side.

    Usage:
    A typical usage is to do bit manipulation like clearing or setting single bits on that register lying on that specific address:

    myDDRD &= ~(1 << PD0); /* clear bit 0 as PD0 is defined as 0 */
    myDDRD |= (1 << PD1);  /* set bit 1 as PD1 is defined as 1   */
    

    For more information about bit manipulation, see here: How do you set, clear, and toggle a single bit?