Using the F() macro to save text for LCD in flash

I've run into a problem with a library I'm using, I'm guessing it's just a little detail to fix, but I'm at a loss.
Normally, with most LCDs and libraries, I would do something like this:
LCD.println(F("HELLO WORL"));

I have this lcd/keyboard controller that comes with a library the manufacturer wrote. It all works well (so far) except I can't save text to the flash memory via F(). An example would be:

disp.lcd_cls(); // clear display
disp.lcd_rowcol(0, 2); //row, col
disp.lcd_print("DRILL TABLE MENU");

in this example, I need to do this, but it won't work:

disp.lcd_print(F("DRILL TABLE MENU"));

It is THIS LCD/KEYPAD CONTROLLER as seen here:

I'm using I2C, and THE LIBRARY IS HERE, which he wrote. I talked to him about it, and he wasn't familiar with the Flash () function.
Is it hard to implement this into his library? I have a lot of text to display and will have to have the F() function.
Thanks,

Is it hard to implement this into his library?

No… although I haven’t looked at the code, because I won’t download from external sites. If you attach it to your post, I would take a look. There are probably two easy ways:

1) Derived his class from the Print class. You must make sure the single-character write method is overridden in his class:

        virtual size_t write(uint8_t c);

The Print class will use that method to provide all the other print methods (int, float, char *, etc.).

2) Add a method to his class, using Print.cpp as an example:

size_t LCDclassName::print(const __FlashStringHelper *ifsh)
{
  PGM_P p = reinterpret_cast<PGM_P>(ifsh);
  size_t n = 0;
  while (1) {
    unsigned char c = pgm_read_byte(p++);
    if (c == 0) break;
    if (write(c)) n++;
    else break;
  }
  return n;
}

The F macro result is of type const __FlashStringHelper *, so that’s the method you need to provide.

The first technique is best, as you may be able to eliminate a bunch of code from his library, duplicating what the Print class is already providing. The second technique may quicker for you if you aren’t familiar with C++ classes.

Cheers,
/dev


P.S. The Print class source code, Print.h and Print.cpp, is in the Arduino install directory, under hardware/arduino/avr/cores/arduino.

Thanks for looking into this. It’s all greek to me. (I’m a self talk arduino-er).
These are the 2 files in the library, plus the examples.

bv4619_I.cpp (7.36 KB)

bv4619_I.h (1.62 KB)

I looked at both those files, .cpp and .h, but I can't make sense of what was recommended to fix the problem. Can someone point me in the right direction? I'd sure appreciate it.

You’ll have to do option 2. Add this to the H file, at line 39:

        void lcd_print(const __FlashStringHelper *ifsh);

Add this to the CPP file, at line 131:

void LCD::lcd_print(const __FlashStringHelper *ifsh)
{
  Wire.beginTransmission(_i2adr);
  Wire.write(3); // data

  PGM_P p = reinterpret_cast<PGM_P>(ifsh);
  while (1) {
    char c = (char) pgm_read_byte(p++);
    if (c == 0) break;
    Wire.write(c);
  }

  Wire.write(13); // always finish with 13  
  Wire.endTransmission();
  delay(1);
}

Then add this to the CPP file, at line 27:

#include <avr/pgmspace.h>

Cheers,
/dev

Thanks so much! I'll check this out tomorrow. I normally like to fully understand everything I get help with on the forum, but I this library stuff is SO over my head, I know I won't. Thanks from me, and I'll forward to update to the library developer.
Cheers,

/dev:
You’ll have to do option 2. Add this to the H file, at line 39:

        void lcd_print(const __FlashStringHelper *ifsh);

Add this to the CPP file, at line 131:

void LCD::lcd_print(const __FlashStringHelper *ifsh)

{
  Wire.beginTransmission(_i2adr);
  Wire.write(3); // data

PGM_P p = reinterpret_cast<PGM_P>(ifsh);
  while (1) {
    char c = (char) pgm_read_byte(p++);
    if (c == 0) break;
    Wire.write(c);
  }

Wire.write(13); // always finish with 13 
  Wire.endTransmission();
  delay(1);
}



Then add this to the CPP file, at line 27:



#include <avr/pgmspace.h>



Cheers,
/dev

Actually, this is one of those times that you can use assignment in a conditional clause.

void LCD::lcd_print(const __FlashStringHelper *ifsh)
{
  Wire.beginTransmission(_i2adr);
  Wire.write(3); // data

  PGM_P p = reinterpret_cast<PGM_P>(ifsh);
  char c;
  while( c = pgm_read_byte(p++) )
  {
    Wire.write(c);
  }

  Wire.write(13); // always finish with 13  
  Wire.endTransmission();
  delay(1);
}

Actually...

LOL, there's lots of things I would rewrite from the Arduino core. That snippet is from Print.cpp. Or just use Cosa. :wink:

if you left the AVR behind and used some other processor, all the proprietary progmem kludes in AVR libC to get around the AVR h/w architecture incompatibilities with C would vanish.
i.e. with other micro-controllers const just works as was intended and required by C.

--- bill