Shifting 2D Array - 8x8 RGB

Greetings forum,

I hope someone could help me out in shifting a 2D array. I recently bought a Colorduino and I have coded many cool patterns and animations. However, I found the need to shift the buffer to create better animations and make the code more streamlined.

I'd like to shiftup, shiftdown, shiftleft, and shiftright. The Colorduino is an 8x8 RGB matrix.

The display buffer looks like this:

byte display_byte[3][64]; //display array - 64 bytes x 3 colours. 0 red, 1 grn, 2 blu 64 pixels

I'd like to shift the display and then call directly:

//send display buffer to display via i2c 
void update_display(byte addr) {   
  BlinkM_sendBuffer(addr, 0, display_byte[0]);   
  BlinkM_sendBuffer(addr, 1, display_byte[1]);   
  BlinkM_sendBuffer(addr, 2, display_byte[2]);  
}

I'd like to create functions like this, where n is num of shifts:
void shiftRight(int n) {

}

I've tried some code here, but nothing meaningful to post:
http://www.learningace.com/doc/4992024/3105e0e2881142fd218f9b6f05c079cb/r-multiarrays
http://www.cplusplus.com/forum/beginner/1521/

99% of the time I've found answers to all my C++ and Arduino questions on the net.

Thanks for your time.

Did you want to rotate the image (pixels shifted off one side come back on the other side)?

If not, what do you want to fill the empty pixels with?

Do you have room for a second buffer (another 3x64 array)?

If you don't have room for a second buffer you might have to shift one pixel at a time. That way you only need a 3x8 array for buffering.

Shifting UP is easy:

memcpy(&buffer[0], &buffer[8], 3*8*7);  // Move the bottom 7 rows up 1 row.

You'd think that moving DOWN would be almost as easy:

memcpy(&buffer[8], &buffer[0], 3*8*7);  // Move the top 7 rows down 1 row.

Unfortunately memcopy() moves the low-addressed bytes first. This means that it moves Row 0 down to Row 1 before it moves Row 1 to Row 2. You end up with 8 copies of Row 0! You have to use a copy function that moves the last bytes (Row 6->Row 7) first and works backward to Row 0->Row 1.

Thanks for the reply.

Pixels shifted should be completely discarded (turned black)...like scrolling text or animations that leave view.

I do have enough room to copy the buffer. I checked it with:

int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

...I have 1157 free (328 chip)

I'm hoping just to manipulate the current buffer, but adding another could be of other use too.

I just want to fill the shifted buffer (or copy) with black:

byte display_byte[0][pixelnum] // red (0,pixelnum)
byte display_byte[1][pixelnum] // grn (0,pixelnum)
byte display_byte[2][pixelnum] // blu (0,pixelnum)

Breaking the 64 pixels into rows and columns does help.

In the library, this function: ...converts the x,y coordinates to pixels nums.

//update display buffer using x,y,r,g,b format
void display(byte x, byte y, byte r, byte g, byte b) {
  byte p = (y*8)+x;   //convert from x,y to pixel number in array
  display_byte[0][p] = r;
  display_byte[1][p] = g;
  display_byte[2][p] = b;
}

Thanks

danoduino:
Breaking the 64 pixels into rows and columns does help.

So change the array to:

byte display_byte[3][8][8];

And change the library function to:

//update display buffer using x,y,r,g,b format
void display(byte x, byte y, byte r, byte g, byte b) {
  display_byte[0][x][y] = r;
  display_byte[1][x][y] = g;
  display_byte[2][x][y] = b;
}

Then the ShiftUp(), ShiftDown(), etc functions become easier.

void ShiftUp(byte shiftCount) {
   if (shiftCount == 0)
      return;  // Nothing to do

   // If the entire buffer is shifted out, just clear it
   if (shiftCount >= ROW_COUNT) {
      ClearBuffer();
      return;
   }

   for (byte row = shiftCount; row < ROW_COUNT; row++)
      CopyRow(row-shiftCount, row);

   for (byte row = ROW_COUNT - shiftCount; row < ROW_COUNT; row++)
      ClearRow(row);
}

I experimented with the memcpy function and it seems to work very well.

byte display_byte[3][64];   // display array - 64 bytes x 3 colours
byte buffer_byte[3][64];    // buffer copy test

void mem() {
  memcpy(buffer_byte, display_byte, sizeof(buffer_byte));  // Copies Buffer display_byte to buffer_byte
}

I tried changing the 2D array to 3D, no luck. Trying to shift every 8th byte in one direction or another would be a nightmare. In looking at the i2c slave code, the slave sets x,y coordinates based on incoming data (64 bytes for each color). i.e.

    if (c == 0){
      for (byte x = 0; x < 8; x++){
        for (byte y = 0; y < 8; y++){
           PixelRGB *p = Colorduino.GetPixel(x,y);  // my comment: Get.Pixel, actually "sets pixel" for writing in the offscreen framebuffer
           p->r = Wire.read();
        }
      }
    }
{ 
   
  //1 pixel = 3 bytes B00000000 B00000000 B00000000. 
  //We send R then G then B bytes as 3 separate transfers
  //This is because if we make the I2C buffer too large, we run out of SRAM for other things on our master Arduino
  
  if (Wire.available()>66) { //when buffer full, process data. 66 =  start byte + colour + 64 pixel data + end byte
    
    // error check - make sure our data starts with the right byte   
    if (Wire.read() != START_OF_DATA) {
      //else handle error by reading remaining data until end of data marker (if available)
      while (Wire.available()>0 && Wire.read()!=END_OF_DATA) {}      
      return;
    }

    byte c = Wire.read(); //read our color byte so we know if these are the R, G or B pixels.
    
    //depeding on c read pixels in as R G or B
    //read red display data
    if (c == 0){
      for (byte x = 0; x < 8; x++){
        for (byte y = 0; y < 8; y++){
           PixelRGB *p = Colorduino.GetPixel(x,y);
           p->r = Wire.read();
        }
      }
    }
    
    //read green display data
    if (c == 1){
      for (byte x = 0; x < 8; x++){
        for (byte y = 0; y < 8; y++){
          PixelRGB *p = Colorduino.GetPixel(x,y);
           p->g = Wire.read(); 
        }
      }
    }
    
    //read blue display data
    if (c == 2){
      for (byte x = 0; x < 8; x++){
        for (byte y = 0; y < 8; y++){
           PixelRGB *p = Colorduino.GetPixel(x,y);
           p->b = Wire.read(); 
        }
      }
    }
    
    //read end of data marker
    if (Wire.read()==END_OF_DATA) {
      //if colour is blue, then update display
      if (c == 2){Colorduino.FlipPage();}
    } 
  }
}

I'm thinking I could have the slave do the work in shifting pixels by adding additional i2c commands:

the following functions exist in the lib:

  void FlipPage() {  // my comment: offscreen to active framebuffer
    cli();
    // swap frame buffers
    PixelRGB *tmp = curDrawFrame;
    curDrawFrame = curWriteFrame;
    curWriteFrame = tmp;
    sei();
  }

  // get a pixel for writing in the offscreen framebuffer
  PixelRGB *GetPixel(unsigned char x,unsigned char y) {
    return curWriteFrame + (y * ColorduinoScreenWidth) + x;
  }

  // get a pixel from the active framebuffer
  PixelRGB *GetDrawPixel(unsigned char x,unsigned char y) {
    return curDrawFrame + (y * ColorduinoScreenWidth) + x;
  }

  // set a pixel in the offscreen frame buffer
  void SetPixel(unsigned char x, unsigned char y, unsigned char r, unsigned char g, unsigned char b)
  {
    PixelRGB *p = GetPixel(x,y);
    p->r = r;
    p->g = g;
    p->b = b;
  }

Thanks again for your time.

I've invited the author of the nice lib to join the discussion. Without this lib, the demo code provided by iteadstudio leaves nothing to be desired.

Kudos to lincomatic and his instructables post: