Combining two uint16_t values to one uint32_t value

Hi all,

I want to combine two uint16_t values to one uint32_t value.

I've written the following example code:

// Example values
uint16_t valueR = 65535;
uint16_t valueK = 12345;

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);

Serial.println("In");
Serial.println(valueR);
Serial.println(valueK);
Serial.println("");

uint32_t value_combined = ((uint32_t)valueR << 16) + valueK;

// Simulating eeprom write and read
// These lines can't be changed as they are used for writing to eeprom
uint8_t value1 = (uint8_t)(value_combined >> 24);
uint8_t value2 = (uint8_t)(value_combined >> 16);
uint8_t value3 = (uint8_t)(value_combined >>  8);
uint8_t value4 = (uint8_t)(value_combined >>  0);
// -------------------------------------------------------------------
// and these are used for reading from eeprom.
value_combined = (value_combined << 8) | value1;
value_combined = (value_combined << 8) | value2;
value_combined = (value_combined << 8) | value3;
value_combined = (value_combined << 8) | value4;
// -------------------------------------------------------------------

uint16_t R = (uint16_t)(value_combined >> 16);
uint16_t K = (uint16_t)(value_combined & 0xFFFF);

Serial.println("Out");
Serial.println(R);
Serial.println(K);
}

void loop() {
  // put your main code here, to run repeatedly:
}

I would appreciate if you could check the code.
Is it correct? Any optimizations possible?

Thanks,

Leo

PS: I posted this in the wrong forum section :frowning: It should be in the "Programming Questions" section.

I don't understand these lines (4 of them):

// and these are used for reading from eeprom.
value_combined = (value_combined << 8) | value1;

You could use an union, or an array with pointers.

Optimization depends on how you are going to use it. If you send four times one byte to the EEPROM, perhaps you can send an 32-bit integer with one command.

Koepel:
I don't understand these lines (4 of them):

// and these are used for reading from eeprom.

value_combined = (value_combined << 8) | value1;




You could use an union, or an array with pointers.

Optimization depends on how you are going to use it. If you send four times one byte to the EEPROM, perhaps you can send an 32-bit integer with one command.

That portion does not concern the topic. It is posted so a functional code is presented.
Offtopic: Sending 4 bytes in a row to the specific eeprom is mandatory and as I pointed out can't be changed.

My concern is: Do I have the "combine" and "separation" code correct. It seems to work but I want to be sure from someone who knows the business.

It seems to work

Looks OK to me, but the only way to be absolutely certain is to check all possible inputs and outputs. At least test all the extreme values.

I still don't understand those 4 lines. Are they just random code ?
If sending 4 bytes in a row is mandatory, then please tell us which eeprom and which library you use. You have not convinced me yet that you need indeed 4 seperate bytes.

Is it an external eeprom ?
Is there a specification for the order of the bytes ? MSB at the lowest address or LSB at the lowest address ?

The combining and seperation is correct.
Using a union will make the code easier to read, and less vulnerable for mistakes.

jremington:
Looks OK to me, but the only way to be absolutely certain is to check all possible inputs and outputs. At least test all the extreme values.

which I have done.

Thanks for the confirmation.

I still don't understand those 4 lines. Are they just random code ?

They produce a 32 bit value from four 8 bit values.

The operation is unnecessary.

Koepel:
I still don't understand those 4 lines. Are they just random code ?
If sending 4 bytes in a row is mandatory, then please tell us which eeprom and which library you use. You have not convinced me yet that you need indeed 4 seperate bytes.

I use my own code exclusively.

Koepel:
Is it an external eeprom ?
Is there a specification for the order of the bytes ? MSB at the lowest address or LSB at the lowest address ?

Correct. External eeprom.

Koepel:
The combining and seperation is correct.
Using a union will make the code easier to read, and less vulnerable for mistakes.

Thanks.
How would such a union look like? That is one area I'm not familiar with.

jremington, I see it now, they convert bytes to 32-bit integer. Thanks.

Leo, you don't use exclusively your own code, because I see the Serial functions. Is the eeprom with I2C ? Are you going to write your own I2C library ?

I think the Arduino is little endian. When a 32-bit integer is stored, the LSByte is stored at the lowest address.

A union has each element in the same memory location. If for example 4 bytes are combined with one 32-bit integer, they are at the same memory location and match the same length.

// The size of this union is 4 bytes.
union 
{
  uint8_t   b[4];            // b[0] is LSByte, b[3] is MSbyte.
  uint16_t w[2];            // w[0] is low word, w[1] is high word.
  uint32_t ul;
} myUnion;

uint16_t valueR = 65535;
uint16_t valueK = 12345;

myUnion.w[1] = valueR;
myUnion.w[0] = valueK;

uint32_t value_combined = myUnion.ul;

I'm not 100% sure that I did it right. You have to check it.

You have also not convinced me yet, that you need seperate bytes.
Perhaps a pointer is needed:

  ...write( (char *) &value_combined, 4);

You have also not convinced me yet, that you need seperate bytes.

Maybe yes , maybe no. The issue is page boundaries in the external eeprom. Single byte writes will always be OK.

Block writes with

  ...write( (char *) &value_combined, 4);

will not succeed if the 4 addresses pass across a page boundary.

However, if the writes are always in blocks of 4 you can be successful if you start at either address 0 or some multiple of 4, as page sizes are always divisible by 4.

@Koepel: Thanks for explaining "union". Your code worked.