New To Programing Registers

Why is the following line of code does not work?

  //  digitalWrite(Step_Pin , !digitalRead(Step_Pin));
    PIND =(PIND > 0b00000010);

I am trying to toggle the GPIO 2 pin. I am trying to toggle PD1 0b00000010 with the xor ( > ).
So what am I doing wrong?
I am using the Itsy Bisy 32U4 3V.

Thank you for sharing your wisdom. :smiley: :smiley:

[sterretje edit]
Moved closing code tag so question was readible.

Drop the "0" preceding the "b"... a "0" prefix indicates octal, base 8.

https://docs.arduino.cc/retired/hacking/software/PortManipulation/

1 Like

> is greater than. ^ is xor

PIND greater than 2 is either true or false. So that part becomes 1 or 0. Then PIND gets assigned a 1 or 0, neither of which affect pin 2.

1 Like

You write a 1 to the pin you want to toggle. For such operations, PIND will almost never appear on the right side of the expression.

This should give better results...

PIND = 0b00000010;

With a "b" following the "0", nope.

3 Likes

I see. A "0" prefix of the "b/B" is still binary.

1 Like

True, to use xor like the OP intended you should be using the PORT register and not the PIN register. Writing 0 to the PIN register does nothing.

3 Likes

On AVR writing a 1 to the bit on PIN register toggles a pin, see the data sheet.

The correct syntax should be:
PIND |= 0b00000010;

Read again what you said nope to please.

Writing a 1 toggles a pin. Just like you said.

Writing a 0 does nothing. If you think that is wrong please show me what writing 0 to a bit in the PIN rgister does.

Sorry, I fixed my message and deleted erroneous "nope"

Please stop. That is NOT correct. That is a SERIOUS BUG. This is correct...

PIND = 0b00000010;
2 Likes

yes, you are right

1 Like

That will work fine, even though it's weird, because it compiles to an SBI instruction...
PIND |= 0b11; is likely to fail, though, because it will actually read the register, do the OR, and write the new value... C really doesn't understand "memory" that doesn't become 1 when you write a 1 to it.

It won't work fine. If pin 3 is set high when you run that line then it would get toggled too.

PIND is 00000110

That OR 00000010 is 00000110

Now there are two pins having a 1 written. Both will toggle and pin 3 goes LOW when you don't expect it.

1 Like
PORTD = PORTD ^ 0b00000010;

Does it do --
Read, modify, and write?

Yes, three separate instructions (including the XOR) versus writing PIND (one instruction, relying on the XOR hidden in the hardware behind PINx writing)

  PORTD = PORTD ^ 0b00000010;
 1c2:	8b b1       	in	r24, 0x0b	; 11
 1c4:	8c 27       	eor	r24, r28
 1c6:	8b b9       	out	0x0b, r24	; 11
  PORTD = PORTD ^ 0b00000010;
 1c8:	8b b1       	in	r24, 0x0b	; 11
 1ca:	8c 27       	eor	r24, r28
 1cc:	8b b9       	out	0x0b, r24	; 11
  PORTD ^= 0b00000010;
 1ce:	8b b1       	in	r24, 0x0b	; 11
 1d0:	8c 27       	eor	r24, r28
 1d2:	8b b9       	out	0x0b, r24	; 11
  PIND = 0b00000010;
 1d4:	c9 b9       	out	0x09, r28	; 9
  PIND = 0b00000010;
 1d6:	c9 b9       	out	0x09, r28	; 9
  PIND = 0b00000010;
 1d8:	c9 b9       	out	0x09, r28	; 9

2 Likes

It will work fine as long as:

  1. You are changing exactly one bit.
  2. SBI (set bit in I/O register) instruction can access the register (0 to 31).
  3. Optimisation is on.

You have to know what you are doing and what the compiler is doing.

#include <avr/io.h>

void tickle_bits()
{
  PIND |= 0b1;			/* register 0x09 (memory address 0x29) */
  PIND |= 0b1100;

  GPIOR2 |= 0b100;		/* 0x2B (0x4B) */
  GPIOR2 |= 0b10101;

  PINK |= 0b1000;		/* (0x106) */ /* ATmega2560 */
  PINK |= 0b10111;
}
Disassembly of section .text:

00000000 <tickle_bits>:
#include <avr/io.h>

void tickle_bits()
{
  PIND |= 0b1;			/* register 0x09 (memory address 0x29) */
   0:	48 9a       	sbi	0x09, 0	; 9
  PIND |= 0b1100;
   2:	89 b1       	in	r24, 0x09	; 9
   4:	8c 60       	ori	r24, 0x0C	; 12
   6:	89 b9       	out	0x09, r24	; 9

  GPIOR2 |= 0b100;		/* 0x2B (0x4B) */
   8:	8b b5       	in	r24, 0x2b	; 43
   a:	84 60       	ori	r24, 0x04	; 4
   c:	8b bd       	out	0x2b, r24	; 43
  GPIOR2 |= 0b10101;
   e:	8b b5       	in	r24, 0x2b	; 43
  10:	85 61       	ori	r24, 0x15	; 21
  12:	8b bd       	out	0x2b, r24	; 43

  PINK |= 0b1000;		/* (0x106) */ /* ATmega2560 */
  14:	e6 e0       	ldi	r30, 0x06	; 6
  16:	f1 e0       	ldi	r31, 0x01	; 1
  18:	80 81       	ld	r24, Z
  1a:	88 60       	ori	r24, 0x08	; 8
  1c:	80 83       	st	Z, r24
  PINK |= 0b10111;
  1e:	80 81       	ld	r24, Z
  20:	87 61       	ori	r24, 0x17	; 23
  22:	80 83       	st	Z, r24
}
  24:	08 95       	ret
1 Like

If pins 2 and 3 are both written HIGH to start with then PIND reads 0b00001100.

How are you getting 0b00001100 | 0b00000100 to only have one high bit?

If you think that or operation does end up with two high bits, then why doesn't it also toggle pin 3 when i write that to PIND?

Hint: I've crashed into this bug before. I know it is real.

That's wack enough to be an argument against ever writing to PINx:

Q: When does "PINx |= Y" not mean "PINx |= Y" ?

A: Whenever Y is a power of 2 and x is small.

Yes. It makes one wish for the days (avr-gcc 3.x? A long time ago!) when you had to use sbi(regX, bit); instead of the compiler folk saying "oh, we'll just optimize the typical C expression." (note that SBI does NOT do an actual read/modify/write cycle on the whole register.) (even worse, I believe that many modern environments, including Arduino, re-implement sbi() as:

#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

which we've noticed does NOT always do the same thing!

This sort of thing causes problems with other registers where "writing a one bit" has effects other than setting the destination bit to one. Notably, some "clear interrupt" registers clear a bit when a one is written, so a statement like:

   myuart->intflags |= UART_ERRINT_F;

will unexpectedly clear more than just the error interrupt flag.

1 Like