Worlds Smallest Useful Arduino Class?

I have an application that consists of a couple of dozen individual programs, called by a top-level menu, each of which creates a large number of object when it runs. To avoid death by memory fragmentation, I decided the best solution was to return to the top-level menu by means of a CPU reset. So, I created the below class to accomplish this. To use it:

#include <SoftReset.h>

....

SoftReset();    // Force a Reset

Below is the entire class definition. Just put it in the file SoftReset.h, and move it to the SoftReset director of your local library.

class SoftReset
{
public:
	SoftReset();
};

SoftReset::SoftReset()
{
	void (*resetFunc)(void) = 0;
	resetFunc();
}

Regards,
Ray L.

Worlds Smallest Useful Arduino Class?

"Useful" is not the word I would use to describe such a thing. Any combination of "foolish", "dangerous", "unnecessary" seems more correct.

While the "reset" is occurring, interrupt service routines will continue to fire. That means one bit of code will be trying to clear the .bss section / initialize the .data section while another bit of code is trying to update the millis / micros variables. And, if the user tries to upload a new sketch, the bootloader will be modifying the running interrupt service routines. And...

I would solve the memory fragmentation problems, personally. If these objects are the same size, they won’t fragment memory. If your subsystems free all of the memory they use (which they should) then the memory will coalesce into one large blob and there will be no issues with fragments.

My impression was that was not the case. My code DOES properly free everything, but from the many comments on here, it seemed to me that was not sufficient. If it is, then I don’t need to do this at all.

If memory does get re-combined, then why is String considered so evil? If all Strings are properly disposed, it should cause no problems.

Regards,
Ray L.

Why bother with a poor man's pseudo reset, when you could stop kicking the watchdog, and get a real hard reset?

RayLivingston: I have an application that consists of a couple of dozen individual programs, called by a top-level menu, each of which creates a large number of object when it runs. To avoid death by memory fragmentation, I decided the best solution was to return to the top-level menu by means of a CPU reset. So, I created the below class to accomplish this.

Regards, Ray L.

If I ever NEED a reset under program control, I simply connect a port to the reset pin and leave it normally "INPUT_PULLUP". But, for reset I digital write it LOW and then turn it on as an output. As soon as it resets, it restarts the code which sets the pin as INPUT_PULLUP.

If all Strings are properly disposed, it should cause no problems.

The issue is that an no time during the running of the sketch are you guaranteed to have all String properly disposed of.

Look at the String class. Pay particular attention to what this bit of code does:

String useless = "This";
useless += " ";
useless += "i";
useless += "s";
useless += " ";
useless += "w";
useless += "a";
useless += "s";
useless += "t";
useless += "e";
useless += "f";
useless += "u";
useless += "l";

How many memory allocations take place? How many times is memory copied? What happens if you have two Strings that you are adding the same character to each time?

Krupski: If I ever NEED a reset under program control, I simply connect a port to the reset pin...

That can lock-up the processor requiring a power toggle to bring it back to life.

[quote author=Coding Badly date=1426532986 link=msg=2142799] That can lock-up the processor requiring a power toggle to bring it back to life.

[/quote]

Well, it's worked for me so far. Maybe I'm lucky? (and obviously, choosing pin 13 for this task is a bad idea :grin: )

Krupski: If I ever NEED a reset under program control, I simply connect a port to the reset pin and leave it normally "INPUT_PULLUP". But, for reset I digital write it LOW and then turn it on as an output. As soon as it resets, it restarts the code which sets the pin as INPUT_PULLUP.

This technique is not recommended.

RayLivingston: My impression was that was not the case. My code DOES properly free everything, but from the many comments on here, it seemed to me that was not sufficient. If it is, then I don't need to do this at all.

If memory does get re-combined, then why is String considered so evil?

Concatenating String objects (as PaulS showed) is much more likely to cause fragmentation, as you will get lots of very small pieces of memory allocated, and the finished one may end up in the middle, thus not allowing them all to be combined into one big piece. Plus, unless you allocate your String using new, you will always have at least one of them.

On the other hand, if a particular function does lots of allocations, and later frees all of them (and does nothing which has the side-effect of putting something in the middle, like using String) then you should have your free memory back in the state it started when you exit that function.

[quote author=Nick Gammon link=msg=2142875 date=1426535599]On the other hand, if a particular function does lots of allocations, and later frees all of them (and does nothing which has the side-effect of putting something in the middle, like using String) then you should have your free memory back in the state it started when you exit that function. [/quote]

Well that is good news, so I don't need to do the reset at all then. Each of my sub-programs cleans up after itself, and discards all objects it creates.

Regards, Ray L.

As AWOL said, If you want to do a reset, at least do it right by generating a h/w reset.
Here it is for the AVR.

/*
 * Function to cause the AVR to reset
 */
#include <avr/wdt.h>
void resetArduino()
{
 noInterrupts();
 wdt_enable(WDTO_15MS);
 while(1); // wait to die and be reborn....
}

— bill

[quote author=Nick Gammon date=1426535599 link=msg=2142875] [resetting via a connection between a pin and reset]

This technique is not recommended.

[/quote] Why? Not arguing with you, but want to know... what's wrong with doing it... the technical reason?

bperrybap:
As AWOL said, If you want to do a reset, at least do it right by generating a h/w reset.
Here it is for the AVR.

/*
  • Function to cause the AVR to reset
    */
    #include <avr/wdt.h>
    void resetArduino()
    {
    noInterrupts();
    wdt_enable(WDTO_15MS);
    while(1); // wait to die and be reborn…
    }



--- bill

Well, that’s NICER because it doesn’t consume an I/O pin, but I’m curious as to what the technical reason for not using a port to do reset is?

Krupski:
…I’m curious as to what the technical reason for not using a port to do reset is?

Although it’s clear using the watchdog is far superior, I’m curious too. How could it lock up?

I fail to see how it could lock up. On assertion of hard reset, all I/Os are automatically configured as inputs, so the pin will be released, and float high, allowing it to come out of reset.

Regards, Ray L.

[quote author=Coding Badly link=msg=2141740 date=1426488778] "Useful" is not the word I would use to describe such a thing. Any combination of "foolish", "dangerous", "unnecessary" seems more correct.

While the "reset" is occurring, interrupt service routines will continue to fire. That means one bit of code will be trying to clear the .bss section / initialize the .data section while another bit of code is trying to update the millis / micros variables. And, if the user tries to upload a new sketch, the bootloader will be modifying the running interrupt service routines. And...

[/quote]

Trivially addressed as follows:

SoftReset::SoftReset()
{
        noInterrupts();
    void (*resetFunc)(void) = 0;
    resetFunc();
}

Regards, Ray L.

RayLivingston: I fail to see how it could lock up. On assertion of hard reset, all I/Os are automatically configured as inputs, so the pin will be released, and float high, allowing it to come out of reset.

I can't find the spot in the datasheet, but the issue is that as reset starts processing the I/O pins are released as inputs, however that is done too soon, it is faster than the documented reset pulse length.

I'll try to find a more authoritative reference, although searching the forum should do it.

So, wait.. I was using the pin method to generator a reset.. Putting in high in setup, followed by a 500ms delay.. Then pulling it low when I want to reset.

What's the best way to accomplish a reset that doesn't require addition hardware?

RayLivingston: Trivially addressed as follows:

Uh huh. With an emphasis on "trivial - of little value or importance".

PWM continues to run. Controlling a heating element? Got a fire extinguisher handy?

Interrupt service routines will resume the moment interrupts are re-enabled by the core. How do you believe that sort of code will handle all global variables being reset?

You will eventually reach the point where your "reset" code does exactly the same thing as a watchdog reset. Which raises the obvious question, why would anyone in their right mind not just use the code in Reply #11?

The executable code in Reply #11 is three lines. Your executable code is three lines. It would now be just as trivial to modify your class to use the correct code.

(@bperrybap, thank you for your post.)