Consider this AVR assembly code:
blink:
sbi PINA, 0 ; Toggle PINA
jmp blink
According to the documentation, this should set bit 0 on port A, however, this code actually causes the bit to toggle.
Why is that?
CodePudding user response:
Why is that?
Because this is how it works on newer AVR devices: You can toggle a port pin by SBI-ing the PIN register. An example is ATmega88, whereas older ATmega8 just sets a bit in PIN.
Advantage is that this allows to atomically toggle a port pin, whereas the traditional IN-XOR-OUT is not atomic, slower and consumes more flash. To make it atomic, you'd have to (temporarily) disable IRQs.
Cf. for the example data sheet of ATmega48/88/168, Section 13 I/O-Ports:
13.2.2 Toggling the Pin
Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn. Note that the SBI instruction can be used to toggle one single bit in a port.
CodePudding user response:
Why? Because hardware wiring will do it. Let look how IO pin is realized.
Here you can see logic diagram for every pin. Output value is driven by D flip-flops in PORTA register. DDRA register enable outputting value to pin. And PINA is second D flip flop in synchronizer. A read the PINA reads value from this flip-flop. As you can see write to PIN (WPx signal) is connected to multiplexor which select input signal for PORTA output flip-flop. In case writing one this mux is switched to upper signal where is connected inverted state of outputting value. Also clk pulse for PORTA flip-flop is generate. Result is that PORTA change his logical value.
sbi PINA, 0
instruction does not toggle PINA but toggle PORTA. PINA always follow signal on the pin after one CPU clock cycle.
If you want set bit 0 of the PORTA, you must use
SBI PORTA, 0