bitmask how do i use when chooing bites

I'm trying to have a go at writing a .cpp and .h file for a 16bit dac (using 24 bit word over spi) the first problem is I need to make three choices in the first bite of data there's 1 bit for read/write a non functioning 0 then 3 bits for choice of mode then another 3 bits for dac channel.

I can just place all 3 setts of data in the correct place of the bite by making them all into 8 bits and bit masking them with an OR | statement as the zeros would only be replaced by ones as they would want to be but I'm not shore how to make the choices of the three bits that I want

void dac::ReWr(bit db23, bit db22)//dac readWrite db23 - db22
{
for ReWr.write(0, 0, 0, 0, 0, 0, 0, 0);//00 write 0B
for ReWr.read(1, 0, 0, 0, 0, 0, 0, 0);//10 read
}
void dac::regi(bit db21, bit db20, bit db19) //dac function db21 - db19
{
for regi.function(0, 0, 0, 0, 0, 0, 0, 0); //000 function register
for regi.data(0, 0, 0, 1, 0, 0, 0, 0); //010 data register + dac + db15 - db0
for regi.coarse(0, 0, 0, 1, 1, 0, 0, 0); //011 coarse gain register + dac + dontcare + db1 - db0
for regi.fine(0, 0, 1, 0, 0, 0, 0, 0); //100 fine gain register + dac + dontcare + db5 - db0
for regi.offset(0, 0, 1, 0, 1, 0, 0, 0); //101 offset register + dac + dontcare + db7 - db0
}
void dac::channel(bit db18, bit db17, bit db16) //dac channel db18 - db16
{
for channel.chanA digitalWrite(0, 0, 0, 0, 0, 0, 0, 0);//000 dac a
for channel.chanB digitalWrite(0, 0, 0, 0, 0, 0, 0, 1);//001 dac b
for channel.chanC digitalWrite(0, 0, 0, 0, 0, 0, 1, 0);//010 dac c
for channel.chanD digitalWrite(0, 0, 0, 0, 0, 0, 1, 1);//011 dac d
for channel.chanAll digitalWrite(0, 0, 0, 0, 0, 1, 0, 0);//100 dac all dac's
}
//use bitwise with "or |" to put the 1's in the right place of the bite "0,0,0,0,0,0,0,0" this adds the weri+regi+channel

Perhaps something like this ( in pseudocode) to select the mask according the data value

switch ( data )
case 0:
// data word numerical value is now 000
// mask off all bits
take data AND mask it with mask = 000
...
case 7:
// data word numerical value is now 111 ( seven)
// mask off none of the bits
take data AND mask it with mask = 111
....

Not sure if masking the data is necessary since after it is masked it always ends same as the original data ,
but hope it helps you to code it.

its mainly to change the channels of the dac but I want the option of adjusting the gain etc so I would end up with an un nessesary combo of lines of code if I can just place the called function it would sit where it wants to be that's why an "OR |" command would be fine but there is three choices the code needs to select for the bite of data to be sent. so I was thinking write them all as bites and overlap them. not shore how this pans out with three overlaps or I could just overlap twice??

I am still unsure if you are asking how to select a mask according what data is presented or how to select 3 bits from a "chunk".
Can you clarify this with areal example?

BTW - the mask / selection must be "ANDed" - not ORed.
Example if you have "011" and want to select value of only bits 0 and 2
"011" AND "101" will equal "001" , so you need to do some more coding to get just bits 0 and 2.
But that is not what you are asking, right.

I'm trying to have a go at writing a .cpp and .h file for a 16bit dac (using 24 bit word over spi) the first problem is I need to make three choices in the first bite of data there's 1 bit for read/write a non functioning 0 then 3 bits for choice of mode then another 3 bits for dac channel.

I can just place all 3 setts of data in the correct place of the bite by making them all into 8 bits and bit masking them with an OR | statement as the zeros would only be replaced by ones as they would want to be but I'm not shore how to make the choices of the three bits that I want

Let's say you have a byte whose value is 0b00110010.

Let's say you want bits 5 to three (remember, we count from zero) to be put into an int variable.

You need to mask out the bits you want with a logical and & and then right-shift them with the logical right shift >>>.

byte b = 0b00110010;
int x = (b & 0b00111000) >>> 3;

Or you can do it the other way around:

byte b = 0b00110010;
int x = (b >>> 3) & 0b111;

The reason you use a logical right shift is that a byte is a signed quantity, and so the arithmetic right-shift >> does sign extension. This means that this:

byte b = 0b10110010;
int x = (b >> 5) & 0b111;

will give you 0b11111101 - not what you were looking for. An arithmetic right shift does a divide-by-two but preserves the sign og the number. So (-12 >> 2) will be -3. Not what you want when you are using bit-fiddling.

Another way to do this is using bitfeilds in structs:

union foo {
  byte x;
  struct bar {
    byte a: 2;
    byte b: 3;
    byte c: 3;
  } y;
};

void zzz() {
  union foo q;
  q.x =  0b11111101;
  byte b = q.y.b;
}

But you need to be careful about order - I'm not sure which way a bitfield stacks the values.

Actually signed 8 bit is char, unsigned 8 bit is byte.

But if I make an Arduino library, byte isn't recognized so I use unsigned char instead.

Another Arduino good one, an unsigned int is a word. Hey, I didn't make that up!

Here is the Arduino Playground Bitmath Tutorial.

PaulMurrayCbr:
But you need to be careful about order - I'm not sure which way a bitfield stacks the values.

It is entirely up to the compiler.

[quote author=C++ standard]Allocation of bit-fields within a class
object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed
into some addressable allocation unit. [ Note: Bit-fields straddle allocation units on some machines and not
on others. Bit-fields are assigned right-to-left on some machines, left-to-right on others[/quote]

The same compiler is even allowed to use different orderings if it feels the need (a change to the code could allow different optimizations, and your bits could be reversed). So unless you access the bits directly, your code is not guaranteed to work the same way it did compiling the code yesterday.

Using a union like you have on an Arduino should be fine, but definitely not guaranteed.

I have created my BitBool library to help with situations like this.

You could alternatively use a union like this:

#include <BitBool.h>

union foo {
  byte x;
  BitBool<8> bits;
};

//...

foo data = { 0b11001100 };
//                    ^ = bit 0
//             ^ = bit 7

data.bits[ 0 ] = true;

if( data.bits[ 7 ] ){

}

//etc...

The best part, is it is just as efficient as using manual bit manipulation. You can also reverse the bit access by changing the declaration to this: BitBool<8, REVERSE_BITS> bits;

This is available in the Library manager. I'm currently working on some updated documentation for it also.

(db23 is the left hand side db16 is on the right hand side)
I don't want to shift any bits around I just want them in the order they are placed that's why I want to "OR" them so if my first selection was write (the most significant bit first on db23) and my next choice was use the data register (db21 db20 db19) and I wanted the info to be sent to the dac
channel B. (db18 db17 db16) I would need to sent the bite of data to look like this

00 010 001 (then my 16bits of power to be set)

mapped as
"00" 000 000 write

00 "010" 000 data register

00 000 "001" dac channel B

=00 010 001 is how I want it to be sent for (write, data, channel)

lifelight:
(db23 is the left hand side db16 is on the right hand side)
I don't want to shift any bits around I just want them in the order they are placed that's why I want to "OR" them so if my first selection was write (the most significant bit first on db23) and my next choice was use the data register (db21 db20 db19) and I wanted the info to be sent to the dac
channel B. (db18 db17 db16) I would need to sent the bite of data to look like this

00 010 001 (then my 16bits of power to be set)

mapped as
"00" 000 000 write

00 "010" 000 data register

00 000 "001" dac channel B

=00 010 001 is how I want it to be sent for (write, data, channel)

Binary 00010001 is decimal 17. That would be the command byte to the DAC?

You would build that as a byte, start with the low order bits.
Please note that << is left shift. Each shift left bit is the value times 2. Example: 1 << 3 == 8.

data = channel ( == 1 )

then

data = data | ( data register << 3 )

then

data = data | ( write <<< 6 )

which would make

1 OR ( 2 <<< 3 ) OR ( 0 <<< 6 ) == 1 | 16 | 0 = 17.

If you don't quickly understand ANY PART of this then you will benefit from that Bitmath Tutorial that I posted a link to on page 1 of this thread. And yeah, missing some basics really adds to your confusion.