Connecting NHD-C0220BiZ-FSW-FBW-3V3M I2C LCD Display to a Teensy

Been working on a Teensy project that needs an I2C LCD display. All I had in my junk bins were 5V displays that I’ve been using on Arduinos. I got a temporary solution running by using a level shifter to shift between the 3.3V Teensy and the 5V LCD. Works, but is clunky and requires a separate 5V power supply.

I went looking for a native I2C 3.3V display and found this one made by Newhaven:

Although it is a 2×20 display, it is quite a bit smaller than the Sainsmart displays I have purchased in the past. It also has a much sharper display and the white backlight makes the text far easier to read than the blue backlight I am used to seeing.

It is $10.40, which is actually about $1 less than the same Sainsmart display (well at the first vendor I found anyway). Irregardless, $10 isn’t bad for a clean display that has a reasonably understandable datasheet.

I received my two displays promptly from Mouser (I never buy one of anything as that pretty much guarantees I’m going to burn it up and have to wait for another).

The Hardware

The datasheet is fairly understandable to a non-pro like myself. I found most of the explanation understandable. The points that took a little understanding (for me) were:

The pins are slightly closer together than .1″; however, I found if I carefully fanned the pins, I could get them into a breadboard. Still, it would have been nice had they been standard.

The schematic shows pullup resistors for the SCL and SDA line, but no values. Some research indicates these should both be 4.7K ohm resistors.

The reset line indicates it must be LOW to be active (e.g. in the reset state). After experimenting, I found I must use a 1K pullup resistor to keep the reset line high. If it just floats, the display will stay in the reset state.

The pins to the side are the power for the backlight where A is the LED anode (+) and K is the LED cathode (-).

I used 1uF capacitors, as suggested for VOUT and C1+ and C1-. Whilst extracting 1uF from the part bin, I pulled out a 10uF and used it by accident. Believe me, you don’t want to do that. The display will do nothing and you’ll waste time trying to figure out what went wrong ūüôā

Here is the schematic of my test project, connecting the Teensy to the LCD:

newhaven

A note about the backlight: I connected it to a 2N3906 PNP transistor so the Teensy can turn the backlight on/off. The backlight is rated for 2.8-3V (and my power supply is 3.3v). An NPN transistor’s voltage drop of .7V was a bit too much, and PNP’s was nearly perfect, giving the display 2.9V. The downside to this scheme is the driving logic is backwards – you must make the Teensy pin LOW to turn on the backlight. Well, I can live with that.

I2C

Once I had the LCD connected and apparently operating, next step was to verify I2C was working. Of course, my first attempt was to simply use the same LiquidCrystal I2C library I used with SainSmart, but, of course, that didn’t work.

I connected a logic analyzer to the SCL and SDA lines and started probing. The datasheet says the I2C address of the LCD is 0x78, but that didn’t seem to work.

I got an I2C scanner running on the Teensy and found it was seeing a device at address 0x3C. That didn’t seem right, but it was the only device connected, and if it was disconnected, I got nothing, so ox3C had to be right.

After doing some research I found that while the vendor will specify an 8 bit address, the Arduino library uses a 7 bit address. The last bit is the read/write bit. If it is 0, the device is read, and 1 written. So read from 0x78 and write to 0x79.

The Arduino I2C library (2wire) gets rid of the read/write bit in the address. If you shift 0x78 right 1 bit (getting rid of the read/write bit), you end up with 0x3C. The library will then append the 0/1 as necessary depending on what you are doing.

Good, now I understand a little more and have written it down so maybe I’ll remember it next time!

Library

Once I had the correct address, I tried the LiquidCrystal library again. I could see the Teensy communicating with the Display and getting ACKs, but nothing was displaying.

I went looking for a driver specifically for the NHD-C0220BiZ-FSW-FBW-3V3M. Seems I spend a lot of time trying to find a good driver when messing with new hardware. But, still, way less time than it would take to write one.

After trying several that did not work, I found this page:

https://bitbucket.org/fmalpartida/st7036-display-driver/downloads

and downloaded LCD_ ST7036_v1.2.0.zip. This library worked!

I rewrote their example program to fit my hardware as follows:

////////////////////////////////////////////////////////////////////////////////////
// []    i2c LCD library Display Test Demo
// []    Original was 4-2-2009  dale@wentztech.com
// []    DGG 2012-04-11 - Libraries were modified to run under Arduino 1.0
// []    DH  2015-08-26 - Altered for my own testing of NewHaven I2C LCD
////////////////////////////////////////////////////////////////////////////////////

#include                "LCD_C0220BiZ.h"
#include                "ST7036.h"
#include                <Wire.h>

const int               backlightPin        = 23;
const int               cols                = 20;
const int               rows                = 2;

ST7036                  lcd                 (rows, cols, 0x78);

//----------------------------------------------------------------------------
void Cursor_Type(
    ){

lcd.setCursor(0,0);
lcd.print("Underline Cursor");
lcd.setCursor(1,0);
lcd.cursor_on();
delay(1000);

lcd.cursor_off();
lcd.setCursor(0,0);
lcd.print("Block Cursor    ");
lcd.setCursor(1,0);
lcd.blink_on();
delay(1000);

lcd.blink_off();
lcd.setCursor(0,0);
lcd.print("No Cursor      ");
lcd.setCursor(1,0);
delay(1000);

} // Cursor_Type

//----------------------------------------------------------------------------
// Assume 16 character lcd

void Characters(
    ){

char                    a;
int                     chartoprint     = 48;

lcd.clear();

for(int i=0 ; i < rows ; i++){
    for(int j=0 ; j < cols ; j++){
        lcd.setCursor(i,j);
        a = char(chartoprint);
        lcd.print(char(chartoprint));
        chartoprint++;
        if(chartoprint == 127)
            return;
        }
    }
} // Characters

//----------------------------------------------------------------------------
void Every_Line(
    int                 lines
    ){

lcd.clear();
for(int i=0 ; i < lines ; i++){
    lcd.setCursor(i,0);
    lcd.print("Line : ");
    lcd.print(i,DEC);
    }
} // Every_Line

//----------------------------------------------------------------------------
void Every_Pos(
    int                 lines,
    int                 cols
    ){

lcd.clear();

for(int i=0 ; i < lines ; i++){
    for(int j=0 ; j< cols ; j++){
        lcd.setCursor(i,j);
        lcd.print(i,DEC);
        }
    }
} // Every_Pos

//----------------------------------------------------------------------------
void setup(
    ) {

int                     duty;
int                     i;

lcd.init();                                                 // Init the display, clears the display
lcd.clear ();

pinMode(backlightPin, OUTPUT);
digitalWrite(backlightPin, LOW);                            // turn it on (actually already is)

lcd.setCursor(0, 0);
lcd.print("Hello World!");                                  // Classic Hello World!
delay(1000);

// dim display
for (i = 0; i <= 100; i = i + 10) {
    analogWrite(backlightPin, map(i, 0, 100, 255, 0));
    delay(500UL);
    }

// brighten display
for (i = 100; i >= 0; i = i - 10) {
    analogWrite(backlightPin, map(i, 0, 100, 255, 0));
    delay(500UL);
    }

// Reset display to full on
lcd.clear ();
lcd.print("Turn Backlight Off");
pinMode(backlightPin, OUTPUT);                              // pinMode must be called to clear analogWrite
digitalWrite(backlightPin, HIGH);
delay(1000UL);

lcd.clear ();
lcd.print("Turn Backlight On");
digitalWrite(backlightPin, LOW);
delay(1000UL);

}

//----------------------------------------------------------------------------
void loop(
    ){

lcd.clear();
lcd.print ("Cursor Test");
delay(1000);
Cursor_Type();

lcd.clear();
lcd.print("Characters Test");
delay(1000);
Characters();
delay(1000);

lcd.clear();
lcd.print("Every Line");
delay(1000);
Every_Line(rows);
delay(1000);

lcd.clear();
lcd.print("Every Position");
delay(1000);
Every_Pos(rows,cols);
delay(1000);

} // loop

Note that in Setup, I use PWM to alter the brightness of the backlight (analogWrite). I then switch back to ‘normal’ mode by using pinMode(n, OUTPUT).

My example can be downloaded from here:

http://www.xyfyx.com/files/NewHavenLCDTest.zip

Here is the breadboarded project:

newhaven-f2

Advertisements
This entry was posted in c-arduino, c-electronics and tagged . Bookmark the permalink.

2 Responses to Connecting NHD-C0220BiZ-FSW-FBW-3V3M I2C LCD Display to a Teensy

  1. Dave says:

    we used 100k pull-ups, works fine

  2. Paul says:

    Many thanks for this. It saved me quite a bit of hair. I should have followed your strategy of buying two displays — for a week I was convinced I toasted one while I waited for a second one to come in, when it turned out to be just my coding.

    BTW: on my rig (a Teensy 3.2), 100k pullups work, but only if there is *nothing* else connected to the lines. The ‘scope shows a very sluggish rise on the clock, not even reaching 3V. Even 10k is not that reliable. 4.7k is bulletproof.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s