Program don't work after reboot

Hello!

I have an interesting problem from my point of view. I’m writing a program where i allocating heap memory with the ‘new’ keyword. I don’t use String and other libraries except Arduboy2 and my custom objects without explicit malloc() and free(). When i compiling and uploading my program sketch replacing another sketch my program works and have 800+ bytes in memory free. But after second reboot it hangs on the boot ‘Arduboy’ logo. I noticed that if boot logo had been disabled after the first reboot the screen hangs not on the initial state of my program but it somehow restores last image on the screen before reboot. Can be the problem in Heap Fragmentation or something like that? Why my program works on the first time when i replacing another sketch?

In my experience this is probably a overrun condition that is occouring during initial boot as well but you don’t notice it since the memory space may be clean where the overrun is walking into, it doesn’t result in any unusual behavior.

My guess is the reboot does something to that memory bit it was overruning into that then causes a crash.

But if you are poking into memory, then the overrun condition could actually just occour at any time if it’s at the wrong address.

Basically unusual behavior is almost always the result of a bug in my code that addresses the wrong memory.

1 Like

Can you take a look at my code? I’m using parametric polymorphism and load order for my prototype object instances.

https://github.com/Lancefiger/FateRogue

Thats gonna be several levels above my pay grade I sometimes have to look up the syntax for making if and loop statements. @Pharap or @MLXXXp are much smarter.

But why can SRAM influence bootloader. I didn’t even use PROGMEM and EEPROM. Only new and delete.

RAM is not cleared during a reboot, and so possibly the bootloader is using those values, or your code as it reinitializes ends up using a slightly different address as the stack moves around.

I don’t know I’m not that smart, but I do know RAM contents stay there between boots, and the bootloader also needs some RAM to do it’s thing so the heap will have different contents from a cold boot or a restart because of the code that had been running in the first boot.

2 Likes

You use lots of PROGMEM, as that’s where you code is stored. When you have strings that aren’t stored in PROGMEM, you actually use twice as much memory - one for the PROGMEM copy and one for the in-RAM copy that’s created at program start. new/delete are generally going to be bad choices for Arduboy games. There’s just not enough RAM on the device to do much, and heap allocations come with overhead for tracking and padding for alignment.

The reason the previous code may affect how your code runs is due to memory initialization. By default, RAM isn’t set to all zeros on startup, only the RAM that needs to be cleared is actually cleared. On a Linux system, new memory pages are zero-filled by default, but that’s not the case on a non-MMU system like this.

1 Like

The problem with that theory is that the screen buffer is a static member variable, so it should be zero-initialised before setup() even runs.

I think what’s actually going on is that the memory in the screen itself still holds whatever was in it before the reboot because display() was never called.


So to track down where the problem lies I did some testing by interleaving Serial.println(__COUNTER__) througout setup(), like so:

void setup()
{
	while(!Serial) {}

	Class::arduboy.begin();
	Class::arduboy.setFrameRate(15);
	Serial.println(__COUNTER__);

	xcur = Class::exemplar->make("C20");
	Serial.println(__COUNTER__);

	ycur = Class::exemplar->make("C7");
	Serial.println(__COUNTER__);

	scene = Class::exemplar->make("S");
	Serial.println(__COUNTER__);

	scene->atPut(Class::Directive::X, xcur);
	Serial.println(__COUNTER__);

	scene->atPut(Class::Directive::Y, ycur);
	Serial.println(__COUNTER__);
	
	scene->atGet(Class::Directive::Build);
	Serial.println(__COUNTER__);
	
	delete xcur;
	Serial.println(__COUNTER__);
	
	delete ycur;
	Serial.println(__COUNTER__);
	
	xcur = Class::exemplar->make("C5");
	Serial.println(__COUNTER__);

	ycur = Class::exemplar->make("C5");
	Serial.println(__COUNTER__);

	scene->atPut(Class::Directive::X, xcur);
	Serial.println(__COUNTER__);

	scene->atPut(Class::Directive::Y, ycur);
	Serial.println(__COUNTER__);

	player = Class::exemplar->make("\x01Player");
	Serial.println(__COUNTER__);

	scene->atPut(Class::Directive::Character, player);	
	Serial.println(__COUNTER__);
}

Note: __COUNTER__ is a compiler-specific macro,
please do not rely on it for any serious code.
I’m only using it here for the sake of quickness.

The output was:

0
1
2
3
4
5

Which puts the sticking point at:

scene->atGet(Class::Directive::Build);

So I threw in a few more serial prints…

case Class::Directive::Build: //build the scene and bounds
	_xsize = ::atoi(_xcoord->toStr());
	Serial.println('A');
	_ysize = ::atoi(_ycoord->toStr());
	Serial.println('B');
	_characters = new Class*[_xsize * _ysize] {};
	Serial.println('C');
	return this;
	break;

(By the way, that break is unreachable code,
the return will exit the function before the break is reached.)

This time I get:

0
1
2
3
4
5
A
B

So, long story short, new is getting stuck.
Chances are you’re trying to allocate too much memory so the Arduboy is just getting stuck.


This is precisely why we say don’t use dynamic memory allocation on Arduboy.
You don’t get a compiler error, you don’t get any kind of warning,
your program just seizes up at runtime and you’re left scratching your head.

So to answer your question:

Your problem isn’t heap fragmentation.
The heap isn’t even living long enough to become fragmented because you’re not deleting anything,
you’re simply trying to allocate more member than the Arduboy can handle.

Honestly though, I dug through your code and I’m having a hard time trying to figure out what the values of _xsize and _ysize actually are.

To be very blunt, I think you seriously need to rethink how your code is designed.
Using new and delete on an embedded system with so little RAM is a bad idea.
Trying to pass integers around as strings and using atoi to parse them back out is also a bad idea.

I can’t help but wonder if perhaps you’re used to using a language like Python or JavaScript so you’re perhaps having a hard time because you’re used to being able to use as much memory as you want, or using odd design patterns that only work in certain environments.

2 Likes

For the sake of further clarification…

When using C++ whether memory is zero-initialised depends very much on how the memory is allocated.

For example, global variables and static member variables are all zero-initialised.

Whether an object allocated with new is zero-initialised depends on both its type and how the new operator is used.
For example, new int would give an uninitialised integer,
whilst new int() would give a zero-initialised integer.

I feel I should point out that it’s possible to store strings entirely in progmem.
It’s only when you use bare string literals without using the F macro that it also causes them to be copied into RAM.

If you use the F macro around a literal or store them manually as a char array in progmem then they’ll be properly stored in progmem.
(In the latter case you have to use a bit of trickery to make print work though.)

1 Like

Ok but it’s not a graphics problem, the code crashes, the memory addressing is likely outside of the buffer.

No, it isn’t.

If you read the rest of my comment, you’ll find that I narrowed the problem down to line 181 of Scene.cpp (_characters = new Class*[_xsize * _ysize] {};), which suggest that it’s probably the new that’s causing it to hang.

2 Likes

One could possibly debug this with a ICE tool?

Thank you very much! Now i know how to debug my code with serial prints.