Fair point. Not sure how I overlooked those,
but I threw the code together in about 5-10 minutes so it’s hardly surprising.
At any rate I didn’t even know ukeleles have mult-coloured strings.
All I know about ukeleles is how to pronounce the name correctly.
(I very briefly dabbled in learning a bit of Hawaiian. Interesting language.)
Unfortunately I don’t have one bookmarked so I’ll write another from scratch.
Basically the Arduboy uses an AVR chip, and AVR chips have three kinds of memory:
- RAM - which is readable and writable, but volatile (which means the data vanishes when the power is turned off)
- PROGMEM (or ‘Flash’) - which can be read byte-by-byte but can only be written in large blocks, and is non-volatile (the data stays after the power is cut). This is where the machine code that tells the CPU what to do is stored, and you can opt to manually store and read data from it using the
PROGMEM
and pgm_read_xxx
macros (where xxx
is byte
, word
, dword
, float
or ptr
)
- EEPROM - which is readable, writable and non-volatile, and is where people store save data
Each one has a different mechanism for being read from, and when you pass a string to print
it has no way of knowing whether the string is in RAM or PROGMEM, so it assumes the string is in RAM.
The flash string helper trick is a solution that the Arduino library writers came up with to tell the print
functions when a string is in progmem.
However, the Arduino library itself only provides the F
macro, which only works with string literals (e.g. arduboy.print(F("Hello"));
), hence I wrote my flash string helper demo to provide a set of functions that makes it possible to use the flash string helper trick with strings that are already stored in progmem but aren’t string literals.
(There’s actually a better solution than the flash string pointer trick that Arduino came up with,
but we’re kind of stuck with it now.)
A small tip/bit of trivia: you don’t actually need the *
when using a function pointer.
If you try to dereference a function pointer, you actually get the same pointer back, so tunings[currentString]
, *tunings[currentString]
and ********tunings[currentString]
all evaluate to the same value.
(This only applies to function pointers, not to other pointers.)
Suprisingly not many people know about this, so it’s not uncommon to find people trying to dereference function pointers before calling them.