Pages: [1]   Go Down
Author Topic: I2C Display with Micro  (Read 728 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, I'm new to Arduino and I'm trying to get a LCD with a 'backpack' I2C expander board working with my Arduino Micro on a simple "Hello world" test. I ran the basic LED blinking examples and they worked fine.

I've been following this thread:

http://forum.arduino.cc/index.php?topic=170817.msg1269860#msg1269860

and trying to implement it. The I2C expander I'm using has the MCP23008 chip. I've added the New LiquidCrystal library V1.2.1.

I get no characters on the display and no backlight. That thread mentioned putting lcd(address,.....,LED,POSITIVE) as a method of lighting the backlight, but both LED and POSITIVE produce a compile error, saying they're "not declared in this scope". If I remove them it compiles and loads fine but does not display anything.

I've also tried the LiquidTWI library and the example included. That one was able to light and blink the backlight but not display characters.

Here's the code. I mapped the inputs to the LCD constructor (that's what you call the lcd(...) thing right?) according to the connections of my expander board and the byte mapping shown in the commented line right above it.

Code:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

//LiquidCrystal_I2C lcd(address,EN,RW,RS,D4,D5,D6,D7)
LiquidCrystal_I2C lcd(0x24,6,5,4,0,1,2,3);  // Set the LCD I2C address


// Creat a set of new characters
const uint8_t charBitmap[][8] = {
   { 0xc, 0x12, 0x12, 0xc, 0, 0, 0, 0 },
   { 0x6, 0x9, 0x9, 0x6, 0, 0, 0, 0 },
   { 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0, 0x0 },
   { 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0, 0x0 },
   { 0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0x0 },
   { 0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0x0 },
   { 0x0, 0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0x0 },
   { 0x0, 0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0x0 }
   
};

void setup()
{
   int charBitmapSize = (sizeof(charBitmap ) / sizeof (charBitmap[0]));
 
  lcd.begin(16,2);               // initialize the lcd

   for ( int i = 0; i < charBitmapSize; i++ )
   {
      lcd.createChar ( i, (uint8_t *)charBitmap[i] );
   }

  lcd.home ();                   // go home
  lcd.print("Hello, ARDUINO "); 
  lcd.setCursor ( 0, 1 );        // go to the next line
  lcd.print (" FORUM - fm   ");
  delay ( 1000 );
}

void loop()
{
   lcd.home ();
   // Do a little animation by writing to the same location
   for ( int i = 0; i < 2; i++ )
   {
      for ( int j = 0; j < 16; j++ )
      {
         lcd.print (char(random(7)));
      }
      lcd.setCursor ( 0, 1 );
   }
   delay (200);
}

Any ideas what to do?
Logged

Dallas, TX USA
Offline Offline
Faraday Member
**
Karma: 63
Posts: 2649
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The thread you referenced is for a PCF8574 i2c i/o expander chip.
You stated that you have a MCP23008 i2c i/o expander so that thread will not apply.
The LiquidCrystal_I2C interface class in fm's currently released library only supports
the PCF8574 chip so it will not work with your backpack.

I've seen 3 different MCP23008 based backpacks and none of them use the pin mapping
you entered into the constructor.
The LIquidTWI library that I've seen is for
the AdaFruit #292 board, but the pin mapping you supplied in your sketchis not for that board.

I'm curious which backpack you have.

Trial and error is not good practice.
And in the case of the MCP23008 it could damage the LCD or MCP23008 if the guesses are wrong.
This is a case were the tiny details really matter.
You need a library that supports the MCP23008
and then you must make sure that it is properly configured for your backpack so the library is setting
the output pins properly.
There is no standard for how to wire the output pins of a i2c i/o expander to a HD44780 LCD
and so boards from different vendors wire it up differently.
And that is why I said you must first make sure that the library supports the MCP23008 and
then you must make sure that it is properly configured for your backpack.

When installing different LCD libraries, you also need to very carefully follow
the instructions as often times you can't have multiple installed at a time.

I have a unreleased add-on for fm's library that supports the MCP23008 but in order to use
it you must know the pin wiring for your backpack. This isn't something to guess at because
the MCP23008 has strong source and sink capabilities and could potentially burn up an LCD
if the library was told the wrong wiring.

--- bill

Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have the JeeLabs LCD Plug and a Longtech 1602A LCD. I did check the datasheets of both to make sure the expander pins matched the LCD pins.

I didn't do trial and error. I pored over the library files and examples for hours to try to educate myself, but it's all new to me. I also tried Adafruit's modified LiquidCrystal library and the LiquidTWI they link to because Adafruit's backpack uses the same MCP23008 expander chip, but neither worked. With those two I didn't see any examples where the constructor used full pin mapping, just used the address as the input. I only tried the full pin mapping above with the library I linked to because it was shown in the examples in the thread I linked to.

The LCD Plug has these connections:

LCD Plug   Display Pin   LCM1602A Pin Name
P0               11                   DB4
P1                12                  DB5
P2                13                  DB6
P3                14                  DB7
P4                4                   RS
P5                N/A
P6                6                   E
P7                16 (actually the base of a driving transistor connected to 16 through a 27 ohm limiting resistor)
(ground)     5                   R/W
NC               7-10             DB0-DB3
Logged

Western New York, USA
Offline Offline
Faraday Member
**
Karma: 32
Posts: 4258
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I did check the datasheets of both to make sure the expander pins matched the LCD pins.
What Bill is saying is that you have to make sure that the library knows which of the MCP23008 pins is connected to which of the LCD plug pins.

Don

Edit:  The information is in the file jlpcb-043.png at your jeelabs link.
« Last Edit: February 11, 2014, 09:38:49 pm by floresta » Logged

Dallas, TX USA
Offline Offline
Faraday Member
**
Karma: 63
Posts: 2649
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

But you do have to admit, there was some "trial and error" going on.

Quote
I only tried the full pin mapping above with the library I linked to because it was shown in the examples in the thread I linked to.
But like a said, that thread was talking about using a PCF8574  chip and your board has
the MCP23008 so why try it? The chips are very different.

Moving on...
So it looks like you've done some research.
And the pin mapping you provided does seem to match the wiring of the JeeLabs LCDPLUG.

It sounds like you are trying to connect the LCDPLUG to an Arduino Micro vs using a JeeLabs JeeNode.

The main problems you are running into is that
-  fm's LiquidCrystal_I2C class doesn't support the MCP23008.
- the AdaFruit board libraries don't allow configuring the wiring, they are hard coded
to the Adafruit board #292 wiring which is different from the Jeelabs LCDPLUG.
- the JeeLabs library is really meant for JeeNodes (it uses soft i2c and doesn't use the SDA/SCL Wire pins)


You have a couple of options,
- modify one of the adafruit libraries to use the LCDPLUG pin mapping

- use the JeeLabs library and make sure to hook up the LCDPLUG AIO and DIO pins to the same
pins that would be used if were using one of the JeeNode ports.
(Not difficult, you just need to look up which pins are used which JeeNode port - It is documented)
http://jeelabs.net/projects/hardware/wiki/JeeNode

- PM me and I can send you some unreleased code for fm's library that will allow you do use that library.
It is a new class that supports the MCP23008
You will have to connect the LCDPLUG to use the pins that the Wire library uses
This means connecting the LCDPLUG AIO to SCL and DIO to SDA
Just keep in mind that since it is unreleased code, not part of fm's library that if you
update the library at some point in the future you existing sketches may break as the
update may or may not have this code in it.

--- bill





Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm not actually using a JeeNode. When I was shopping around for a I2C display solution I hadn't yet looked at the Arduino code environment, and I didn't even realize JeeNodes were a thing. I thought I had just stumbled upon a handy expander board. Once I learned about the Arduino's library system, it seemed like the JeeLabs code added an unnecessary amount of confusion to what was already new to me, so I went in search of a more general library that conformed to standard Arduino code.

You have a couple of options,
- modify one of the adafruit libraries to use the LCDPLUG pin mapping
[snip]
- PM me and I can send you some unreleased code for fm's library that will allow you do use that library.
It is a new class that supports the MCP23008

I think one of these is my best option. Whichever results in the fastest code would be my preference (I keep seeing references to different libraries being faster). The display part of my final code will be the least important part, so I need to make sure it doesn't unduly tax the controller.

What does it take to modify the pin mapping?

Thanks.
Logged

Dallas, TX USA
Offline Offline
Faraday Member
**
Karma: 63
Posts: 2649
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

To change the pin mapping in the adafruit library code is fairly simply.
You will see the hard coded pin mappings in their LiquidCrystal() constructor code
in LiquidCrystal.cpp
Just change them to match your wiring.

The pin mapping for the LiquidTWI library is totally hard coded in the actual code and
doesn't use defines - just raw bit twiddling code.
It requires totally re-writing the code in the send() function of the LiquidTWI.cpp module.


The AdaFruit library is DOG slow.
This is because it is emulating the digitalRead()/digitalWrite() interface across the i2c bus.
While interesting, it is slow because it does a full i2c access and write for each bit/pin.
The LiquidTWI library will be quite a bit faster as it writes all 8 bits at once.
The IIC interface class code I wrote is around twice as fast as LiquidTWI library because
I run the MCP23008 in a more efficient mode and an top of that I manage the i2c bus more efficiently.

This table tells the full story:

Code:
16Mhz AVR
Interface    ByteXfer    16x2FPS      Ftime
----------------------------------------------
4BIT          338uS        86.92     11.51ms (orignal Liquid Crystal)
adafruit     4000uS         7.35     136.02ms (Adafruit mcp23008 lib,i2c mode)
LiquidTWI    1340uS        21.95      45.57ms (LiquidTWI lib v1.5.1)

4BIT           98uS       298.58      3.35ms
SR2W           76uS       388.62      2.57ms
SR_2W          72uS       406.90      2.46ms (SR in 2 wire mode)
SR_3W          61uS       480.03      2.08ms (SR in 3 wire mode)
SR3W          102uS       287.92      3.47ms
I2C           957uS        30.74      32.25ms (pcf8574 @ 100kbit/sec)
IIC pcf8574   544uS        54.03      18.51ms (pcf8574 @ 100kbit/sec)
IIC mcp23008  645uS        45.62      21.92ms (mcp23008 @ 100kbit/sec)

The ByteXfer column is how long it takes to transfer each byte to the LCD.
The 16x2 FPS column is the number of times per second a 16x2 display could be updated
The Ftime column is how long each full 16x2 frame takes to update.
i.e. how long it takes to fully update a 16x2 LCD display.

You can see how fast each interface is with each library.
When using a mcp23008:
Adafruit: 4000us
LiquidTWI: 1340us
IIC mcp23008: 645us

So you can see the IIC interface class code I wrote is considerably faster than the other two libraries
and allows fully configuration of the pin wiring.

Some other considerations, the other libraries don't provide full compatibility
with the LiquidCrystal library. This means that when you change libraries or interfaces
you will need to go in an tweak your sketch code.
Say you change to using a different i2c backpack like one with a PCF8574 or switch to 4bit mode, or use a shift register.
with fm's library you simply change the constructor, and are done. No sketch code tweaks will be
necessary. With the others, it isn't quite so simple.
Things get really sticky with the Adafruit library if you are wanting to use other LiquidCrystal
compatible libraries as its doesn't really play nice with other libraries.
So say you go get a PCF8574 based backpack, then depending on which library you use,
you may have to uninstall the Adafruit library. (i.e. fm's library and Adafruit cannot coexist)
fms' library is the only library has configurable pin wiring.

This is the reason I tell people not to mess with the other libraries and to use fm's library.
In your case, at least right now, it is a bit special in that you are needing mcp23008 support
and fm's currently released library doesn't support that chip.

So I'd recommend 1 of two things:
1) to patch Adafruits library (it is pretty easy as I showed above)
2) pm me for some unreleased code for fm's library

I go with option #2 but keep in mind it is unreleased code and the final
release may break your existing sketch code if you update to the newer library.

--- bill




Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks. One more question: can the I2C speed be successfully changed to Fast 400kHz mode? I saw a mention somewhere in these forums about overriding the default 100kHz speed. Anything to speed it up.
Logged

Dallas, TX USA
Offline Offline
Faraday Member
**
Karma: 63
Posts: 2649
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

There are ways to bump up the i2c clock, but you run the risk of it not working with certain slave devices.
Also, since the Wire library doesn't have that capability you have to directly hit the hardware and
it is different on different micro-controllers.

For character based LCDs I don't find the current speed of the i2c clock to be much of a limiting factor
at least not from a visual stand point.

Another thing to consider is if you bump up the clock, you may run into some issues as some
libraries depend on the speed of the interface to account for some of the needed delays
when sending commands to the display.

Unless you have some specific need to lower the MCU overhead, I wouldn't worry about it.


--- bill
« Last Edit: February 12, 2014, 07:42:07 pm by bperrybap » Logged

NSW Australia
Offline Offline
Faraday Member
**
Karma: 80
Posts: 3234
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

For character based LCDs I don't find the current speed of the i2c clock to be much of a limiting factor at least not from a visual stand point.

From a visual standpoint, generally none of this matters, not only due to visual persistence, but the substantial persistence of the LCD itself.

What does matter is that slow writing makes it all the more difficult to interleave this code with timing tasks in your main loop.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It's not the speed of the display I'm worried about, it's that I will also have a DAC on the I2C bus which will get heavy use and I want it to be as fast as possible.
Logged

Pages: [1]   Go Up
Jump to: