I have been modifying my cLEDMatrix class to support irregular layouts but there several approaches I can take, so thought I would ask which method would be the most useful.
When declaring the Matrix you could pass an uint8_t array with 1 bit per led, so for a 80x10 matrix it would be 100 bytes which can be const. It only uses a few extra bytes of ram for the row or column indexes, but also has extra code of 170 to 250 bytes and is slower.
When declaring the Matrix you could pass the same type of bitmap array but the class would allocate either a uint8 or uint16 array for the led indexes. This option would be quick but uses much more ram and program memory.
You declare the Matrix with a flag which then allocates the extra uint8 or unit16 array depending on the number of leds. Then you can use a function with X/Y parameters to exclude leds. As quick as option 2 in use.
Hope the above makes sense. I don’t have any irregular matrix’s but have been asked for this a few times. So am hoping people that have/use them could tell me of their preference
I already have a type 1 written, but don’t like the code overhead on each X/Y call. My personal preference would be for type 3.
In general, I’d try to conserve RAM at the expense of program space, and also not worry TOO much about a few cycles between approaches. That’s my general feeling here, anyway.
Beyond that, my only serious experience with irregular matrices was for the RGBShades, which resulted in this code:
Maybe that’ll be useful to think about, maybe not, but the RGBShades are one concrete example of an irregular matrix that people might care about.
Update: Looking at that code again now, I’d consider moving the ShadesTable into PROGMEM, since it never changes in this case. Frees up a bunch of SRAM for other uses. (cc: @Garrett_Mace aka Mr. RGBShades)
Moving table into PROGMEM is definitely a TODO there, though we’re not RAM constrained yet. We use PROGMEM a lot on the LED Matrix Shades for things like text and graphic bitmaps, CIE brightness curve, sine table, etc.
I could be wrong here, but I was under the impression that ‘const’ data is placed in PROGMEM anyway. I decided to check this, so I downloaded rgbshades and played a little
If you move the ShadesTable definition outside of the function scope the program size reduces by 440 bytes and ram by 4 bytes!
Then removing the ‘const’, reduces the program size by another 56 bytes but adds 80 bytes to ram usage.
I can’t get to see the assembly code, but it certainly seems that predefined data is better to be global const.
Nice science there. And I also think there’s one more invisible variable here: stack size.
I suspect that if the array is inside the function, it’s dynamically allocated (as RAM) on the stack, and initialized with the values shown (that’s the 440 bytes of program size, I bet). There’s no trivial way to tell at compile time what the actual total depth of the stack will be, though some newer Arduino IDE versions have given an estimate in the verbose compiler output.
So the best bet is probably to declare constant data like this as const globals, where it’ll automatically get compiled into the flash program memory. If you don’t want to pollute the global namespace for some reason, you can probably put the data inside a function as long as it’s const and PROGMEM’d.
I won’t have time to dissect this tonight, but it’d be great to actually dig into the stack-vs-heap SRAM as well the more obvious SRAM-vs-flash questions.
Thanks for doing some digging and sharing your results!
If you wanted to keep the data local to the function you can declare it as ‘static const’ which seems to keep the program size the same as declaring it global i.e. smaller.