Bitmask length limitations?

Hi, can anyone shine some light on this please?

I'm trying to set 16 individual port pin outputs, here named DO0~DO15, according to the bits in a 16-bit unsigned int.

My method is to take the 16-bit variable, bitwise-AND it with a successively moving '1' bit, and set port pins according to the result. I believe the result should only return a 1 or a 0, equating to a HIGH or LOW respectively.

The method seems to work for the lower 8 bits, but the upper 8 bits always return zeros. The port lines are fine otherwise. Have I misunderstood something?

Thanks,
Matt.

unsigned int DoutStateWord;
.
.
.
void WriteAllDigiOuts() {

// takes DoutStateWord (16bit) and outputs MSB:LSB bits to DO15:DO0
// TODO: figure out why only lower 8 bits are and-maskable

  digitalWrite(DO0,   (DoutStateWord & 1) );
  digitalWrite(DO1,   (DoutStateWord & 2) );
  digitalWrite(DO2,   (DoutStateWord & 4) );
  digitalWrite(DO3,   (DoutStateWord & 8) );
  digitalWrite(DO4,   (DoutStateWord & 16) );
  digitalWrite(DO5,   (DoutStateWord & 32) );
  digitalWrite(DO6,   (DoutStateWord & 64) );
  digitalWrite(DO7,   (DoutStateWord & 128) );
  digitalWrite(DO8,   (DoutStateWord & 256) );
  digitalWrite(DO9,   (DoutStateWord & 512) );
  digitalWrite(DO10,  (DoutStateWord & 1024) );
  digitalWrite(DO11,  (DoutStateWord & 2048) );
  digitalWrite(DO12,  (DoutStateWord & 4096) );
  digitalWrite(DO13,  (DoutStateWord & 8192) );
  digitalWrite(DO14,  (DoutStateWord & 16384) );
  digitalWrite(DO15,  (DoutStateWord & 32768) );
}

Some proof that the upper 8 bits are NOT all zero would be useful.

Some proof that the upper 8 bits are NOT all zero would be useful.

Indeed; well, I was incrementing the variable by 1 and then calling the function, so you'll have to believe my separately testing that it was reaching 0xFFFF and rolling back over! :slight_smile:

I've changed the method now, and the following works perfectly instead:

void WriteAllDigiOuts() {
  // takes DoutStateWord (16bit) and outputs MSB:LSB bits to DO15:DO0

  digitalWrite(DO0,   (DoutStateWord & 1) );
  digitalWrite(DO1,   (DoutStateWord >> 1 & 1) );
  digitalWrite(DO2,   (DoutStateWord >> 2 & 1) );
  digitalWrite(DO3,   (DoutStateWord >> 3 & 1) );
  digitalWrite(DO4,   (DoutStateWord >> 4 & 1) );
  digitalWrite(DO5,   (DoutStateWord >> 5 & 1) );
  digitalWrite(DO6,   (DoutStateWord >> 6 & 1) );
  digitalWrite(DO7,   (DoutStateWord >> 7 & 1) );
  digitalWrite(DO8,   (DoutStateWord >> 8 & 1) );
  digitalWrite(DO9,   (DoutStateWord >> 9 & 1) );
  digitalWrite(DO10,  (DoutStateWord >> 10 & 1) );
  digitalWrite(DO11,  (DoutStateWord >> 11 & 1) );
  digitalWrite(DO12,  (DoutStateWord >> 12 & 1) );
  digitalWrite(DO13,  (DoutStateWord >> 13 & 1) );
  digitalWrite(DO14,  (DoutStateWord >> 14 & 1) );
  digitalWrite(DO15,  (DoutStateWord >> 15 & 1) );
}

...So does this imply that the Arduino's implementation of bitwise-AND is limited to 8 bits wide?!? :slight_smile:

The type of the second parameter of digitalWrite() is uint8_t (on AVR boards).
The higher bits are simply ignored.

oqibidipo:
The type of the second parameter of digitalWrite() is uint8_t (on AVR boards).
The higher bits are simply ignored.

Ah that makes sense; many thanks.

protomoose:
Ah that makes sense; many thanks.

Yes, and strictly speaking it's only supposed to take a parameter of either LOW (or 0) and HIGH (or 1). Though it does the same as boolean here, with anything non-zero being treated as 1. The problem is that it probably truncates it to 8 bits before doing that.

BTW. Did you know that you can write to the 8 bit ports in parallel if you wish (so only two writes instead of 16).

For example:

PORTD = lowByte(DoutStateWord);
PORTB = highByte(DoutStateWord);

Update:

Confirmed. It definitely truncates it to byte before testing for zero/non zero. For "int x" parameter digitalWrite outputs LOW for x=0 and HIGH for x = 1 ... 255. However it writes LOW for x = 256, 512, 1024 etc.