Sand-ular-automata

Have been playing around with porting this on my watchX, but equally portable to an Arduboy with an accelerometer!

Here’s the original:

…it freezes up after a short while though - running out of RAM I think? Have got the bitmap(s) stored in PROGMEM, but doing something hacky to pass the array to functions:

memcpy_P(tmpbuff, hourglasstop, BUFSIZE);

Couldn’t get my head around how to pass a PROGMEM array properly? :face_with_raised_eyebrow:

2 Likes

Unless you’re using new or malloc you can’t run out of RAM as such.
If there isn’t enough RAM for the stack and the stack overflows then typically an AVR chip just resets.

Most likely your code is getting stuck in an infinite loop somewhere.

That’s going to really eat into your progmem.

Also there’s two definitions of hourglasstop in the source code.
Hopefully only one is being included, otherwise you’ve got an ODR violation and the code won’t compile.

You pass them the same as normal arrays.
They’re the same type because the language has no concept of ‘progmem’.

PROGMEM is replaced with a compiler-specific attribute.
pgm_read_byte is replaced with inline assembly.

(In the past I have actually experimented with writing wrapper types to make it easier to differentiate between the two with reasonable success. I’ve never published anything though, because I’ve only ever written them as part of libraries that I’ve considered too unfinished to publish. And of course, once you publish something people expect you to support it and provide bug fixes. :P)


Speaking of normal arrays:

void driftEast(uint8_t framebuffer[BUFSIZE], uint8_t glassbuffer[BUFSIZE]) 

Using BUFSIZE doesn’t actually guarantee that the array passed is that size.
The arrays in that function signature will decay to pointers,
meaning that the actual function signature is:

void driftEast(uint8_t * framebuffer, uint8_t * glassbuffer) 

To match specifically sized arrays you’d have to do:

void driftEast(uint8_t (&framebuffer)[BUFSIZE], uint8_t (&glassbuffer)[BUFSIZE]) 

Which causes the arrays to be taken by reference to a fixed size array rather than allowing them to decay to pointers.

Deleted the duplicate - thanks :slight_smile:

Well, when I make the following changes (to directly pass the PROGMEM array instead of first copying it to a temporary RAM array):

Then this is what I get:

IMG_20190531_0615533

That’s because you’re just indexing the array instead of using pgm_read_byte.

When working with a progmem array you need to use pgm_read_byte(&array[index]) instead of array[index].
The reason for that is because AVR chips actually have a machine code separate instruction for reading from progmem and the compiler isn’t able to decide when to use it.

(Also note that you can’t write to an array in progmem.)

OK! After a little time away from this to think, I’ve gotten my head around it and added a separate getSand_P() for PROGMEM which works :partying_face: (still freezing up after a short while though…)

2 Likes

Sounds about right.

I’d need quite a bit of time to debug that.
I struggle to read K&R style code,
and the code doesn’t have many comments.

A tad slow, but very ‘swish’ nonetheless.

Reminds me of this from a long time ago!

1 Like

This made me smile.