Correction proposed to lcd.createChar 2nd arg should be pointer to const uint8_t

Problem:
The character bitmap argument for lcd.createChar is incorrectly identified as potentially modified by the routine. This limits the parameter to dynamic ram. If all 8 custom characters are defined, the cost is 64 bytes of variable memory, reduceable to 8 bytes by copying each bitmap from program memory to a single 8 byte variable before calling createChar. A user-workaround isn’t needed because the createChar routine doesn’t modify the bitmap, it simply writes the bytes to the character memory of the LCD controller. The argument can be identified as not modified by createChar by adding the const qualifier. NB: const uint8_t * is a pointer to constant byte, uint8_t * const is a constant pointer to a byte and const uint8_t * const is a constant pointer to a constant byte. Since the arguments are passed by value, there’s nothing gained by identifying the pointer as unchanged, only the bitmap.

Proposed:
In LiquidCrystal.h the line

void createChar(uint8_t, uint8_t[]);

   to be changed to

void createChar(uint8_t, const uint8_t[]);

       or the equivalent

void createChar(uint8_t, const uint8_t *);

and in LiquidCrystal.cpp the line

void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) {
     
   to be changed to

void LiquidCrystal::createChar(uint8_t location, const uint8_t charmap[]) {

        or the equivalent

void LiquidCrystal::createChar(uint8_t location, const uint8_t *charmap) {

the current source code for the routine is;

// Allows us to fill the first 8 CGRAM locations
// with custom characters
void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) {
  location &= 0x7; // we only have 8 locations 0-7
  command(LCD_SETCGRAMADDR | (location << 3));
  for (int i=0; i<8; i++) {
    write(charmap[i]);
  }
}

The proposed change has no impact on any existing use of the routine. The only practical effect is to remove the restriction that the pointer argument must point to read-write memory and allow the argument to point to read-only memory. In theory it would also allow the compiler to better optimize the calling routine knowing that the bitmap isn’t altered by createChar.

I now see this topic was been touched upon in 2017 in Arduino Forum.

The proposed change is correct for the standard C (and C++) language and has no effect on existing code, but the usefulness of the proposed change depends on the target processor.

For AVR architecture processors that have program memory visible in the RAM address space (e.g. those with gcc attributes avrxmega3 and avrtiny) program memory can be read by the same load instruction used for RAM. The proposed correction has the effect of allowing the character bitmap to be in program memory.

For AVR architecture targets without a unified memory space, the load instruction can't read from program memory. To use program memory to hold the character bitmap the LiquidCrystal library would have to be modified for those targets. Either a distinctly named createChar_P function or a createChar variation selected by the GCC compiler program memory variable attribute attribute((progmem)) can be used. The normal practice for Arduino has been to encapsulate extensions to the language standard by using distinctly named functions with _P added to the usual function name. Having the library use progmem transparently depends on compiler specific extensions, although progmem itself is also a compiler specific extension. To address program memory for the LCD character bitmap data requires the line with write(charmap[ i ]) to be changed to write(pgm_read_byte(&charmap[ i ])).