Direct drive 5x7 Matrix Serial Control (animation)

Hi, i've just attached a 5x7 Matrix to my arduino and been successful to control it using a few example projects i found around the forum.
Now i'm trying to Customize the code to display frames received through serial port.

for now i'm using "FrequencyTimer2" for interrupts, i've also read about the TimerOne library...can anyone advise me as to which one would be better for the job?

The idea was to sent picture information row by row as one byte per row in the form of
'00000', (0)
'11111', (31)
....
with some value like 255 as a new frame signal.

(there is no code for any serial transmission yet since i haven't figured out the strategy for synchronizing the frame transfer from the processing output with my arduino input)

i'm stuck in the early beginning while translating the binary values to individual pixels per column.

i've read the bitmask tutorial at http://www.arduino.cc/en/Tutorial/BitMask
after trying to adapt it to my needs i seem to get jibberish for the output (which probably results from mistakes on my part ^^)

here's what i've got so far:

#include <FrequencyTimer2.h>

/**/
const int rows[] = { 1,2,3,4,5,6,7 };
const int cols[] = { 8, 9, 10, 11, 12 };

const int NUM_COLS = 5;
const int NUM_ROWS = 7;

void setup()
{  
  // initialize output pins
  for (int c = 0; c < NUM_COLS; c++)
  {
    pinMode(cols[c], OUTPUT);
    digitalWrite(cols[c], LOW);
  }

  for (int r = 0; r < NUM_ROWS; r++)
  {
    pinMode(rows[r], OUTPUT);
    digitalWrite(rows[r], LOW);
  }
 // configure frequencyTimer2
 FrequencyTimer2::disable();
 FrequencyTimer2::setPeriod(2000);
 FrequencyTimer2::setOnOverflow(refresh);
}

// test-buffer
byte buffer[NUM_ROWS] = {
    11111,
    11111,
    11111,
    11111,
    11111,
    11111,
    11111
};

int col = NUM_COLS - 1;
int row = NUM_ROWS - 1;

void refresh()
{  
  digitalWrite(rows[row], HIGH);
  
  row++;
  if (row >= NUM_ROWS)
    row = 0;
    
  byte mask = 10000;
  
  for (int col = 0; col < NUM_COLS; col++){   
    digitalWrite(cols[col], (buffer[row] & mask) ? HIGH : LOW); // this is where i screw up, is it?? ^^
    mask >>= 1; 
  }  
  
 digitalWrite(rows[row], LOW);
}
  
void loop()
{
  delay(1000);  
}

thanks to anyone who is willing to help :slight_smile:

All your values that you give in binary (buffer and mask) need to have "B" before them, otherwise they're treated as decimals. For example, in the Buffer, you have seven values of 11111, which is the same as 10101101100111 in binary - which gets truncated to 1100111 to fit in a byte, and then to 100111 to fit on the display. Same thing in the "mask" - 10000 is 10011100010000 in binary (which actually gets truncated to the correct value.. huh).

Anyway, just remember to add that B before putting in anything binary!

Thanks, i've figured it out for now....the tutorial left me confused because i haven't seen any 'B's there, now i see they have the data as decimals, and the mask as 000001, which is 1 both in decimal and binary so no B needed there.
anyways i've corrected my code and it works fine.
Now i'm coming to the tricky bit of receiving frames via serial, which is working (kind of) but quite slow...i will post the code later when i'm at work.

Anything regarding TimerOne? is there any difference (speed?) in handling interrupts between it and FrequencyTimer2?

Thanks!!

Alright, this is what i've got so far...I sketched up a simple routine to retrieve columns from serial buffer (i guess it would be more efficient to do everything by row instead of column, since i would only need 5 bytes for a frame instead of 7 (while still having the option to have control bytes for frame start and frame end)...it's on the toDo list)

right now my problem is that the response is kind of slow (about 300ms to fill a frame), any idea why?
I'm still clueless about how to manage any overflow issues when i receive more columns than the aruino can handle because they will just build up in the buffer...

#include <FrequencyTimer2.h>

/**/
const int rows[] = { 13,2,3,4,5,6,7 };
const int cols[] = { 8, 9, 10, 11, 12 };

const int NUM_COLS = 5;
const int NUM_ROWS = 7;

void setup()
{  
  Serial.begin(9600);
  // initialize output pins
  for (int c = 0; c < NUM_COLS; c++)
  {
    pinMode(cols[c], OUTPUT);
    digitalWrite(cols[c], LOW);
  }

  for (int r = 0; r < NUM_ROWS; r++)
  {
    pinMode(rows[r], OUTPUT);
    digitalWrite(rows[r], LOW);
  }
 // configure frequencyTimer2
 FrequencyTimer2::disable();
 FrequencyTimer2::setPeriod(2000);
 FrequencyTimer2::setOnOverflow(refresh);
}

// test-buffer
byte buffer[NUM_ROWS] = {
    B11111,
    B10001,
    B10101,
    B11111,
    B10101,
    B10001,
    B11111
};

int col = NUM_COLS - 1;
int row = NUM_ROWS - 1;

void refresh()
{   
  digitalWrite(rows[row], HIGH); 
  row++;
  if (row >= NUM_ROWS)
    row = 0;
    
  for (int col = 0; col < NUM_ROWS; col++){   
    digitalWrite(cols[col], (buffer[row] & (1<<col)) ? HIGH : LOW);
  } 
 digitalWrite(rows[row], LOW);
}
  
int y=0;
void loop()
{
  readSerial();
}

void readSerial(){
  if (Serial.available()){
    if (y==NUM_ROWS) y=0;
    buffer[y]=Serial.read();  
    y++;
  }
}

What is this?

 FrequencyTimer2::setPeriod(2000);

xanok:
What is this?

 FrequencyTimer2::setPeriod(2000);

it's the time between interrupts for freq.timer (in microseconds), i've just taken the value from one of the tutorials.. if i set it too high the matrix starts to flicker.

I don't get why it is 300ms either - it should be like 7ms. What experiment has convinced you that you are that slow? From what is the frame data sent to the Arduino? My only guess is that somehow your are too long in the interrupt routine and thus only giving very small time to the "main" program. Try changing it - fex only updating one column thus avoiding the inner loop - or lower the frequency.

OK i've got it now :slight_smile:

200 ist the sync byte that marks the start of a frame. It works quite well when I do some simple animations in Processing.

#include <FrequencyTimer2.h>

/**/
const int rows[] = { 13,2,3,4,5,6,7 };
const int cols[] = { 8, 9, 10, 11, 12 };

const int NUM_COLS = 5;
const int NUM_ROWS = 7;

void setup()
{  
  Serial.begin(9600);
  // initialize output pins
  for (int c = 0; c < NUM_COLS; c++)
  {
    pinMode(cols[c], OUTPUT);
    digitalWrite(cols[c], LOW);
  }

  for (int r = 0; r < NUM_ROWS; r++)
  {
    pinMode(rows[r], OUTPUT);
    digitalWrite(rows[r], LOW);
  }
 // configure frequencyTimer2
 FrequencyTimer2::disable();
 FrequencyTimer2::setPeriod(500);
 FrequencyTimer2::setOnOverflow(refresh);
}

// test-buffer
byte buffer[NUM_ROWS] = {
    B11111,
    B10001,
    B10101,
    B00111,
    B10101,
    B10001,
    B11111
};
byte rxBuffer[NUM_ROWS];

int col = NUM_COLS - 1;
int row = NUM_ROWS - 1;

void refresh()
{     
    digitalWrite(rows[row], HIGH);
  
    row++;
    if (row >= NUM_ROWS)
    row = 0;
    
    for (int col = 0; col < NUM_COLS; col++){   
      digitalWrite(cols[NUM_COLS-col-1], (buffer[row] & (1<<col)) ? HIGH : LOW); 
    } 
    digitalWrite(rows[row], LOW);
}

void loop()
{
  readSerial();
}

void readSerial(){
 if (Serial.available() > NUM_ROWS){    
  byte test = Serial.read();
    if(test == 200){     
      for(int i = 0; i<NUM_ROWS;i++){
          buffer[i]=Serial.read();
      }
    } 
  }
 
}