MAX7219  & LED Matrix limitations?

hi, I'm using a MAX7219 to drive a Kingbright 8x8 LED Matrix.

Arduino is receiving serial data from Processing - 8 bytes, 10 times per second. This gets written to the Matrix, each serial byte is a row in a Sprite object, so the whole Matrix is being animated 10 times per second.

I'm using the Matrix and Sprite Libraries, and all is good, but things tend to crap out after 64 'frames' of animation. This is still the case if I slow things down to 1 frame per second - the LED Array goes blank after 64 refreshes.

So, is there a buffer in the MAX7219 which gets full, or some other feature of the hardware that might need attention?

There seems to nothing in these libraries to clear buffers or some such, and looking at the MAX7219 datasheet there are no likely registers other than "Scan Limit" and "Shutdown"

BTY I'm using Matrix and Sprite Libraries as I didn't get good results with LEDarray.

Any suggestions here? Many thanks, Tobie

ok, I have this working well now. I used the lower level code posted here by tomk ness here - Arduino Playground - Max7219, there's an error in line 62+63, should be this:

byte max7219_reg_digit6      = 0x07;
byte max7219_reg_digit7      = 0x08;

Here's the code I'm happy with, it takes 8 bytes sent from Processing to generate the output for the LED matrix:

/* 
 code for max 7219 from maxim, controlling an 8x8 LED matrix
 
 Orginal code by Nicholas Zambetti and Dave Mellis Interaction Design Institute Ivrea Dec 2004
 First modification by Marcus Hannerstig  K3, malmö högskola 2006
 Second modification by tomekness FH-Potsdam Feb 2007
 This version Tobie Kerridge ar Goldsmiths London March 2008
 
 This version looks for incoming serial bytes to create the Matrix pattern
 Processing is taking video input and sending the data as 8 bytes
 
 */

// define pins for the max7219 
nt dataIn = 5;
int load = 6;
int clock = 7;

// define max7219 registers, these are in the Maxim datasheet
byte max7219_reg_noop        = 0x00;
byte max7219_reg_digit0      = 0x01;
byte max7219_reg_digit1      = 0x02;
byte max7219_reg_digit2      = 0x03;
byte max7219_reg_digit3      = 0x04;
byte max7219_reg_digit4      = 0x05;
byte max7219_reg_digit5      = 0x06;
byte max7219_reg_digit6      = 0x07;
byte max7219_reg_digit7      = 0x08;
byte max7219_reg_decodeMode  = 0x09;
byte max7219_reg_intensity   = 0x0a;
byte max7219_reg_scanLimit   = 0x0b;
byte max7219_reg_shutdown    = 0x0c;
byte max7219_reg_displayTest = 0x0f;

// aditional pins and global variables
int debugPin = 13;   
int byteHeadCount;
int byteDataCount;
int prevByteValue;
int matrixFrameCount;
char incomingByte;
byte byteData[8];
boolean byteDataFlag = false;

void setup() 
{ 
  // inintialise serial port:
  Serial.begin(9600);
  
  // set up I/O for the max7219
  pinMode(dataIn, OUTPUT);
  pinMode(clock,  OUTPUT);
  pinMode(load,   OUTPUT); 

  //initialise the max 7219
  maxSingle(max7219_reg_scanLimit, 0x07);      
  maxSingle(max7219_reg_decodeMode, 0x00);
  maxSingle(max7219_reg_shutdown, 0x01);
  maxSingle(max7219_reg_displayTest, 0x00);
  // clear matrix
  for (int e=1; e<=8; e++) {
    maxSingle(e,0);
  }
  maxSingle(max7219_reg_intensity, 0x0f & 0x0f);
} 

void loop() 
{ 
  // look for incoming serial data:
  if (Serial.available() > 0) {
    // read the incoming byte:
    incomingByte = Serial.read();
    if (byteDataFlag){
      readSerData(); 
    }
    else{
      readSerHeader(); 
    }
    prevByteValue = incomingByte;
  }
} 

// this function collects 8 bytes of useful data
void readSerData(){
  byteData[byteDataCount] = incomingByte;
  byteDataCount++;
  if (byteDataCount == 8){
    byteDataFlag = false;
    serBytesToMatrix();
    byteDataCount = 0;
  }
} 

// this function looks for 8 matching header bytes
void readSerHeader(){
  // count header bytes
  if (incomingByte == 85) {
    if (prevByteValue == 85) {
      byteHeadCount++;
    }
    if (byteHeadCount == 7) {
      byteHeadCount = 0;
      byteDataFlag = true;
    }
  }
  else{
    byteHeadCount = 0; 
  }
}

// this function writes data bytes to the LED Matrix
void serBytesToMatrix(){
  blankMatrix();
  maxSingle(1,byteData[0]);
  maxSingle(2,byteData[1]);
  maxSingle(3,byteData[2]);
  maxSingle(4,byteData[3]);
  maxSingle(5,byteData[4]);
  maxSingle(6,byteData[5]);
  maxSingle(7,byteData[6]);
  maxSingle(8,byteData[7]);
}

// some clever bit shifting here to use the max7219
void putByte(byte data) {
  byte i = 8;
  byte mask;
  while(i > 0) {
    mask = 0x01 << (i - 1);      // get bitmask
    digitalWrite( clock, LOW);   // tick
    if (data & mask){            // choose bit
      digitalWrite(dataIn, HIGH);// send 1
    }
    else{
      digitalWrite(dataIn, LOW); // send 0
    }
    digitalWrite(clock, HIGH);   // tock
    --i;                         // move to lesser bit
  }
}

// talks to the max7219
void maxSingle( byte reg, byte col) {    
  digitalWrite(load, LOW);       // begin    
  putByte(reg);                  // specify register
  putByte(col);//((data & 0x01) * 256) + data >> 1); // put data  
  digitalWrite(load, LOW);       // and load da shit
  digitalWrite(load,HIGH);
}

// uses the 2 functions above
void blankMatrix(){
  // empty registers, turn all LEDs off
  for (int e=1; e<=8; e++) {
    maxSingle(e,0);
  } 
}

// something to check things are well
void initAnimation() {
  blankMatrix();
  delay(1000);
  maxSingle(1,B00000001);
  delay(100);
  maxSingle(2,B00000010);
  delay(100);
  maxSingle(3,B00000100);
  delay(100);
  maxSingle(4,B00001000);
  delay(100);
  maxSingle(5,B00010000);
  delay(100);
  maxSingle(6,B00100000);
  delay(100);
  maxSingle(7,B01000000);
  delay(100);
  maxSingle(8,B10000000);
  delay(100);  
}

ah, although this is a hardware section, here's the matching Processig code which take input from video -

/*
 * This takes a small camera feed, and scales it to fit the screen
 * It also uses the matrix data to send serial bytes to Arduino
 * Arduino can then draw the live camera matrix to an LED array 
 * thanks to initial code for Brightness Thresholding by Golan Levin. 
 *
 * Tobie Kerridge, Goldsmiths, University of London March 2008
 * 
 */

import processing.video.*;
import processing.serial.*;
Capture video;
Serial arduinoSerPort;

color black = color(0);
color white = color(255);
int threshold = 127; // Set the threshold value
float pixelBrightness; // Declare variable to store a pixel's color
//single matrix=8,8,80 3x3Matrix=24,24,24 8x6Matrix=64,48,10
int numPixels;
int matrixWidth = 8;
int matrixHeight = 8;
int matrixMult = 80;
int screenWidth = matrixWidth * matrixMult;
int screenHeight = matrixHeight * matrixMult;
int cycles;
int bitValue;
int[] matrixBitTable = new int[matrixWidth*matrixHeight];
byte [] serialBytes = new byte[8];
String tempSerialString = "";
boolean dataDump = false;


void setup() {
  size(screenWidth, screenHeight);
  // Uses the default video input, see the reference if this causes an error
  video = new Capture(this, matrixWidth, matrixHeight, 12);
  //frameRate(6);
  numPixels = matrixWidth * matrixHeight;
  noCursor();
  // Open the port that the board is connected to and use the same speed (9600 bps)
  println(Serial.list());
  arduinoSerPort = new Serial(this, Serial.list()[0], 9600);
  //arduinoSerPort = new Serial(this, "/dev/tty.usbserial-A4004BWB", 9600);

}

// 
void draw() {
  if (video.available()) {
    // 1) get input from video camera:
    video.read();
    video.loadPixels();
    loadPixels();
    int matrix_x = 0;
    int matrix_y = 0;

    // 2) Draw video pixels to a scaled grid
    // a single pixel from the video feed gets drawn as a set of pixels
    for (int i = 0; i < numPixels; i++) {
      pixelBrightness = brightness(video.pixels[i]);
      // test to see if the thresholded value is White: 
      if (pixelBrightness > threshold) {
        for (int offset_x = 0; offset_x < matrixMult; offset_x++) {
          for (int offset_y = 0; offset_y < matrixMult; offset_y++) {
            int tempPixel = (matrix_x * matrixMult) + ((matrix_y * matrixMult) * screenWidth);
            pixels[tempPixel+offset_x+(screenWidth * offset_y)] = white;
          }
        }
        bitValue = 1;
      } 
      // the thresholded value is black:
      else { 
        for (int offset_x = 0; offset_x < matrixMult; offset_x++) {
          for (int offset_y = 0; offset_y < matrixMult; offset_y++) {
            int tempPixel = (matrix_x * matrixMult) + ((matrix_y * matrixMult) * screenWidth);
            pixels[tempPixel+offset_x+(screenWidth * offset_y)] = black;
          }
        }
        bitValue = 0;
      }
      // create an array to hold bitvalues for Arduino LED - this is using an 8x8 displayonly
      int boolLoc = matrix_x + (matrix_y * 8);
      matrixBitTable[boolLoc] = bitValue;
      // update a model of the video grid as we scan through the pixels
      matrix_x++;
      if(matrix_x == matrixWidth){
        matrix_x = 0;
        matrix_y++;
      }
    }

    // 4) update the image on the screen:
    updatePixels();
    cycles++;

    // 5) send bytes to Arduino
    // send some strangely symetrical bytes as a header packet:
    for (int x = 0; x < 8; x++) {
      arduinoSerPort.write(85);
    }
    // put bitvalues from the camera into serial bytes  - this is using an 8x8 display only
    for (int x = 0; x < 8; x++) {
      tempSerialString = "";
      // build a bit sequence as a string for conversion
      for (int y = 0; y < 8; y++) {
        int tablePointer = y+(8*x);
        tempSerialString += str(matrixBitTable[tablePointer]);
      }
      // convert that binary string into a byte value, and send it!:
      int tempInt = unbinary(tempSerialString);
      print(tempSerialString+", ");
      byte tempByte = byte(tempInt);
      serialBytes[x] = tempByte;
      arduinoSerPort.write(serialBytes[x]); 
      //print(serialBytes[x]+", ");
    }
    println("");
    
    //delay(10000);
  }
}

Thanks Tobie,

ok, I have this working well now. I used the lower level code posted here by tomk ness here - http://www.arduino.cc/playground/LEDMatrix/Max7219, there's an error in line 62+63, should be this:

byte max7219_reg_digit6      = 0x07;

byte max7219_reg_digit7      = 0x08;

I fixed it in the playground article

Eberhard