NewHaven OLED Display on I2C


#1

I’ve got my NewHaven Character OLED wired up I2C. I I’ve confirmed wiring and voltage (5V) but I can’t get it to even turn on or I see no activity from the OLED… I’ve tried another one I had too… no luck. I’ve modified the sketch here at this link and used their wiring diagram. I’m not sure if I need the 10K Ohm pullup resistors or not.

Newhaven Display Forum Tutorial

anyone have an easier/basic “starter” I2C setup for an OLED Character Display. Any help would be appreciated.


NHD-0420DZW-AB5 OLED Display incorrect output
#2

It’s always best to explicitly state how you have wired than just

Also the exact type and a link to the datasheets/schematics to hardware devices should be part of the original post.

I found a datasheet here
This display is by default set for MPU-6800 Parallel communication. For serial (SPI not I2C) you’d need to set the jumpers accordingly (see datasheet).

Alternatively I now found this other display which has I2C, but still needs jumpers to select the interface


#3

Apologies @ScruffR. I’ll attach my code below which has my pin config for the photon and the display. The datasheet for my display is NHD-0420CW-AG3 I’ve followed the instructions in the datasheet on pg 4-5 and “I think” I’ve interpreted them right … but not totally sure… like /RES… I have that tied high… should it be low and on some posts I’ve seen that you need pull-up resistors on SDA/SCL pins. I’ve seen some folks use 4.7K ohm or 10K ohm tied to 3.3V. Then finally docs say 2.8V ~ 5V… is 3.3V ok or do I need to convert to 2.8V or 5V explicit.

/*
 * from Demo_NHD0420CW-Ax3_I2C.ino
 * 
 * Tutorial sketch for use of character OLED slim display family by Newhaven with Arduino Uno (Brian Beardmore: modifying for Particle Photon), using 
 * only Wire (I2C) library.  Models: NHD0420CW-Ax3, NHD0220CW-Ax3, NHD0216CW-Ax3. Controller: US2066
 * in this example, the display is connected to Photon via I2C interface.
 *
 * Displays on the OLED alternately a 4-line message and a sequence of character "block".
 * This pgm ssumes the use of a 4x20 display; if different, modify the values of the two variables 
 * ROW_N e COLUMN_N.
 * The pgm uses the minimum possible of Photon pins; if you intend to use also /RES line, 
 * the related instructions are already present, it's sufficient to remove the comment markers.
 *
 * The circuit modified by Brian Beardmore for Particle Photon I2C:
 * OLED pin 1 (Vss)          to VSS ground
 * OLED pin 2 (VDD)          to 3.3V
 * OLED pin 3 (REGVDD)       to GND (not using 5V, docs say take to GND)
 * OLED pin 4 (SA0)          to VSS ground should use 0x3C address (to assign I2C address 0x3D, connect to VDD)
 * OLED pin 5 and 6          to VSS ground
 * OLED pin 7 (SCL)          to Photon D1 (SCL); 10K pull-up resistor on OLED pin to 3.3V? Do I need this?
 * OLED pin 8 and 9 (SDAin,SDAout are jumpered) to Photon D0 (SDA); 10K pull-up resistor on each OLED pin 8 and 9 to 3.3V? Do I need this?
 * OLED pin 10 to 15         to VSS ground
 * OLED pin 16 (/RES)        to VDD 3.3V
 * OLED pin 17 (BS0)         to VSS ground  ** I2C config BSO to GND (low)
 * OLED pin 18 (BS1)         to VDD 3.3V    ** I2C condig BS1 to 3.3V (high)
 * OLED pin 19 (BS2)         to Vss ground  ** I2C config Bs2 to GND (low)
 * OLED pin 20 (Vss)         to Vss ground
 *
 * Original example created by Newhaven Display International Inc.
 * Modified and adapted to Arduino Uno 15 Mar 2015 by Pasquale D'Antini
 * Modified 19 May 2015 by Pasquale D'Antini
 * Modified 06 Feb 2017 by Brian Beardmore for Particle Photon
 *
 * This example code is in the public domain.
 */

#include <application.h> // added for Photon support

const byte ROW_N = 4;                 // Number of display rows
const byte COLUMN_N = 20;             // Number of display columns

//const byte RES = 13;                // Arduino's pin assigned to the Reset line (optional, can be always high)

const byte SLAVE2W = 0x3C;            // Display I2C address, in 7-bit form: 0x3C if SA0=LOW, 0x3D if SA0=HIGH

const byte TEXT[4][21] = {"1-Newhaven Display--", 
                          "2-------Test--------", 
                          "3-16/20-Characters--", 
                          "4!@#$%^&*()_+{}[]<>?"};         // Strings to be displayed

byte new_line[4] = {0x80, 0xA0, 0xC0, 0xE0};               // DDRAM address for each line of the display
byte rows = 0x08;                     // Display mode: 1/3 lines or 2/4 lines; default 2/4 (0x08)
byte tx_packet[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
                                      // Packet to be transmitted (max 20 bytes)
// _______________________________________________________________________________________

void command(byte c)                  // SUBROUTINE: PREPARES THE TRANSMISSION OF A COMMAND
{
   tx_packet[0] = 0x00;               // Control Byte; C0_bit=0, D/C_bit=0 -> following Data Byte contains command
   tx_packet[1] = c;                  // Data Byte: the command to be executed by the display
   send_packet(2);                    // Transmits the two bytes
}
// _______________________________________________________________________________________

void data(byte d)                     // SUBROUTINE: PREPARES THE TRANSMISSION OF A BYTE OF DATA
{
   tx_packet[0] = 0x40;               // Control Byte; C0_bit=0, D/C_bit=1 -> following Data Byte contains data
   tx_packet[1] = d;                  // Data Byte: the character to be displayed
   send_packet(2);                    // Transmits the two bytes
}
// _______________________________________________________________________________________

void send_packet(byte x)              // SUBROUTINE: SEND TO THE DISPLAY THE x BYTES STORED IN tx_packet
{
   byte ix = 0;                       // Bytes index
  
   Wire.beginTransmission(SLAVE2W);   // Begin the transmission via I2C to the display with the given address
   for(ix=0; ix<x; ix++)              // One byte at a time, 
   {
      Wire.write(tx_packet[ix]);      //  queue bytes for transmission
   }
   Wire.endTransmission();            // Transmits the bytes that were queued 
}
// _______________________________________________________________________________________

void output(void)                     // SUBROUTINE: DISPLAYS THE FOUR STRINGS, THEN THE SAME IN REVERSE ORDER
{
   byte r = 0;                        // Row index
   byte c = 0;                        // Column index

   command(0x01);                     // Clears display (and cursor home)
   delay(2);                          // After a clear display, a minimum pause of 1-2 ms is required
   
   for (r=0; r<ROW_N; r++)            // One row at a time,
   {
      command(new_line[r]);           //  moves the cursor to the first column of that line
      for (c=0; c<COLUMN_N; c++)      // One character at a time, 
      {
         data(TEXT[r][c]);            //  displays the correspondig string
      }
   }

   delay(2000);                       // Waits, only for visual effect purpose
   
   for (r=0; r<ROW_N; r++)            // One row at a time,
   {
      command(new_line[r]);           //  moves the cursor to the first column of that line
      for (c=0; c<COLUMN_N; c++)      // One character at a time, 
      {
         data(TEXT[3-r][c]);          //  displays the correspondig string (in reverse order)
      }
   }
}
// _______________________________________________________________________________________

void blocks(void)                     // SUBROUTINE: FILLS THE ENTIRE DISPLAY WITH THE CHARACTER "BLOCK"
{
   byte r = 0;                        // Row index
   byte c = 0;                        // Column index

   command(0x01);                     // Clear display (and cursor home)
   delay(2);                          // After a clear display, a minimum pause of 1-2 ms is required

   for (r=0; r<ROW_N; r++)            // One row at a time,
   {
      command(new_line[r]);           //  moves the cursor to the first column of that line
      for (c=0; c<COLUMN_N; c++)      // One character at a time, 
      {
         data(0xDB);                  //  displays the character 0xDB (block)
         delay(50);                   // Waits, only for visual effect purpose
      }
      delay(500);                     // Waits, only for visual effect purpose
   }
}
// _______________________________________________________________________________________

void setup(void)                      // INITIAL SETUP
{
//   pinMode(RES, OUTPUT);            // Initializes Arduino pin for the Reset line (optional)
//   digitalWrite(RES, HIGH);         // Sets HIGH the Reset line of the display (optional, can be always high)
   delayMicroseconds(200);            // Waits 200 us for stabilization purpose
   Wire.begin();      // Initiate the Wire library and join the I2C bus as a master
   delay(10);         // Waits 10 ms for stabilization purpose
   
   if (ROW_N == 2 || ROW_N == 4)
      rows = 0x08;                    // Display mode: 2/4 lines
   else
      rows = 0x00;                    // Display mode: 1/3 lines
   
   command(0x22 | rows); // Function set: extended command set (RE=1), lines #
   command(0x71);        // Function selection A:
   data(0x5C);           //  enable internal Vdd regulator at 5V I/O mode (def. value) (0x00 for disable, 2.8V I/O)
   command(0x20 | rows); // Function set: fundamental command set (RE=0) (exit from extended command set), lines #
   command(0x08);        // Display ON/OFF control: display off, cursor off, blink off (default values)
   command(0x22 | rows); // Function set: extended command set (RE=1), lines #
   command(0x79);        // OLED characterization: OLED command set enabled (SD=1)
   command(0xD5);        // Set display clock divide ratio/oscillator frequency:
   command(0x70);        //  divide ratio=1, frequency=7 (default values)
   command(0x78);        // OLED characterization: OLED command set disabled (SD=0) (exit from OLED command set)
   
   if (ROW_N > 2)
      command(0x09);  // Extended function set (RE=1): 5-dot font, B/W inverting disabled (def. val.), 3/4 lines
   else
      command(0x08);  // Extended function set (RE=1): 5-dot font, B/W inverting disabled (def. val.), 1/2 lines
   
   command(0x06);        // Entry Mode set - COM/SEG direction: COM0->COM31, SEG99->SEG0 (BDC=1, BDS=0)
   command(0x72);        // Function selection B:
   data(0x0A);           //  ROM/CGRAM selection: ROM C, CGROM=250, CGRAM=6 (ROM=10, OPR=10)
   command(0x79);        // OLED characterization: OLED command set enabled (SD=1)
   command(0xDA);        // Set SEG pins hardware configuration:
   command(0x10);        //  alternative odd/even SEG pin, disable SEG left/right remap (default values)
   command(0xDC);        // Function selection C:
   command(0x00);        //  internal VSL, GPIO input disable
   command(0x81);        // Set contrast control:
   command(0x7F);        //  contrast=127 (default value)
   command(0xD9);        // Set phase length:
   command(0xF1);        //  phase2=15, phase1=1 (default: 0x78)
   command(0xDB);        // Set VCOMH deselect level:
   command(0x40);        //  VCOMH deselect level=1 x Vcc (default: 0x20=0,77 x Vcc)
   command(0x78);        // OLED characterization: OLED command set disabled (SD=0) (exit from OLED command set)
   command(0x20 | rows); // Function set: fundamental command set (RE=0) (exit from extended command set), lines #
   command(0x01);        // Clear display
   delay(2);             // After a clear display, a minimum pause of 1-2 ms is required
   command(0x80);        // Set DDRAM address 0x00 in address counter (cursor home) (default value)
   command(0x0C);        // Display ON/OFF control: display ON, cursor off, blink off
   delay(250);           // Waits 250 ms for stabilization purpose after display on
   
   if (ROW_N == 2)
      new_line[1] = 0xC0;             // DDRAM address for each line of the display (only for 2-line mode)
}
// _______________________________________________________________________________________

void loop(void)                       // MAIN PROGRAM
{  
   output();                          // Execute subroutine "output"
   delay(2000);                       // Waits, only for visual effect purpose
   blocks();                          // Execute subroutine "blocks"
   delay(2000);                       // Waits, only for visual effect purpose
}


#4

I’d definetly try with the 10k pull-ups.

Not sure how the display copes with 3.3V instead of 2.8V, but you could always go for 5V via Vin (also pullups to Vin).

I think /RES can be left N/C since it should have a pull-up on board.
If you want to reset via code, you could use this code with 5V too

const int _res = D6; // any pin other than A3 or DAC (not 5V tolerant)
void setup() {
  pinMode(_res, INPUT); // set for hi-Z (=default)
  ...
}

void resetDisplay() {
  pinMode(_res, OUTPUT);
  digitalWrite(_res, LOW);
  delay(100);
  pinMode(_res, INPUT); // set for hi-Z (=default)
}

You could also use the I2C scanner to first check if the display is found at all.


OLED 4pin I2C (GND VDD SCK SDA) with Photon [SOLVED]
#5

ok, got home tonight and starred at this thing until I’m blue in the face. I can’t see it and I’ve tried my setup on two different Photon’s and two different NHD-0420CW OLED displays. @ScruffR, I got the I2C scanner, thanks for that tip! and it’s showing it cannot find the I2C display anywhere… should find it on 0x3C… (…I also powered Pin4 to find it on 0x3D, no luck) So I think I have a wiring problem or hardware problem… but really 2 displays are bad out of the box or I somehow fried them???.. I’m not thinking so, so starring at the wiring again…and these goofy pullup resistors… thought about moving them closer to the Photon Pins, I may try that.

my version of the I2C Scanner code…

// --------------------------------------
// i2c_scanner
//
// Version 1
//    This program (or code that looks like it)
//    can be found in many places.
//    For example on the Arduino.cc forum.
//    The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
//     Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26  2013
//    V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
//    by Arduino.cc user Krodal.
//    Changes by louarnold removed.
//    Scanning addresses changed from 0...127 to 1...119,
//    according to the i2c scanner by Nick Gammon
//    http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
//    As version 4, but address scans now to 127.
//    A sensor seems to use address 120.
// Version 6, November 27, 2015.
//    Added waiting for the Leonardo serial communication.
//
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//
 
#include "application.h"
 
 
void setup()
{
  Wire.begin();
 
  Serial.begin(9600);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");
}
 
 
void loop()
{
  byte error, address;
  int nDevices;
 
  Serial.println("Scanning...");
 
  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
 
    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");
 
      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknow error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
 
  delay(5000);           // wait 5 seconds for next scan
}


#6

Hey @bbeardmore, I was having the same problem, so I gave the datasheet more scrutiny and looked closely at the configuration for this example code. It turns out you need to connect pin 16 to either VSS or a software reset pin. In your image, it looks like you have 16 connected to VDD. I connected it to VSS and the displayed kicked on as expected.


#7

@aholmes sorry so late on the reply! YES! this was exactly my problem and I fixed t and am off and running now!