Go Down

Topic: ArDeci -> MAX7219 (x3) -> RGB 8x8 LED Matrix prob. (Read 10175 times) previous topic - next topic

paulofisch

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 :) 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

paulofisch

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 :-)

bHogan

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.
"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

paulofisch

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: [Select]

#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++;
}
}



bHogan

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.
"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

justfred

(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?

paulofisch

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: [Select]
#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);
}
}


paulofisch

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

bHogan

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!
"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

paulofisch

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.

bHogan

#10
Apr 07, 2008, 03:19 am Last Edit: Apr 07, 2008, 03:26 am by BroHogan Reason: 1
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 - http://www.youtube.com/watch?v=H0gHbbGkvzA

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.
"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

paulofisch

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 ;-)

bHogan

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: [Select]
/* 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 . . .
"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

bHogan

Code: [Select]


// 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
"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

mem

#14
Apr 08, 2008, 05:21 am Last Edit: Apr 08, 2008, 05:21 am by mem Reason: 1
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  ;)

Good to hear you have it working  :)

Go Up