writing new Rainbowduino Firmware

Hello everybody,
just registered in this forum.

I’m working on a new (and I hope better) firmware for Rainbowduino.

My goal is to have a fully functional communication protocol to handle the led as an 8x8 display.
I want also to include the support for multiple Rainbow.
I’m not sure (lack of knoledge in Arduino) if multiple Rainbow can communicate each other via I2C, while the same channel is used by Arduino to send the graphic commands to the Rainbow chain.

Here follows the code I’ve written during the last weekend.
It’s far away to be complete. All the I2C communication part is absolutely missing.
Some code, especially the low-level control and the timer functions are derived from the actual firmware.
I’m considering the idea of rewriting (again) everything object oriented.

I’ve a wierd bug and I don’t understand where is the problem. Unfortunately, without a debugger is very hard to find.
The bug is documented in the code.
Basically, I have to call a function (clearBuffer) during setup() to have everything working. And I really don’t understand why. If you notice the compiled code size, with and without the function mentioned it varies. Why? I’ve no idea.

Thanks in avance for every help and collaboration.

Rainbowduino_Firmware_3_0b.pde (part I)

#include "Rainbow.h"

#include <Wire.h>
#include <avr/pgmspace.h>

extern unsigned char dots_color[8][3][8][4];    // define Two Buffs (one for Display ,the other for receive data)
extern unsigned char GammaTab[4][16];           // define the Gamma value for correct the different LED matrix
extern unsigned char ASCII_Char[62][8];

unsigned char line, level;
unsigned char g8Flag1;

byte dispGamma;
byte bufFront, bufBack, bufCurr;

unsigned char RainbowCMD[5]={0,0,0,0,0};
byte State=0;

void setup() {
  _init_gfx();
  _init();      // Initialize Ports, Timer and Interrupts
   clearBuffer(BLACK);  // <<**THE BUG** WHY? Why if I comment this line the code size reduces and nothing works?
}

void loop() {
  // Display char 'A' on black
  clearBuffer(0x0, 0x0, 0x0);
  printChar(0, 0, 0x0, 0x8, 0xf, 'A');
  swapBuffers();
  
/* FULL TESTING OF FUNCTIONS - UNCOMMENT TO EXECUTE
  // Scroll char 'P' from left to right
  int i;
  for(i=-8; i<8; i++) {
    clearBuffer(BLACK);
    printChar(i, 0, 0x0, 0x0, 0xf, 'P');
    swapBuffers();
    delay(100);
  }
  
  // Plot dot-by-dot char D on yellow, then scrolls it away
  clearBuffer(0x7, 0x9, 0x0); 
  setPixel(1,1, 0, 0, 0xf);
  setPixel(2,1, 0, 0, 0xf);
  setPixel(3,1, 0, 0, 0xf);
  setPixel(4,2, 0, 0, 0xf);
  setPixel(4,3, 0, 0, 0xf);
  setPixel(4,4, 0, 0, 0xf);
  setPixel(4,5, 0, 0, 0xf);
  setPixel(3,6, 0, 0, 0xf);
  setPixel(2,6, 0, 0, 0xf);
  setPixel(1,6, 0, 0, 0xf);
  setPixel(1,5, 0, 0, 0xf);
  setPixel(1,4, 0, 0, 0xf);
  setPixel(1,3, 0, 0, 0xf);
  setPixel(1,2, 0, 0, 0xf);
  for (i=0; i<10; i++) {
    swapBuffers();
    clearBuffer(0x7, 0x9, 0x0);
    copyFrontBuffer(-1, -1);
    delay(150);
  }

   // Cycle all the Aux buffer showing the predefined content 
  for(i=0; i<6; i++) {
    showAuxBuffer(i);
    delay(200);
  }
  swapBuffers();

  // Cycle all the chars of predefined font
  for(i='0';i<'9';i++) {
    clearBuffer(0x0, 0x0, 0x0);
    printChar(0, 0, 0x1, 0x4, 0xf, i);
    swapBuffers();
    delay(100);
  }
  for(i='A';i<'Z';i++) {
    clearBuffer(0x0, 0x0, 0x0);
    printChar(0, 0, 0x1, 0x4, 0xf, i);
    swapBuffers();
    delay(100);
  }
  for(i='a';i<'z';i++) {
    clearBuffer(0x0, 0x0, 0x0);
    printChar(0, 0, 0x1, 0x4, 0xf, i);
    swapBuffers();
    delay(100);
  }
UNCOMMENT TO DO FULL TESTING */
}

/*----------------------------------------------------------------------------*/
/* DRAWING FUNCTIONS                                                          */
/*----------------------------------------------------------------------------*/

void _init_gfx() { // Init the graphic side
  dispGamma = 1;
  bufFront=0;
  bufBack=1;
  bufCurr=0;    
}


void setGamma(byte g) { // Change the gamma array
  if ( g < MAX_GAMMA_SETS ) {
    dispGamma = g;
  }
}

void setPixel(byte x, byte y, byte r, byte g, byte b) {
  if ( (x>=0 && x<8) && (y>=0 && y<8) ) {
    byte mask = 0xF0;
    if ( !(x % 2) ) { // If x is unpair, shift four bit left color components
      r = (r << 4);
      g = (g << 4);
      b = (b << 4);
      mask = 0x0F;
    }
  
    x /= 2;
    replace_dot(bufBack, x, y, bufBack, x, y, r, g, b, mask);
  }
}  

void printChar(int x, int y, byte r, byte g, byte b, unsigned char ASCII) { // Print a char using array ASCII_Char as font source
  unsigned char idx;
  byte bitmask;
  int row, col;
  int l;

  if((ASCII > 64) && (ASCII < 91)) idx=ASCII-55; // Convert from ASCII to index of character's array
  else if((ASCII > 96) && (ASCII < 123)) idx=ASCII-61;
  else if((ASCII >= '0') && (ASCII <= '9')) idx=ASCII-48;
  
  l = 0;
  for (row=(7+y); row>=y; row--) {
    
    if ( row < 8 && row >= 0 ) { // Check if row is within visible area
 
      bitmask = pgm_read_byte(&(ASCII_Char[idx][l]));  // Extract the bitmask for each line of the character
      
      if ( x > 0 ) bitmask = (bitmask << x);  // Shift the bitmask according to x-offset
      else bitmask = (bitmask >> -x);
  
      for (col=0; col<4; col++) {
        if ( bitmask & B00000001 ) {  // Check the first bit of the bitmask
          replace_dot(bufBack, col, row, bufBack, col, row, (r << 4), (g << 4), (b << 4), 0x0F);
        }
        if ( bitmask & B00000010 ) {  // Check the second bit of the bitmask
          replace_dot(bufBack, col, row, bufBack, col, row, r, g, b, 0xF0);
        }
        bitmask = (bitmask >> 2);  // Shift the bitmask two bits left
      }
    }
    l++;
  }
}

/* BUFFERS HANDLING */

void swapBuffers() { // Swap Front with Back buffer
  bufFront = !bufFront;
  bufBack = !bufBack;
  while(bufCurr != bufFront) {    // Wait for display to change.
    delayMicroseconds(10);
  }
}

void showAuxBuffer(byte n) { // Show an Auxiliary buffer
  if (n < MAX_AUX_BUFFERS) {
    bufFront = n+2;
   while(bufCurr != bufFront) {  // Wait for display to change.
      delayMicroseconds(10);
    }
  }
}

void storeToAuxBuffer(byte n, byte buf) { // Store the Front (visible) buffer to Aux Buffer #
  byte x, y;
  if (n < MAX_AUX_BUFFERS) {
    n+=2;
    for (y=0; y<8; y++) {
      for (x=0; x<4; x++) {
        dots_color[n][R][y][x]=dots_color[buf][R][y][x];
        dots_color[n][G][y][x]=dots_color[buf][G][y][x];
        dots_color[n][B][y][x]=dots_color[buf][B][y][x];
      }
    }
  }
}

void getFromAuxBuffer(byte n) { // Retrieve Aux Buffer # to Back (not visibile) buffer;
  byte x, y;
  
  if (n < MAX_AUX_BUFFERS) {
    n+=2;
    for (y=0; y<8; y++) {
      for (x=0; x<4; x++) {
        dots_color[bufBack][R][y][x]=dots_color[n][R][y][x];
        dots_color[bufBack][G][y][x]=dots_color[n][G][y][x];
        dots_color[bufBack][B][y][x]=dots_color[n][B][y][x];
      }
    }
  }
}

void clearBuffer(byte r, byte g, byte b) {  // Clear the Back buffer and fill with selected color
  byte x, y;
  r = r | (r << 4);
  g = g | (g << 4);
  b = b | (b << 4);

  for (y=0; y<8; y++) {
    for (x=0; x<4; x++) {
      dots_color[bufBack][G][y][x]=g;
      dots_color[bufBack][R][y][x]=r;
      dots_color[bufBack][B][y][x]=b;
    }
  }
}

void copyFrontBuffer(int x, int y) { // Copy the Front buffer to the Back one, offsetting it by x and y
  int row, col;
  int offy, offx;
  byte t0, t1, t2;
  for (row=0; row<8; row++) {
    
    offy = row-y;
    if ( offy>=0 && offy<8 ) {
      for (col=0; col<4; col++) {
        
        offx = col+(x/2);
        if ( offx>=0 && offx<4 ) {
          if ( !(x%2) ) {
            dots_color[bufBack][R][row][col]=dots_color[bufFront][R][offy][offx];
            dots_color[bufBack][G][row][col]=dots_color[bufFront][G][offy][offx];
            dots_color[bufBack][B][row][col]=dots_color[bufFront][B][offy][offx];
          } else {
            t0 = dots_color[bufFront][R][offy][offx];
            t1 = dots_color[bufFront][G][offy][offx];
            t2 = dots_color[bufFront][B][offy][offx];
            
            if ( x >= 0 ) {
              replace_dot(bufBack, col, row, bufBack, col, row, (t0 >> 4), (t1 >> 4), (t2 >> 4), 0xF0);
              offx = col+1; // I reuse offx variable to avoid initializing a new one. This affect only the 3 lines below.
              if ( offx < 4)
                replace_dot(bufBack, offx, row, bufBack, offx, row, (t0 << 4), (t1 << 4), (t2 << 4), 0x0F);
            } else {
              replace_dot(bufBack, col, row, bufBack, col, row, (t0 << 4), (t1 << 4), (t2 << 4), 0x0F);
              offx = col-1; // I reuse offx variable to avoid initializing a new one. This affect only the 3 lines below.
              if ( offx >= 0)
                replace_dot(bufBack, offx, row, bufBack, offx, row, (t0 >> 4), (t1 >> 4), (t2 >> 4), 0xF0);
            }
            
          }
        }
        
      }
    }
    
  }
}

void replace_dot(byte fromBuf, int fromX, int fromY, byte toBuf, int toX, int toY, byte vR, byte vG, byte vB, byte mask) {
  // Replace a single dot ( 4 byte ) in toBuf buffer with the value from fromBuf buffer
  dots_color[toBuf][0][toY][toX]=(vG | (dots_color[fromBuf][0][fromY][fromX] & mask));
  dots_color[toBuf][1][toY][toX]=(vR | (dots_color[fromBuf][1][fromY][fromX] & mask));
  dots_color[toBuf][2][toY][toX]=(vB | (dots_color[fromBuf][2][fromY][fromX] & mask));
}

cont…

Raibowduino_Firmware_3_0B.pde(part 2)

/*----------------------------------------------------------------------------*/
/* I2C EVENT HANDLING FUNCTIONS                                               */
/*----------------------------------------------------------------------------*/

void receiveEvent(int howMany) {
  unsigned char i=0;
  
  while(Wire.available() > 0) { 
    RainbowCMD[i]=Wire.receive(); // BUG #1: potential overflow, writes out of bounds
    i++;
  }

  if((i==5) && (RainbowCMD[0] == 'R')) State=processing;
  else State=waitingcmd;      
}

void requestEvent(void) { // While processing or checking previous directive, request other commands
  Wire.send(State); 
  if ((State==processing) || (State==checking)) SetRequest;
}


/*----------------------------------------------------------------------------*/
/* LED MATRIX DISPLAY HANDLING                                                */
/*----------------------------------------------------------------------------*/

void flash_next_line(unsigned char line,unsigned char level) { // Scan one line
  disable_oe;
  close_all_line;

  if(line < 3) { // Open the line and close others
    PORTB  = (PINB & ~0x07) | 0x04 >> line;
    PORTD  = (PIND & ~0xF8);
  } else {
    PORTB  = (PINB & ~0x07);
    PORTD  = (PIND & ~0xF8) | 0x80 >> (line - 3);
  }
  
  shift_24_bit(line,level);
  enable_oe;
}

void shift_24_bit(unsigned char line,unsigned char level)   // Display one line by the color level in buff
{
  unsigned char color=0,row=0;
  unsigned char data0=0,data1=0;
  
  le_high;
  for(color=0;color<3;color++) { //GBR
    for(row=0;row<4;row++) {
      data1=dots_color[bufCurr][color][line][row]&0x0f;
      data0=dots_color[bufCurr][color][line][row]>>4;

      if(data0>level)  //gray scale,0x0f aways light
        shift_data_1
      else
        shift_data_0
      clk_rising;
      
      if(data1>level)
        shift_data_1
      else
        shift_data_0
      clk_rising;
    }
  }
  le_low;
}


/*----------------------------------------------------------------------------*/
/* INIT TIMERS AND INTERRUPT FUNCTIONS                                        */
/*----------------------------------------------------------------------------*/

void _init(void) // define the pin mode
{
  DDRD=0xff; // Configure ports (see http://www.arduino.cc/en/Reference/PortManipulation): digital pins 0-7 as OUTPUT
  DDRC=0xff; // analog pins 0-5 as OUTPUT
  DDRB=0xff; // digital pins 8-13 as OUTPUT
  PORTD=0;   // Configure ports data register (see link above): digital pins 0-7 as READ
  PORTB=0;   // digital pins 8-13 as READ

  level = 0;
  line = 0;

  Wire.begin(4);                  // join i2c bus (address optional for master) 
  Wire.onReceive(receiveEvent);   // define the receive function for receiving data from master
  Wire.onRequest(requestEvent);   // define the request function for the request from maseter 
  init_timer2();                  // initial the timer for scanning the LED matrix
}

void init_timer2(void) // Initialize Timer2
{
  TCCR2A |= (1 << WGM21) | (1 << WGM20);   
  TCCR2B |= (1<<CS22);                    // by clk/64
  TCCR2B &= ~((1<<CS21) | (1<<CS20));     // by clk/64
  TCCR2B &= ~((1<<WGM21) | (1<<WGM20));   // Use normal mode
  ASSR |= (0<<AS2);                       // Use internal clock - external clock not used in Arduino
  TIMSK2 |= (1<<TOIE2) | (0<<OCIE2B);     //Timer2 Overflow Interrupt Enable
  TCNT2 = GammaTab[gamma][0];
  sei();   
}

ISR(TIMER2_OVF_vect)              //Timer2 Service 
{ 
  TCNT2 = GammaTab[gamma][level]; // Reset a  scanning time by gamma value table
  flash_next_line(line,level);    // sacan the next line in LED matrix level by level.
  line++;
  if(line > 7) {                  // when have scaned all LEC the back to line 0 and add the level
    line = 0;
    level++;
    if(level>15) {
      level = 0;
      bufCurr = bufFront;         // do the actual swapping, synced with display refresh.
    }
  }
}

Rainbow.h

#ifndef Rainbow_h
#define Rainbow_h

#define FRONT_BUFFER       bufFront
#define BACK_BUFFER        bufBack

#define MAX_AUX_BUFFERS    6
#define MAX_GAMMA_SETS     4

#define BLACK              0x0, 0x0, 0x0
#define WHITE              0xF, 0xF, 0xF
#define BLUE               0x0, 0x0, 0xF
#define GREEN              0x0, 0xF, 0x0
#define RED                0xF, 0x0, 0x0

#define G                  0
#define R                  1
#define B                  2

//=============================================
//MBI5168
#define SH_DIR_OE    DDRC
#define SH_DIR_SDI   DDRC
#define SH_DIR_CLK   DDRC
#define SH_DIR_LE    DDRC

#define SH_BIT_OE    0x08
#define SH_BIT_SDI   0x01
#define SH_BIT_CLK   0x02
#define SH_BIT_LE    0x04

#define SH_PORT_OE   PORTC
#define SH_PORT_SDI  PORTC
#define SH_PORT_CLK  PORTC
#define SH_PORT_LE   PORTC
//============================================
#define clk_rising  {SH_PORT_CLK&=~SH_BIT_CLK;SH_PORT_CLK|=SH_BIT_CLK;}
#define le_high     {SH_PORT_LE|=SH_BIT_LE;}
#define le_low      {SH_PORT_LE&=~SH_BIT_LE;}
#define enable_oe   {SH_PORT_OE&=~SH_BIT_OE;}
#define disable_oe  {SH_PORT_OE|=SH_BIT_OE;}

#define shift_data_1     {SH_PORT_SDI|=SH_BIT_SDI;}
#define shift_data_0     {SH_PORT_SDI&=~SH_BIT_SDI;}

//============================================
#define close_all_line      {PORTD&=~0xf8;PORTB&=~0x07;}

//============================================
#define CheckRequest (g8Flag1&0x01)
#define SetRequest (g8Flag1|=0x01)
#define ClrRequest (g8Flag1&=~0x01)

//==============================================
#define waitingcmd 0x00
#define processing  0x01
#define checking  0x02

#endif

cont…

data.c (part 1)

#include <avr/pgmspace.h>

// Default Gamma
//unsigned char GammaTab[16]=
//    {0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7};

// Better Gamma, empirically determiened
unsigned char GammaTab[4][16]= {
    {0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7},    // Default linear gamma
    {0xFF,0xFE,0xFD,0xFC,0xFB,0xF9,0xF7,0xF5,0xF3,0xF0,0xED,0xEA,0xE7,0xE4,0xE1,0xDD},    // Progressive gamma
    {0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7},
    {0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7,0xE7}
};


unsigned char dots_color[8][3][8][4] = {
//== 0 ================================================
{
  { {0x00,0x00,0x00,0x4b}, //green 
    {0x00,0x00,0x04,0xbf},
    {0x00,0x00,0x4b,0xff},
    {0x00,0x04,0xbf,0xff},
    {0x00,0x4b,0xff,0xff},
    {0x04,0xbf,0xff,0xff},
    {0x4b,0xff,0xff,0xff},
    {0xbf,0xff,0xff,0xfd}
  },
  { {0xff,0xfd,0x71,0x00}, //red 
    {0xff,0xd7,0x10,0x00},
    {0xfd,0xf1,0x00,0x00},
    {0xda,0x10,0x00,0x00},
    {0x71,0x00,0x00,0x01},
    {0x10,0x00,0x00,0x17},
    {0x00,0x00,0x01,0x7e},
    {0x00,0x00,0x17,0xef}
  },
  { {0x06,0xef,0xff,0xff}, //blue 
    {0x6e,0xff,0xff,0xff},
    {0xef,0xff,0xff,0xfa},
    {0xff,0xff,0xff,0xa3},
    {0xff,0xff,0xfa,0x30},
    {0xff,0xfa,0xa3,0x00},
    {0xff,0xfa,0x30,0x00},
    {0xff,0xa3,0x00,0x00}
  }
},
//== 1 =================================================
{
  { {0x00,0x00,0x00,0x4b}, //green
    {0x00,0x00,0x04,0xbf},
    {0x00,0x00,0x4b,0xff},
    {0x00,0x04,0xbf,0xff},
    {0x00,0x4b,0xff,0xff},
    {0x04,0xbf,0xff,0xff},
    {0x4b,0xff,0xff,0xff},
    {0xbf,0xff,0xff,0xfd}
  },
  { {0xff,0xfd,0x71,0x00}, //red 
    {0xff,0xd7,0x10,0x00},
    {0xfd,0xf1,0x00,0x00},
    {0xda,0x10,0x00,0x00},
    {0x71,0x00,0x00,0x01},
    {0x10,0x00,0x00,0x17},
    {0x00,0x00,0x01,0x7e},
    {0x00,0x00,0x17,0xef}
  },
  { {0x06,0xef,0xff,0xff}, //blue
    {0x6e,0xff,0xff,0xff},
    {0xef,0xff,0xff,0xfa},
    {0xff,0xff,0xff,0xa3},
    {0xff,0xff,0xfa,0x30},
    {0xff,0xfa,0xa3,0x00},
    {0xff,0xfa,0x30,0x00},
    {0xff,0xa3,0x00,0x00}
  }
 },
//== 2 == AUX0 =========================================
 {
  { {0xff,0xbf,0x00,0x00}, //green
    {0xff,0xbf,0x00,0x00},
    {0xff,0xbf,0x00,0x00},
    {0xff,0xbf,0x00,0x00},
    {0xff,0xbf,0x00,0x00},
    {0xff,0xbf,0x00,0x00},
    {0x01,0x23,0x45,0x67},
    {0x89,0xab,0xcd,0xef}
  },
  { {0xff,0x00,0xff,0x00}, //red
    {0xff,0x00,0xff,0x00},
    {0xff,0x00,0xff,0x00},
    {0xff,0x00,0xff,0x00},
    {0xff,0x00,0xff,0x00},
    {0xff,0x00,0xff,0x00},
    {0x01,0x23,0x45,0x67},
    {0x89,0xab,0xcd,0xef}
  },
  { {0xf0,0xf0,0xd0,0xf0}, //blue 
    {0xf0,0xf0,0xd0,0xf0},
    {0xf0,0xf0,0xd0,0xf0},
    {0xf0,0xf0,0xd0,0xf0},
    {0xf0,0xf0,0xd0,0xf0},
    {0xf0,0xf0,0xd0,0xf0},
    {0x01,0x23,0x45,0x67},
    {0x89,0xab,0xcd,0xef}
  }
 },
//== 3 == AUX1 =========================================
 {
  { {0x00,0x00,0x00,0x00}, //green 
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x12,0x34,0x57},
    {0x89,0xAB,0xCD,0xEF},
    {0x01,0x23,0x45,0x67},
    {0x89,0xAB,0xCD,0xEF},
  },
  { {0x00,0x00,0x00,0x00}, //red
    {0x00,0x00,0x00,0x00},
    {0x00,0x12,0x34,0x57},
    {0x89,0xAB,0xCD,0xEF},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x01,0x23,0x45,0x67},
    {0x89,0xAB,0xCD,0xEF},
  },
  { {0x00,0x12,0x34,0x57}, //blue
    {0x89,0xAB,0xCD,0xEF},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x01,0x23,0x45,0x67},
    {0x89,0xAB,0xCD,0xEF},
  }
 },
//== 4 == AUX2 =========================================
 {
  { {0x00,0x00,0x00,0x4b}, //green
    {0x00,0x00,0x04,0xbf},
    {0x00,0x00,0x4b,0xff},
    {0x00,0x04,0xbf,0xff},
    {0x00,0x4b,0xff,0xff},
    {0x04,0xbf,0xff,0xff},
    {0x4b,0xff,0xff,0xff},
    {0xbf,0xff,0xff,0xfd}
  },
  { {0xff,0xfd,0x71,0x00}, //red
    {0xff,0xd7,0x10,0x00},
    {0xfd,0xf1,0x00,0x00},
    {0xda,0x10,0x00,0x00},
    {0x71,0x00,0x00,0x01},
    {0x10,0x00,0x00,0x17},
    {0x00,0x00,0x01,0x7e},
    {0x00,0x00,0x17,0xef}
  },
  { {0x06,0xef,0xff,0xff}, //blue
    {0x6e,0xff,0xff,0xff},
    {0xef,0xff,0xff,0xfa},
    {0xff,0xff,0xff,0xa3},
    {0xff,0xff,0xfa,0x30},
    {0xff,0xfa,0xa3,0x00},
    {0xff,0xfa,0x30,0x00},
    {0xff,0xa3,0x00,0x00}
  }
 },
//== 5 == AUX3 =========================================
 {
  { {0x00,0x00,0x00,0x00}, //green
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00}
  },
  { {0x0f,0xff,0xff,0xff}, //red
    {0x0f,0xff,0xff,0xff},
    {0x0f,0xff,0xff,0xff},
    {0x0f,0xff,0xff,0xff},
    {0x0f,0xff,0xff,0xff},
    {0x0f,0xff,0xff,0xff},
    {0x0f,0xff,0xff,0xff},
    {0x0f,0xff,0xff,0xff}
  },
  { {0x00,0x00,0x00,0x00}, //blue
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00}
  }
 },
//== 6 == AUX4 =========================================
 {
  { {0xff,0xfd,0x71,0x00}, //green
    {0xff,0xfd,0x71,0x00},
    {0xff,0xfd,0x71,0x00},
    {0xff,0xfd,0x71,0x00},
    {0xff,0xfd,0x71,0x00},
    {0xff,0xfd,0x71,0x00},
    {0xff,0xfd,0x71,0x00},
    {0xff,0xfd,0x71,0x00}
  },
  { {0x00,0x00,0x00,0x00}, //red
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00}
  },
  { {0x00,0x00,0x00,0x00}, //blue
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00},
    {0x00,0x00,0x00,0x00}
  }
 },
//== 7 == AUX5 =========================================
 {
  { {0xFF,0xFF,0xFF,0x4b}, //green
    {0xFF,0xFF,0xF4,0xbf},
    {0x00,0x00,0x4b,0xff},
    {0x00,0x04,0xbf,0xff},
    {0x00,0x4b,0xff,0xff},
    {0x04,0xbf,0xff,0xff},
    {0x4b,0xff,0xff,0xff},
    {0xbf,0xff,0xff,0xfd}
  },
  { {0xff,0xfd,0x71,0x00}, //red
    {0xff,0xd7,0x10,0x00},
    {0xfd,0xf1,0x00,0x00},
    {0xda,0x10,0x00,0x00},
    {0x71,0x00,0x00,0x01},
    {0x10,0x00,0x00,0x17},
    {0x00,0x00,0x01,0x7e},
    {0x00,0x00,0x17,0xef}
  },
  { {0x06,0xef,0xff,0xff}, //blue
    {0x6e,0xff,0xff,0xff},
    {0xef,0xff,0xff,0xfa},
    {0xff,0xff,0xff,0xa3},
    {0xff,0xff,0xfa,0x30},
    {0xff,0xfa,0xa3,0x00},
    {0xff,0xfa,0x30,0x00},
    {0xff,0xa3,0x00,0x00}
  }
 },
//== 8 == AUX6 =========================================
 {
  { {0xFF,0xFF,0xFF,0x4b}, //green
    {0xFF,0xFF,0xF4,0xbf},
    {0x00,0x00,0x4b,0xff},
    {0x00,0x04,0xbf,0xff},
    {0x00,0x4b,0xff,0xff},
    {0x04,0xbf,0xff,0xff},
    {0x4b,0xff,0xff,0xff},
    {0xbf,0xff,0xff,0xfd}
  },
  { {0xff,0xfd,0x71,0x00}, //red
    {0xff,0xd7,0x10,0x00},
    {0xfd,0xf1,0x00,0x00},
    {0xda,0x10,0x00,0x00},
    {0x71,0x00,0x00,0x01},
    {0x10,0x00,0x00,0x17},
    {0x00,0x00,0x01,0x7e},
    {0x00,0x00,0x17,0xef}
  },
  { {0x06,0xef,0xff,0xff}, //blue
    {0x6e,0xff,0xff,0xff},
    {0xef,0xff,0xff,0xfa},
    {0xff,0xff,0xff,0xa3},
    {0xff,0xff,0xfa,0x30},
    {0xff,0xfa,0xa3,0x00},
    {0xff,0xfa,0x30,0x00},
    {0xff,0xa3,0x00,0x00}
  }
 }
};

unsigned char ASCII_Char[62][8] PROGMEM = {
    {0x0,0x38,0x44,0x4C,0x54,0x64,0x44,0x38},   // 0
    {0x0,0x38,0x10,0x10,0x10,0x10,0x18,0x10},   // 1
    {0x0,0x7C,0x8,0x10,0x20,0x40,0x44,0x38},    // 2
    {0x0,0x38,0x44,0x40,0x20,0x10,0x20,0x7C},   // 3
    {0x0,0x20,0x20,0x7C,0x24,0x28,0x30,0x20},   // 4
    {0x0,0x38,0x44,0x40,0x40,0x3C,0x4,0x7C},    // 5
    {0x0,0x38,0x44,0x44,0x3C,0x4,0x8,0x30},     // 6
    {0x0,0x8,0x8,0x8,0x10,0x20,0x40,0x7C},      // 7
    {0x0,0x38,0x44,0x44,0x38,0x44,0x44,0x38},   // 8
    {0x0,0x18,0x20,0x40,0x78,0x44,0x44,0x38},    // 9

    {0x0,0x44,0x44,0x7C,0x44,0x44,0x28,0x10},//A
    {0x0,0x3C,0x44,0x44,0x3C,0x44,0x44,0x3C},//B   
    {0x0,0x38,0x44,0x4,0x4,0x4,0x44,0x38},//C   
    {0x0,0x1C,0x24,0x44,0x44,0x44,0x24,0x1C},//D  
    {0x0,0x7C,0x4,0x4,0x3C,0x4,0x4,0x7C}, //E
    {0x0,0x4,0x4,0x4,0x3C,0x4,0x4,0x7C}, //F
    {0x0,0x78,0x44,0x44,0x74,0x4,0x44,0x38},//G
    {0x0,0x44,0x44,0x44,0x7C,0x44,0x44,0x44}, //H
    {0x0,0x38,0x10,0x10,0x10,0x10,0x10,0x38} , //I
    {0x0,0x18,0x24,0x20,0x20,0x20,0x20,0x70},  //J
    {0x0,0x44,0x24,0x14,0xC,0x14,0x24,0x44},   //K
    {0x0,0x7C,0x4,0x4,0x4,0x4,0x4,0x4},//L
    {0x0,0x44,0x44,0x44,0x54,0x54,0x6C,0x44}, //M
    {0x0,0x44,0x44,0x64,0x54,0x4C,0x44,0x44},  //N
    {0x0,0x38,0x44,0x44,0x44,0x44,0x44,0x38},  //O
    {0x0,0x4,0x4,0x4,0x3C,0x44,0x44,0x3C},   //P
    {0x0,0x58,0x24,0x54,0x44,0x44,0x44,0x38},//Q
    {0x0,0x44,0x24,0x14,0x3C,0x44,0x44,0x3C},  //R
    {0x0,0x3C,0x40,0x40,0x38,0x4,0x4,0x78},//S
    {0x0,0x10,0x10,0x10,0x10,0x10,0x10,0x7C},// T
    {0x0,0x38,0x44,0x44,0x44,0x44,0x44,0x44},// U   
    {0x0,0x10,0x28,0x44,0x44,0x44,0x44,0x44},// V     
    {0x0,0x28,0x54,0x54,0x54,0x44,0x44,0x44},// W    
    {0x0,0x44,0x44,0x28,0x10,0x28,0x44,0x44},// X   
    {0x0,0x10,0x10,0x10,0x28,0x44,0x44,0x44},// Y    
    {0x0,0x7C,0x4,0x8,0x10,0x20,0x40,0x7C},// Z

cont…

data.c (part 2)

    {0x0,0x78,0x44,0x78,0x40,0x38,0x0,0x0},// a   
    {0x0,0x3C,0x44,0x44,0x4C,0x34,0x4,0x4},// b    
    {0x0,0x38,0x44,0x4,0x4,0x38,0x0,0x0},// c    
    {0x0,0x78,0x44,0x44,0x64,0x58,0x40,0x40},// d    
    {0x0,0x38,0x4,0x7C,0x44,0x38,0x0,0x0},// e    
    {0x0,0x8,0x8,0x8,0x1C,0x8,0x48,0x30},// f    
    {0x38,0x40,0x78,0x44,0x44,0x78,0x0,0x0},// g    
    {0x0,0x44,0x44,0x44,0x4C,0x34,0x4,0x4},// h   
    {0x0,0x38,0x10,0x10,0x10,0x18,0x0,0x10},// i    
    {0x18,0x24,0x20,0x20,0x20,0x30,0x0,0x20},// j    
    {0x0,0x24,0x14,0xC,0x14,0x24,0x4,0x4},// k    
    {0x0,0x38,0x10,0x10,0x10,0x10,0x10,0x18},// l    
    {0x0,0x44,0x44,0x54,0x54,0x2C,0x0,0x0},// m   
    {0x0,0x44,0x44,0x44,0x4C,0x34,0x0,0x0},// n    
    {0x0,0x38,0x44,0x44,0x44,0x38,0x0,0x0},// o    
    {0x4,0x4,0x3C,0x44,0x44,0x3C,0x0,0x0},// p    
    {0x40,0x40,0x58,0x64,0x64,0x58,0x0,0x0},// q   
    {0x0,0x4,0x4,0x4,0x4C,0x34,0x0,0x0},// r    
    {0x0,0x3C,0x40,0x38,0x4,0x38,0x0,0x0},// s    
    {0x0,0x30,0x48,0x8,0x8,0x1C,0x8,0x8},// t   
    {0x0,0x58,0x64,0x44,0x44,0x44,0x0,0x0},// u    
    {0x0,0x10,0x28,0x44,0x44,0x44,0x0,0x0},// v   
    {0x0,0x28,0x54,0x54,0x44,0x44,0x0,0x0},// w    
    {0x0,0x44,0x28,0x10,0x28,0x44,0x0,0x0},// x   
    {0x38,0x40,0x78,0x44,0x44,0x44,0x0,0x0},// y   
    {0x0,0x7C,0x8,0x10,0x20,0x7C,0x0,0x0},// z
};

Join togheder the code “Rainbowduino_Firmware_3_0B.pde” part 1 and 2
Join togheder the code “data.c” part 1 and 2

ALL HELP ARE WELCOME

@Uncle F:
I managed to transfer it to my Rainbowduino after having defined "gamma" in your code - and it works nicely. Keep up the good work!
Looking forward to seeing the next update.
Sic

@Sic

Did you tried to remove the clearBuffer() call in setup()?
If yes, does everything works as before or not?

Let me know...

BTW, about "gamma" variable, you should change it with "dispGamma". I forgot to change those lines when I decided to change the variable's name.

@Uncle: Yes, I removed the clearBuffer() call in setup() and, as you mentioned, nothing worked at all. Really strange.
Don’t know whether this helps: clearBuffer() can be omitted in setup() provided variables r,g,b are declared and have a value assigned in loop().

byte r; byte g; byte b;

void setup() {
  _init_gfx();
  _init();      // Initialize Ports, Timer and Interrupts
//   clearBuffer(BLACK);  // <<**THE BUG**
}

void loop() {
  r = 0;  g = 0;  b = 0;
  // Display char 'A' on black
  clearBuffer(0x0, 0x0, 0x0);
  printChar(0, 0, 0x0, 0x8, 0xf, 'A');
  swapBuffers();

Cheers Sic

@Sic

Well, I'm very confused...

I tryed to initialize and set the variables 'r', 'g' and 'b' and, in fact, removing the ClearBuffer() in setup() it works...

But, damm'it, I don't understand why...

I mean, those variables are used only inside the functions and they are properly initialized in the function's prototype.
Where is the damm bug... I know, it's something really stupid, and it has to be somewhere...

Anyway, I'm now going to work on the I2C part... I'll keep you updated.
Let me know if you find the bloody bug.

Best,
Fester

BUG: at the end of the loop(), you need to add an extra "swapBuffers();" to avoid that the buffers go out of synch.
When they go out of synch, you see that the scrolling "P" has a jerky movement and the blue "D" against yellow disappear.
This is another thing that I can not fully explain...
Let me know if, without the extra swapBuffers(), this happes also to you.

@ Fester:
Can observe the same for the additionally required swapBuffers() in loop(). Right, looks like buffers are out of sync. But not in the very first and second run. Disappearance of the blue 'D' starts with run 3 onwards every second time, i.e. in run 3, 5, 7 and so on it's gone whereas there are no issues in run 1,2,4,6, etc.

Strangely enough: If you skip cycling the aux buffers, everything stays in sync and additonal sawpBuffers() at the end of loop() is not needed anymore.
Cheers
Sic

@Sic

Thanks very much, I've figured out where the problem is.

The bug is that, after the call showAuxBuffer(), on the next swapBuffers() call there is the risk that bufFront and bufBack gets the same value.
This means that, after this point, the buffer is written while shown.

I think that changing swapBuffers() function in this way, the problem should be solved:

void swapBuffers() { // Swap Front with Back buffer
  if ( bufFront > 1 ) { // If we're showing an Aux Buffer
    bufFront = bufBack;
    bufBack = !bufBack;
  } else {
    bufFront = !bufFront;
    bufBack = !bufBack;
  }
  while(bufCurr != bufFront) {    // Wait for display to change.
    delayMicroseconds(10);
  }
}

ADD: weel, looks like it works, even without the last extra swapBuffers()... let me know if it does work for you.

Damm thing, I'm getting crazy.

@Sic et alt.
Sic, guys, I NEED YOUR HELP!

I can't manage to make the I2C work in my code. The funny thing is that the I2C part, like most (if not all) of the low-level part is copied from the original firmware.

Load my firmware on the Rainbowduino hardware. Rainbowduino_Firmware_v3_0e.zip

Then, load my master software on the Arduino 2009.
Rainbowduino_v3_0_Master.zip

The master software, on the Arduino 2009, prints to the serial port. Opening the terminal in the Arduino Development Environment, you're supposed to see the ouput of each turn of the cycle in loop().
Unfortunately it hangs during the first run. It outputs only '0'.

Now, if you load on the Rainbow the original firmware (Rainbow_CMD_2.0), maybe with a little change (only for testing purpose) removing the check that each chain received via I2C must be 5 byte long, and you start again the master software on the Arduino 2009, you'll see that everything works.
Here is my modified version (only for testing purpose) of Rainbow_CMD_2_0_mod.zip

Well, if you compare, line-by-line (character-by-character) the two codes (Raibowduino_Firmware_v3_0.pde and Rainbow_CMD_2_0.pde), you'll see that they match perfectly. Or, at least, that's what I see.
Why my code does not work?

I really don't understand: either I'm getting dumb or there is something really strange happening.
Or, maybe, there is a tiny, little, stupid mistake, invisible to my eyes.

Don't know... I must admit I'm newby on Arduino, but regarding coding I've have quite a bit of experience... Uffa, I miss a proper debugger.

I hope that the links will work, I'm testing Google Docs.
Looking forward for your help,
cheers,
Fester.

ADD: not sure that Google Docs works also for non-members. Here there is another link to those files:
Rainbowduino_Firmware_v3_0e.zip (7.84KB)
Rainbowduino_v3_0_Master.zip (1.05KB)
Rainbow_CMD_V2_0_mod.zip (4.51KB)

Bug must be located in rainbow.h
Used the original version and just added your #definitions
…and it works.
Hang in there!
Cheers
Sic

@Sic

Once again thanks for the hint... I'm going to investigate, even if I've checked it many times...

But the circle is getting narrow... we'll find the bloody bug.

Thanks man, I really apreciate your precious help.

@Sic

No, it still does not work.

I'm now using exactly the original rainbow.h, I resolved and removed every one of my defines. The only difference is that my one is called "rainbow_copy.h", but I think it doesn't matter.

But still, it hangs... bloody thing!

I fell my self like an idiot, I cannot manage to find the difference between the original code and my one.

If you have anything that works, please send it to me...

Cheers,
Fester

Sorry for that. Looks like I was too fast yesterday. Took me a while to figure out what I actually did:
Before I exchanged rainbow.h I had replaced data.c. When I changed it back the declaration of ‘dots_color’ with its old dimensions, i.e. [5][3][8][4], was still there. That was/is the reason why your master file was/is cycling through the loop.
Cheers
Sic

@Sic

Don't be sorry, you're helping me a lot and I'm most thankfull for that.

So, if I understand, the problem should be in data.c?
May be I ran out of SRAM? Well, I expect to have some sort of warning for that...

I made a simple count. SRAM should be 1024b (I guess it's the same also for the Rainbowduino, but I havn't checked in deep).
dots_color is 833*4, 768bytes.
GammaTab is 64bytes.
ASCII_Char does not count because it should be in the PROGMEM space.
Even if I add an extra 100byte for the variables used in the code (wich I guess is large enough), I'm still below the 1024b.

Anyway, I'm going to investigate on data.c. Little by litte, removing every single piece of code I've added, I sould remain with the bug in my hand... at least I hope.

I'll keep you posted.

@Sic,

I FOUND THE BLOODY DAMM BUG!
And I'm the dumbest man in the world.

Yes, the bug was in data.c and it's, as I supposed, stupid, tiny and almost invisible.

Here it is:

unsigned char dots_color[8][3][8][4] = {
//== 0 ==========
{
  { {0x00,0x00,0x00,0x4b}, //green 
    {0x00,0x00,0x04,0xbf},

(...)

//== 8 == AUX6 ====
  { {0xFF,0xFF,0xFF,0x4b}, //green
    {0xFF,0xFF,0xF4,0xbf},
    {0x00,0x00,0x4b,0xff},

(...)

    {0xff,0xa3,0x00,0x00}
  }
 }
};

Well, it's not needed to be a Pure Math Scientist to calculate that from buffer 0 to buffer 8 makes a total of nine buffers, not eight as I have initialized the array.

I can blame the compiler, but I think it's more honest to blame my self.

Ok, now we're back on track... I'll keep you posted, as usual.

Thanks again, you helped me a lot to reduce the circle of possibilities around the damm bug.

Cheers,
Fester

ADD: after further testing, I have to say that there is also a problem of memory (or, at least, this is what I suppose). I cannot manage to have more than 6 buffer.
Now, with dots_color dimensioned [6][3][8][4] it works (without the extra clean buffer or your solution of initializing r, g and b);
with dots_color dimensioned [7][3][8][4] (or more) it hangs as usual.
Not sure of how much SRAM is available in the Rainbowduino and how much of it I'm using.

@Sic, et alt...

At last, the firmware is now working. Here you find a link to the latest version (it includes the firmware for the Rainbowdouino and the master code for the controlling Arduino): Firmware_v_3_0f.zip (it's Google Docs, let me know if it works, otherwise I'll use the other method)

I've reduced the number of Aux Buffers to 4 (AUX0 to AUX3) for a total of 6 buffers (as I wrote on the previous post, for memory reasons).
The GammaTab also reduces to 3, even if I'm not sure that a gamma array is useful.
Probably it's better to have a color index table (maybe for some sort of plasma color cycling?). It sould be dimensioned [3][16] or, may be, [2][3][16]... well, we'll see...

Let me know what you think about the code. Any idea or suggestion is welcome.

Cheers,
Fester

@Sic, at alt...

Throw away any previous version, and download this one:
[u]Rainbowduino_Firmware_v3_0g.zip[/u] (via Google Projects)
or
[u]Rainbowduino_Firmware_v3_0g.zip[/u] (via Google Documents)
Please let me know if one of them (if not both) doesn't work.

Hopefully the nasty bugs I was experiencing are solved, and the architecture is getting shape.
I'm starting to be satisfied about the I2C part, I can also control more tha one Rainbowduino independently. You just need to flash each Rainbowduino with a different value for I2C_DEVICE_ADDRESS.

Also the Master side is getting there. I have, now, a unique function to send commands, with a variable number of arguments, to the slave Rainbowduino.

Please, test it, enjoy it, and give me your impression, suggestion and ideas.

Looking forward your comments.
Fester

ADD: a proper Google Code project is now available here: [u]http://code.google.com/rainbowduino-firmware[/u]

Great!! Well done!
Tested it as is successfully on my rainbowduino.
Until recently I was regretting having bought that non-documented piece of hardware - now I'm thinking already of buying another one to expand to 16x8 pixels... :slight_smile:
Thanks
Sic

(However, I didn't manage to get my favorite function to work: CMD_SET_PIXEL / SetPixel() - I guess the arguments are still x, y, R, G, B ?)