M2TKLIB Hello World with LiquidCrystal_I2C

I am trying to use M2TKLIB with my I2C 20x4 LCD panel. I tried modifying the hello world program to use the different library...

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include "M2tk.h"
#include "utility/m2ghlc.h"

LiquidCrystal_I2C lcd(0x3F,20,4);

M2_LABEL(hello_world_label, NULL, "Hello World!");
M2tk m2(&hello_world_label, NULL, NULL, m2_gh_lc);

void setup() {
  m2_SetLiquidCrystal(&lcd, 16, 2);
}

void loop() {
  m2.draw();
  delay(500);
}

But I get the following errors

In file included from HelloWorld.cpp:29:0:
/home/myhome/sketchbook/libraries/M2tklib/utility/m2ghlc.h:27:27: fatal error: LiquidCrystal.h: No such file or directory
compilation terminated.

So I tried a simple change to m2ghlc.h

//#include <LiquidCrystal.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

But more errors appear...

In file included from HelloWorld_for_m2tklib.cpp:29:0:
/home/myhome/sketchbook/libraries/M2tklib/utility/m2ghlc.h:31:26: error: variable or field ‘m2_SetLiquidCrystal’ declared void
/home/myhome/sketchbook/libraries/M2tklib/utility/m2ghlc.h:31:26: error: ‘LiquidCrystal’ was not declared in this scope
/home/myhome/sketchbook/libraries/M2tklib/utility/m2ghlc.h:31:41: error: ‘lc_ptr’ was not declared in this scope
/home/myhome/sketchbook/libraries/M2tklib/utility/m2ghlc.h:31:57: error: expected primary-expression before ‘cols’
/home/myhome/sketchbook/libraries/M2tklib/utility/m2ghlc.h:31:71: error: expected primary-expression before ‘rows’
HelloWorld_for_m2tklib.cpp: In function ‘void setup()’:
HelloWorld_for_m2tklib.cpp:40:34: error: ‘m2_SetLiquidCrystal’ was not declared in this scope

So I thought I had better ask before making matters worse :slight_smile:

The simple answer is, M2tklib does not support LiquidCrystal_I2C.

If you want to support LiquidCrystal_I2C, you need to locate "m2ghlc.cpp"
Replace LiquidCrystal with LiquidCrystal_I2C, but also replace all member function calls with the equivalent one from LiquidCrystal_I2C.
For example you will find:

    case M2_GFX_MSG_START:
      m2_gh_lc_cursor_y = 255;
      m2_lc_ptr->noCursor();
      m2_lc_ptr->noBlink();
      m2_lc_ptr->clear();

So, for noCursor() you need to find the corresponding function name to switch the cursor off.

Once this is done all your errors should go away.

Oliver

I was starting to come to that conclusion myself. It seems that nearly all LCD libraries seem to target the non-I2C devices, so although I really like how the I2C display interfaces with only a couple of pins, it makes more work whenever I want to use a library like M2TKLIB.

Thanks for the help.

Can you provide a link to the I2C lib? I will check if i can do the porting.

Oliver

olikraus:
Can you provide a link to the I2C lib? I will check if i can do the porting.

Oliver

The one I have is from http://www.dfrobot.com/image/data/DFR0154/LiquidCrystal_I2Cv1-1.rar

However, googling it just now, I see others, but they all seem very similar - maybe a common ancestry.
For example
https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads/LiquidCrystal_V1.2.1.zip
http://hmario.home.xs4all.nl/arduino/LiquidCrystal_I2C/LiquidCrystal_I2C.zip

ok, thanks.

I have created issue 98 for this: Google Code Archive - Long-term storage for Google Code Project Hosting.

Oliver

olikraus:
ok, thanks.

I have created issue 98 for this: Google Code Archive - Long-term storage for Google Code Project Hosting.

Oliver

Much appreciated. As a beginner, I wasn't sure of the situation with all the various libraries and hardware surrounding the Arduino. It can all be a bit confusing, but all the support that is available is great.

I added the New LiquidCrystal Library (https://bitbucket.org/fmalpartida/new-liquidcrystal/) as output engine to M2tklib.
A first beta release for the New LiquidCrystal Library is available for download: Google Code Archive - Long-term storage for Google Code Project Hosting.

Oliver

olikraus:
I added the New LiquidCrystal Library (https://bitbucket.org/fmalpartida/new-liquidcrystal/) as output engine to M2tklib.
A first beta release for the New LiquidCrystal Library is available for download: Google Code Archive - Long-term storage for Google Code Project Hosting.

Oliver

Thanks. I just downloaded it and am trying to understand how to make the Hello World example work with my I2C display. Firstly I had to include Wire.h to get it to compile.

Then I tried to convert it to I2C by including the different library and changing how the lcd object was created (and changing the setup to 20x4 from 16x2)

#include <Wire.h> 
//#include <LiquidCrystal.h>
#include <LiquidCrystal_I2C.h>
#include "M2tk.h"
#include "utility/m2ghnlc.h"


LiquidCrystal_I2C lcd(0x3F);

M2_LABEL(hello_world_label, NULL, "Hello World!");
M2tk m2(&hello_world_label, NULL, NULL, m2_gh_nlc);

void setup() {
  m2_SetNewLiquidCrystal(&lcd, 20, 4);
}

void loop() {
  m2.draw();
  delay(500);
}

This is producing these errors

In file included from HelloWorld.pde:42:
/home/myhome/sketchbook/libraries/M2tklib/utility/m2ghnlc.h:32: error: variable or field ‘m2_SetNewLiquidCrystal’ declared void
/home/myhome/sketchbook/libraries/M2tklib/utility/m2ghnlc.h:32: error: ‘LCD’ was not declared in this scope
/home/myhome/sketchbook/libraries/M2tklib/utility/m2ghnlc.h:32: error: ‘lc_ptr’ was not declared in this scope
/home/myhome/sketchbook/libraries/M2tklib/utility/m2ghnlc.h:32: error: expected primary-expression before ‘cols’
/home/myhome/sketchbook/libraries/M2tklib/utility/m2ghnlc.h:32: error: expected primary-expression before ‘rows’
HelloWorld:45: error: no matching function for call to ‘LiquidCrystal_I2C::LiquidCrystal_I2C(int)’
/home/myhome/sketchbook/libraries/LiquidCrystal_I2C/LiquidCrystal_I2C.h:57: note: candidates are: LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t, uint8_t, uint8_t)
/home/myhome/sketchbook/libraries/LiquidCrystal_I2C/LiquidCrystal_I2C.h:55: note: LiquidCrystal_I2C::LiquidCrystal_I2C(const LiquidCrystal_I2C&)
HelloWorld.pde: In function ‘void setup()’:
HelloWorld:51: error: ‘m2_SetNewLiquidCrystal’ was not declared in this scope

So assuming I just don't understand :slight_smile: I thought it was time to ask advice.

Hi

Well, as far as possible, i tested this release in my environment. So, this is what i did:

  1. Install a fresh Arduino IDE (I have used 1.0.3)
  2. Download LiquidCrystal_V1.2.1.zip from https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads
    It is really important to use LiquidCrystal_V1.2.1.zip, which contains the base class LCD ( this was missing in on your PC).
  3. In your installation directory, located the libraries folder. Extract LiquidCrystal_V1.2.1.zip in that folder. Among others
    this will overwrite the original LiquidCrystal Library.
  4. Install m2tklib and update the example as you already did. Now it should compile.

Oliver

I got it to compile thanks.

Unfortunately, that library just doesn't work with my display. Even their own HelloWorld_i2c example that comes with the Liquidcrystal library just produces a flashing backlight. The DFRobot library (and other libraries that I mentioned) does work with my display, so they've done something different. However they won't work with M2TKLIB because they lack things like LCD.h (I think). So I am stuck.

The DFRobot library (and other libraries that I mentioned) does work with my display

I have added support for one of the libraries you mentioned in reply #4.

Oliver

My fault. I was sure they all worked when I first tried them, maybe I had an earlier version, or a modified one. When I googled for examples for my previous post, that one came up and I assumed it was the same. I am currently using the DFRobot one at the moment and it definitely works. I don't really understand how some can work, and others fail. Must be varying hardware out there too. Hopefully they will all eventually work as they iron out the bugs and add support for all the variations.

digimate:
I don't really understand how some can work, and others fail. Must be varying hardware out there too. Hopefully they will all eventually work as they iron out the bugs and add support for all the variations.

There is varying i2c to hd44780 hardware out there.
Some librarys are hard coded for a particular wiring/pin mapping and
some libraries like fm's allow the pin mapping to be configured.
So, In the case of fm's library the library is not the actual problem
but rather the problem comes down to the user properly filling in the constructor which configures the pin mappings
for the library.
fm's library has a default output pin mapping for how the wires/traces are connected
between the pcf8574 chip and the hd44780 interface.
It is unwise not to fill in the full constructor and use the default mappings since
different PCF8574 based boards wire up the connections differently.
The default pin mapping in the library is for fm's lcd i/o expander board
and many of the i2c based boards are not wired up the same way.

When the pin mapping is wrong/incorrect, the library will compile just fine,
but since it has been told the incorrect pin mappings, it will not be able to properly
initialize and drive the lcd.

Unfortunately, There is no way to have the library automatically detect the wiring
and automatically set up the pin mappings.

To ensure that i2c interface works with fm's library, it is best
to always properly fill in the full constructor which includes all the pin mappings rather than only fill
in the i2c address, which will cause the library use the pin mappings of fm's lcdio board, which is
different from many of the other i2c to hd44780 boards out there.
Plus, the default pin mappings do not include backlight control over the i2c interface since
fm's lcd i/o board does not support this.

If you fill in the full constructor, you can not only ensure that the pin mappings are correct,but
also configure the library for how to control the backlight over the i2c interface.


Oliver,
for m2tk how do you detect the different libraries to handle initialization?
i.e. different libraries use different initialization functions. Most call begin() and but some call init()

--- bill

bperrybap:
There is varying i2c to hd44780 hardware out there.
Some librarys are hard coded for a particular wiring/pin mapping and
some libraries like fm's allow the pin mapping to be configured.
So, In the case of fm's library the library is not the actual problem
but rather the problem comes down to the user properly filling in the constructor which configures the pin mappings
for the library.
fm's library has a default output pin mapping for how the wires/traces are connected
between the pcf8574 chip and the hd44780 interface.
It is unwise not to fill in the full constructor and use the default mappings since
different PCF8574 based boards wire up the connections differently.
The default pin mapping in the library is for fm's lcd i/o expander board
and many of the i2c based boards are not wired up the same way.

When the pin mapping is wrong/incorrect, the library will compile just fine,
but since it has been told the incorrect pin mappings, it will not be able to properly
initialize and drive the lcd.

Unfortunately, There is no way to have the library automatically detect the wiring
and automatically set up the pin mappings.

To ensure that i2c interface works with fm's library, it is best
to always properly fill in the full constructor which includes all the pin mappings rather than only fill
in the i2c address, which will cause the library use the pin mappings of fm's lcdio board, which is
different from many of the other i2c to hd44780 boards out there.
Plus, the default pin mappings do not include backlight control over the i2c interface since
fm's lcd i/o board does not support this.

If you fill in the full constructor, you can not only ensure that the pin mappings are correct,but
also configure the library for how to control the backlight over the i2c interface.

Well, thanks for filling me in on all that. I know nothing about constructors, and I really feel I have jumped in the deep end here. Still, it looks like there's hope of making it work, and I'm game to try.

I need to find out where and how to set up the pin mappings, and what they really should be. I'll try looking the code and google, but if anyone can lead me in the right direction, that would help :slight_smile: .

I found this data on the connections of my display

?PIN CONNECTIONS
Pin Symbol Function
1 VSS Ground for Logic(0V)
2 VDD Power supply for Logic(+5V)
3 V0 Power supply for LCD Driver
4 RS H: Data?L: Instruction Code
5 R/W H: Read; L: Write
6 E Enable signal
7~14 DB0~DB7 Data Bus Line
15 A Backlight Power(+5V)
16 K Backlight Power(0V)

and tried to write a 'constructor' as follows (based on the library code I have copied at the bottom of this post

LiquidCrystal_I2C lcd ( 0x3F, 6, 5,4 , 
                        7, 8, 9, 10,
                         15,POSITIVE);

All I am getting at the moment is the backlight turns off and nothing is displayed (although there seems to be 2 lines of faint characters (this is a 4 line display)

One thing I thought was odd is that it only has 4 data pins in the constructor, but the table above talks about 8. I did try pins 11 to 14 instead of 7 to 10, but it doesn't seem to make any difference.

   /*!
    @method     
    @abstract   Class constructor. 
    @discussion Initializes class variables and defines the I2C address of the
    LCD. The constructor does not initialize the LCD.
    
    @param      lcd_Addr[in] I2C address of the IO expansion module. For I2CLCDextraIO,
    the address can be configured using the on board jumpers.
    @param      En[in] LCD En (Enable) pin connected to the IO extender module
    @param      Rw[in] LCD Rw (Read/write) pin connected to the IO extender module
    @param      Rs[in] LCD Rs (Reset) pin connected to the IO extender module
    @param      d4[in] LCD data 0 pin map on IO extender module
    @param      d5[in] LCD data 1 pin map on IO extender module
    @param      d6[in] LCD data 2 pin map on IO extender module
    @param      d7[in] LCD data 3 pin map on IO extender module
    */
   LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t En, uint8_t Rw, uint8_t Rs, 
                     uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7 );
   // Constructor with backlight control
   LiquidCrystal_I2C(uint8_t lcd_Addr, uint8_t En, uint8_t Rw, uint8_t Rs, 
                     uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7,
                     uint8_t backlighPin, t_backlighPol pol);

Another step forward ! Figured out the constructor numbers are bit numbers, so I had to follow traces on the backpack board to see where the pfc8574 pins were wired to on the LCD display proper. Then translate those to bit numbers.

For anyone else with a sainsmart LCD display with their "lcd2004" I2C adapter, the following seems to work.

 LiquidCrystal_I2C lcd ( 0x3F,2,1,0, 4,5,6,7,3,POSITIVE);

Good to see that you made some progress here. Do the m2tklib examples work?

I have selected fm's New LiquidCrystal mainly because of the large number of supported display types. It has also a nice software architecture with a common base class (class LCD). All other variants are derived from this base clase. So I was able to use the base class inside m2tk and do the testing with the 8bit parallel variant. Indeed all my testing with the New LiquidCrystal lib had been very successful, so i was hoping that also the I2C variant will work without bigger problems.

@Bill: M2tk calls the "begin()" member function of the LCD base class to init the display. I can't remember if there exists something like a "init()" member function. It turned out, that the LCD base class had the same interface as the original Arduino LiquidCrystal class. And also my tests with the 8 bit hardware setup had not revealed any issue concerning init.

Oliver

Yes, was just writing this when you posted - now the M2TKLIB Hello World example works, modified as below. Changes are to include <Wire.h>, to include <LiquidCrystal_I2C.h> instead of <LiquidCrystal.h>, and to set it up using "LiquidCrystal_I2C lcd ( 0x3F,2,1,0, 4,5,6,7,3,POSITIVE);"

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include "M2tk.h"
#include "utility/m2ghnlc.h"

LiquidCrystal_I2C lcd ( 0x3F,2,1,0, 4,5,6,7,3,POSITIVE);

M2_LABEL(hello_world_label, NULL, "Hello World!");
M2tk m2(&hello_world_label, NULL, NULL, m2_gh_nlc);

void setup() {
  m2_SetNewLiquidCrystal(&lcd, 16, 2);
}

void loop() {
  m2.draw();
  delay(500);
}

Thanks for ALL the help !

olikraus:
@Bill: M2tk calls the "begin()" member function of the LCD base class to init the display. I can't remember if there exists something like a "init()" member function. It turned out, that the LCD base class had the same interface as the original Arduino LiquidCrystal class. And also my tests with the 8 bit hardware setup had not revealed any issue concerning init.

I worked with fm to ensure that the library is transparently compatible with the original LiquidCrystal library.
The reason I brought up the begin()/init() issue is that there are some other i2c libraries out there (which I wouldn't recommend)
but are never the less popular and in use.
Those other i2c libraries have different constructors and specify the geometry in the constructor
and then use a call to init() to initialize them vs begin().
To me this is not smart since it makes them incompatible with the LiquidCrystal initialization.
But since it appears that your code calls the lcd initialization, it will matter to your code
if you decide to support these other i2c to hd44780 libraries.

My personal opinion, don't support those libraries and be done with it.
Just steer people to fm's library which works the same on many different interfaces.

--- bill