Running out of Sram / program hang.

If the program hangs for any reason, is it likey cto cause any damage to the chip?

I have a system that hands sometimes after around 2000 loops when using the I2C bus, but not writing to it and just using serial, is fine.

If I were to not notice it had hung (for instance coding something else) would it case a problem?

Also as a secondary question, id there a maximum number of times the Arduino can be written to? If so could this be causing it to hang?

Do you mean like getting caught in an infinite loop?

while (1);

No, harmless. This is very close to what happens when you do this:

void setup() {
  // do stuff
  // do more stuff
  // do even more stuff
}

void loop() {}

In this case, loop() will be called, return, then be called again, return again, then be called again... on and on until reset / power-off.

Yes, there is a limit to number of flash writes. It's a big number, though. If I remember correctly (too lazy to look it up), it's something like 10,000 or 100,000 writes. I haven't tracked how many times I've uploaded sketches to some of my most active chips, but I'm pretty sure it hasn't been nearly that many.

manicmoddin:
If the program hangs for any reason, is it likey cto cause any damage to the chip?

Microcontrollers (and even your computer) very rarely "hangs." Instead it starts executing code in an unexpected path.

For example, it is possible for unexpected code to start doing unexpected things to an I/O, which would result in damage. However, the likelyhood is pretty low. So generally "hanging code" isn't damaging.

manicmoddin:
Also as a secondary question, id there a maximum number of times the Arduino can be written to? If so could this be causing it to hang?

Yes. Program memory is rated for 10,000 writes while the EEPROM (different memory space) has a 100,000 limit.

Consider that writes to program memory can't happen faster than you click upload and that process starts, so worst case you are looking at once per minute. At 10,000 writes, you could corrupt the flash Program Memory in 7 days if you clicked upload once a minute for 24 hours. (See how unlikely this is?)

Part of the programming memory is to read back the contents as verification. So if there was a damaged cell, you'd know when the chip was programmed.

Many thanks for the reply, sorry for the delay in getting back to you, ive been busy trying to build a windows to I2C interface to see if it is the display chip thats the problem or the Arduino program.

It turnsout that on the PC, I can send i2c signals all day long with no problem, but with the arduino using my libary Ihave a problem a few times around the loop().

It is often around the 2460th time round.

I have written a simple sketch but not sure if I should put it in here or not.

Jimmy

Just post your code and we can help you out. Without the code we can only guess.

Please use the #button to get appropiate code tags (its above the smileys :slight_smile:

Cheers, I never know where to put anything in the forum.

First I'll add my libary which I have adapted from the Liquid Crystall Libary

MAX6955.h

//max6955.h
#ifndef Maxim
#define Maxim

#include "arduino.h"
#include <inttypes.h>
#include "Print.h"


class Maxim6955 : public Print {
 public:
   Maxim6955(uint8_t address); //constructor
   void begin(uint8_t test);
   void clear();

   virtual size_t write(uint8_t);
   using Print::write;

 private:
   void send(uint8_t);
   //void writeI2C();
   uint8_t _address;
   uint8_t _off;
   uint8_t _holder;
   uint8_t _string;
   uint8_t _d0;
   uint8_t _d1; 
   uint8_t _d2;
   uint8_t _d3;
   uint8_t _d4;
   uint8_t _d5;
   uint8_t _d6;
   uint8_t _d7;
};

#endif

MAX6955.cpp

//max6955.cpp

#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <Wire.h>
#include "Arduino.h"
#include "max6955.h"

Maxim6955::Maxim6955(uint8_t address) {
  _address = address;
  _off = 0x00;
}

void Maxim6955::begin(uint8_t testMode) {
  //start configuring the display
  Wire.beginTransmission(_address);
  Wire.write(0x01);        // Write to the decode resgister;
  Wire.write(0b11111111); //decode all digits 1 is decode 0 gives direct access
  Wire.write(0x01);       //Intensity default, guess I should take this from a pin to see where the dash lights are at...
  Wire.write(0x07);       // hex easiest way of seeing which digits to scan (all 8 is 0x07)
  Wire.write(0x01);       // Control Reg 0x01 is shutdown off
  Wire.endTransmission();
  
  
  //device setup to accept charectures now, are we doing a display test?
  
  if(testMode == 1) {
    
    //test is wanted, this lightsup all segments for 1.5 seconds then turns off
    Wire.beginTransmission(_address);
    Wire.write(0x07);     //TestRegister
    Wire.write(0x01);     //Turn it on
    Wire.endTransmission();
    
    delay(1500); //delay 1.5 seconds
    
    Wire.beginTransmission(_address);
    Wire.write(0x07);     //TestRegister
    Wire.write(_off);     //Turn it off
    Wire.endTransmission();
  }
  
  else {
    Wire.beginTransmission(_address);
    Wire.write(0x07);     //TestRegister
    Wire.write(_off);     //Turn it off
    Wire.endTransmission();

    
  } //end test;
  
  
} //END BEGIN





/******************* High Level commands */

void Maxim6955::clear() {
  //manual function to clear display
  _d0 = 32; //space char
  _d1 = 32; //space char
  _d2 = 32; //space char
  _d3 = 32; //space char
  _d4 = 32; //space char
  _d5 = 32; //space char
  _d6 = 32; //space char
  _d7 = 32; //space char
  
  Wire.beginTransmission(_address);
  Wire.write(0x20);     //TestRegister
  Wire.write(_d0);       //"space" Char
  Wire.write(_d1);       //"space" Char
  Wire.write(_d2);       //"space" Char
  Wire.write(_d3);       //"space" Char
  Wire.write(_d4);       //"space" Char
  Wire.write(_d5);       //"space" Char
  Wire.write(_d6);       //"space" Char
  Wire.write(_d7);       //"space" Char
  Wire.endTransmission();
}


inline size_t Maxim6955::write(uint8_t value) {
  send(value);
  return 1; // assume sucesss
}


// Send to a string
void Maxim6955::send(uint8_t value) {
 _d0 = _d1;
 _d1 = _d2;
 _d2 = _d3;
 _d3 = _d4;
 _d4 = _d5;
 _d5 = _d6;
 _d6 = _d7;
 _d7 = value;
  
  //_holder = value;
  

  Wire.beginTransmission(_address);
  
 

  Wire.write(0x20);
  Wire.write(_d0);
  Wire.write(_d1);
  Wire.write(_d2);
  Wire.write(_d3);
  Wire.write(_d4);
  Wire.write(_d5);
  Wire.write(_d6);
  Wire.write(_d7);

  Wire.endTransmission();
}

now the sketch

//max6955.ino

#include <Wire.h>
#include <max6955.h>

Maxim6955 max1(0x60);
int x = 0;

void setup() {
  max1.begin(1);
}

void loop() {
  max1.clear();
  //delay(500);
  max1.print(x);
  x++;
  delay(1000);
  //Serial.println(x);
}

The same also happens if I do not use my libary and insted just send the I2C data by using the following

//////////////////////////////////////////////////////////////////
//  The inner workings of the golem...
//  brightness pin 2 on arduino
//  TMP36 on Pin A0
/////////////////////////////////////////////////////////////////
#include <Wire.h>;

int x = 0;       // count the loops to see if we get a hang

int mode = 0;    // Default mode theat the system boots up in

int testOff = 0; // for some reason will not let me reite 0x00 tot he system so define it here
int digit0 = 32; // "space char as default - blank digit on boot"
int digit1 = 32; // "space char as default - blank digit on boot"
int digit2 = 32; // "space char as default - blank digit on boot"
int digit3 = 32; // "space char as default - blank digit on boot"
int digit4 = 32; // "space char as default - blank digit on boot"
int digit5 = 32; // "space char as default - blank digit on boot"
int digit6 = 32; // "space char as default - blank digit on boot"
int digit7 = 32; // "space char as default - blank digit on boot"
byte numbers[10]; //array to hold the numbers in , not sure It i will need

int max1 = 0x60; //address of first max6955 chip

int brightness = 0x0D; //original brightness level
int tempPin = A0;

//////////////////////////////////////////////////////////////////
//       MAX6955 REGISTERS
//////////////////////////////////////////////////////////////////

int regDecode = 0x01;
int regIntens = 0x02;
int regScan   = 0x03;
int regConfig = 0x04;
int regTest   = 0x07;

//////////////////////////////////////////////////////////////////
//        END REGISTER SETUP
//////////////////////////////////////////////////////////////////

void setup() {
  pinMode(2, INPUT);
  //pinMode(tempPin, INPUT);
  Serial.begin(9600);
  Wire.begin(0x00);
  wireSetup();
  show(); //sends initial chars to the display
  
  //setup nuumbers
  numbers[0] = 48;
  numbers[1] = 49;
  numbers[2] = 50;
  numbers[3] = 51;
  numbers[4] = 52;
  numbers[5] = 53;
  numbers[6] = 54;
  numbers[7] = 55;
  numbers[8] = 56;
  numbers[9] = 57;
  numbers[0] = 48;
  
  Serial.println("End Setup"); //for debug, lets me know when its free.
}

void loop() {
    
/////////////// count demo////////////////////
  for(int x=0; x<10000; x++){
    if(x<10) {
      digit0 = numbers[0];
      digit1 = numbers[0];
      digit2 = numbers[0];
      digit3 = numbers[x];
    }
    else if(x<100) {
      digit0 = numbers[0];
      digit1 = numbers[0];
      digit2 = numbers[x / 10];
      digit3 = numbers[x % 10];
    }
    else if(x<1000) {
      digit0 = numbers[0];
      digit1 = numbers[x / 100];
      digit2 = numbers[(x % 100)/10];
      digit3 = numbers[x % 10];
    }
    else if(x<10000) {
      digit0 = numbers[x / 1000];
      digit1 = numbers[(x % 1000)/100];
      digit2 = numbers[(x % 100)/10];
      digit3 = numbers[x % 10];
    }
    show();
    delay(50);
  }

//////END COUNT DEMO ????????????????????
} //end loop

void show() {
  Wire.beginTransmission(max1);
  Wire.write(0x02);
  Wire.write(brightness);
  Wire.endTransmission();
  Wire.beginTransmission(max1);
  Wire.write(0x20);
  Wire.write(digit0);
  Wire.write(digit1);
  Wire.write(digit2);
  Wire.write(digit3);
  Wire.write(digit4);
  Wire.write(digit5);
  Wire.write(digit6);
  Wire.write(digit7);
  Wire.endTransmission();
   
  ////////////////////////
  //    serial debug    //  
  ////////////////////////
  Serial.print(char(digit0));
  Serial.print(char(digit1));
  Serial.print(char(digit2));
  Serial.print(char(digit3));
  Serial.print(char(digit4));
  Serial.print(char(digit5));
  Serial.print(char(digit6));
  Serial.println(char(digit7));
  
  /////////////////////////
  //  end serial debug   //
  /////////////////////////
}

void wireSetup() {
  Wire.beginTransmission(max1);
  Wire.write(regTest);
  Wire.write(0x01);
  Wire.endTransmission();
  delay(1500);
  Wire.beginTransmission(max1);
  Wire.write(regTest);
  Wire.write(testOff);
  Wire.endTransmission();
  Wire.beginTransmission(max1);
  Wire.write(regDecode);
  Wire.write(0b11111111); //decode all digits 1 is decode 0 gives direct access
  Wire.write(0x01);       //Intensity default, guess I should take this from a pin to see where the dash lights are at...
  Wire.write(0x07);       // hex easiest way of seeing which digits to scan (all 8 is 0x07)
  Wire.write(0x01);       // Control Reg 0x01 is shutdown off
  Wire.endTransmission();
}

Any help would be greatly apprechiated.

I have narrowed it down to the arduino, and the fact that it hangs / stops says to me its running out of ram, if I reset the arduino (withouth disturbing the power supply), it will start from the beggining, so it appears not to be the display chip.

Finally, if I enable the serial output, it stops sending serial data when it hangs also.

Many thanks

Jimmy

int x = 0;       // count the loops to see if we get a hang

int mode = 0;    // Default mode theat the system boots up in

int testOff = 0; // for some reason will not let me reite 0x00 tot he system so define it here
int digit0 = 32; // "space char as default - blank digit on boot"
int digit1 = 32; // "space char as default - blank digit on boot"
int digit2 = 32; // "space char as default - blank digit on boot"
int digit3 = 32; // "space char as default - blank digit on boot"
int digit4 = 32; // "space char as default - blank digit on boot"
int digit5 = 32; // "space char as default - blank digit on boot"
int digit6 = 32; // "space char as default - blank digit on boot"
int digit7 = 32; // "space char as default - blank digit on boot"

None of these need to be ints. In fact, most of them look like they should be chars.

In any case, I don't see a huge amount of SRAM being consumed. I'd look elsewhere for the problem, like a failure to communicate between the Arduino and the I2C device - like a Wire function waiting forever.

Finally, if I enable the serial output, it stops sending serial data when it hangs also.

Which is where?

PaulS:
None of these need to be ints. In fact, most of them look like they should be chars.

No problem - I'll change these over and report back

PaulS:
I'd look elsewhere for the problem, like a failure to communicate between the Arduino and the I2C device - like a Wire function waiting forever.

That is possible, so how would I find this, first instinct would be to add a Serial.print() in the library for Wire, but while I was writing my own I could not fathom how to get this to work, but will see what I can do.

in the show() command of the 2nd example there is the block of

////////////////////////
  //    serial debug    //  
  ////////////////////////
  Serial.print(char(digit0));
  Serial.print(char(digit1));
  Serial.print(char(digit2));
  Serial.print(char(digit3));
  Serial.print(char(digit4));
  Serial.print(char(digit5));
  Serial.print(char(digit6));
  Serial.println(char(digit7));
  
  /////////////////////////
  //  end serial debug   //
  /////////////////////////

I may have been better describing it as ther serial debug hangs.

Many thanks for the feedback so far though and any further ideas welcomed.

Once I get this sorted, I can make some real progress with the project.

Jimmy

That is possible, so how would I find this, first instinct would be to add a Serial.print() in the library for Wire, but while I was writing my own I could not fathom how to get this to work, but will see what I can do.

ok, I have had a quick look through the twi.c file and found the function twi_writeTo()

This returns a number depending on what its sucsess is:

  • Output 0 .. success
  • 1 .. length to long for buffer
  • 2 .. address send, NACK received
  • 3 .. data send, NACK received
  • 4 .. other twi error (lost bus arbitration, bus error, ..)

on my serial out I got a 4 when it hangs, so this is a problem with the bus then? so either my wires, breadboard or the connections in the Arduino / max breakout board I think.

I have twisted the data and the clock wires together to hopefully cancel out interferance, but this dont seem to work, other than soldering to the boards, I'm at a loss as to a better option.

What size pull-up resistors on the I2C lines?

Twisting wires together doesn't cancel interference unless those two wires carry equal-but-opposite signals that are fed to a balanced input. AFAIK, it can only hurt as the signals may then couple to each other.

Also, I would refactor your module like so:

char data[8];  // Forget _d0-_d7

uint8_t Maxim6955::write(uint8_t chr) {
  
  Wire.beginTransmission(_address);
  Wire.write(0x20);
  
  // Shift values back one digit, writing along the way to save a second loop
  for (uint8_t i = 1; i < 8; i++) {
    Wire.write(data[i]);
    data[i-1] = data[i];
  }
  
  // Shift in new char and write it
  data[7] = chr;
  Wire.write(chr);
  
  Wire.endTransmission();
  
  // Return an error code if you have one...
  return (TWI_error_code);
}


// Print C-style strings
uint8_t Max6955::print(char *str) {
  uint8_t i = 0;
  uint8_t ret;

  // Loop through C-style string and write each char
  while (str[i] != 0x00) {
    ret = write(str[i]);
    if (ret != 0) break;
  }
  
  // Pass along any errors
  return ret;
}

// Overload print for C++ strings
uint8_t Max6955::print(String str) {
  // Loop through string chars one at a time, calling write(char) for each
  // Return error code from write(char) if != 0
}

// You may wish to overload print for ints, floats, etc.  Up to you.

// Call print with 8 spaces
uint8_t Max6955::clear() {
  return print("        ");
}

I'm a C guy, so I'm not totally up to speed on C++ .. at least, the finer details of classes. I'm halfway through a book, but not ready to write my own code here, so you'll have to fill in the details on the C++ String handling, and any errors I made on calling conventions within a namespace.

These are using 4.7K ohm as per the datasheet, so stumped on that.

SirNickity:
Twisting wires together doesn't cancel interference unless those two wires carry equal-but-opposite signals that are fed to a balanced input. AFAIK, it can only hurt as the signals may then couple to each other.

Also, I would refactor your module like so:

char data[8];  // Forget _d0-_d7

uint8_t Maxim6955::write(uint8_t chr) {
 
  Wire.beginTransmission(_address);
  Wire.write(0x20);
 
  // Shift values back one digit, writing along the way to save a second loop
  for (uint8_t i = 1; i < 8; i++) {
    Wire.write(data[i]);
    data[i-1] = data[i];
  }
 
  // Shift in new char and write it
  data[7] = chr;
  Wire.write(chr);
 
  Wire.endTransmission();
 
  // Return an error code if you have one...
  return (TWI_error_code);
}

// Print C-style strings
uint8_t Max6955::print(char *str) {
  uint8_t i = 0;
  uint8_t ret;

// Loop through C-style string and write each char
  while (str[i] != 0x00) {
    ret = write(str[i]);
    if (ret != 0) break;
  }
 
  // Pass along any errors
  return ret;
}

// Overload print for C++ strings
uint8_t Max6955::print(String str) {
  // Loop through string chars one at a time, calling write(char) for each
  // Return error code from write(char) if != 0
}

// You may wish to overload print for ints, floats, etc.  Up to you.

// Call print with 8 spaces
uint8_t Max6955::clear() {
  return print("        ");
}




I'm a C guy, so I'm not totally up to speed on C++ .. at least, the finer details of classes. I'm halfway through a book, but not ready to write my own code here, so you'll have to fill in the details on the C++ String handling, and any errors I made on calling conventions within a namespace.

Many thanks I will try with untwisted wires and get back, if it makes a differnece, with regards to the code, it makes little sence to me, I wrote that a while ago, over a coupke of days of bodging some together, will give it a try though and see if it helps :smiley:

Jimmy