Pages: [1] 2 3   Go Down
Author Topic: ArDeci -> MAX7219 (x3) -> RGB 8x8 LED Matrix prob.  (Read 6367 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Folks, Newbie looking for his first nugget of advice.

I've just got the Arduino Deci' and am loving it. I've tinkered with the MAX7219 and the Sparkfun/Tinker.it RGB 8x8 Matrix and got it working fine with a single colour after an initial brainfart with anode/cathode connections.

Now I've gone for the big win and tried to cascade another MAX7219 to light the second colour. It has not quite worked :/

I would like to know whether I'm trying to pee up a rope and need to try another direction (to essentially recreate sparkfun's serial backpack, but hey, I'm in the UK smiley or if what I'm trying is possible and I've made a dumb error.

LED Matrix: (http://tinker.it/ukstore/product_info.php?cPath=29&products_id=70)
Matrix Datasheet: (http://www.sparkfun.com/datasheets/Components/FYM-23881ABxxx.pdf) (Shows CA version, but I'm pretty sure I have the CC version as advertised)
Tutorial I done followed: (http://www.arduino.cc/playground/LEDMatrix/Max7219)

THE PROBLEM: What happens is this: With the second chip in place, any row I try to light up shows the correct LED's brightly-lit, but all the other LED's in the row strobe as well. Power is from the ArDeci's 5v/Gnd rails and seems to be enough juice. The wiring seems pukka as ironing out a couple of bugs got me to the stage where I can see the circuit almost doing the right thing, but with *ahem* non-aesthetic side-effects.

My theories are:
  • a) The clock signal needs boosting and the power rails needs smoothing, as the playground articles mention. I will try this this week once rswww.com send me the parts I need.
  • b) The MAX7219 will not play nice when the chips are sharing the cathode rails. The circuits I've seen show cascaded chips with 16 separate connections for the cathodes and anodes for each chip. The Matrix has 32 connections, 8 K's and then 3x(8A)'s for the colours.
  • c) I've got the CA version of the matrix by accident (the serial is smudged so I cannot be 100% on this)
  • d) Something else entirely or all of the above.

Thoughts, team?  :-/

Once I've got this ironed out we can move on to PWM of all 192 LED's and why it's won't work with the MAX7219 ;P
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Obviously I didn't search hard enough as this thread seems to describe exactly the problem I have:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1200123531

Anyone who ends up here with the same problem may want to wander there :-)
Logged

Denver
Offline Offline
God Member
*****
Karma: 19
Posts: 778
Inactive - PM
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I was able to get a 2 color matrix working that had a similar configuration. The trick was to alternate the shutdown between the MAX72XX's. It worked, but it was a little flakey - hopefully due to my poor implementation of the ISR to cause the shutdown.

Here's the last link in a chain that has what I have written on this . . .
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1203615068

Here is white paper on this written by MAXIUM . . .
http://www.maxim-ic.com/appnotes.cfm/appnote_number/1004

I'm not sure if there is "enough time in a second" to get this working for 3 colors, but it might work. I'd sure like to see it work.
I'd bet if someone wrote a more sophisticated routine to handle the alternate shutdown of the 3 MAX chips - it would work.

Hope this helps, good luck.
Logged

"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Cheers for the info Bro, it did the trick. The results are a little flaky, but at least resemble something that actually works :-)

Will now go for the madness of the third colour!

Incidentally, here's my main test loop which produces no glitches but a barely perceptible flicker on the LED's, using the MAX routines from the playground:

Code:
#define DUTY_CYCLE 20
#define CYCLES_PER 50

void loop () {

  // every cycle
  // toggle shutdown
  if (maxInShutdown == MAX_FOR_RED) {
    maxOne(MAX_FOR_GREEN, max7219_reg_shutdown, 0x00);
    maxOne(MAX_FOR_RED, max7219_reg_shutdown, 0x01);
    maxInShutdown = MAX_FOR_GREEN;
  } else {
    maxOne(MAX_FOR_RED, max7219_reg_shutdown, 0x00);
    maxOne(MAX_FOR_GREEN, max7219_reg_shutdown, 0x01);
    maxInShutdown = MAX_FOR_RED;
  }

if ((millis() - previousMillis) > DUTY_CYCLE) {
  // reset difference
  previousMillis = millis();
  // increment cycle
  cycles = ++cycles % CYCLES_PER; // reset where we are in the second cycle range;
  
    jim = e;
  
    for (x=1; x<4; x++) {
      bob = jim % 256;
      maxOne(MAX_FOR_GREEN, x, bob);
      maxOne(MAX_FOR_RED, 9-x, 255-bob);
      jim = jim >> 8;
    }

    e++;
}
}

Logged

Denver
Offline Offline
God Member
*****
Karma: 19
Posts: 778
Inactive - PM
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Happy that helped. That was a good idea to test it within loop before using an ISR.
I take it, it works well with the test loop, but flaky with the ISR (rows don't always clear, etc.)
I also assume that you will eventually need to use an ISR in the real ap.
If so, I'm wondering if using the FrequencyTimer2 lib might be the way to go.
http://www.arduino.cc/playground/Code/FrequencyTimer2/
In any case, I'm curious to hear how it turns out.
Logged

"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

0
Offline Offline
Newbie
*
Karma: 0
Posts: 27
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

(piggybacking onto this thread) I found an answer to this before, but now I can't relocate.

Where does one buy a MAX7219/MAX7221?  I guess I can get "samples" from
http://www.maxim-ic.com/
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/1339/t/or
- or buy them for $14?  

Or Digikey, which I always find confusing because they have too many choices:
http://search.digikey.com/scripts/DkSearch/dksus.dll?lang=en&site=US&keywords=max7219&x=0&y=0
http://search.digikey.com/scripts/DkSearch/dksus.dll?Detail?name=MAX7219ENG%2B-ND

Suggestions?
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

OK Bro, have got the blues up and running and have been poking around with Frequency lib. Results are encouraging but not perfect. Key facts:
  • The interrupts seem to interfere with the update cycle to the matrix which seems to be causing the glitches.
  • Turning off the interrupts during updates kills glitches but means a noticeable dead space/flicker during matrix update. I will see in the next couple of days if a clock boost transistor cures this.
  • Otherwise the interrupt seems to work fine and flickerfree the rest of the time as long as the matrix update doesn't happen too often.
  • RGBFTW!
  • FrequencyTimer2 throws a compile error in the Ard 11 environment. Something about the interrupt function being prev. declared as C++.

Next I'm gonna try the clock boost and adding a decent power rail to eliminate that as a factor but it may be the update takes too long to ever work. Pertinent code below:
Code:
#include <FrequencyTimer2.h>

unsigned long bob = 0;
unsigned long jim = 0;
unsigned long mary = 0;
unsigned long previousMillis = 0;

// Below for MAX7221s with 3 color support
#define DUTY_CYCLE 500
#define MAX_FOR_GREEN 1                // The address of the MAX72XX for the green leds
#define MAX_FOR_RED 2                  // The address of the MAX72XX for the red leds
#define MAX_FOR_BLUE 3                  // The address of the MAX72XX for the blue leds
int maxInShutdown=MAX_FOR_GREEN;       // tells which MAX72XX is currently off

int dataIn = 2;
int load = 3;
int clock = 4;

int maxInUse = 3;    //change this variable to set how many MAX72XX's you'll use

unsigned long x = 0;
unsigned long e = 0;           // just a varialble

                     // define max7219 registers
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;

void maxAll (byte reg, byte col) {    // initialize  all  MAX7219's in the system
  int c = 0;
  digitalWrite(load, LOW);  // begin    
  for ( c =1; c<= maxInUse; c++) {
  shiftOut(dataIn, clock, MSBFIRST, reg);  // specify register
  shiftOut(dataIn, clock, MSBFIRST, col);//((data & 0x01) * 256) + data >> 1); // put data
    }
  digitalWrite(load, LOW);
  digitalWrite(load,HIGH);
}

void maxThree(byte rega, byte cola, byte regb, byte colb, byte regc, byte colc) {    

  int c = 0;
  digitalWrite(load, LOW);  // begin    

  shiftOut(dataIn, clock, MSBFIRST, regc);  // specify register
  shiftOut(dataIn, clock, MSBFIRST, colc);//((data & 0x01) * 256) + data >> 1); // put data

  shiftOut(dataIn, clock, MSBFIRST, regb);  // specify register
  shiftOut(dataIn, clock, MSBFIRST, colb);//((data & 0x01) * 256) + data >> 1); // put data

  shiftOut(dataIn, clock, MSBFIRST, rega);  // specify register
  shiftOut(dataIn, clock, MSBFIRST, cola);//((data & 0x01) * 256) + data >> 1); // put data

  digitalWrite(load, LOW); // and load da shit
  digitalWrite(load,HIGH);
}

// LED channel cycle function
extern "C" void tugled(void) {

  // every cycle
  // toggle shutdown
  if (maxInShutdown == MAX_FOR_RED) {
    maxThree(max7219_reg_shutdown, 0x01, max7219_reg_shutdown, 0x00, max7219_reg_shutdown, 0x00);
    maxInShutdown = MAX_FOR_GREEN;
  } else if (maxInShutdown == MAX_FOR_GREEN) {
    maxThree(max7219_reg_shutdown, 0x00, max7219_reg_shutdown, 0x01, max7219_reg_shutdown, 0x00);
    maxInShutdown = MAX_FOR_BLUE;
  } else {
    maxThree(max7219_reg_shutdown, 0x00, max7219_reg_shutdown, 0x00, max7219_reg_shutdown, 0x01);
    maxInShutdown = MAX_FOR_RED;
  }
}

void setup () {

  pinMode(dataIn, OUTPUT);
  pinMode(clock,  OUTPUT);
  pinMode(load,   OUTPUT);

  beginSerial(9600);
  digitalWrite(13, HIGH);  

//initiation of the max 7219
  maxAll(max7219_reg_scanLimit, 0x07);      
  maxAll(max7219_reg_decodeMode, 0x00);  // using an led matrix (not digits)
  maxAll(max7219_reg_shutdown, 0x00);    // in shutdown mode
  maxAll(max7219_reg_displayTest, 0x00); // no display test
  for (e=1; e<=8; e++) {    // empty registers, turn all LEDs off
    maxAll(e,0);
  }
  maxAll(max7219_reg_intensity, 0x0f & 0x0f);    // the first 0x0f is the value you can set
                                                  // range: 0x00 to 0x0f  
  pinMode(11,OUTPUT);
  FrequencyTimer2::setPeriod(2048);
  FrequencyTimer2::setOnOverflow( tugled);
  FrequencyTimer2::enable();

  e = 0;
  x = 1;

}

void loop () {

if ((millis() - previousMillis) > DUTY_CYCLE) {
  
  // reset difference
  previousMillis = millis();
  FrequencyTimer2::setOnOverflow( 0);
    jim = (e % 8)+1;
  
    for (x=1; x<=jim; x++) {
      maxThree(x, B10011011, x, B01010111, x, B00101111);
    }
    for (x=jim+1; x<=8; x++) {
      maxThree(x, B00000000, x, B00000000, x, B00000000);
    }
    
    e++;
  //}
  FrequencyTimer2::setOnOverflow( tugled);
}
}
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
(piggybacking onto this thread) I found an answer to this before, but now I can't relocate.

Where does one buy a MAX7219/MAX7221?  I guess I can get "samples" from

I think this is the thread you found, I remembered the guy was selling them for $7 so searched for that ;-)
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1203747843/10#10
Logged

Denver
Offline Offline
God Member
*****
Karma: 19
Posts: 778
Inactive - PM
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Paul,
I just tried your code and saw much better results over what I had. Thanks!
(At first I thought I had a column out, till I realized I only have a 2 color matrix!)

I think the concept of a duty cycle and not toggling shutdown any old time made the difference.
I need to understand what you're doing a little better, and then try the technique in my ap.

I notice you didn't use the LedControl lib. Do you see any reason why it couldn't be used?

Hope the 3rd color works out. Then I'll be off to the store to get another MAX and a new matrix!
Logged

"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

No reason not to use LEDControl AFAIK, the Max Lib was just the first lib I tried :-)

For the most part the app is just a kludge to get things working, but running the interrupt during the update cycle seems to be the no no, which makes sense as you're sending conflicting commands on the SPI to the chips.

The third colour is fine except for the delay and flicker while updating the grid. I want to chase this down. Updating all 192 lights takes around 5ms according to a rough timing using millis(), which seems way too short to cause flicker, so I'm going for power and clock boost now to see if that helps.
Logged

Denver
Offline Offline
God Member
*****
Karma: 19
Posts: 778
Inactive - PM
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Perhaps your flicker problem has something to do with duty cycle idea. I worked with your code to move everything out of loop() and call the matrix via LedControl lib.  Before each call to the lib, I turned off the ISR, and turned it on afterwards. However, I also got ride of the duty cycle concept, and when I did, I found I could update the display very quickly and accurately. (here's what I wound up with -

Again, it's 2 color only, but it should work for 3. Something you might try, anyway. If you like, I'll post my example.
« Last Edit: April 06, 2008, 08:26:34 pm by BroHogan » Logged

"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

0
Offline Offline
Newbie
*
Karma: 0
Posts: 9
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It's looks smooth and groovy :-> Would love to see the example!

Would also be nice to see an example of best practice for coding this schtuff up. Leads me to think I must be doing something wrong with the power though.

I've got me a boat load of single colour matrices coming from China ;-)
Logged

Denver
Offline Offline
God Member
*****
Karma: 19
Posts: 778
Inactive - PM
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

OK, completed code below. Now maybe I can unplug from the matrix!
It should be easy to add the 3rd MAX. I'd guess you'll have to tweak the timing when you do.
Good luck & keep us posted.
Code:
/* Matrix Demo 4/5/08 BroHogan
 * Demos 2 color 8x8 matrix with shared cathodes. Driven by 2 MAX7821's (see data sheet)
 * - all the rows on the first chip tied to the same row numbers on the second chip
 * - all the segments on the 2nd chip to the columns for the other color
 * Since the rows are tied together, you must put one chip in shutdown while the other writes.
 * This is done here in an ISR driven by FrequencyTimer2. Also, you shouldn't send
 * commands to the MAX's when shutdown is toggeling. Therefore, LedControl commands are
 * wrapped by code to disable and re-enable the the shutdown ISR.
 * If you run the ISR or update the matrix too fast, It will lock up.
 * Play with the ISR speed and SHORT_DELAY time to see what works for you.
 */

#include <FrequencyTimer2.h>
#include "LedControl.h"

#define GREEN_MAX 0                    // address of the MAX7221 for the green leds
#define RED_MAX 1                      // address of the MAX7221 for the red leds
#define SHORT_DELAY 10                 // minimum time between calls (5 may crash after awhile)
#define LONG_DELAY 1000                // when a long delay is needed between demos

int maxInShutdown=GREEN_MAX;           // tells which MAX7221 is currently off
byte light_green = true;               // flag for Skip_Rows()


LedControl lc=LedControl(10,9,8,2); // pin 10=DataIn, pin 9=CLK, pin 8=LOAD(CS) + 2 MAX7221s

void togShutdown(void) {    //This ISR toggles shutdown between the 2 MAX7221's
  if(maxInShutdown==RED_MAX){          // not puting BOTH in shutdown first, is much faster
    lc.shutdown(GREEN_MAX,true);
    lc.shutdown(RED_MAX,false);
    maxInShutdown=GREEN_MAX;
  }
  else {
    lc.shutdown(RED_MAX,true);
    lc.shutdown(GREEN_MAX,false);
    maxInShutdown=RED_MAX;
  }
}  

void setup() {
  lc.setIntensity(GREEN_MAX,10);       // 0 = dim, 15 = full brightness
  lc.setIntensity(RED_MAX,10);
  ClearMatrix();                       // clears both colors
  //pinMode(11,OUTPUT);                // can use for debug with piezo to test if ISR is on
  // set ISR speed - me think in Hz! (period = 1000000L/Hz) Setting is critical to operation!
  FrequencyTimer2::setPeriod(1000000L/320); // ~320Hz seems best (flicker starts @ 300Hz)
  FrequencyTimer2::setOnOverflow(togShutdown); // define the ISR
  FrequencyTimer2::enable();           // start the ISR timer
}

void loop() { // everything here is just a demo

  // 1st DEMO
  All_Rows(GREEN_MAX);                 // light up all LEDs with each color
  delay(LONG_DELAY);
  ClearMatrix();
  All_Rows(RED_MAX);
  delay(LONG_DELAY);
  ClearMatrix();
  All_Rows(GREEN_MAX);
  All_Rows(RED_MAX);
  delay(LONG_DELAY);
  ClearMatrix();

  // 2nd DEMO
  Skip_Rows();                         // good test for accuracy
  delay(LONG_DELAY);
  ClearMatrix();

  // FOURTH DEMO
  for(int i=0;i<8;i++){                // for each column . . .
    Rand_Col(i);                       // random green, red orange - trippy!
  }
  delay(LONG_DELAY);
  ClearMatrix();

  // DONE
  delay(LONG_DELAY);
}
// CONTINUED . . .

Damn those comments! - continued . . .
Logged

"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

Denver
Offline Offline
God Member
*****
Karma: 19
Posts: 778
Inactive - PM
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:

// Demo functions . . .
void All_Rows(int color) {  // lights entire matrix (by row - fastest) the selected color
  for(int row=0;row<8;row++) {
    delay(SHORT_DELAY);
    SetRow(color,row,B11111111);       // note call is NOT to LedControl, but to wrapper
  }
}

void Skip_Rows() { // 1st pass alternates green & red, 2nd adds green to red making orange
  for(int row=0;row<8;row++) {
    for(int col=0;col<8;col++) {
      delay(SHORT_DELAY);
      if (light_green == true) SetLed(0,row,col,true);
      else SetLed(1,row,col,true);     // note call is NOT to LedControl, but to wrapper
      light_green = !light_green;
    }
  }
  light_green = !light_green;
  for(int row=0;row<8;row++) {
    for(int col=0;col<8;col++) {
      delay(SHORT_DELAY);
      if (light_green == true) SetLed(0,row,col,true);
      light_green = !light_green;
    }
  }
}

void Rand_Col(int col){  // drops random colors in each column
  long color;
  randomSeed(millis());                // get random seed
  for(int row=0;row<8;row++) {
    color = random(1,4);               // pick a random color to light
    if (color == 1)SetLed(0,row,col,true); // light the red LED
    if (color == 2)SetLed(1,row,col,true); // light the green LED
    if (color == 3){
      SetLed(0,row,col,true);          // light the red LED
      SetLed(1,row,col,true);          // light the green LED
    }
    delay(SHORT_DELAY);
  }
}


// Wrappers for LedControl functions . . .
void SetLed(byte Color, byte Row,byte Col, byte State){
  FrequencyTimer2::setOnOverflow(0);   // turn off interupt when you command the chip
  lc.setLed(Color,Row,Col,State);
  FrequencyTimer2::setOnOverflow(togShutdown); // turn on interupt
}

void SetRow(byte Color, byte Row, byte State){
  FrequencyTimer2::setOnOverflow(0);   // turn off interupt when you command the chip
  lc.setRow(Color,Row,State);
  FrequencyTimer2::setOnOverflow(togShutdown); // turn on interupt
}

void SetColumn(byte Color, byte Col, byte State){  // (not used by any demos here)
  FrequencyTimer2::setOnOverflow(0);   // turn off interupt when you command the chip
  lc.setColumn(Color,Col,State);
  FrequencyTimer2::setOnOverflow(togShutdown); // turn on interupt
}

void ClearMatrix(){
  FrequencyTimer2::setOnOverflow(0);   // turn off interupt when you command the chip
  lc.clearDisplay(GREEN_MAX);
  lc.clearDisplay(RED_MAX);
  FrequencyTimer2::setOnOverflow(togShutdown); // turn on interupt
}


BTW,thanks to a tip from 'mem', it compiles with Rel. 0015
John
Logged

"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

London
Offline Offline
Faraday Member
**
Karma: 8
Posts: 6240
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote

BTW,thanks to a tip from 'mem', it compiles with Rel. 0015
John

Hi John, where did you get Rel 0015 from ?




Just joking, I know thats  0011  smiley-wink

Good to hear you have it working  smiley
« Last Edit: April 07, 2008, 10:21:59 pm by mem » Logged

Pages: [1] 2 3   Go Up
Jump to: