Reading Bits from Registers

Is there any better way than this:

#define bitRead(value, bit) (((value) >> (bit)) & 0x01)

(I was told this is an already defined macro, so no need to redefine).

Say I'm trying to read from PINA (as I would think you are meant to)

The arduino reference has BitRead etc.

cypherrage:
(I was told this is an already defined macro, so no need to redefine).

cypherrage:
Is there any better way than this:

Maybe if you explain what is "a better way" and why you need it...

You can also discretely mask for the bits:

if ((PINA & B00010000) == 0){
// do one thing if bit 4 for example is low
}
else {
// do something else if bit is high
}

guix:
Maybe if you explain what is "a better way" and why you need it...

I was reading about how "Port Manipulation" is a lot faster and space saving (double win), so I was reading through the Mega2560 datasheet, changing things up, and then I think, how do people who normally do all this stuff read individual bits? All I ever see is writing bits, but I just can't remember how people read bits from these registers.

Pretty much in a previous post Nick Gammon showed me these macros but said that he rarely uses them, so I was curious if other people used something else.

cypherrage:
how do people who normally do all this stuff read individual bits? All I ever see is writing bits, but I just can't remember how people read bits from these registers.

Bit masking and shifting, but that's what the macro does.

So there isn't really any reason not to use the macro?

Also, if anyone has an easy way to set one bit = anotherBit, that would be tight.

cypherrage:
So there isn't really any reason not to use the macro?

You can save a single instruction by using CrossRoads example if you need the nanoseconds (assuming you are using it in a comparison).

Also, if anyone has an easy way to set one bit = anotherBit, that would be tight.

Using CrossRoads example:

// Sets bit 5 of PINA to bit5 of PINB
if ((PINA & B00010000) == 0){
  PINB &= B11101111;
}
else {
  PINB |= B00010000;
}

Ahh ok, that makes sense.

Somewhat related should be last question:

Something like this works of course ? alpha = bitRead(PINA, PINA0);

But if I do something like this things do not work out:

#define alphaPlane (PINA, PINA0)
...
alpha = bitRead(alphaPlane);

I assume that when you define something with parentheses around it, that it substitutes the parentheses in as well (and bitRead((PINA, PINA0)) does not work), but I'm not sure how to define "alphaPlane" in that manner without parentheses. I tried just taking them out but that does not work.

There are three pretty standard ways to do bit reads and writes:

  • bitRead(), bitSet(), and bitClear()
  • _BV()
  • Direct bit mask manipulation like Crossroads’ example

There are several issues that I can think of that may make one way better than another.

  • Does it work?
  • Is it easy for you to understand and program?
  • Is it easy for other programmers to understand and maintain?
  • Does the compiler generate efficient machine code?

Most of these are subjective questions that only you can answer, but I’m going to say three things.

One would think that directly manipulating the bits is the more complex for our brains to handle, but gives the most control. However, there are still things I wouldn’t have thought of. Notice that Arrch says B00010000 is bit 5 and Crossroads says it’s bit 4. Well, it depends on whether you consider bit 0 valid or not.

The code in the Arduino libraries doesn’t use bitRead(). It uses _BV().

There are actually machine code instructions for various bit operators. SBI, CBI, SBIC, SBRC… These are usually slightly more efficient than using the more general bit shifts and & and | and ~ operations. The compiler does a pretty good job of using them when it can figure out exactly what you’re doing, but it isn’t always possible. If that efficiency is important to you, you can try both ways and examine the assembly code.

When would you and when would you not consider bit 0 valid? I just noticed what you pointed out, how they used that same bit as 4 and then 5. Was that just syntax between counting from 0-7 vs 1-8?

From the BV macro: “#define _BV( bit ) ( 1<<(bit) )”, if you do something like _BV(PINA4) then you will get B00010000 right? So from the original example:

if (!(PINA & _BV(PINA4))) {
// do one thing if bit 4 for example is low
}
else {
// do something else if bit is high
}

Is that what you meant?

Bytes have 8 bits, by convention they are numbered 7-0 from MSB to LSB. If you talk to any engineer, 0 will always be the LSB. The datasheet also calls them 7-0.
You can reference them however you want in your program as long as you are consistent in their usage. Anyone reading your code will question you on it for not following convention.

As far as setting & clearing bits, I often do this to set & clear bits when using SPI for fast transfers.
(I don’t use the macro conventions because as a late comer to C/C++ progamming I didn’t realize all the stuff existed - and now that I know they do, I like the direct manipulation better because its easier for me to see what I am doing).
For example, using PortB bit 4 as the latch/output register clock to send data out to 4 shift registers that are driving 7-segment displays:

PORTB = PORTB & B11101111; //clear bit 4
for (x=0; x<4; x=x+1){
SPI.transfer(fontArray[dataArray[x]]);  // fontArray is the mapping of Segments to output pins, dataArray holds the digits to display
}
PORTB = PORTB | B00010000; // set bit 4

Timing tests show that the for loop adds ~12uS for every pass thru, so when I’m looking for even faster I would use 4 SPI.transfer commands instead and skip the for loop:

PORTB = PORTB & B11101111; //clear bit 4
SPI.transfer(fontArray[dataArray[0]]); 
SPI.transfer(fontArray[dataArray[1]]);
SPI.transfer(fontArray[dataArray[2]]);
SPI.transfer(fontArray[dataArray[3]]);
PORTB = PORTB | B00010000; // set bit 4

And if I’m concerned about going really fast I’ll skip SPI.transfer and write to the SPI register directly and follow with a bunch of NOPs vs waiting for SPI.transfer to detect an interrupt showing the transfer is complete so it can send another byte (I think that’s the correct explanation). Nick Gammon turned me on to this method.
(I need to confirm, I think SPDR and 16 nop’s (no-op) is correct - takes 16 clocks to move 8 bits out, so the register write and then 16 clocks. I checked this once with a logic analyzer to confirm the nops moved all the data out correctly, playing around with adding/deleting until I had good data going out every time)

PORTB = PORTB & B11101111; //clear bit 4
SPDR=(fontArray[dataArray[0]]);nop;nop;nop; nop;nop;nop; nop;nop;nop; nop;nop;nop; nop;nop;nop;nop;
SPDR=(fontArray[dataArray[1]]);nop;nop;nop; nop;nop;nop; nop;nop;nop; nop;nop;nop; nop;nop;nop;nop;
SPDR=(fontArray[dataArray[2]]);nop;nop;nop; nop;nop;nop; nop;nop;nop; nop;nop;nop; nop;nop;nop;nop;
SPDR=(fontArray[dataArray[3]]);nop;nop;nop; nop;nop;nop; nop;nop;nop; nop;nop;nop; nop;nop;nop;nop;
PORTB = PORTB | B00010000; // set bit 4

Some might say doing that isn’t very portable across devices. I personally don’t give a hoot about that as I’m writing code for a specific device and I want it to go fast. PORTB-4 is the SS pin on as 1284. If I go and copy this code for use on a 328 then I’ll have to remember to change it to PORTB-2.

So there’s a hardware engineer’s perspective for you 8)