MAX7219 turning off?

Hello forum. I am experimenting with the ethernet shield and have made a basic webpage that randomly generates a 2 digit number that I am displaying via a MAX7219 to two 7 segment LEDS. Exciting stuff I know, but this is a starting off point for a larger project!

Everything seems to be running along just dandy and the 7 segments are happily displaying their numbers but then randomly the 7 segments will go blank (off) and will not come back. This happens sometimes after 10+ loops and sometimes after only 2. I would suspect my wiring (not ruling it out though!) but it seems to work just fine for awhile. Resetting it will get things going again but then it'll blank out after a bit.

Below is my code.. Is there something that I've done wrong here to cause this to happen? I added the disp_cnt variable to see if it was always happening after X amount of loops but saw no consistency whatsoever. Any advice would be greatly appreciated!! Thanks!

/*
 Silly Data Getter
*/

#include <SPI.h>
#include <Ethernet.h>
#include "LedControl.h"

//digits
int disp1 = 0;  //digit 1
int disp2 = 1;  //digit 2

char Str[11];
int num = 0;
int disp_cnt = 0;

long pollingInterval = 10000; // in milliseconds

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = {  0x90, 0xA2, 0xDA, 0x00, 0x98, 0x31 };
char serverName[] = "server.com";

// Initialize the Ethernet client library
// with the IP address and port of the server 
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;

/*
 Now we need a LedControl to work with.
 pin 4 -> DataIn |  pin 3 -> CLK | pin 2 -> LOAD | One MAX72XX.
 */
LedControl lc=LedControl(4,3,2,1);

void setup() {
  /*
   The MAX72XX is in power-saving mode on startup,
   we have to do a wakeup call
   */
  lc.shutdown(0,false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0,8);
  /* and clear the display */
  lc.clearDisplay(0); 
  // start the serial library:
  Serial.begin(9600);
  //pinMode(relayPin, OUTPUT);
  // start the Ethernet connection:
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    while(true);
  }
  // give the Ethernet shield time to initialize:
  delay(2000);

}

void displayServing(int number) {
    disp_cnt++;
    Serial.println(disp_cnt);
    
    int dig_ones;
    int dig_tens;
    
    //set ones and tens
    dig_ones = number%10;
    dig_tens = number/10;
    //now serving
    lc.setDigit(0,disp1,dig_tens,false);
    lc.setDigit(0,disp2,dig_ones,false); 
    delay(250);
}

void loop()
{
    Serial.println("connecting...");

  // if you get a connection, report back via serial:
  if (client.connect(serverName, 80)) {
    Serial.println("connected");
    // Make a HTTP request:
    client.println("GET path/to/data");
    client.println();
    int timer = millis();
    delay(1000);
  } 
  else {
    // if you didn't get a connection to the server:
    Serial.println("connection failed");
    
  }

  // if there's data ready to be read:
  if (client.available()) {
     int i = 0;
     
     //put the data in the array:
     do {
       Str[i] = client.read();
       i++;
       delay(1);
     } while (client.available());
     
     // Pop on the null terminator:
     Str[i] = '\0';
     //convert server's repsonse to a int so we can evaluate it
     num = atoi(Str); 
     
     Serial.print("Server's response: ");
     Serial.println(num);
  } else {
     Serial.println("No response from server."); 
  }
    Serial.println("Disconnecting.");
    client.stop();

  //show the number
  displayServing(num);
  delay(pollingInterval);
}

Are you overheating things?

Page 10 of datasheet:
"If the scan-limit register is set for three digits or less, individual digit drivers will dissipate excessive amounts
of power. Consequently, the value of the RSET resistor must be adjusted according to the number of digits displayed,
to limit individual digit driver power dissipation.
Table 9 lists the number of digits displayed and the corresponding maximum recommended segment current
when the digit drivers are used."

Thanks for the reply Crossroads! I think I have the the correct RSET selected. The maximum current given by Table 9 for 2 digits is 20mA and the RSET that I have selected is 33kOhm which should safely limit the mA going to ISEG (if I am thinking about this correctly). I am following the instructions from here Arduino Playground - MAX72XXHardware and my simplified schematic is as follows.

I think I'll need to re-try the circuit on my breadboard to see if perhaps my soldering/wiring skills are to blame (highly plausible). See anything else that might be faulty? Thanks again for the help!

Where do you tell it that you are only using 2 digits?

Hmm.. I guess I don't explicitly tell it I'm only using 2 digits. Should I be doing that? This sketch began with me hacking up the demo sketch below and I don't see a spot in it for declaring how many digits I'm using. I see a spot for telling it how many MAX72XX's I'm using though which is only 1.. Am I missing something here? Thanks!!

//We always have to include the library
#include "LedControl.h"

/*
 Now we need a LedControl to work with.
 ***** These pin numbers will probably not work with your hardware *****
 pin 12 is connected to the DataIn 
 pin 11 is connected to the CLK 
 pin 10 is connected to LOAD 
 We have only a single MAX72XX.
 */
LedControl lc=LedControl(12,11,10,1);

/* we always wait a bit between updates of the display */
unsigned long delaytime=250;

void setup() {
  /*
   The MAX72XX is in power-saving mode on startup,
   we have to do a wakeup call
   */
  lc.shutdown(0,false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0,8);
  /* and clear the display */
  lc.clearDisplay(0);
}

/*
  This method will scroll all the hexa-decimal
 numbers and letters on the display. You will need at least
 four 7-Segment digits. otherwise it won't really look that good.
 */
void scrollDigits() {
  for(int i=0;i<13;i++) {
    lc.setDigit(0,3,i,false);
    lc.setDigit(0,2,i+1,false);
    lc.setDigit(0,1,i+2,false);
    lc.setDigit(0,0,i+3,false);
    delay(delaytime);
  }
  lc.clearDisplay(0);
  delay(delaytime);
}

void loop() { 
  writeArduinoOn7Segment();
  scrollDigits();
}

I looked into "setScanLimit" and it seemed like I would need it in my sketch however adding

/*Limit to 2 digits*/
  lc.setScanLimit(1, 1);

to my setup did not seem to fix the issue.

Well I thought I had this all sorted out and was about to write a victory post but the LED's have just shut down again..

I had a prototype of the circuit still on my breadboard so last night I moved the MAX7219 back over to there and tested. I ran it for a long time and it worked! I then figured something was wrong with my circuit. I had basically resigned myself to rebuilding the board that I had made but as a last ditch effort I went over and tried as best I could to clean up my soldering work in case something was getting mucked up there. I moved the MAX7219 back over and fired it up and it ran for well over an hour no problem.

This morning I ran it for hours without fail. Something odd happened over lunch and it was only writing to Dig0. I've since reset it and had it work and then sputter out again. Sometimes for a long while and sometimes quite quickly.

I'm still not confident that I have the scanlimit thing sorted out either.

Additionally should I be resetting things when it loops to clear things out? Any other thoughts on why this might be occurring? Thanks!!

For starters, I'd set the scan limit to four digits (0x3) just for grins, to avoid any of the potential pitfalls with two or one digit. There is no downside to doing this. If scan limit was not being explicitly set, I'm puzzled as to how two digits are being displayed at all, since the datasheet says it powers up set to scan one digit.

The other thing I found was that some of the registers may contain random values at power-on. I have one that likes to go into display test when it's powered up.

Per the datasheet, the chip does go into shutdown mode at power-up. Before leaving shutdown mode, I explicitly set all the configuration registers the way I want them, I make no assumptions as to initial values. So I set Decode Mode, Intensity, Scan Limit, and Display Test. Then I set the Shutdown register to 1 for normal operation.

I do similar to start mine up:

void setup() // stuff that runs once before looping forever
{
  // start up SPI to talk to the MAX7221
  SPI.begin(); // nothing in () because we are the master
  pinMode(SS, OUTPUT);  // Slave Select for SPI 

  //  MAX7221: write shutdown register  
  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(SHUTDOWN_ADDRESS);  // select the Address,
  SPI.transfer(0x00);      // select the data, 0x00 = Outputs turned off
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip:
  // Serial.println("shutdown register, dislays off");

  // put known values into MAX7221 so doesn't have weird display when actually turned on
  // 0x0F = blank digit
  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(leftscore_tens_address);  // select the Address,
  SPI.transfer(0x0F);      // select the data
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip

  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(leftscore_ones_address);  // select the Address,
  SPI.transfer(0x0F);      // select the data
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip

  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(rightscore_tens_address);  // select the Address,
  SPI.transfer(0x0F);      // select the data
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip  

  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(rightscore_ones_address);  // select the Address,
  SPI.transfer(0x0F);      // select the data
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip

  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(minutes_tens_address);  // select the Address,
  SPI.transfer(0x0F);      // select the data
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip

  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(minutes_ones_address);  // select the Address,
  SPI.transfer(0x0F);      // select the data 
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip

  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(seconds_tens_address);  // select the Address,
  SPI.transfer(0x0F);      // select the data
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip  

  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(seconds_ones_address);  // select the Address,
  SPI.transfer(0x0F);      // select the data 
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip

 //  MAX7221: 
  //  write intensity register
  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(INTENSITY_ADDRESS);  // select the Address,
  SPI.transfer(intensity);      // select the data
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip:
  //Serial.println("intensity register ");

  // write scanlimit register
  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(SCANLIMIT_ADDRESS);  // select the Address,
  SPI.transfer(0xFF);      // select the data - FF = all 8 digits
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip:
  //Serial.println("scanlimit register ");

  // write decode register
  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(DECODE_MODE);  // select the Address,
  SPI.transfer(0xFF);      // select the data - FF = all 8 digits
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip:
  //Serial.println("decode register ");

  //display test
  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(DISPLAYTEST_ADDRESS);  // select the Address,
  SPI.transfer(0x01);      // select the data
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip:
  //Serial.println("digit display test on ");
  delay (100);

  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(DISPLAYTEST_ADDRESS);  // select the Address,
  SPI.transfer(0x00);      // select the data
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip:
  //Serial.println("digit display test off ");
  delay (100);

  // write shutdown register for normal display operations
  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(SHUTDOWN_ADDRESS);  // select the Address,
  SPI.transfer(0x01);      // select the data, 0x01 = Normal Ops
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip:
  //Serial.println("shutdown register, displays on ");

}

This is great! I need to look into adding this to my code..
Looks like I might need to learn to write to the MAX using SPI instead of the LedControl api maybe. I'll start reading up on this.

On the hardware side of things I moved my capacitors closer to incoming voltage to see if perhaps it was a de-coupling issue as was suggested in this thread http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1279746561. I've been running it this morning for about an hour without it shutting off so we'll see!

Thanks again for all the help!

I did it "longhand" as it were because I was reading the data sheet and wanted to understand what was needed.

I'm sure each of these

  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(rightscore_tens_address);  // select the Address,
  SPI.transfer(0x0F);      // select the data
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip

could have done as a function instead, maybe:

void SPIwrite (7221register, 7221data){

  digitalWrite(SS,LOW);  // take the SS pin low to select the chip:
  SPI.transfer(7221register);  // select the Address,
  SPI.transfer(7221data);      // select the data
  digitalWrite(SS,HIGH);   // take the SS pin high to de-select the chip
}

and then call them as

SPIwrite(rightscore_tens_address, 0x0F);

Runs really fast that way too, no gazillions of jumps to and from functions. Maybe even do direct port access inplace of the digitalWrites for th SS line.
But at the time I was working out the logic of the whole sketch, and was easier for me to follow to see it all written out.

Techbot:
On the hardware side of things I moved my capacitors closer to incoming voltage...

Very good idea, the datasheet sez:

Supply Bypassing and Wiring
To minimize power-supply ripple due to the peak digit
driver currents, connect a 10?F electrolytic and a 0.1?F
ceramic capacitor between V+ and GND as close to
the device as possible. The MAX7219/MAX7221 should
be placed in close proximity to the LED display, and
connections should be kept as short as possible to
minimize the effects of wiring inductance and electromagnetic
interference. Also, both GND pins must be
connected to ground.

CrossRoads:
Runs really fast that way too, no gazillions of jumps to and from functions.

You could tell the difference? Maybe I should take up fencing, might make my eyes faster! :wink:

CrossRoads:
I did it "longhand" as it were because I was reading the data sheet and wanted to understand what was needed.

A man after my own heart, I rolled my own too, just starting to play with the thing. Not quite a library, just a handful of functions specific to my hardware which was a four-digit clock display with colons. The colon dots are individually addressable, and have their own common cathode, so they act like a fifth digit. So for my initial testing, I could make calls like:

    initMax72();
    displayInt(hour(t) * 100 + minute(t));   //t is a time_t
    max72Colon(0x60);                        //turn colon on
    max72Colon(0x00);                        //turn colon off
    max72Brightness(brightness);

Here are my functions FWIW, they can go in a separate tab in the IDE, may need some tweaking, like I said, they're somewhat specific to my hardware, but pretty straightforward.

#define M72REG_NOOP 0
#define M72REG_DIG0 1
#define M72REG_DIG1 2
#define M72REG_DIG2 3
#define M72REG_DIG3 4
#define M72REG_DIG4 5
#define M72REG_DIG5 6
#define M72REG_DIG6 7
#define M72REG_DIG7 8
#define M72REG_DECODE_MODE 9
#define M72REG_INTENSITY 10
#define M72REG_SCAN_LIMIT 11
#define M72REG_SHUTDOWN 12
#define M72REG_DISPLAY_TEST 15

#define MIN_BRIGHT 0
#define MAX_BRIGHT 15
#define SS 10

void displayInt(int i)
{
    sendMax72(M72REG_DIG0, i % 10);
    i /= 10;
    sendMax72(M72REG_DIG1, i % 10);
    i /= 10;
    sendMax72(M72REG_DIG2, i % 10);
    sendMax72(M72REG_DIG3, i/10 );
}

void max72Colon(byte c)
{
    sendMax72(M72REG_DIG4, c);
}

void max72Brightness(int b)
{
    if (b >= MIN_BRIGHT && b <= MAX_BRIGHT) sendMax72(M72REG_INTENSITY, b);
}

void sendMax72(byte reg, byte data)
{
    digitalWrite(SS, LOW);
    SPI.transfer(reg);
    SPI.transfer(data);
    digitalWrite(SS, HIGH);
}

void initMax72(void)
{
    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE0);
    SPI.begin();
    delay(10);
    sendMax72(M72REG_SHUTDOWN, 0);          //shutdown mode
    sendMax72(M72REG_DISPLAY_TEST, 0);      //turn off display test just in case
    sendMax72(M72REG_SCAN_LIMIT, 4);        //digits 0-4, digit 4 is colon
    sendMax72(M72REG_DECODE_MODE, 0x0F);    //BCD decode digits 0-3
    sendMax72(M72REG_DIG0, 0xF);            //blank all digits
    sendMax72(M72REG_DIG1, 0xF);
    sendMax72(M72REG_DIG2, 0xF);
    sendMax72(M72REG_DIG3, 0xF);
    sendMax72(M72REG_DIG4, 0x00);
    sendMax72(M72REG_INTENSITY, MAX_BRIGHT);
    sendMax72(M72REG_SHUTDOWN, 1);          //normal operation
}

I didn't use any functions, just all long hand.
After a few rewrites, working out design as I went, I ended up with 4 sections of code in void loop:

Pseudo-code:
void loop(){

did 1/4 second pass? Update colon & 4 time display variables, set the display update flag to show an udpate is needed.

did an RF/remote control command come in? ignore it if time is running except for start/stop. If time is not running, execute it; update score, time variables as needed, including variables that control 6 decimal points used as warning, penalty, etc. indicators.  Set the display update flag to show an udpate is needed.

is the display update flag set? perform spi writes to the max7221, clear the flag.

was a touch scored message received? (another promini board does that, the promini that does the above had run of pins when I added this feature) stop the time from running, turn on score lights, sound buzzer, send serial message for the remote lights.

}

The thing works great because most of the time nothing is happening, of the 4 if conditions only 1 is met every 1/4 second, and the 8 SPI writes that occur go really quick.
No interrupts, no functions. Just fast polling.