What is the purpose of the double negation operators !! here ? Is this to create some artificial delay like how inverter circuits in cascade produce some delay equal to the sum of their propagation delays ? As I tried writing my own implementation of this shiftOut function, I came up with the following:
digitalWrite(dataPin, data & 1); // extract LSB
data = data >> 1; // shift all bits to right (logical shift)
Which does the same thing but is a lot more intuitive.
It coverts the bitmask to a boolean, under the assumption that digitalWrite() wants a boolean rather than a random value. The first ! a boolean NOT; doubling it converts the boolean to the original bit sense.
(Actually these days it wants a pinstatus, so a more correct statement would be)
digitalWrite(dataPin, (val & (1 << i)) ? HIGH : LOW);
I don't know why they shift 1 by i and do the AND vs shifting val, especially since the AVR doesn't do multibit shifts very well.
But if the coder who wrote shiftOut() was so concerned about bit shifting being slow, why is the for-loop coded like that? On each literation of that for-loop, that 1 gets shifted by multiple bits to make a mask to compare with val. I think a total of 7+6+...2+1 == 28 shifts will get done in total. It could have been coded so that the mask gets shifted once on each iteration, a total of 8 shifts.
if (bitOrder == lsbfirst) {
for (i = 1; i != 0; i <<= 1) {
digitalWrite(dataPin, (val & i) ? HIGH : LOW);
digitalWrite(clockPin_, LOW);
digitalWrite(clockPin_, HIGH);
}
}
That's a nice theory, but apparently the current version of gcc will create a loop counter instead of using just the shifted value. (a 16bit loop counter at that!)
I don't know why; perhaps something to do with the loosely defined (or overly strict?) rules about integer overflows.
(heh. The other direction works fine!)
digitalWrite(dataPin, (val & 128) != 0);
I'd be really surprised if that produces better (or even different) code than !!(val &128)
If we really wanted to speed it up, we'd replace the digitalWrite() calls (but then it wouldn't be chip-independent any more )
@NerdRalph did some Heavy duty optimization of "SPI Output" for AVR. It's both AVR specific and (muc) less general than the Arduino shiftOut, but it's probably as good as one can do (Ralph is good!)