adafruit / RGB-matrix-Panel

Arduino library and example code for the 16x32 RGB matrix panels in the shop
http://www.adafruit.com/products/420
303 stars 145 forks source link

Possible Buffer overrun causing flickering #2

Closed davidadsit closed 12 years ago

davidadsit commented 12 years ago

I have a gist of my code available here: https://gist.github.com/1542148

Here is what it does: Scroll text until input is detected Display a message briefly Track the number of inputs from 2 pins on screen Display a message when the inputs reach a certain number

What I am seeing is that when I increase the number of scrolling characters over 16 (line 46 of the gist), there is flickering on the screen when it is displaying the score. The flicker occurs when line 184 is called.

If I reduce the scrolling text to no more than 16 characters, there is no flicker. If I comment out the print statement on line 184, there is no flicker.

I have been unable to diagnose or fix it beyond that and I am wondering if the matrix uses a 16 character print buffer or something of the sort and we are over-running the buffer?

I am using an Uno board with the 16x32 matrix panel.

PaintYourDragon commented 12 years ago

Howdy. I haven't looked at this in detail yet, but already know the likely culprit...

The string- and character-drawing functions aren't particularly intelligent just yet, and don't perform any full-character clipping of their own. At present, every pixel of every character (even ones entirely off the edges) invokes a call to drawPixel(), and clipping occurs there, per-pixel. With long enough strings in the mix, those wasted cycles will become more noticeable.

davidadsit commented 12 years ago

So do you have any recommendations for us other than just using a shorter string?

PaintYourDragon commented 12 years ago

A bit swamped at the moment, but let me see if I can't beat the code into submission today and add better clipping functionality. I'm 99.44% certain this would fix then phenomenon you're seeing.

PaintYourDragon commented 12 years ago

Hi David. Okay, had some time to mess with this, got it fixed. Turns out we're BOTH wrong. :)

I misunderstood what you meant by "flickering," assumed you meant like Atari 2600 Pac Man ghosts (dating myself there!), and in turn assumed this was due to slow rendering. That wasn't the root cause, but I added the character clipping to the library anyway, and scrolling text is noticeably faster. Committed to repository just now.

Ran your code, saw what you were talking about. Problem is that the Arduino RAM is just plain FULL. Double-buffered animation on the 16x32 matrix requires 1.5K of the Arduino's 2K of RAM. After other Arduino core libraries stake their memory claim, that really leaves only a bit over 100 bytes of RAM free for one's own code to use! String constants, by default, are placed in RAM, not program memory, and what's happening is that this longer string declaration is then exceeding the available space:

scrollingText = "WELCOME TO THE ASYLUM";

The solution requires placing constant data (such as strings) in program memory using the PROGMEM directive. Doing this with an array of strings is a particularly convoluted set of flaming hoops (see http://www.nongnu.org/avr-libc/user-manual/pgmspace.html for gritty details). First, declare each string constant separately using PROGMEM, and then declare a string array separately with PROGMEM, containing the list of string constants:

char msg0[] PROGMEM = "WELCOME TO THE ASYLUM",
     msg1[] PROGMEM = "GOOD LUCK!",
     *msg[] PROGMEM = { msg0, msg1 };

Next, the scrollingText pointer is replaced with a number -- an index into the msg[] array. Change this:

char *scrollingText;

to this:

byte scrollingMsgNum = 0;

At various locations in your code where you were previously setting scrollingText to a string, instead set scrollingMsgNum to the desired message number (0 or 1 for now, but maybe you'll have more later).

Finally, the code that prints the message to the display needs to access the PROGMEM strings, based on the above message number. Change this:

matrix.print(scrollingText);

to this:

matrix.print((const __FlashStringHelper *)pgm_read_word(&msg[scrollingMsgNum]));

And that should take care of the problem. Welcome to the asylum!

PaintYourDragon commented 12 years ago

FYI: directly printing PROGMEM strings like this only works in Arduino 1.0. Accomplishing the same in Arduino 0023 is something of a nuisance. If you haven't yet upgraded to 1.0, this might be a good opportunity.

davidadsit commented 12 years ago

Thank you so much for your help! This has solved my last problem and I am able to deploy now. :) This is excellent!