1
\$\begingroup\$

Im using ATmega328P with Atmel Studio. I have a problem understanding the register manipulation in this code:

#include <avr/io.h>

int main(void)
{
    DDRB =  0b00000111;
    PORTB = 0b00000111;

    while (1)
    {           
        PORTB = 0b00000000;         
        PORTB = 0b00000111;     
    }
}

And here is its assembly:

     5: {
     6:     DDRB =  0b00000111;
00000040 87.e0                LDI R24,0x07      Load immediate 
00000041 84.b9                OUT 0x04,R24      Out to I/O location 
     7:     PORTB = 0b00000111;
00000042 85.b9                OUT 0x05,R24      Out to I/O location 
    12:         PORTB = 0b00000000;
00000043 15.b8                OUT 0x05,R1       Out to I/O location 
00000044 fd.cf                RJMP PC-0x0002        Relative jump 

And here is the view of I/O registers for PORTB for the last execution:

enter image description here

My question is:

If we go step by step, here 00000111 is moved to R24 cpu register and it is moved DDRB register which is at the address 0x04:

        DDRB =  0b00000111;
00000040 87.e0                LDI R24,0x07      Load immediate 
00000041 84.b9                OUT 0x04,R24      Out to I/O location 

Here the same bit pattern at R24 is applied to the register PORTB

     PORTB = 0b00000111;
00000042 85.b9                OUT 0x05,R24      Out to I/O location 

But what is happeing in the last two lines here:

00000043 15.b8                OUT 0x05,R1       Out to I/O location 
00000044 fd.cf                RJMP PC-0x0002        Relative jump 

First of all what is R1 which is not declared? And my code has nothing to do with PINB register but how come the PINB's PINB0, PINB1 and PINB2 becomes 1 here? Last two lines are:

\$\endgroup\$
2
  • 1
    \$\begingroup\$ It looks like (at a guess) it's relying on R1 being initialised to zero either in the startup code or by the processor reset. And it looks like the input ports shadow the value of the output ports - which makes sense, electrically. \$\endgroup\$
    – pjc50
    Commented Feb 24, 2017 at 11:44
  • \$\begingroup\$ @pjc50 What do you mean by "input ports shadow the value of the output ports"? \$\endgroup\$
    – user16307
    Commented Feb 24, 2017 at 12:37

1 Answer 1

6
\$\begingroup\$

First of all what is R1 which is not declared?

r0 ... r31 are the AVR's general purpose registers. r1 is set to 0x00 by the start up code gcc implicitly generates and is then assumed by the compiler to contain 0x00 forever. Hence, wherever 0x00 is needed but a literal cannot be used, gcc simply uses r1. (Similarily, r0 is reserved as temporary storage register and may be used for any purpose in any piece of code because gcc will never use it to store anything across a function call or an inline assembly section.)

See also https://gcc.gnu.org/wiki/avr-gcc#Register_Layout.

And my code has nothing to do with PINB register but how come the PINB's PINB0, PINB1 and PINB2 becomes 1 here?

PINx represents the value (high/low) as seen on the pin. When you output a value via PORTx, that value also is reflected in the PINx (delayed by 1 clock cycle, IIRC). That's also explicitly mentioned in the datasheets.

\$\endgroup\$
7
  • \$\begingroup\$ Interesting. Never saw this information in any tutorials. I dont know the reason to spend an extra clock cycle for this. Also I cant see the address of PINx which is 0X23 in the assembly code. (?) \$\endgroup\$
    – user16307
    Commented Feb 24, 2017 at 12:58
  • 2
    \$\begingroup\$ The reason for the extra cycle is that it's not the PORTx register value that gets copied, but PINx always reads the pin's value. So when you output a value on a pin in one cycle it's not until the next cycle that the input logic detects the new value and puts it into the PINx register. \$\endgroup\$
    – JimmyB
    Commented Feb 24, 2017 at 13:03
  • \$\begingroup\$ "I cant see the address of PINx which is 0X23 in the assembly code." - Why should you? Your program does not access that register. \$\endgroup\$
    – JimmyB
    Commented Feb 24, 2017 at 13:05
  • \$\begingroup\$ ok you mean the compiler takes care of that "always read pin value" part? \$\endgroup\$
    – user16307
    Commented Feb 24, 2017 at 13:07
  • 4
    \$\begingroup\$ No, the hardware always reads the pin value into PINx on every cycle. \$\endgroup\$
    – pjc50
    Commented Feb 24, 2017 at 13:09

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.