Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 9 of 9

Thread: Writing bits to a larger type

  1. #1

    Writing bits to a larger type

    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 by neroroxxx; 03-04-2019 at 08:27 PM.

  2. #2
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,379
    Quote Originally Posted by neroroxxx View Post
    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.

  3. #3
    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.

  4. #4
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,136
    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

  5. #5
    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!

  6. #6
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,136
    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

  7. #7
    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

  8. #8
    wrapping "value" in my macro did the job, thank you for noticing that!! HUGE HELP!

  9. #9
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany NRW
    Posts
    5,679
    Didn't show the the compiler a warning? It should warn about that.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •