2d array not populated correctly when using bitshift

Hope you're having a good day.

I am likely doing something stupid, but can't seem to see it!

I am trying to populate an array like this:


Where two 16 bit ADC values are merged into one 32 bit cell using bitshift (I am using an esp32, so it's quicker to send data this way).
I also have an additional 2 channels that records a timestamp at channel 0 each timestep.

Here is the code (N.B. just using arbitary values to fill array). All prints are for debugging / printing array:

#define numOfCh 8
#define numOfTs 64

uint16_t adcSample1 = 0b1111111111111111;
uint16_t adcSample2 = 0b1111111111111111; 

void setup() {
  Serial.begin(115200);
}

void loop() {

  // create new array and populate it
  long buff[numOfCh+2][numOfTs/2];
  for(int ts = 0; ts<numOfTs; ts++){
    for(int ch = 0; ch<numOfCh; ch++){
      
      Serial.print("Channel: ");
      Serial.println(ch);
      Serial.print("Timestep: ");
      Serial.println(ts);
      
      if(ts%2 == 0){
        buff[ch][numOfTs/2] = adcSample1 << 16;
        Serial.print("Even - 16 bitshift: ");
        Serial.println(buff[ch][numOfTs/2],BIN);
        if(ch == 0){
          buff[8][ts/2] = 0b11111111111111111111111111111111;
          Serial.print("CH 0 detected, adding micros(): ");
          Serial.println(buff[8][ts/2],BIN);
        }
        Serial.println();
      }
      else{
        buff[ch][numOfTs/2] += adcSample2;
        Serial.print("Odd - appending to array: ");
        Serial.println(buff[ch][numOfTs/2],BIN);
        if(ch == 0){
          buff[9][ts/2] = 0b11111111111111111111111111111111;
          Serial.print("CH 0 detected, adding micros(): ");
          Serial.println(buff[9][ts/2],BIN);
        }
        Serial.println();
      }
    }
  }

  // print array  
  for(int ch = 0; ch<(numOfCh+2); ch++){
    for(int ts = 0; ts<(numOfTs/2); ts++){
      Serial.print(buff[ch][ts],BIN);
      Serial.print(" ");
    }
    Serial.println();
  }
  Serial.println("-------------");
  delay(100);

}

This is what the array is when printed to serial:

I expect to see all cells populated with 11111111111111111111111111111111

When printing each time it populates a cell in the array I get: 1111111111111110000000000000000 after bitshift then 11111111111111111111111111111111 after adding secondary 16 bit to cell which is as expected.

What am doing wrong :sleepy:

Thanks in advance for your time,
Will

1 Like

Why do you bother playing with 32 bits and but shift, just create an array of struct, the struct holding whatever records you want to keep

Quicker to send data where?

          buff[8][ts/2] = 0b11111111111111111111111111111111;

Why buff[8], and later buff[9]? What is the significance of the undocumented magic numbers 8 and 9?

These are the additional 2 channels that records a timestamp each time channel 0 is read.

This could be a better implementation, although I am not at all confident with structs

When you create an array of the size X

T myarray[X];

the last element you can access is

myarray[X-1]

trying to access

myarray[X]

will lead to out of bounds read/write and who knows what else

uint16_t adcSample1 = 0b1111111111111111;
...
buff[ch][numOfTs/2] = adcSample1 << 16;

adcSample1 is 16 bits long, so when shifted by 16 bits, all the data will be lost. Make it a uint32_t.

I am writing the adcSamples to buff which is a long (32 bits) so that is not the problem sadly

@willpowell Can you elaborate a little on what your application is supposed to do? Maybe there are easier ways to achieve your goal. Are you sure you actually need all this bit shifting, for instance?

Solved! buff[ch][numOfTs/2] was meant to be buff[ch][ts/2]

Knew it was something stupid. Thanks everyone!

Just as its faster to send 32 bit values. I tried sending 16 bit array and was much slower. Oh well solved now!

Again, send to where? and how? But if you consider it solved, fine. I find it somewhat dubious.

As it's now working , clearly you are right to say it's not a problem! But, I suspect, not for the reason you think...

If you ran this code on an 8-bit MCU, it would not work, I suspect. The reason that it does work ok is not because you are writing the results to a 32-bit variable, it's because you are running it on a 32-bit MCU. Sounds like a subtle distinction, I realise, but a potentially important one. On an 8-bit MCU, the result of "adcSample1 << 16" would be treated as a 16-bit value and bits would be lost. But on a 32-bit MCU, the result of "adcSample1 << 16" would be treated as a 32-bit value and no bits are lost.

Can anyone confirm my theory?

thanks for posting this question earlier for me, im just starting out my arduino project

1 Like

Sorry, the ESP32's A:D converter is a 12bit and fits nicely into a int16_t. But, converting it to a float.

The question is really about what happens when you shift a 16-bit value by 16 bits on a 32-bit MCU Vs an 8-bit MCU. Could be any value, does not have to be from an ADC.

It's not the MCU, it's the compiler's choice of word size for 'int'. If you use int32_t it should be the same on either an 8 bit or 32 bit processor (16 or 32 bit 'int').

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.