Unpredictable array manipulation behaviour

hi, this one has me stumped. I have 2 arrays of chars - as you can see these are 2-d arrays. I’m trying to move the contents of 1 array into the other, shifting each row 1 place to the left, and moving the character on the far left to the far right. This is a table of on and off values for a scrolling LED matrix.

The problem is things are not behaving as expected, and the buffer array looks wrong. I’ve managed to reproduce the code here. There are 2 arrays, the contents of array 1 are printed, a routine puts array 1 data into array 2, shifting the data as described, finally array 2 is printed.

I’ve used 2 arrays to try to overcome the problem, thinking the use of a buffer would help directly manipulating a single array.

Is everyone seeing the same problem? Any ideas how I can work around this? Where is the error being created?

int a;
int b;

char arrayShiftInit;
char arrayShiftTemp;

//bitmap data:
char* bitmapRows[]={
  "000000000000000000000000000000",
  "000000000000000000000000000000",
  "000010000000000000010000000000",
  "000010000000000000010000000000",
  "000010000000000000010000000000",
  "000010000000000000010000000000",
  "000010000000000000010000000000",
  "000110000000000000110000000000",
  "000110000000000000110000000000",
  "010111010000000010111010000000",
  "101101111111111101101111111111",
  "000001000000000000001000000000",
  "000000000000000000000000000000",
  "000000000000000000000000000000"};

//buffer data:
char* bitmapRowsBuffer[]={
  "000000000000000000000000000000",
  "000000000000000000000000000000",
  "000000000000000000000000000000",
  "000000000000000000000000000000",
  "000000000000000000000000000000",
  "000000000000000000000000000000",
  "000000000000000000000000000000",
  "000000000000000000000000000000",
  "000000000000000000000000000000",
  "000000000000000000000000000000",
  "000000000000000000000000000000",
  "000000000000000000000000000000",
  "000000000000000000000000000000",
  "000000000000000000000000000000"};


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

void loop() {

  // 1 print rows in bitmapRows
  Serial.println("bitmapRows:");
  for (a=0; a<14; a++){
    for (b=0; b<30; b++){
      Serial.print(bitmapRows[a][b], BYTE);
    }
    Serial.println();
  }

  // offset to bitmap to buffer:
   for(a=0; a<14; a++){
    arrayShiftInit = bitmapRows[a][0];
    for(b=0; b<30; b++){
      if (b == 29) {
        arrayShiftTemp = arrayShiftInit;
      }
      else{
        arrayShiftTemp = bitmapRows[a][b+1];
      }
      bitmapRowsBuffer[a][b] = arrayShiftTemp;
    }
  }

  // 1 print rows in bitmapRowsBuffer
  Serial.println("bitmapRowsBuffer:");
  for (a=0; a<14; a++){
    for (b=0; b<30; b++){
      Serial.print(bitmapRowsBuffer[a][b], BYTE);
    }
    Serial.println();
  }
  
  
  Serial.println();
  delay(10000);
}

I don't knoe anout the original problem, but you're extremely close to running out of RAM if you aren't out already.

Don't shift the data, shift your view of the data by applying an offset. Use something like (i + display_index) % sizeof(bitmapRows) to index the column instead of i.

-j

hi j, can you expand on that a little? Here’s how I see it:

matrixOffset++;
  for (a=0; a<14; a++){
    for (b=0; b<30; b++){
      i = matrixOffset+b;
      if (matrixOffset <30){
        Serial.print(bitmapRows[a][i], BYTE);
      }else{
        Serial.print(bitmapRows[a][i-30], BYTE);
      }
    }
  }

So I understand the principle of shifting the view rather than the data, the line you suggest is a little tricky for me!

hi, I’ve simplified the code to apply a visual offset to a single array of data.

I’m still seeing peculiar results printed using Serial.print, the shifted data becomes progressively worse.

It’s absolutely possible I’m doing something wrong here, but I can’t see what :-?

int a;
int b;
int i;
int j;
int matrixOffset;

//bitmap data:
char* bitmapRows[]={
  "000000000000000000000000000000",
  "000000000000000000000000000000",
  "000010000000000000010000000000",
  "000010000000000000010000000000",
  "000010000000000000010000000000",
  "000010000000000000010000000000",
  "000010000000000000010000000000",
  "000110000000000000110000000000",
  "000110000000000000110000000000",
  "010111010000000010111010000000",
  "101101111111111101101111111111",
  "000001000000000000001000000000",
  "000000000000000000000000000000",
  "000000000000000000000000000000"};

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

void loop() {

  // print rows in bitmapRows
  Serial.println("bitmapRows:");
  for (a=0; a<14; a++){
    for (b=0; b<30; b++){
      Serial.print(bitmapRows[a][b], BYTE);
    }
    Serial.println();
  }
  
  // print matrix offset:
  Serial.print("offset ");
  Serial.println(matrixOffset);
  for (a=0; a<14; a++){
    for (b=0; b<30; b++){
      i = matrixOffset+b;
      if (matrixOffset >29){
        i = i-30;
      }
      Serial.print(bitmapRows[a][i], BYTE);
    }
    Serial.println();
  }
  
  matrixOffset++;
  Serial.println();
  delay(1000);
}

Here’s the serial output after 193 iterations of the loop:

bitmapRows:
000000000000000000000000000000
000000000000000000000000000000
000010000000000000010000000000
000010000000000000010000000000
000010000000000000010000000000
000010000000000000010000000000
000010000000000000010000000000
000110000000000000110000000000
000110000000000000110000000000
010111010000000010111010000000
101101111111111101101111111111
000001000000000000001000000000
000000000000000000000000000000
000000000000000000000000000000
offset 193
0000000000001000000000        
0000000000001000000000        
      > > ] | ?     bitmapRows
      > > ] | ?     bitmapRows
      > > ] | ?     bitmapRows
      > > ] | ?     bitmapRows
      > > ] | ?     bitmapRows
 offset  Á   °         ¡£    
 offset  Á   °          Á£    
                              
                              
                              
0000000000001000000000        
0000000000001000000000

OK, the problem here was typo, fixed code below.

Any tips on making this more efficient would be great…

// just a test to sort out the loop:

int a;
int b;
int i;
int j;
int matrixOffset;

//bitmap data:
char* bitmapRows[]={
  "000000000000000000000000000000",
  "000000000000000000000000000000",
  "000010000000000000010000000000",
  "000010000000000000010000000000",
  "000010000000000000010000000000",
  "000010000000000000010000000000",
  "000010000000000000010000000000",
  "000110000000000000110000000000",
  "000110000000000000110000000000",
  "010111010000000010111010000000",
  "101101111111111101101111111111",
  "000001000000000000001000000000",
  "000000000000000000000000000000",
  "000000000000000000000000000000"};

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

void loop() {

  // 1 print rows in bitmapRows
  // Serial.println("bitmapRows:");
  for (a=0; a<14; a++){
    for (b=0; b<30; b++){
      // Serial.print(bitmapRows[a][b], BYTE);
    }
    // Serial.println();
  }
  
  
  Serial.print("offset ");
  Serial.println(matrixOffset);
  for (a=0; a<14; a++){
    for (b=0; b<30; b++){
      i = matrixOffset+b;
      if (i>29){
        i = i-30;
      }
      Serial.print(bitmapRows[a][i], BYTE);
    }
    Serial.println();
  }
  
  matrixOffset++;
  Serial.println();
  delay(1000);
}

FYI, the modulus operator % gives the remainder of integer division, so i = (matrixOffset + b) % 30 is the same as

i = matrixOffset+b;
      if (i>29){
        i = i-30;
      }

(but the compiler probably produces the same instructions for both, so don't sweat it).

I think I've pontificated elsewhere on the forum that correctness is priority #1 in coding followed closely by readability #2, and don't worry about efficiency unless/until you know that the code needs to be more efficient.

Having said that, you're effectively taking a byte to store a single bit. If you want to make more efficient use of RAM (by a factor of 8) at the cost of slightly more complex code, store the bitmap in binary and use bitwise manipulations to extract the data from the array. For example, your 31x14 = 434 byte array (yes, 31, that's a string with the invisible but oh-so necessary null character on the end) could be stored in an array of 14 long ints, total RAM 56 bytes. The resulting code wouldn't be any more complex to execute, could even be simpler, but it's a bit tougher to understand if you aren't used to bitwise manipulation.

-j

It's a very different application but there is a thread linked below with an example of code that started as byte array and ended up as a bit array that may provide some examples of using bit arrays. http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1214715130;start=all

Yes that makes sense, using an array of bits for RAM 56 bytes is much better!

I'll look through the bit mask example, and post the improved routine when it's working.

Here's an image of the hardware. I'm using 3 MAX6952 drivers, each one controls four 5*7 Kingbright TA07-11GWA matrices. The board was designed in a free version of Eagle, and the PCB was manufactured by PCB-Pool.

http://www.cadsoftusa.com/freeware.htm http://www.pcb-pool.com/ppuk/info.html

Here's the code in its entirety:

http://www.materialbeliefs.com/process/vitalsigns/code/VS_heart6.pde

And even a video of it in action (the simulator in the background was written in Processing):

http://www.materialbeliefs.com/process/vitalsigns/video/VS-Breath-PCB-sm.mov

cool!

Y'know, if a waveform is your target output (not sure if that is the case, or the heartbeat is a demo), you may want to think about rotating your view of the data 90 degrees - think columns instead of rows. An array of 30 (columns) each containing 14 bits (really a 16 bit int) indicating pixels for that column may make sense.

Even more compact memory-wise ([u]if[/u] the waveform assumption is correct), each entry in the array could be a simple integer, indicating which row is lit (this assumes only 1 row is lit). That reduces memory consumption to 1 byte per column, or 30 bytes. (If you're seriously hardcore about memory conservation, you could do this with have the space, storing a column in the low nibble and another in the high nibble of each byte, but that may be a bit extreme).

nice project!

-j

Thanks, I will indeed rotate the data as you describe.

I think there needs to be scope for more than one row in each column to be 'on', so I can't get things super tiny, though the 15 byte data format you mention is very clean.

15 bytes. The thread started with my 2 arrays that totalled 840 bytes of RAM!