2

Background

I'm reading a 24-bit ADC value into a uint32. Using SPI bus, here's the logic:

value = SPI.transfer(0);   // read first 8 bits (MSB first)
value <<= 8;               // shift bits left
value |= SPI.transfer(0);  // read next 8 bits
value <<= 8;               // shift bits left
value |= SPI.transfer(0);  // read final 8 bits

As such I'm left with this ADC reading:

00000000 11111111 11111111 11111111
         MSB                    LSB

(Ignore the leading zeros for now.)

Now I transfer this value over ethernet like so:

client.write((const byte*) &value, sizeof(value));

The problem is this:

  • The value is stored as MS bit first.
  • client.write() transmits it LS byte first.

I am using NodeRED as a TCP server. So at the other end, I receive the data like this:

11111111 11111111 11111111 00000000
     LSB          MSB

I understand this is the expected behavior, but I would like to switch the BYTE order around before sending, so that it is read in NodeRed native endianness.


Question

Perhaps I should do some bit shifting at the point of reading the ADC, to accommodate the fact that client.write() sends the least significant byte first, like this:

  byte1 = SPI.transfer(0);
  byte2 = SPI.transfer(0);
  byte3 = SPI.transfer(0);
  response = byte3;
  response <<= 8;
  response = byte2;
  response <<= 8;
  response = byte1;

Is this the most efficient way in terms of clock cycles?

Please note that my MCU is a Teensy 4.1, and I'm transferring 10,000 readings per second. I would like to keep the clock cycles for any necessary bitwise operations to a minimum, so that the timing of ADC readings are affected as little as possible.

0

2 Answers 2

2

You can use an array of byte to save the shifts at all. This solution should be the one with the least clock cycles, and with no additional memory usage.

static byte value[4] = { 0 };

    /* ... */

    /* value[0] is still 0. */
    value[1] = SPI.transfer(0);
    value[2] = SPI.transfer(0);
    value[3] = SPI.transfer(0);

    client.write(value, sizeof value);

Some notes:

  1. Using an array avoids the re-interpretation of a 32 bit variable as a byte array. You read bytes from SPI, and write() expects a byte array. This circumvents your endianness issue completely.

  2. In the call of write() you don't need to cast the address of value to const byte *, because the const is a qualifier for the called function. It is not allowed to change the bytes pointed to.

  3. Making the array static saves you from zeroing the first byte repeatedly. BTW, it is sufficient to provide the first byte, as all other bytes are zeroed automatically. However, the last bytes will be updated on each transfer.

  4. sizeof is an operator, not a function. However, it is quite common to use it with a type instead of an object, and then you need parentheses because of the syntax. But it is better to use the respective object, actually you mean that.

1
  • You have explained this really well, but just to confirm as I get to grips with this idea, you are saying instead of using an in32_t function and creating a response value, then reading / shifting each byte into the value, it's better to create an array of bytes? So let's say I am storing 100 values, I would have a 2D array (100 x 3 or whatever)? I am sure the answer is "yes" but I just wanted to fully understand. Also what if I want to cast to float and send that value, with bytes swapped as well? Is it best to read into an array, then somehow cast 3 vals in the array to a float?
    – hazymat
    Feb 11, 2022 at 11:30
-1
// reverse wire order:
client.write((const byte*) &value + 3, 1);
client.write((const byte*) &value + 2, 1);
client.write((const byte*) &value + 1, 1);
client.write((const byte*) &value,     1);
1
  • 3
    Just nitpicking but... I would add either spaces around + or parentheses around (const byte*) &value. Otherwise it looks like + binds more tightly than the cast, which is of course not the case. Feb 1, 2022 at 19:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.