0
Offline
Newbie
Karma: 0
Posts: 9
Arduino rocks
|
 |
« on: March 30, 2008, 03:05:45 pm » |
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
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 9
Arduino rocks
|
 |
« Reply #1 on: March 30, 2008, 03:24:05 pm » |
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=1200123531Anyone who ends up here with the same problem may want to wander there :-)
|
|
|
|
|
Logged
|
|
|
|
|
Denver
Offline
God Member
Karma: 19
Posts: 777
Inactive - PM
|
 |
« Reply #2 on: March 30, 2008, 03:39:20 pm » |
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/1004I'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
Newbie
Karma: 0
Posts: 9
Arduino rocks
|
 |
« Reply #3 on: March 30, 2008, 08:24:34 pm » |
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: #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
God Member
Karma: 19
Posts: 777
Inactive - PM
|
 |
« Reply #4 on: March 31, 2008, 11:13:28 am » |
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
Newbie
Karma: 0
Posts: 9
Arduino rocks
|
 |
« Reply #6 on: March 31, 2008, 07:46:31 pm » |
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: #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
Newbie
Karma: 0
Posts: 9
Arduino rocks
|
 |
« Reply #7 on: April 01, 2008, 06:23:02 am » |
(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
God Member
Karma: 19
Posts: 777
Inactive - PM
|
 |
« Reply #8 on: April 01, 2008, 10:45:25 pm » |
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
Newbie
Karma: 0
Posts: 9
Arduino rocks
|
 |
« Reply #9 on: April 02, 2008, 06:55:43 pm » |
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
God Member
Karma: 19
Posts: 777
Inactive - PM
|
 |
« Reply #10 on: April 06, 2008, 08:19:36 pm » |
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
Newbie
Karma: 0
Posts: 9
Arduino rocks
|
 |
« Reply #11 on: April 07, 2008, 05:05:32 am » |
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
God Member
Karma: 19
Posts: 777
Inactive - PM
|
 |
« Reply #12 on: April 07, 2008, 10:04:16 pm » |
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. /* 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
God Member
Karma: 19
Posts: 777
Inactive - PM
|
 |
« Reply #13 on: April 07, 2008, 10:08:24 pm » |
// 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
Faraday Member
Karma: 6
Posts: 6226
Have fun!
|
 |
« Reply #14 on: April 07, 2008, 10:21:35 pm » |
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 
|
|
|
|
« Last Edit: April 07, 2008, 10:21:59 pm by mem »
|
Logged
|
|
|
|
|
|