Program causes MCU to hang on boot

I have spent the last 4 days writing a program to take around 50 inputs and give about 35 outputs, mostly through shift registers.

This is to test a series of precision fluid pumps over about 4 hours - so many of the timers don’t allow for overflow. This code is complex enough without that!

My problem is that the “void autoRun()” function (1st function after Setup) causes the ATMega328 MCU to hang at boot, and on the serial port I just get a repeating pattern.

I have a fading LED which cycles roughly once every 2 seconds to tell me the MCU is running, which does not even light up.

If I remove large chunks of the “void autoRun()” code, the parts that remain work fine. I cannot narrow down which bits are causing it to hang or why.

I have built my own PCB to control this, as 16 IC’s on prototype board is not easy!

Please have spoons at the ready to gauge your eyes out after looking at my code (I’ve only been coding for 2 months).

Code attached as an attachment

code.ino (119 KB)

The first thing I would eliminate is an out-of-RAM condition. It's of particular interest because of all the strings you Serial.print().

A quick way to buy back a bunch of ram is to enclose the strings in your serial print statements in F(), like this:

Serial.print("xyz");     // change this
Serial.print(F("xyz"));  // into this

Try that in all your Serial.print strings and see if it helps...


I agree with billroy’s suggestion. One way to test for this type of problem is to insert a piece of code that prints out the amount of available memory - if your problem is caused by memory exhaustion then by simplifying your sketch you should eventually be able to reduce the memory requirements until it runs, at which point you can print out the available memory and watch that reducing as you reinstate code. If you see the available memory getting very small as you approach the problem then it confirms that this is the problem. There are a couple of code fragments posted in the playground which show two ways to measure free memory. One way compares the addresses of the top of the stack with the bottom of the heap and this is the one I recommend. The other simply allocates and releases successively bigger chunks of memory from the heap until it fails; this one is IMO less useful because it returns the amount of contiguous space in the heap, not the space available for the stack to use.

many of the timers don’t allow for overflow. This code is complex enough without that!

Handling timer overflow is just a matter of comparing timer values correctly - it doesn’t need any extra code or any additional complexity, just the correct technique for making the comparisons.

unsigned long previousMillis;

if(millis() - previousMillis > interval)
    // do whatever you need to happen when the interval has elapsed
    previousMillis += interval; // if you want to do this at regular intervals, update the state ready for next time

The critical part is the IF statement. There are various alternative ways to code this which are logically equivalent if you ignore number overflow, but which don’t handle overflow correctly - you need to do it exactly as shown above. Also ensure that time values are always held as unsigned long values.

You are using WAY, WAY, more than the 2k of memory that is present on the ATmega328.

 avr-size *.elf
   text    data     bss     dec     hex filename
  21716    6286     272   28274    6e72 test_pumps.cpp.elf

This means that people's suggestions on reducing RAM size (starting with your constant strings) are definitely a REQUIREMENT...

On the plus side, using the F() construct helps A LOT in this case.

avr-size *.elf
   text    data     bss     dec     hex filename
  29446      42     272   29760    7440 test_pumps.cpp.elf

Since I already did it anyway, here’s the modified code. I don’t know how correct this is; I did a pretty blind wholesale replace operation, since you had many such Serial.print() calls. But starting with this should be less painful than using the Arduino IDE to do the replacements manually!

test_pumps.ino (120 KB)

Thanks very much guys, the F trick worked great. I'll have to read up about memory as its a new concept to me!