Writing bits to a larger type

Status
Not open for further replies.

neroroxxx

Well-known member
Hi guys, i hope i'm phrasing the title right, I have a struct with a couple of uint32_t types, in those 32 bits i store multiple values, some are 2-bit values some are 4-bit some are 7 bit some are 1-bit and so on, this struct gets stored to EEPROM hence why i went with 32-bit unsigned ints to store these values to save EEPROM space rather than using a uint8_t for a value that will never use more than 2-bits or 4-bits etc.

Because of this i have to use bit manipulation to read these values, so to read say bits 25,26,27 as a 3-bit value since it will never go above the number 7 I do something like this:

Code:
(myStruct.data1>>25) & 0x07;

Easy enough, i reads the data properly.

The issue i'm having tho is writing a value to that location, in javascript i use 2 functions, one to clear the bits and one to write to them

Code:
// clear the bits 
myStruct.data1 = CLEAR_BITS_TO_LOCATION( myStruct.data1, 0x07, 25  );

// write the bits
myStruct.data1 = WRITE_BITS_TO_LOCATION( myStruct.data1, value & 0x07, 25  );

function CLEAR_BITS_TO_LOCATION(target, value, shift=0){
    return (target &= ~(value << shift)) >>> 0;
}
function WRITE_BITS_TO_LOCATION(target, value, shift=0){
    return (target |= (value << shift)) >>> 0;
}

This works perfectly! I tried to do the same thing in C++ by using macros

Code:
#define CLEAR_BITS_TO_LOCATION(target, value, shift) (target &= ~(value << shift))
#define WRITE_BITS_TO_LOCATION(target, value, shift) (target |= (value << shift))

CLEAR_BITS_TO_LOCATION(myStruct.data1,0x07,25);
WRITE_BITS_TO_LOCATION(myStruct.data1,value & 0x07,25);

However that does nothing in c++ i'm unable to write any data to it.

So now my question is, is this the right approach to write a set of bits to a larger type in C++?

Hoepfully i was able to word this post properly as i suck at explain things lol

Thank you in advance.
 
Last edited:
Hi guys, i hope i'm phrasing the title right, I have a struct with a couple of uint32_t types, in those 32 bits i store multiple values, some are 2-bit values some are 4-bit some are 7 bit some are 1-bit and so on, this struct gets stored to EEPROM hence why i went with 32-bit unsigned ints to store these values to save EEPROM space rather than using a uint8_t for a value that will never use more than 2-bits or 4-bits etc.

The current EEPROM functions (EEPROM.get and EEPROM.put) now use a template, so that you can store and read an entire structure, rather than having to write each byte separately like you used to have to. So in this case, use whatever is convenient.
 
Thank you for the reply, Yes that's what i do, i write to the struct first then i "put" the struct into EEPROM, however i have to first write those bits to the struct before storing it which is where writing these bits to those 32-bit ints comes in.

I'm just trying to save space in EEPROM since i'm using most of it for other things other than these settings.
 
hi nero, you can try something like this to update the 3 bits:

0x7 == 0b111 <— mark all 3 bits as enabled
so:

myUint32var &= ~(0x7 << 25); // we clear 3 bits starting at bit 25 to 27
myUint32var |= (0x3 << 25); // we write a new value to that location (0x3, or 0b011)

be aware that constant values must be suffix appended (3UL vs 0x3), and never shift greater than your primitive type

i try to avoid defines for simple things like this
 
Thank you for the reply, that's exactly what i've been doing lol except with macros

Code:
#define CLEAR_BITS_TO_LOCATION(target, value, shift) (target &= ~(value << shift))
#define WRITE_BITS_TO_LOCATION(target, value, shift) (target |= (value << shift))
// clear the bits to the location by writing 0x07 (0b111)
CLEAR_BITS_TO_LOCATION(myStruct.data1,0x07,25);
// write the bits to that location (i had a typo in my original post and had CLEAR_BITS twice)
WRITE_BITS_TO_LOCATION(myStruct.data1,value & 0x07,25);

So there must be something else i'm doing wrong, at least now i know that those macros should be doing the job.

Thanks!
 
you should also wrap (value & 0x7), im not exactly sure what takes precedance but i always enclose the values before the shift, otherwise your define will look like this:

“value & 0x7 << 25”, where value could (maybe) be AND’d to 0x7 << 25

you could do this as well:

(target |= ((value) << shift));

that will enclose your value & 0x7 at same time
 
AHH!!! you are right, i'm looking at it as if it's a function but i forgot it's a MACRO! i'll test it
 
Status
Not open for further replies.
Back
Top