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

Thread: Bitshift problem - Endian issue?

  1. #1
    Member
    Join Date
    Nov 2015
    Location
    Germany
    Posts
    23

    Bitshift problem - Endian issue?

    Hello,

    i have a problem and i do not understand why this happen.

    I want to write a function where i can extract X-Bits from a Byte Array of 8 Bytes.

    What i need are i.e. 12 Bit, started from Byte 0 Bit 4 to Byte 1 Bit 7.
    This may differ, that's why i want to have this function which i just call and say start-bit and length.

    This is what i have:

    Code:
    unsigned char byte1[8] = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF };
    
    unsigned long result = 0;
    unsigned long realResult = 0;
    
    unsigned long ByteToLong( byte const *pData, byte BitOffset, byte BitSize)
    {
      unsigned long bytetolongvalue = 0;
      
      byte c = ( BitOffset + BitSize ) / 8;
      c * 8 == BitOffset + BitSize ? 0 : c++;
      
      memcpy ( &bytetolongvalue, pData, c );
      
      bytetolongvalue <<= ( sizeof ( bytetolongvalue ) - c ) * 8 + BitOffset;
      bytetolongvalue >>= 8 * sizeof ( bytetolongvalue ) - BitSize;
      
      return bytetolongvalue;
    }
    
    void setup()
    {
      Serial.begin(9600);
    
    
      Serial.println("--12 Bit 4...16--");
      result = ByteToLong(byte1, 4, 12);
      Serial.print("Byte To Long result: ");
      Serial.println(result, HEX);
    
      // CORRECT RESULT IS:
      realResult = ((byte1[1] & 0xFF) << 4);
      realResult |= (((byte1[0]) >> 4) & 0x0F);
      Serial.print("realResult: ");
      Serial.println(realResult ,HEX);
    
    }
    
    void loop()
    {
    	
      
    }
    The result of the function is Hex: 412
    But i expect 341.

    I also played around with byteswap, endians and so on, but i could not find the right way.

    Can someone help me to find a solution what the problem is?
    It must be something with the memory storage of the bytes, that this is swapped.

    But how is it swapped and what should i do? If the memory / processor is using the bytes in a different way, do i have to bring the byte array in a form that the processor is using it like i want and then swap it back?

    Thanks a lot.

    Thomas

  2. #2
    What you have done is equivalent to this:

    Code:
    union {
        uint8_t byte1[8] = { 0xff, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12 };
        uint64_t val;
    } x;
     
    (x.val >> 3) & 0xfff) = 412

  3. #3
    Senior Member
    Join Date
    May 2017
    Posts
    202
    I suspect there is something wrong in the shifters. Looking at your data
    ( damn proportional fonts )
    Code:
     
       result   412
       expect  341
    So it looks like you shifted up too far and lost the 3 off the top of the long.
    And did not shift down far enough and retained the 2 in the nibble on the least significant end. Or this shift was ok and this result was due to the previous shift up being incorrect.

  4. #4
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,068
    This should do the trick:
    Code:
    unsigned char byte1[8] = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF };
    
    unsigned long result = 0;
    unsigned long realResult = 0;
    
    unsigned long ByteToLong( byte const *pData, byte BitOffset, byte BitSize)
    {
      uint64_t bytetolongvalue;
      
      memcpy ( &bytetolongvalue, pData, 8 );
    
      // Shift to the left removes unwanted bits on the left.
      bytetolongvalue <<= 64 - BitSize - BitOffset;
      // Shift to the right removes unwanted bits on the right
      bytetolongvalue >>= 64 - BitSize;
      
      return bytetolongvalue;
    }
    
    void setup(void)
    {
      Serial.begin(9600);
    
    
      Serial.println("--12 Bit 4...16--");
      result = ByteToLong(byte1, 4, 12);
      Serial.print("Byte To Long result: ");
      Serial.println(result, HEX);
    
      // CORRECT RESULT IS:
      realResult = ((byte1[1] & 0xFF) << 4);
      realResult |= (((byte1[0]) >> 4) & 0x0F);
      Serial.print("realResult: ");
      Serial.println(realResult ,HEX);
    
    }
    
    void loop(void)
    {
    }
    Output:
    Code:
    --12 Bit 4...16--
    Byte To Long result: 341
    realResult: 341
    The Teensy processor is little-endian, so in this declaration:
    Code:
    unsigned char byte1[8] = { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF };
    the low order byte is 0x12 and when interpreted as a 64-bit integer the whole thing is:
    Code:
    0xFFDEBC9A78563412
    Pete

  5. #5
    Member
    Join Date
    Nov 2015
    Location
    Germany
    Posts
    23
    Pete, that is fantastic.

    Thanks so much.
    So, as soon as i copy just x Bytes it throws the bytes in little endians, and i could not do it as easy as i want.

    Your solution is perfect, easy, small and working
    It looks that i was thinking too complicated.

    Cheers,
    Thomas

Posting Permissions

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