Re: Program works only after pressing the reset button

Uhg. My turn to have this problem. Here’s my code. Weird things will “fix it” for example, if you remove EEPROM.put(eeAddress, count) in loop(), it will run without a problem. (Of course I need those lines of code for the program to be correct.) Would love some advice here.

#include <SPI.h>
#include <EEPROM.h>

#define NUM_VOTES 3
#define TRIGGER_LOW 28
#define TRIGGER_HIGH 36

#define NUMBER_OF_DIGITS 4
#define COIL_ENERGIZE_TIME 150

byte setLastNumbersSentToSignalexToZeroInterrupt = 0; // int 0 is on pin 2 of the UNO

//byte mic5801EnablePin = 8;
//byte mic5801StrobePin = 9;
byte slaveSelectPin = 10;
//  miso is on pin 12
//  SPI clock is on pin 13
int count = 0;
int eeAddress = 0;
int resetPin = 0;
int incrementPin = 2; 
int readVal = 0;
int readVal2 = 0;

/*
*  each mic5801 has a strobe pin and an enable pin
*  the input control voltages are applied, mic5801 reads the input when the strobe
*     pin goes high.
*  output is enabled when enable pin goes low.
*  only need to enable for 150ms (coil energize time)
*/

byte mic5801EnablePin[NUMBER_OF_DIGITS] = {8,6,4,A5};
byte mic5801StrobePin[NUMBER_OF_DIGITS] = {9,7,5,3};


byte lastNumbersSentToSignalex[NUMBER_OF_DIGITS][2] = {{0,0},{0,0},{0,0},{0,0}};

byte numbersToSignalex[10][2]= {
 {250, 16}, //0
 {96, 188}, //1
 {214, 34}, //2
 {244, 40}, //3
 {108, 140}, //4
 {188, 72}, //5
 {190, 64}, //6
 {224, 60}, //7
 {254, 0}, //8
 {252, 8} //9
};

uint8_t incheses[NUM_VOTES];
uint8_t incheses_idx = 0;

void setup () {
 for (int i = 0; i < NUM_VOTES; ++i) {
   incheses[i] = 0;
 }

 // Uncomment to set counter back to ZERO
//  count = 0;
//  EEPROM.put(eeAddress, count);

 Serial.begin(9600);
 // TODO: Add pause for first 3 seconds to ignore any spurious inputs from other Arduino
 
 //  initialize 5801 (disable it)
 for (int i; i<NUMBER_OF_DIGITS; i++) {
   pinMode(mic5801EnablePin[i], OUTPUT);
   pinMode(mic5801StrobePin[i], OUTPUT);
   digitalWrite(mic5801EnablePin[i], HIGH);
   digitalWrite(mic5801StrobePin[i], LOW);
 }

 SPI.begin();
 SPI.setBitOrder(MSBFIRST);

 pinMode(incrementPin, INPUT);      // sets pin to listen for signal to count up 1
 pinMode(resetPin, INPUT);          // sets pin to listen for reset signal

 EEPROM.get(eeAddress, count); //Get last number stored in EEPROM in there case where power is lost
 
 // initialize display
 for (int i=0; i<NUMBER_OF_DIGITS; i++) {
   setSignalex(i, numbersToSignalex[0]);
 }
 setCount(count);
 digitalWrite(13, LOW);
}

unsigned long last_enforce = 0;

void loop () {
 unsigned long pulse_length = pulseIn(incrementPin, HIGH, 50000);
 uint8_t inches = (uint8_t)(pulse_length / 147);
 incheses[incheses_idx] = inches;
 incheses_idx = (incheses_idx + 1) % NUM_VOTES; 

 uint8_t num_different = 0;
 bool a_zero = false;
 for (int i = 0; i < NUM_VOTES; ++i) {
   if (incheses[i] < TRIGGER_LOW || incheses[i] > TRIGGER_HIGH) {
     num_different += 1;
   }
   a_zero = a_zero || incheses[i] == 0;
 }

 if (num_different > 1 && !a_zero) {
   Serial.println("increment");
   count += 1;
   setCount(count);
   EEPROM.put(eeAddress, count);
   delay(1500);
 }
}

void setCount(int count) {
   count = count % 10000;
   int digit0 = count % 10;
   int digit1 = ((int) count / 10) % 10;
   int digit2 = ((int) count / 100) % 10;
   int digit3 = ((int) count / 1000);
   Serial.print(String(count) + " " + String(digit3) + " " + String(digit2) + " " + String(digit1) + " " + String(digit0) + "\n");
   setSignalex(0,numbersToSignalex[digit0]);
   setSignalex(1,numbersToSignalex[digit1]);
   setSignalex(2,numbersToSignalex[digit2]);
   setSignalex(3,numbersToSignalex[digit3]);
}

void setSignalex(int digit, byte value[2]) {
 /*  we can save power by comparing the digit currently displayed with
  *  the new digit and only energizing the coils that need to change
  *  (otherwise, we might energize coils that are already in the
  *   desired position, wasting power)
  */   
 byte valuesSentToShiftRegister[2];
 valuesSentToShiftRegister[0]=(value[0] ^ lastNumbersSentToSignalex[digit][0]) & value[0];
 valuesSentToShiftRegister[1]=(value[1] ^ lastNumbersSentToSignalex[digit][1]) & value[1];
 lastNumbersSentToSignalex[digit][0] = value[0];
 lastNumbersSentToSignalex[digit][1] = value[1];
 /*
  *  Use SPI to write the values to the two shift registers.
  */
 writeValuesToShiftRegistersUsingSPI(valuesSentToShiftRegister);
 /*
  *  The output of the shift registers is sent to ALL the current drivers (MIC5801BN)
  *  But they only update their input registers when the strobe line goes HIGH
  *  We strobe only the digit to which we want to write the new values.
  *  strobeMIC5801 also enables those two line drivers to send current to the coils
  */
 strobeMIC5801(digit);
}

/*
*  send values to shift registers using SPI.
*  take the shift registers offline while the
*  values are shifting to prevent intermediate
*  shift results from appearing on the outputs
*  take HIGH when all bits are in correct position
*/

void writeValuesToShiftRegistersUsingSPI(byte value[2]) {
 digitalWrite(slaveSelectPin, LOW);
 SPI.transfer(value[0]);
 SPI.transfer(value[1]);
 digitalWrite(slaveSelectPin, HIGH);
}

/*
*  void strobeMIC5801()
*
*  mic5801bn strobe pin must be set to high in order for the input
*  levels on the input pins to be recorded in the internal registers.
*
*  mic5801bn enable pin must be set to LOW in order for the output
*  pins to be enabled (in accordance with the values strobed to internal registers)
*
*  according to documentation, the 6 inch signalex digit requires 90ms of current
*  however in practice I found 150ms to be required.
*/

void strobeMIC5801(int i) {
 digitalWrite(mic5801StrobePin[i], HIGH);
 delay(1);
 digitalWrite(mic5801StrobePin[i], LOW);
 digitalWrite(mic5801EnablePin[i], LOW);
 delay(COIL_ENERGIZE_TIME);  // energize the coils for 150ms, 90ms should do but this signalex might be defective
 digitalWrite(mic5801EnablePin[i], HIGH);
}

AndrewCC:
My turn to have this problem.

This is a very old Thread.

What Arduino are you using?

Describe the symptoms that YOU experience in as much detail as possible - just in case they are subtly different from the earlier cases.

It would be a good idea to get a USB-TTL cable and connect it to Tx Rx and GND so that you can view the Serial output even though the Arduino is not powered from the USB port. That will also allow you to add several Serial.print() statements so you can monitor progress through the code.

...R

Didn’t realize how old it was. Should I start a new one?

Some more details.

-1) I’m using an Arduino Uno.

  1. I can reproduce the issue by plugging my Arduino into 12V supply. If I reset the Arduino then it seems to get past the issue. This includes pressing the reset button on the Arduino, as well as reseting by, e.g., uploading a new program via USB.

  2. When the program fails it doesn’t get to the loop() portion of my code. Serial.print on the first line of loop() won’t appear in my Arduino Console.

  3. I have been using Serial.prints to debug. It seems like when the program fails, Serial.prints will contain garbage in addition to my statements. For example, instead of printing “hello” to the console, it will print “h?llo”. Then it appears to hang, without reaching my loop().

  4. I think it’s something to do with SPI. I’ve noticed that when the program hangs, the LED connected to Pin 13 is lit. When the program doesn’t hang, the LED will flicker and then go dark. My understanding is that SPI uses Pin 13, and as you can see my program uses SPI, so that kind of makes sense.

  5. Changing the program in the loop() code can make the problem go away, but I haven’t created a change to the program that doesn’t change its behavior and make the problem go away. For example, removing the EEPROM.put in loop() makes the problem go away. This is especially curious because when the program fails, it never even makes it to loop(). So why changing code in loop() impacts the outcome is a mystery to me.

  6. I’ve reproduced this behavior on multiple bare Arduino Unos (i.e. one with nothing connected but the USB and 12V input). So, in principle, anyone should be able to reproduce the behavior. Steps are A) plug Arduino Uno into USB. B) upload the code above, C) unplug Arduino Uno from USB. D) plug Arduino into 12V supply. E) Observe that after startup Pin 13 LED is lit solid. F) Reset Arduino using the reset button. G) Observe that after startup Pin 13 LED is dark. I’ve occasionally had to reset twice I think. But it seems pretty consistent.

Time to hit the human reset button. Maybe it will make sense tomorrow.

I have requested the Moderator to move your question to its own Thread.

I am still not at all clear what your symptoms are.

Are there circumstances in which the program always works correctly? If so, what are they?

This is not wise

   Serial.print(String(count) + " " + String(digit3) + " " + String(digit2) + " " + String(digit1) + " " + String(digit0) + "\n");

Just use several simple print statements and don't use String.

It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. Just use cstrings - char arrays terminated with 0.

...R

Thread split.

REPLIES

I am still not at all clear what your symptoms are.

At a high level the goal of this program is to run 4 mechanical seven segment displays made by Signalex. The display is operated by solenoids which hide or display particular segments of the display. The program is supposed to setup() by displaying zero on every digit, reading a saved value from EEPROM, and then displaying the saved value. (The loop() and interrupts use a sensor to trigger incrementing a counter, which triggers a new number displayed on the Signalexes, but that part doesn’t have a problem.)

What I’m finding is that:

  • Usually (let’s say 80% of the time) when I power on the Arduino setup() does not complete. Instead it stops during near some pinMode() calls, potentially it’s stopping during a digie().
  • Usually (let’s say 90% of the time) when it fails this way, I can press the reset button on the Arduino and after rebooting it’ll run setup() and loop() and interrupts correctly.

Are there circumstances in which the program always works correctly

I guess the answer to that is “no”, because even reset is only a 90% of the time thing. (I haven’t actually bothered to record exactly how many times it succeeds over how many times I reset, so maybe it’s 70% or maybe 95%.)

I can change the program to make it complete setup() 100% of the time. But I haven’t been able to write a program that does what I need it to do, and complete 100% of the time.

It is not a good idea to use the String

Thanks for the tip!

NEW STUFF

Here’s the latest iteration of code.

  • I switched from using pulseIn to interrupts. pulseIn had problems unrelated to the bug I’m describing here.
  • I added signal_code_position() to setup, which helps me figure out where the program gets stuck.
  • Removed String
  • Lots of code cleanup. (I didn’t write the first version.)

Re: signal_code_position(). signal_code_position() flashes LED 13 in a particular pattern of short and long flashes so you can tell where in the program signal_code_position() is called. The program seems fine through the first three signal_code_position()s, but doesn’t complete the 4th signal_code_position().

I think the simplest way for someone else to understand what’s going on would be to run the program themselves. The only thing you need is an Arduino Uno. The code crashes before finishing setup().

Really appreciate the help.

#include <SPI.h>
#include <EEPROM.h>

#define NUM_VOTES 3
#define TRIGGER_LOW 28
#define TRIGGER_HIGH 36

#define NUMBER_OF_DIGITS 4
#define COIL_ENERGIZE_TIME 150

#define SONAR_PIN 2
#define SLAVE_SELECT_PIN 10
#define EEPROM_ADDRESS 0

/*
 *  each mic5801 has a strobe pin and an enable pin
 *  the input control voltages are applied, mic5801 reads the input when the strobe
 *     pin goes high.
 *  output is enabled when enable pin goes low.
 *  only need to enable for 150ms (coil energize time)
 */

byte mic5801EnablePin[NUMBER_OF_DIGITS] = {8,6,4,A5};
byte mic5801StrobePin[NUMBER_OF_DIGITS] = {9,7,5,3};


byte lastNumbersSentToSignalex[NUMBER_OF_DIGITS][2] = {{0,0},{0,0},{0,0},{0,0}};

byte numbersToSignalex[10][2]= {
  {250, 16}, //0
  {96, 188}, //1
  {214, 34}, //2
  {244, 40}, //3
  {108, 140}, //4
  {188, 72}, //5
  {190, 64}, //6
  {224, 60}, //7
  {254, 0}, //8
  {252, 8} //9
};

int count = 0;

uint8_t incheses[NUM_VOTES];
uint8_t incheses_idx = 0;
bool person_sliding = false;

void setup () {
  // Uncomment to set counter back to ZERO
//  count = 0;
//  EEPROM.put(EEPROM_ADDRESS, count);

  pinMode(13, OUTPUT);

  signal_code_position();

  for (int i = 0; i < NUM_VOTES; ++i) {
    incheses[i] = 0;
  }

  signal_code_position();

#ifdef DEBUG
  Serial.begin(9600);
#endif

  signal_code_position();

  //  initialize 5801 (disable it)
  for (int i; i<NUMBER_OF_DIGITS; i++) {
    pinMode(mic5801EnablePin[i], OUTPUT);
    pinMode(mic5801StrobePin[i], OUTPUT);
    digitalWrite(mic5801EnablePin[i], HIGH);
    digitalWrite(mic5801StrobePin[i], LOW);
  }

// SETUP() STOPS INSIDE THIS CALL TO SIGNAL_CODE_POSITION()
  signal_code_position();

  pinMode(SONAR_PIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(SONAR_PIN), sonarPing, CHANGE);

  signal_code_position();

  EEPROM.get(EEPROM_ADDRESS, count);

  signal_code_position();

  // initialize display
  SPI.begin();
  signal_code_position();

  setCount(count);
}

#define SCP 1
uint8_t foo_n = 1;
void signal_code_position() {
#ifdef SCP
  delay(1000);

  for(uint8_t i = 0; i < foo_n; ++i) {
    digitalWrite(13, LOW);
    delay(125);
    digitalWrite(13, HIGH);
    delay(125);
  }

  digitalWrite(13, LOW);
  delay(1000);
  
  foo_n += 1;
#endif
}

unsigned long last_enforce = 0;

void loop () {
  if (person_sliding) {
#ifdef DEBUG
    Serial.println("increment");
#endif
    count += 1;
    setCount(count);
    EEPROM.put(EEPROM_ADDRESS, count);
    delay(1500);
    person_sliding = false;
  }
}

uint16_t sonarStart = 0;
void sonarPing() {
  uint16_t now = micros();
  if (digitalRead(SONAR_PIN) == HIGH) {
    sonarStart = now;
  } else {
    if (now > sonarStart) {
      uint8_t inches = (now - sonarStart) / 147;
      incheses[incheses_idx] = inches;
      incheses_idx += 1;
      incheses_idx %= NUM_VOTES;
      update_person_sliding();
    }
  }
}

void update_person_sliding() {
  uint8_t num_different = 0;
  bool a_zero = false;
  for (int i = 0; i < NUM_VOTES; ++i) {
    if (incheses[i] < TRIGGER_LOW || incheses[i] > TRIGGER_HIGH) {
      num_different += 1;
    }
    a_zero = a_zero || incheses[i] == 0;
  }
  person_sliding = num_different > 1 && !a_zero;
}

void setCount(int count) {
  count = count % 10000;
  int digit0 = count % 10;
  int digit1 = ((int) count / 10) % 10;
  int digit2 = ((int) count / 100) % 10;
  int digit3 = ((int) count / 1000);
#ifdef DEBUG
  Serial.print(count);
  Serial.print(" ");
  Serial.print(digit3);
  Serial.print(" ");
  Serial.print(digit2);
  Serial.print(" ");
  Serial.print(digit1);
  Serial.print(" ");
  Serial.println(digit0);
#endif
  setSignalex(0,numbersToSignalex[digit0]);
  setSignalex(1,numbersToSignalex[digit1]);
  setSignalex(2,numbersToSignalex[digit2]);
  setSignalex(3,numbersToSignalex[digit3]);
}

void setSignalex(int digit, byte value[2]) {
  /*  we can save power by comparing the digit currently displayed with
   *  the new digit and only energizing the coils that need to change
   *  (otherwise, we might energize coils that are already in the
   *   desired position, wasting power)
   */   
  byte valuesSentToShiftRegister[2];
  valuesSentToShiftRegister[0]=(value[0] ^ lastNumbersSentToSignalex[digit][0]) & value[0];
  valuesSentToShiftRegister[1]=(value[1] ^ lastNumbersSentToSignalex[digit][1]) & value[1];
  lastNumbersSentToSignalex[digit][0] = value[0];
  lastNumbersSentToSignalex[digit][1] = value[1];
  /*
   *  Use SPI to write the values to the two shift registers.
   */
  writeValuesToShiftRegistersUsingSPI(valuesSentToShiftRegister);
  /*
   *  The output of the shift registers is sent to ALL the current drivers (MIC5801BN)
   *  But they only update their input registers when the strobe line goes HIGH
   *  We strobe only the digit to which we want to write the new values.
   *  strobeMIC5801 also enables those two line drivers to send current to the coils
   */
  strobeMIC5801(digit);
}

/*
 *  send values to shift registers using SPI.
 *  take the shift registers offline while the
 *  values are shifting to prevent intermediate
 *  shift results from appearing on the outputs
 *  take HIGH when all bits are in correct position
 */

void writeValuesToShiftRegistersUsingSPI(byte value[2]) {
  digitalWrite(SLAVE_SELECT_PIN, LOW);
  SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
  SPI.transfer(value[0]);
  SPI.transfer(value[1]);
  SPI.endTransaction();
  digitalWrite(SLAVE_SELECT_PIN, HIGH);
}

void strobeMIC5801(int i) {
  digitalWrite(mic5801StrobePin[i], HIGH);
  delay(1);
  digitalWrite(mic5801StrobePin[i], LOW);
  digitalWrite(mic5801EnablePin[i], LOW);
  delay(COIL_ENERGIZE_TIME);  // energize the coils for 150ms, 90ms should do but this signalex might be defective
  digitalWrite(mic5801EnablePin[i], HIGH);
}

Hot diggity! I think I found it.

for (int i; i<NUMBER_OF_DIGITS; i++) {
  pinMode(mic5801EnablePin[i], OUTPUT);
  pinMode(mic5801StrobePin[i], OUTPUT);
  digitalWrite(mic5801EnablePin[i], HIGH);
  digitalWrite(mic5801StrobePin[i], LOW);
}

What is the value of i when this is initialized? Does it default to 0? Or will it be essentially random? For the record I inherited these lines of code :sunglasses:

FWIW, after a handful of experiments, I'm confident that the above was the issue. For anyone else that finds this thread, hoping for a solution to "Program works only after pressing the reset button", I recommend the following:

  1. For me, the issue was a buffer overrun. Double and triple check your pointer references, and array indexes.

  2. It probably works after reseting because your memory is a bit better initialized after running through the code once already.

Good luck!

AndrewCC:
Hot diggity! I think I found it.

for (int i; i<NUMBER_OF_DIGITS; i++) {

pinMode(mic5801EnablePin[i], OUTPUT);
  pinMode(mic5801StrobePin[i], OUTPUT);
  digitalWrite(mic5801EnablePin[i], HIGH);
  digitalWrite(mic5801StrobePin[i], LOW);
}




What is the value of i when this is initialized? Does it default to 0? Or will it be essentially random? For the record I inherited these lines of code :sunglasses:

i would have a random value here.

AndrewCC:
What is the value of i when this is initialized?

It is normal to write a FOR loop like this

for (int i = 0; i<NUMBER_OF_DIGITS; i++)

…R

Yep.... this was a basic coding mistake. Just like 'basic' programming ... eg. Gwbasic... visual basic etc.... for i = 1 to X, or i = 0 to X etc .... that's the way to do it.

Also, I find that it's usually best to not assume 'system default' values for anything, unless we're absolutely sure that it's truly going to be the default --- for every system that the code is going to be compiled.