Ints assigned the value of digital read behave unexpectedly

My issue is that when I use the result of digitalRead to create an integer used as the index of an array, the wrong array value is selected.

I have an array of uint32_t in progmem - FreqRegisters[832].

{update - I am starting to wonder if uint32_t is allowed on Atmega328p - Arduino Uno R3 as word size in an array }

It is arranged in four banks. Each bank holds 13 register values for 16 synthesizers.
A 2-bit code read on pins 18 and 19 determines the Bank offset (0,208,416,624).
Then, depending on which synthesizer is to be programmed, I calculate an offset within the bank to get to the first register for that synthesizer. I can calculate the needed offsets from constants or variables untiI I introduce the digitalReads to get the bits.

I am aware that digitalRead returns HIGH or LOW and that the returned result should not be treated as anything else. I have tried to use the HIGH/LOW results directly and I have not been successful. For example, I tried to determine the value of BankNew as below.

//if (( digitalRead(19) == LOW)  && (digitalRead(18) == LOW)) { BankNew = 0;}
//if (( digitalRead(19) == HIGH) && (digitalRead(18) == LOW)) { BankNew = 1;}
//if (( digitalRead(19) == LOW)  && (digitalRead(18) == HIGH)){ BankNew = 2;}
//if (( digitalRead(19) == HIGH) && (digitalRead(18) == HIGH)){ BankNew = 3;}

BankNew would print correctly in this case, but it could not be used in an array index as expected. If I set it with "BankNew = 3 " just after the above code, the code that followed worked OK.

When I could not make that work, I reworked the code with some other options, one that works and another one that does not. I will use this as my example,

FreqRegisters is defined as const uint32_t FreqRegisters[ 832 ] PROGMEM = {0,1,2,3 .......}

void WriteRegister32(uint32_t value, byte SynthNum) is a routine above in the source. I don't think that routine is relevant because my prints capture the problem before I call it .

void loop(){

int i,FCRI,A,B,BankNew,BankOld,Value,Synth;
BankOld = 3;
BankNew = 0;

//Pins 18 and 19 are setup to be Input_pullup and they are working properly

/* Assignment Option 1 - Assign digitalRead results to ints */
/* Both are tied low                                                                     */
//A=digitalRead(19);
//B=digitalRead(18);

/* Assignment Option 2 - Force assignment to ints */
A=LOW;
B=LOW;

The rest works  when I use Assignment option 2. Works means that when BankNew is used to calculate FRCI and FRCI is used as the index of FreqRegisters, I get  the  expected results. Read on to see what I mean.                                                                            
                                                                            
if (( A == LOW) && (B == LOW)) { BankNew=0;}
if (( A == HIGH) && (B == LOW)) { BankNew=1;}
if (( A == LOW) && (B == HIGH)) { BankNew=2;}
if (( A == HIGH) && (B == HIGH)) { BankNew=3;}


In both cases, I get the expected results when I print A,B and BankNew. For example 0:0:0. Also, for FCRI below I get 0 and for FCRI+2 I get 2. However, the FreqRegisters index calculated from FCRI + 2 is incorrect for option 1.

FreqRegisters[FCRI + 2] = 3099113656 for option 1 (Not correct)
FreqRegisters[FCRI + 2] = 12587898 for option 2 = 0xc0137a (correct)
In FreqRegisters[0+2] is 0xc0137a

Also - If I set it to 0,1,2,3 with BankNew = 0 , what follows works.


String p1=";";
Serial.println(A + p1 + B + p1 + BankNew);

    SPI.beginTransaction(SPISettings(7000000, MSBFIRST, SPI_MODE0));
    
    for (Synth=0;Synth<1;Synth++) // Cut the loop to 1 for my test
    {
      FCRI = (BankNew * 16 * 13) + (Synth * 13);

      Serial.println(FCRI); << As expected
      Serial.println(FCRI+2); << As expected
      Serial.println(FreqRegisters[FCRI]);  << Incorrect for option1
      Serial.println(FreqRegisters[FCRI + 2]); << Incorrect for option1
      
/*And so what follows is incorrect for option 1 */

      WriteRegister32(FreqRegisters[FCRI + 2],Synth);  //10
      WriteRegister32(FreqRegisters[FCRI + 8],Synth);  //4
      WriteRegister32(FreqRegisters[FCRI + 10],Synth); //2
      WriteRegister32(FreqRegisters[FCRI + 11],Synth); //1
      WriteRegister32(FreqRegisters[FCRI + 12],Synth); //0
      WriteRegister32(FreqRegisters[FCRI +  8],Synth); //4
      delayMicroseconds(225);
      WriteRegister32(FreqRegisters[FCRI + 12],Synth); //0
      delayMicroseconds(500);
    }
    
    SPI.endTransaction();  
}

Yes, standard C/C++.

If you simply assign the result of digitalRead() to an integer variable, you will get 1 or 0.

To get a two bit index (0-3) you could try something like this:

int result = ( ((int) digitalRead(pinB)) << 1) | ((int) digitalRead(pinA));

When posting code, please post ALL of it.

you keep saying uint32_t but keep referring to int.

uint32_t - unsigned 32 bit integer
int (on avr) - signed 16 bit integer

if you want to use uint32_t then use it

uint32_t myvar = 123;

Also

int i,FCRI,A,B,BankNew,BankOld,Value,Synth;

don’t do this. Inside the loop these are NOT initialised to 0 unless you explicitly assign value to them.

Thank you for the quick responses. My issue was not with combining the bits to get the 2-bit index. That works.

My array is of uint32 and I agree with killzone_kid that I can have an array of uint32 in progmem. Thanks for the confirmation.

I just proved that the root of the problem seems to be in the way that I tried to used access the uint32 array FreqRegiters

Like this, FreqRegisters[FCRI + 2]

Instead of like this, pgm_read_dword(FreqRegisters + FCRI + 2)

Why FreqRegisters[FCRI + 2] worked if I created BankNew without the use of digitalRead is still a mystery. I am going to close this. Thank you again,

Perhaps the compiler simply replaces someUint[23] (the code you used to debug) by looking up the number in your table at compile time. So the call to your array is simply not in your code and therefore cannot fail.
If you make it conditional, the compiler sees it is not a constant and needs to implement the whole lot...

By the way, you did a lot of good debugging to isolate your problem.

Thank you for the response. I think it is the kind of issue that you describe. pgm_read_dword() must avoid that optimization.

I will dump a hex listing this weekend to see if I can tell. I will share what I find if it is useful.

I have never given up before, but I was ready to on this one. It seemed so clear that it should be working.

If you give up you have no one but yourself to blame for it. C++ is old, reliable and tested language. Your lack of knowledge could be the culprit, but it is never to late to learn.

Wouldn't it be easier to let the compiler do the index math?

const uint32_t FreqRegisters[4][16][13] PROGMEM =

Then you could use pgm_read_dword(&FreqRegisters[Bank][Synth][Reg]) to get the right uint32_t from PROGMEM

(See: avr-libc: <avr/pgmspace.h>: Program Space Utilities)

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