Odd array index behavior

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm having this problem in Arduino, but I don't get much help over on the arduino.cc forum, so I thought I'd try over here.  After all, there IS an AVR in there (smiley) and I think this is more of a C conceptual problem than an Arduino problem.

 

    uint8_t i = 0, X = 0, Y = 140;
    for (i = 0; i < 10; i++) {
      Partial_Update_Init_Background1(WIDTH_PIXELS,  //X size
                                    HEIGHT_PIXELS, //Y size
                                    0xff);         //image data
      if (i == 2) {
        Partial_Update_Display_Area(X, Y, digits2[i].width, digits2[i].height, digits2[i].dig); // x location in bytes, y loc. in pixels
        delay(1000);
      }
      Partial_Update_Display_Area(X, Y, digits2[4].width, digits2[4].height, digits2[4].dig); // x location in bytes, y loc. in pixels
      delay(1000);
   }

The above code is intended to cause the value of i to be displayed on an epaper display (e.g. when i is 0, 0 should appear on the display).  Partial_Update_Display_Area() is what actually does the displaying, and the second call of this function above is all I should need.  I've hard-coded the indexes in this call arbitrarily to 4 (it works fine with any value 0 - 9) because if I use i, garbage ensues.  In the if statement, however, I can use any value for i (0 - 9) and the function works as it should.  The if statement is only there as part of my effort to track down what the problem is, so far to no avail.  If I replace the == in the if statement with < (e.g. i < 4), the Partial_Update_Display_Area() breaks there, too.  What might be causing this behavior (using a variable works fine in some situations but not in the one I really need it in)?  Thanks for any tips.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When you use `if (i == 2)` you make just one single call to `Partial_Update_Display_Area` for this entire code snippet. If you use `i < 4`, you make multiple calls, one after another. Something in the implementation of `Partial_Update_Display_Area` breaks down when you make multiple calls.

 

In other words, this has nothing to do with array indexes. The source of the error is elsewhere.

Last Edited: Wed. Sep 25, 2019 - 12:19 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It may be that the error is elsewhere, as you suggest, but the if statement has no else clause, so when using i == 2 there will be two calls to Partial_Update_Display_Area() (when i is 2) and one otherwise.  When testing i < 4 there will also be two calls for each iteration of i (when i is less than 4), and one call the rest of the time.  If I eliminate the if statement, and replace the index in the function call with i, so that it's called only once for each iteration, I get garbage, which is how I discovered this problem.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just a guess here, try making “i” volatile and see what happens.
volatile uint8_t i;

Jim

 

 

 

 

Last Edited: Wed. Sep 25, 2019 - 01:13 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lautman wrote:
I've hard-coded the indexes in this call arbitrarily to 4 (it works fine with any value 0 - 9) because if I use i, garbage ensues

So the code in #1 is your debug code that works fine.
.
You may show us the original code that causes garbage.

Majid

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When the compiler can know what i is, or you use a fixed index, it will not go through the trouble of going through the calculations at runtime to provide the call arguments as it already knows what they are since your digits2 struct is const (I assume , from your other tread).

 

Which points to something about calculating the struct offsets/values. My guess-

you are using PROGMEM, which also means its up to you to access those vars through pgm_read_ functions/macros. I don't know what Arduino has available, but 'normal' avr compiler can use the __flash directive and the compiler takes care of the var access through lpm's. If Arduino cannot use __flash, then you are stuck using pgm_read_ to access the flash vars.

 

Partial_Update_Display_Area(X, Y, pgm_read_word( &digits2[i].width ), pgm_read_word( &digits2[i].height ), digits2[i].dig);

digits2[i].dig is an array (I assume), so there is nothing to lookup as the address is calculated and passed (no data access), the called function will deal with the data lookup via pgm_read_.

 

My __flash example from your other thread-

https://www.avrfreaks.net/commen...

notice no pgm_read stuff, as long as any flash function arguments are also marked as __flash const.

 

You also don't need to pass individual struct members as arguments, as you can pass a pointer to the whole struct and let the called function get whatever it needs-

Partial_Update_Display_Area(X, Y, &digits2[i]);

 

let the called function deal with it-

Partial_Update_Display_Area(X, Y, digit_t* pd){

  uint16_t w = pgm_read_word( &pd->width );

  uint16_t h = pgm_read_word( &pd->height );

}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ki0bk wrote:

Just a guess here, try making “i” volatile and see what happens.
volatile uint8_t i;

Jim

 

Thanks, Jim.  Worth a try, but didn't fix the problem.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> Partial_Update_Display_Area(X, Y, pgm_read_word( &digits2[i].width ), pgm_read_word( &digits2[i].height ), digits2[i].dig);

 

Thanks, curtvm!  That was it.  Actually Partial_Update_Display_Area(X, Y, pgm_read_byte_near( &digits2[i].width ), pgm_read_byte_near( &digits2[i].height ), digits2[i].dig); , but I never would have thought to look into that without your suggestion.  All good for now.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you remember your other thread where I said you'd need a double dereference? ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm guessing the issue may be with the definition of the digits2 struct array.   When the index is a constant the compiler can generate a constant argument (at compile time), but when "i" it can't, so if you have that in flash the compiler is not generating the instructions to move to sram.  And I'm guessing clawson's comment above is your solution.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I do. But I was having trouble getting that to work due to my inexperience using double dereferencing. So I tried using the approach suggested by curtvm and got that to work.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What I meant was that to dereference anything in PROGMEM you have to pgm_read_XXX() it. So if you have struct pointers in PROGMEM you need one pgm_read_word() to pick up the pointer. Then the thing it is pointing at is also in PROGMEM so you need another pgm_read_block() to then read the data that pointer points to. That is "double".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Now I realize that you and curtvm were basically saying the same thing, but I hadn't encountered pgm_read_XXX() before, so it wouldn't have occurred to me, and seeing that in curtvm's post pointed me in the right direction.