# AVR bitwise operation: making a NOT with a microcontroller

I'm programming an ATtiny10, i have two spare pins, one of which is the external interrupt pin on PB2, and i want to write the inverse of that signal to PB1. I want to spare a component, since i have already the uC and some pins.

So far, the best option i could come up with, is:

PORTB = (PORTB & ~(1<<PB1)) | ((~PINB & (1<<PB2))>>1)

Used in the IRQ routine associated with the change of INT0.
Basically clearing the PB1 bit, inverting PINB, masking it and shifting to the right by one place.

The other option is using an if statement and branch the code, which doesn't really satisfy me.

Is there an easier way to do this, that i cannot see?

• The first one-liner you've shown may look messy, but I would consider it the best way. Just change the rightmost >> 1 to >> PB2, so that it actually uses the pin defs instead of hardcode. – Vicente Cunha Sep 5 '18 at 12:34
• @VicenteCunha i'm shifting by the position difference between PB1 and PB2, not by PB2. I could shift by (PB2-PB1) – valerio_new Sep 5 '18 at 13:00

In assembly code it would just be a matter of testing a single bit and then setting another bit to 1 or 0, if you write C code close enough to that assembly code, then that might be what the compiler will turn it into.

Compilers are usually very clever. Perhaps your code is already being converted to that assembly code, or maybe even something that is more efficient.

If I were to personally do it then I wouldn't care because you are over-optimizing a non-existent problem. But for the sake of being pedantic, then I'd look into the compiled assembly code and verify that it is what I believe is the most efficient code. Or I would just write some C code that hopefully makes the compiler turn it into what I think is the most efficient code.

if(PINB&(1<<PB2)){//This is essentially a bit test instruction
PORTB&=~(1<<PB1);//This is essentially a bit clear instruction
}else{
PORTB|=(1<<PB1);//This is essentially a bit set instruction
}


The bottom line is that it probably doesn't matter. The total number of clocks spent on this minuscule part of your code might go from 10 to maybe 6, or maybe it already was 6 because the compiler is smart. All in all, a couple of clocks here, some there, doesn't really matter.

Here's the test that OP performed, might be interesting for future readers:

  26:blink-prescaler-register.c ****   PORTB = (PORTB & ~(1<<PB1)) | (((PINB ^ (1<<PB2)) & (1<<PB2))>>1);
107                    .loc 1 26 0
108 0010 62B1              in r22,0x2
109 0012 50B1              in r21,0
110 0014 5095              com r21
111 0016 5470              andi r21,lo8(4)
112 0018 452F              mov r20,r21
113 001a 50E0              ldi r21,0
114 001c 5595              asr r21
115 001e 4795              ror r20
116 0020 562F              mov r21,r22
117 0022 5D7F              andi r21,lo8(-3)
118 0024 452B              or r20,r21
119 0026 42B9              out 0x2,r20

VERSUS:
27:blink-prescaler-register.c ****   if(PORTB&(1<<PB2)){//This is essentially a bit test instruction
95                    .loc 1 27 0
96 000a 129B              sbis 0x2,2
97 000c 00C0              rjmp .L5
28:blink-prescaler-register.c ****   PORTB&=~(1<<PB1);//This is essentially a bit clear instruction
98                    .loc 1 28 0
99 000e 1198              cbi 0x2,1
100 0010 00C0              rjmp .L4
101                .L5:
30:blink-prescaler-register.c ****   PORTB|=(1<<PB1);//This is essentially a bit set instruction
102                    .loc 1 30 0
103 0012 119A              sbi 0x2,1
104                .L4:


Instruction wise, my version is about half. I suppose the compiler wasn't smart enough in this particular case.

Also, from OP tests, propagation delay:

The blue track is the input signal, assuming 5.1V*(0.6) = 3.06 V for the high treshold voltage (trigger at 3.04V because of scope settings).

The expression that OP proposed is the CH1 (yellow, labeled), while the white one is the response time with the IF statement.

The difference in time between the two is 1.64 uS, about 13 clock cycles if the uC internal oscillator is calibrated correctly. So with the expression the propagation delay is almost double.

• > "you are over-optimizing a non-existent problem" Yes, i'm definitely doing that. But it is for learning's sake – valerio_new Sep 5 '18 at 12:58
• And yes, you were right. Here is the assembly: hastebin.com/isofoqesux.m Plus, in my version in pushes and pops 5 register, while in yours only has to store and retrive 3. So yes, definitely more efficient – valerio_new Sep 5 '18 at 13:05
• I've done some more testing with the scope: valerionappi.it/wp-content/uploads/2018/09/… The blue track is the input signal, assuming 5.1V*(0.6) = 3.06 V for the high treshold voltage (trigger at 3.04V because of scope settings). The expression that i proposed is the CH1 (yellow, labeled), while the white one is the response time with the IF statement. The difference in time between the two is 1.64 uS, about 13 clock cycles if the uC internal osc is calibrated correctly. So with the expression the propagation delay is almost double – valerio_new Sep 5 '18 at 18:52
• Often, you tell compilers how clever they need to be, and what they're optimizing for -- execution time, memory,.... Free versions of some compilers are often limited in optimization levels or options. While this difference is dramatic here, without compiler info and calling flags, it's hard to put too much weight on it. – Scott Seidman Sep 6 '18 at 16:09
• @ScottSeidman you are right. I'm using avr-gcc with -Os for optimization. I should try with a more up to date version maybe – valerio_new Sep 6 '18 at 17:15

Avoiding an if that may result in a branch should not be you priority, especially on AVR where branches are 1 or 2 cycles (depending on the value of the condition!)

In this case, your solution would probably use a register and arithmetic operation, a rewrite to an if statement like Harry Svensson's answer would use only bit-branch and bit-set/clear operations, that do not change the status register (SREG).

In both cases, if you really want minimal execution time, you could consider using a "naked" interrupt (ISR_NAKED) to prevent the compiler from storing a bunch of registers and popping them upon return.

When you don't use registers (hint hint) there is no need to save them and your ISR can be very small indeed. Just make sure your generated code does not actually use any registers like you intend by inspecting the generated code after recompile, or write the ISR in assembly.

#include <avr/interrupt.h>
ISR(PCINT0_vect)
{
if(PINB&(1<<PB2)){//This is essentially a bit test instruction
PORTB&=~(1<<PB1);//This is essentially a bit clear instruction
}else{
PORTB|=(1<<PB1);//This is essentially a bit set instruction
}
}

int main(int argc, char** argv)
{}


compiles with avr-gcc -S -O3 bitwise_not.c -mmcu=attiny10 to:

    .file   "bitwise_not.c"
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__SREG__ = 0x3f
__CCP__ = 0x3c
__tmp_reg__ = 16
__zero_reg__ = 17
.text
.global __vector_2
.type   __vector_2, @function
__vector_2:
push r17
push r16
in r16,__SREG__
push r16
ldi __zero_reg__,0
/* prologue: Signal */
/* frame size = 0 */
/* stack size = 3 */
.L__stack_usage = 3
sbic 0,2
rjmp .L5
sbi 0x2,1
/* epilogue start */
pop r16
out __SREG__,r16
pop r16
pop r17
reti
.L5:
cbi 0x2,1
/* epilogue start */
pop r16
out __SREG__,r16
pop r16
pop r17
reti
.size   __vector_2, .-__vector_2
.section    .text.startup,"ax",@progbits
.global main
.type   main, @function
main:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
ldi r24,0
ldi r25,0
ret
.size   main, .-main
.ident  "GCC: (GNU) 5.4.0"


(note the aggressive optimization of duplicating the epilogue)

#include <avr/interrupt.h>
ISR(PCINT0_vect, ISR_NAKED)
{
if(PINB&(1<<PB2)){//This is essentially a bit test instruction
PORTB&=~(1<<PB1);//This is essentially a bit clear instruction
}else{
PORTB|=(1<<PB1);//This is essentially a bit set instruction
}
reti(); //Must be explicitly called when using ISR_NAKED
}

int main(int argc, char** argv)
{}


compiles to (using the same command)

    .file   "bitwise_not.c"
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__SREG__ = 0x3f
__CCP__ = 0x3c
__tmp_reg__ = 16
__zero_reg__ = 17
.text
.global __vector_2
.type   __vector_2, @function
__vector_2:
/* prologue: naked */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
sbis 0,2
rjmp .L2
cbi 0x2,1
rjmp .L3
.L2:
sbi 0x2,1
.L3:
/* #APP */
;  9 "bitwise_not.c" 1
reti
;  0 "" 2
/* epilogue start */
/* #NOAPP */
.size   __vector_2, .-__vector_2
.section    .text.startup,"ax",@progbits
.global main
.type   main, @function
main:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
ldi r24,0
ldi r25,0
ret
.size   main, .-main
.ident  "GCC: (GNU) 5.4.0"

• As much as I hate using if statements, in this case I believe it is the most optimal. I'd be glad to see if you could show it be done better without an if statement. – Harry Svensson Sep 6 '18 at 5:34
• Just curious, why do you hate if? Especially on AVR where there is no branch prediction, hardly any pipelines to flush an definitely no speculative execution it will usually translate to a single branch or skip instruction that executes in 1 or 2 cycles with no side effects – Pelle Sep 6 '18 at 20:41
• Well, I'm coming from a PC background, so what you just named are things I've learned to avoid. - Sorry for not being specific. In this particular case on an AVR I agree, an if is not that hurtful. – Harry Svensson Sep 7 '18 at 4:16