Newhaven Display Forum

Newhaven Products => OLEDs => Topic started by: oldmaker on March 25, 2015, 06:15:09 PM

Title: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: oldmaker on March 25, 2015, 06:15:09 PM
Hi,
I read some posts asking for use of NHD0420CW-Ax3 display family with Arduino Uno.
So I modified the example supplied by Newhaven and adapted it to Arduino Uno, for tutorial purpose. They are fully tested.
I hope these examples may be useful for beginners.

Tutorial 1 - display connected to Arduino Uno via I2C interface:
Code: [Select]
/*
 * Demo_NHD0420CW-Ax3_I2C.ino
 *
 * Tutorial sketch for use of character OLED slim display family by Newhaven with Arduino Uno, using
 * only Wire (I2C) library.  Models: NHD0420CW-Ax3, NHD0220CW-Ax3, NHD0216CW-Ax3. Controller: US2066
 * in this example, the display is connected to Arduino via I2C interface.
 *
 * Displays on the OLED alternately a 4-line message and a sequence of character "block".
 * This sketch assumes the use of a 4x20 display; if different, modify the values of the two variables
 * ROW_N e COLUMN_N.
 * The sketch uses the minimum possible of Arduino's 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:
 * OLED pin 1 (Vss)          to Arduino pin ground
 * OLED pin 2 (VDD)          to Arduino pin 5V
 * OLED pin 3 (REGVDD)       to Arduino pin 5V
 * OLED pin 4 (SA0)          to Vss ground   (to assign I2C address 0x3D, connect to VDD 5V)
 * OLED pin 5 and 6          to Vss ground
 * OLED pin 7 (SCL)          to Arduino pin A5 (SCL); 10K pull-up resistor on OLED pin
 * OLED pin 8 and 9 (SDAin,SDAout) to Arduino pin A4 (SDA); 10K pull-up resistor on OLED pin
 * OLED pin 10 to 15         to Vss ground
 * OLED pin 16 (/RES)        to Arduino pin Reset or VDD 5V (or to Arduino pin D13, to control reset by sw)
 * OLED pin 17 (BS0)         to Vss ground
 * OLED pin 18 (BS1)         to VDD 5V
 * OLED pin 19 (BS2)         to Vss ground
 * 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
 *
 * This example code is in the public domain.
 */

#include <Wire.h>

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
}
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: oldmaker on March 25, 2015, 06:17:18 PM
Tutorial 2 - display connected to Arduino Uno via 8-bit 6800 parallel interface:
Code: [Select]
/*
 * Demo_NHD0420CW-Ax3_parallel_6800_8b.ino
 *
 * Tutorial sketch for use of character OLED slim display family by Newhaven with Arduino Uno, without
 * using any library.  Models: NHD0420CW-Ax3, NHD0220CW-Ax3, NHD0216CW-Ax3. Controller: US2066
 * In this example, the display is connected to Arduino via 8-bit 6800 parallel interface.
 *
 * Displays on the OLED alternately a 4-line message and a sequence of character "block".
 * This sketch assumes the use of a 4x20 display; if different, modify the values of the two variables
 * ROW_N e COLUMN_N.
 * The sketch uses the minimum possible of Arduino's pins; if you intend to use also R/W, /CS or /RES
 * lines, the related instructions are already present, it's sufficient to remove the comment markers.
 *
 * The circuit:
 * OLED pin 1 (Vss)    to Arduino pin ground
 * OLED pin 2 (VDD)    to Arduino pin 5V
 * OLED pin 3 (REGVDD) to Arduino pin 5V
 * OLED pin 4 (D/C)    to Arduino pin D2
 * OLED pin 5 (R/W)    to Vss ground (always write); to enable also read, connect to Arduino pin D13
 * OLED pin 6 (E)      to Arduino pin D3
 * OLED pin 7 (DB0)    to Arduino pin D4
 * OLED pin 8 (DB1)    to Arduino pin D5
 * OLED pin 9 (DB2)    to Arduino pin D6
 * OLED pin 10 (DB3)   to Arduino pin D7
 * OLED pin 11 (DB4)   to Arduino pin D8
 * OLED pin 12 (DB5)   to Arduino pin D9
 * OLED pin 13 (DB6)   to Arduino pin D10
 * OLED pin 14 (DB7)   to Arduino pin D11
 * OLED pin 15 (/CS)   to Vss ground  (or to Arduino pin D12, in case of use of more than one display)
 * OLED pin 16 (/RES)  to Arduino pin Reset or VDD 5V (or to Arduino pin D13, to control reset by sw)
 * OLED pin 17 (BS0)   to Vss ground
 * OLED pin 18 (BS1)   to Vss ground
 * OLED pin 19 (BS2)   to VDD 5V
 * OLED pin 20 (Vss)   to Vss ground
 *
 * Original example created by Newhaven Display International Inc.
 * Modified and adapted to Arduino Uno 16 Mar 2015 by Pasquale D'Antini
 * Modified 19 May 2015 by Pasquale D'Antini
 *
 * This example code is in the public domain.
 */

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

const byte DC = 2;                    // Arduino's pin assigned to the D/C line
//const byte RW = 13;                 // Arduino's pin assigned to the R/W line (optional, can be always low)
const byte E = 3;                     // Arduino's pin assigned to the E line
//const byte CS = 12;                 // Arduino's pin assigned to the /CS line (optional, can be always low)
//const byte RES = 13;                // Arduino's pin assigned to the Reset line (optional, can be always high)
const byte DATA_PINS[8] = {4, 5, 6, 7, 8, 9, 10, 11};      // Arduino's pins assigned to the data bus

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)
// _______________________________________________________________________________________

void command(byte c)                  // SUBROUTINE: PREPARES THE TRANSMISSION OF A COMMAND
{
   digitalWrite(DC, LOW);             // Sets LOW the D/C line of the display -> command
//   digitalWrite(RW, LOW);           // Sets LOW the R/W line of the display (optional, can be always low)
   send8bit(c);                       // Sends the byte on the data bus
   enableCycle();                     // Calls the enable signal cycle subroutine
}
// _______________________________________________________________________________________

void data(byte d)                     // SUBROUTINE: PREPARES THE TRANSMISSION OF A BYTE OF DATA
{
   digitalWrite(DC, HIGH);            // Sets HIGH the D/C line of the display -> data
//   digitalWrite(RW, LOW);           // Sets LOW the R/W line of the display (optional, can be always low)
   send8bit(d);                       // Sends the byte on the data bus
   enableCycle();                     // Calls the enable signal cycle subroutine
}
// _______________________________________________________________________________________

void enableCycle(void)                // SUBROUTINE: EXECUTE THE ENABLE SIGNAL CYCLE (DATA LATCH)
{
   delayMicroseconds(1);              // Waits 1 us (required for timing purpose)
//   digitalWrite(CS, LOW);           // Sets LOW the /CS line of the display (optional, can be always low)
   digitalWrite(E, HIGH);             // Sets HIGH the E line of the display
   delayMicroseconds(1);              // Waits 1 us (required for timing purpose)
   digitalWrite(E, LOW);              // Sets LOW the E line of the display
//   digitalWrite(CS, HIGH);          // Sets HIGH the /CS line of the display (optional, can be always low)
   delayMicroseconds(1);              // Waits 1 us (required for timing purpose)
}
// _______________________________________________________________________________________

void send8bit(byte value)             // SUBROUTINE: SENDS THE BYTE ON THE DATA BUS
{
   for (byte i = 0; i < 8; i++)                          // One bit at a time,
   {
      digitalWrite(DATA_PINS[i], (value >> i) & 0x01);   //  sets the eight lines of the data bus,
   }                                                     //  to send the character to the display
}
// _______________________________________________________________________________________

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(DC, OUTPUT);               // Initializes Arduino pin for the D/C line
   digitalWrite(DC, LOW);             // Sets LOW the D/C line of the display
//   pinMode(RW, OUTPUT);             // Initializes Arduino pin for the R/W line (optional)
//   digitalWrite(RW, LOW);           // Sets LOW the R/W line of the display (optional, can be always low)
   pinMode(E, OUTPUT);                // Initializes Arduino pin for the E line
   digitalWrite(E, LOW);              // Sets LOW the E line of the display
//   pinMode(CS, OUTPUT);             // Initializes Arduino pin for the /CS line (optional)
//   digitalWrite(CS, HIGH);          // Sets HIGH the /CS line of the display (optional, can be always low)
   for (byte i=0; i<8; i++)
   {
      pinMode(DATA_PINS[i], OUTPUT);     // Initializes all Arduino pins for the data bus
      digitalWrite(DATA_PINS[i], LOW);   // Sets LOW the data bus
   }
//   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
   
   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
}
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: oldmaker on March 25, 2015, 06:20:06 PM
I have an example for 4-bit 6800 parallel interface, too, but it doesn't run as expected.
There is something wrong I don't see or something I don't know.
In attachment there is the image of the output on the display.

UPDATE April 22: thanks to Michael_L, the error has been discovered and the code, fixed, now runs as expected.

Tutorial 3 - display connected to Arduino Uno via 4-bit 6800 parallel interface:
Code: [Select]
/*
 * Demo_NHD0420CW-Ax3_parallel_6800_4b.ino
 *
 * Tutorial sketch for use of character OLED slim display family by Newhaven with Arduino Uno, without
 * using any library.  Models: NHD0420CW-Ax3, NHD0220CW-Ax3, NHD0216CW-Ax3. Controller: US2066
 * In this example, the display is connected to Arduino via 8-bit 6800 parallel interface.
 *
 * Displays on the OLED alternately a 4-line message and a sequence of character "block".
 * This sketch assumes the use of a 4x20 display; if different, modify the values of the two variables
 * ROW_N e COLUMN_N.
 * The sketch uses the minimum possible of Arduino's pins; if you intend to use also R/W, /CS or /RES
 * lines, the related instructions are already present, it's sufficient to remove the comment markers.
 *
 * The circuit:
 * OLED pin 1 (Vss)    to Arduino pin ground
 * OLED pin 2 (VDD)    to Arduino pin 5V
 * OLED pin 3 (REGVDD) to Arduino pin 5V
 * OLED pin 4 (D/C)    to Arduino pin D2
 * OLED pin 5 (R/W)    to Vss ground (always write); to enable also read, connect to Arduino pin D13
 * OLED pin 6 (E)      to Arduino pin D3
 * OLED pin 7 (DB0)    to Vss ground
 * OLED pin 8 (DB1)    to Vss ground
 * OLED pin 9 (DB2)    to Vss ground
 * OLED pin 10 (DB3)   to Vss ground
 * OLED pin 11 (DB4)   to Arduino pin D8
 * OLED pin 12 (DB5)   to Arduino pin D9
 * OLED pin 13 (DB6)   to Arduino pin D10
 * OLED pin 14 (DB7)   to Arduino pin D11
 * OLED pin 15 (/CS)   to Vss ground  (or to Arduino pin D12, in case of use of more than one display)
 * OLED pin 16 (/RES)  to Arduino pin Reset or VDD 5V (or to Arduino pin D13, to control reset by sw)
 * OLED pin 17 (BS0)   to VDD 5V
 * OLED pin 18 (BS1)   to Vss ground
 * OLED pin 19 (BS2)   to VDD 5V
 * OLED pin 20 (Vss)   to Vss ground
 *
 * Original example created by Newhaven Display International Inc.
 * Modified and adapted to Arduino Uno 16 Mar 2015 by Pasquale D'Antini
 * Modified 19 May 2015 by Pasquale D'Antini
 *
 * This example code is in the public domain.
 */

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

const byte DC = 2;                    // Arduino's pin assigned to the D/C line
//const byte RW = 13;                 // Arduino's pin assigned to the R/W line (optional, can be always low)
const byte E = 3;                     // Arduino's pin assigned to the E line
//const byte CS = 12;                 // Arduino's pin assigned to the /CS line (optional, can be always low)
//const byte RES = 13;                // Arduino's pin assigned to the Reset line (optional, can be always high)
const byte DATA_PINS[4] = {8, 9, 10, 11};                  // Arduino's pins assigned to the data bus

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)
// _______________________________________________________________________________________

void command(byte c)                  // SUBROUTINE: PREPARES THE TRANSMISSION OF A COMMAND
{
   digitalWrite(DC, LOW);             // Sets LOW the D/C line of the display -> command
//   digitalWrite(RW, LOW);           // Sets LOW the R/W line of the display (optional, can be always low)
   send4bit(c >> 4);                  // Sends the higher 4 bits on the data bus
   enableCycle();                     // Calls the enable signal cycle subroutine
   send4bit(c);                       // Sends the lower 4 bits on the data bus
   enableCycle();                     // Calls the enable signal cycle subroutine
}
// _______________________________________________________________________________________

void data(byte d)                     // SUBROUTINE: PREPARES THE TRANSMISSION OF A BYTE OF DATA
{
   digitalWrite(DC, HIGH);            // Sets HIGH the D/C line of the display -> data
//   digitalWrite(RW, LOW);           // Sets LOW the R/W line of the display (optional, can be always low)
   send4bit(d >> 4);                  // Sends the higher 4 bits on the data bus
   enableCycle();                     // Calls the enable signal cycle subroutine
   send4bit(d);                       // Sends the lower 4 bits on the data bus
   enableCycle();                     // Calls the enable signal cycle subroutine
}
// _______________________________________________________________________________________

void enableCycle(void)                // SUBROUTINE: EXECUTE THE ENABLE SIGNAL CYCLE (DATA LATCH)
{
   delayMicroseconds(1);              // Waits 1 us (required for timing purpose)
//   digitalWrite(CS, LOW);           // Sets LOW the /CS line of the display (optional, can be always low)
   digitalWrite(E, HIGH);             // Sets HIGH the E line of the display
   delayMicroseconds(1);              // Waits 1 us (required for timing purpose)
   digitalWrite(E, LOW);              // Sets LOW the E line of the display
//   digitalWrite(CS, HIGH);          // Sets HIGH the /CS line of the display (optional, can be always low)
   delayMicroseconds(1);              // Waits 1 us (required for timing purpose)
}
// _______________________________________________________________________________________

void send4bit(byte value)             // SUBROUTINE: SENDS HALF BYTE ON THE DATA BUS
{
   for (byte i = 0; i < 4; i++)                          // One bit at a time,
   {
      digitalWrite(DATA_PINS[i], (value >> i) & 0x01);   //  sets the four lines of the data bus,
   }                                                     //  to send the half character to the display
}
// _______________________________________________________________________________________

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(4, OUTPUT);
   digitalWrite(4, LOW);
   pinMode(5, OUTPUT);
   digitalWrite(5, LOW);
   pinMode(6, OUTPUT);
   digitalWrite(6, LOW);
   pinMode(7, OUTPUT);
   digitalWrite(7, LOW);
   pinMode(DC, OUTPUT);               // Initializes Arduino pin for the D/C line
   digitalWrite(DC, LOW);             // Sets LOW the D/C line of the display
//   pinMode(RW, OUTPUT);             // Initializes Arduino pin for the R/W line (optional)
//   digitalWrite(RW, LOW);           // Sets LOW the R/W line of the display (optional, can be always low)
   pinMode(E, OUTPUT);                // Initializes Arduino pin for the E line
   digitalWrite(E, LOW);              // Sets LOW the E line of the display
//   pinMode(CS, OUTPUT);             // Initializes Arduino pin for the /CS line (optional)
//   digitalWrite(CS, HIGH);          // Sets HIGH the /CS line of the display (optional, can be always low)
   for (byte i=0; i<4; i++)
   {
      pinMode(DATA_PINS[i], OUTPUT);     // Initializes all Arduino pins for the data bus
      digitalWrite(DATA_PINS[i], LOW);   // Sets LOW the data bus
   }
//   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
   
   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
}
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: oldmaker on April 13, 2015, 03:16:14 AM
Tutorial 4 - display connected to Arduino Uno via SPI interface:
Code: [Select]
/*
 * Demo_NHD0420CW-Ax3_SPI.ino
 *
 * Tutorial sketch for use of character OLED slim display family by Newhaven with Arduino Uno, without
 * using any library.  Models: NHD0420CW-Ax3, NHD0220CW-Ax3, NHD0216CW-Ax3. Controller: US2066
 * in this example, the display is connected to Arduino via SPI interface.
 *
 * Displays on the OLED alternately a 4-line message and a sequence of character "block".
 * This sketch assumes the use of a 4x20 display; if different, modify the values of the two variables
 * ROW_N e COLUMN_N.
 * The sketch uses the minimum possible of Arduino's pins; if you intend to use also /RES or /CS lines,
 * the related instructions are already present, it's sufficient to remove the comment markers.
 *
 * The circuit:
 * OLED pin 1 (Vss)    to Arduino pin ground
 * OLED pin 2 (VDD)    to Arduino pin 5V
 * OLED pin 3 (REGVDD) to Arduino pin 5V
 * OLED pin 4 to 6     to Vss ground
 * OLED pin 7 (SCLK)   to Arduino pin D13 (SCK)
 * OLED pin 8 (SID)    to Arduino pin D11 (MOSI)
 * OLED pin 9 (SOD)    to Arduino pin D12 (MISO) (optional, can be not connected)
 * OLED pin 10 to 14   to Vss ground
 * OLED pin 15 (/CS)   to Vss ground  (or to Arduino pin D2, in case of use of more than one display)
 * OLED pin 16 (/RES)  to Arduino pin Reset or VDD 5V (or to Arduino pin D3, to control reset by sw)
 * OLED pin 17 (BS0)   to Vss ground
 * OLED pin 18 (BS1)   to Vss ground
 * OLED pin 19 (BS2)   to Vss ground
 * OLED pin 20 (Vss)   to Vss ground
 *
 * Original example created by Newhaven Display International Inc.
 * Modified and adapted to Arduino Uno 30 Mar 2015 by Pasquale D'Antini
 * Modified 19 May 2015 by Pasquale D'Antini
 *
 * This example code is in the public domain.
 */

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

//const byte CS = 2;                  // Arduino's pin assigned to the /CS line (optional, can be always low)
//const byte RES = 3;                 // Arduino's pin assigned to the Reset line (optional, can be always high)
const byte SCLK = 13;                 // Arduino's pin assigned to the SCLK line
const byte SDIN = 11;                 // Arduino's pin assigned to the SID line
//const byte SDOUT = 12;              // Arduino's pin assigned to the SOD line (optional, can be not connected)

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)
// _______________________________________________________________________________________

void command(byte c)                  // SUBROUTINE: PREPARES THE TRANSMISSION OF A COMMAND
{
   byte i = 0;                        // Bit index
   
   for(i=0; i<5; i++)
   {
      digitalWrite(SDIN, HIGH);
      clockCycle();
   }
   for(i=0; i<3; i++)
   {
      digitalWrite(SDIN, LOW);
      clockCycle();
   }
   
   send_byte(c);                      // Transmits the byte
}
// _______________________________________________________________________________________

void data(byte d)                     // SUBROUTINE: PREPARES THE TRANSMISSION OF A BYTE OF DATA
{
   byte i = 0;                        // Bit index
   
   for(i=0; i<5; i++)
   {
      digitalWrite(SDIN, HIGH);
      clockCycle();
   }
   digitalWrite(SDIN, LOW);
   clockCycle();
   digitalWrite(SDIN, HIGH);
   clockCycle();
   digitalWrite(SDIN, LOW);
   clockCycle();
   
   send_byte(d);                      // Transmits the byte
}
// _______________________________________________________________________________________

void send_byte(byte tx_b)             // SUBROUTINE: SEND TO THE DISPLAY THE BYTE IN tx_b
{
   byte i = 0;                        // Bit index
   
   for(i=0; i<4; i++)
   {
      if((tx_b & 0x01) == 1)
      {
         digitalWrite(SDIN, HIGH);
      }
      else
      {
         digitalWrite(SDIN, LOW);
      }
      clockCycle();
      tx_b = tx_b >> 1;
   }
   
   for(i=0; i<4; i++)
   {
      digitalWrite(SDIN, LOW);
      clockCycle();
   }
   
   for(i=0; i<4; i++)
   {
      if((tx_b & 0x1) == 0x1)             // <------- Change
      {
         digitalWrite(SDIN, HIGH);
      }
      else
      {
         digitalWrite(SDIN, LOW);
      }
      clockCycle();
      tx_b = tx_b >> 1;
   }
   
   for(i=0; i<4; i++)
   {
      digitalWrite(SDIN, LOW);
      clockCycle();
   }
}
// _______________________________________________________________________________________

void clockCycle(void)                 // SUBROUTINE: EXECUTE THE CLOCK SIGNAL CYCLE
{
//   digitalWrite(CS, LOW);           // Sets LOW the /CS line of the display (optional, can be always low)
//   delayMicroseconds(1);            // Waits 1 us (required for timing purpose)
   digitalWrite(SCLK, LOW);           // Sets LOW the SCLK line of the display
   delayMicroseconds(1);              // Waits 1 us (required for timing purpose)
   digitalWrite(SCLK, HIGH);          // Sets HIGH the SCLK line of the display
   delayMicroseconds(1);              // Waits 1 us (required for timing purpose)
//   delayMicroseconds(1);            // Waits 1 us (required for timing purpose)
//   digitalWrite(CS, HIGH);          // Sets HIGH the /CS line of the display (optional, can be always low)
}
// _______________________________________________________________________________________

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(SCLK, OUTPUT);             // Initializes Arduino pin for the SCLK line
   digitalWrite(SCLK, HIGH);          // Sets HIGH the SCLK line of the display
   pinMode(SDIN, OUTPUT);             // Initializes Arduino pin for the SDIN line
   digitalWrite(SDIN, LOW);           // Sets LOW the SDIN line of the display
//   pinMode(SDOUT, INPUT);           // Initializes Arduino pin for the SDOUT line (optional, can be not connected)
//   pinMode(CS, OUTPUT);             // Initializes Arduino pin for the /CS line (optional)
//   digitalWrite(CS, HIGH);          // Sets HIGH the /CS line of the display (optional, can be always low)
//   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
   
   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
}
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: Michael_L on April 22, 2015, 11:48:41 AM
Thanks for sharing your code!  As for your question in your 3rd tutorial, try changing the value after command DA is sent to 0x10 instead of 0x00.  ;)
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: oldmaker on April 22, 2015, 04:00:10 PM
Thank you very much, Michael.
I did so many tests and attempts that I didn't see I had swapped two lines  ;D
Code fixed and post updated.
Thanks again.
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: macsboost on May 04, 2015, 09:11:18 PM
can you share your display pinout.
I have yet to get my display to work.

I have another i2c display working from the same tutorial from another mfg, so something must be right.
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: oldmaker on May 06, 2015, 01:41:43 PM
The complete pinout is reported in the comment text at the beginning of each tutorial.
The examples are all tested with two Newhaven display.
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: macsboost on May 07, 2015, 11:42:10 PM
thanks!  too many sleepless nights!
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: Rage441 on October 19, 2015, 11:44:06 PM
Thanks for the great work on this.  Just got it running tonight.  I'm trying to change the brightness of the display, tried changing the contrast value, (0x7F is the default) but it doesn't seem to have any effect; am I missing something else?
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: Paul_B on October 20, 2015, 07:44:56 AM
Please try this code, let me know if the contrast changes.

https://github.com/NewhavenDisplay/NHD_US2066

Code: [Select]
//---------------------------------------------------------
/*

NHD_0216AW_XB3.ino

Program for writing to Newhaven Display Slim OLEDs based on US2066 controller.

Pick one up today in the Newhaven Display shop!
------> http://www.newhavendisplay.com/oled-slim-character-oleds-c-119_825.html

This code is written for the Arduino Mega.

Copyright (c) 2015 - Newhaven Display International, LLC.

Newhaven Display invests time and resources providing this open source code,
please support Newhaven Display by purchasing products from Newhaven Display!

*/
//---------------------------------------------------------

#include <SPI.h>
#include <Arduino.h>
#include <Wire.h>
#include <avr\io.h>

#include "NHD_US2066.h"
unsigned char text1[] = {" Please Support "};
unsigned char text2[] = {"  Open-Source   "};
unsigned char text3[] = {"   Hardware &   "};
unsigned char text4[] = {"   Software !!  "};

unsigned char text5[] = {"Newhaven Display"};
unsigned char text6[] = {" 2X16 Character "};
unsigned char text7[] = {"  Slim  Design  "};
unsigned char text8[] = {"----------------"};



void output()
{
                int i;

        command(0x01);
        delay(2);
        for(i=0;i<16;i++){
          data(text1[i]);
        }
       
        command(0xA0);
        for(i=0;i<16;i++){
          data(text2[i]);
        }

        delay(2000);

        command(0x01);
        delay(2);
        for (i=0;i<16;i++){
                                data(text3[i]);
        }
               
        command(0xA0);
        for (i=0;i<16;i++){
                                data(text4[i]);
        }

        delay(3500);
       
        command(0x01);
        delay(2);
        for(i=0;i<16;i++){
          data(text5[i]);
        }
       
        command(0xA0);
        for(i=0;i<16;i++){
          data(text6[i]);
        }

        delay(2000);

        command(0x01);
        delay(2);
        for (i=0;i<16;i++){
                                data(text7[i]);
        }
               
        command(0xA0);
        for (i=0;i<16;i++){
                                data(text8[i]);
        }

}

void blocks()
{
                int i;

        command(0x01);
        delay(2);

        for(i=0;i<16;i++){
          data(0x1F);
        }

        command(0xA0);
        for(i=0;i<16;i++){
          data(0x1F);
        }
}

void setup()
{
init_oled();
}

void loop()

  while(1)
  {
    //output();
   
    blocks();
    command(0x78);
    command(0x2A);
    command(0x79);
   
    command(0x81);  //set contrast control
    command(0x01);  //set contrast control
   
    delay(2000);
   
    command(0x81);  //set contrast control
    command(0xFF);  //set contrast control
   
    delay(2000); 
  }
}

Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: Paul_B on October 20, 2015, 07:46:58 AM
In order for you to send the “Set Contrast Control”  command RE and SD must be set to 1, please see the attachment.

E.g. The following commands set RE – SD  to the appropriate values before setting the contrast.

command(0x78);
command(0x2A);
command(0x79);             

I recommend you review the US2066 datasheet, this will give you a better understanding on how to send commands.

http://www.newhavendisplay.com/app_notes/US2066.pdf

Hope this helps  ;)
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: Rage441 on November 05, 2015, 09:44:21 PM
Appreciate the help on this one, but still having issues.  I'm running the code in tutorial 1, I2C interface, 5v, Arduino Uno.   Tried changing the contrast value in the code and it has no effect.  Tried adding the code above and that has no effect either.  Sometimes the display dims a little, but it's not consistent.  I should be able to dim this right down to almost nothing.  The most change in brightness I've seen is maybe from 100% to 80%.  Was troubleshooting again tonight and now the display won't turn on.  Ran an I2C Scanner sketch and can see the I2C address of 3C for the display, So it's communicating.  Rechecked all input pins and they getting power and ground in the right places.  Tried reloading Tutorial 1 sketch to no effect.  Anyone have any ideas?
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: Saurabh_B on November 06, 2015, 08:35:50 AM
Hi,

Would you be able to post the code snipped of how you are adjusting the contrast?
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: Morne on April 01, 2016, 04:15:45 PM
Hello all!

First of all I want to send out huge thanks to Pasquale for providing these examples, they made it very easy for me to get started with the 20x4 character OLED. However I noticed that the SPI example used bit banged software SPI, which is rather slow and filling the screen with characters take about 40 ms.

Not completely statsfiende by this I decided change the implementation to use HW SPI. And after a few hours of struggling I finally got it working! It is also super fast. Filling the screen now takes slightly less than 1 ms, which is even faster then using the 4 bit 6800 interface (11 ms to fil the screen).

So, without more ado, here is the code for a HW SPI implementation.

Code: [Select]
/*
 * Demo_NHD0420CW-Ax3_SPI_HW.ino
 *
 * Tutorial sketch for use of character OLED slim display family by Newhaven with Arduino Uno, without
 * using any library.  Models: NHD0420CW-Ax3, NHD0220CW-Ax3, NHD0216CW-Ax3. Controller: US2066
 * in this example, the display is connected to Arduino via SPI interface.
 *
 * Displays on the OLED alternately a 4-line message and a sequence of character "block".
 * This sketch assumes the use of a 4x20 display; if different, modify the values of the two variables
 * ROW_N e COLUMN_N.
 * The sketch uses the minimum possible of Arduino's pins; if you intend to use also /RES or /CS lines,
 * the related instructions are already present, it's sufficient to remove the comment markers.
 *
 * The circuit:
 * OLED pin 1 (Vss)    to Arduino pin ground
 * OLED pin 2 (VDD)    to Arduino pin 5V
 * OLED pin 3 (REGVDD) to Arduino pin 5V
 * OLED pin 4 to 6     to Vss ground
 * OLED pin 7 (SCLK)   to Arduino pin D13 (SCK)
 * OLED pin 8 (SID)    to Arduino pin D11 (MOSI)
 * OLED pin 9 (SOD)    to Arduino pin D12 (MISO) (optional, can be not connected)
 * OLED pin 10 to 14   to Vss ground
 * OLED pin 15 (/CS)   to Vss ground  (or to Arduino pin D2, in case of use of more than one display)
 * OLED pin 16 (/RES)  to Arduino pin Reset or VDD 5V (or to Arduino pin D3, to control reset by sw)
 * OLED pin 17 (BS0)   to Vss ground
 * OLED pin 18 (BS1)   to Vss ground
 * OLED pin 19 (BS2)   to Vss ground
 * OLED pin 20 (Vss)   to Vss ground
 *
 * Original example created by Newhaven Display International Inc.
 * Modified and adapted to Arduino Uno 30 Mar 2015 by Pasquale D'Antini
 * Modified 19 May 2015 by Pasquale D'Antini
 * Modified to use hardware SPI 1 April 2016 by Joakim Sandström
 *
 * This example code is in the public domain.
 */

// inslude the SPI library:
#include <SPI.h>


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

//const byte RES = 3;                 // Arduino's pin assigned to the Reset line (optional, can be always 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)
// _______________________________________________________________________________________
void command(byte c)                  // SUBROUTINE: PREPARES THE TRANSMISSION OF A COMMAND
{
  SPI.transfer(0x1F);

  send_byte(c);                      // Transmits the byte
}


// _______________________________________________________________________________________
void data(byte d)
{
  SPI.transfer(0x5F);

  send_byte(d);
}

// _______________________________________________________________________________________
void send_byte(byte tx_b)
{
  //Split the bytes into two and pad the last four bits with 0s
  byte tx_b1 = tx_b & 0x0F;
  byte tx_b2 = (tx_b >> 4) & 0x0F;

  //Or together the bytes
  int tx_int = (tx_b2<<8)|tx_b1;

  //transfer it
  SPI.transfer16(tx_int);
}

// _______________________________________________________________________________________

void output(void)                     // SUBROUTINE: DISPLAYS THE FOUR STRINGS, THEN THE SAME IN REVERSE ORDER
{
  unsigned long lastTime = 0;
  unsigned long temp;
  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

  lastTime = millis();
  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)
    }
  }
  temp = millis() - lastTime;
  Serial.println(temp);
}
// _______________________________________________________________________________________

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)
  SPI.begin();
  SPI.setBitOrder(LSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV2);
  SPI.setDataMode(SPI_MODE3);

  delayMicroseconds(200);            // Waits 200 us 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)
  Serial.begin(115200); //For performance measurement
}
// _______________________________________________________________________________________

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
}
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: Chris O. on April 03, 2016, 03:08:57 PM
Hi

Can anyone help me test this code, simply don't have the 2 OLED displays hardware do to it right now.

Transactional SPI setup with 2  NHD0420CW-Ax3 OLED displays.
1st OLED running on 8MHz.
2nd OLED running on 4MHz.
 
Code: [Select]
/*
 * Demo_NHD0420CW-Ax3_SPI_HW.ino
 *
 * Tutorial sketch for use of character OLED slim display family by Newhaven with Arduino Uno, with
 * using HW SPI library.  Models: NHD0420CW-Ax3, NHD0220CW-Ax3, NHD0216CW-Ax3. Controller: US2066
 * in this example, the display is connected to Arduino via SPI interface.
 *
 * Displays on the OLED alternately a 4-line message and a sequence of character "block".
 * This sketch assumes the use of a 4x20 display; if different, modify the values of the two variables
 * ROW_N e COLUMN_N.
 * The sketch uses the minimum possible of Arduino's pins; if you intend to use also /RES or /CS lines,
 * the related instructions are already present, it's sufficient to remove the comment markers.
 *
 * The circuit:
 * OLED pin 1 (Vss)    to Arduino pin ground
 * OLED pin 2 (VDD)    to Arduino pin 5V
 * OLED pin 3 (REGVDD) to Arduino pin 5V
 * OLED pin 4 to 6     to Vss ground
 * OLED pin 7 (SCLK)   to Arduino pin D13 (SCK)
 * OLED pin 8 (SID)    to Arduino pin D11 (MOSI)
 * OLED pin 9 (SOD)    to Arduino pin D12 (MISO) (optional, can be not connected)
 * OLED pin 10 to 14   to Vss ground
 * OLED pin 15 (/CS)   to Vss ground (or to Arduino Pin D10(1st device) ~ Pin D9(2nd device), in case of use of more than one display)
 * OLED pin 16 (/RES)  to Arduino pin Reset or VDD 5V (or to Arduino pin D3, to control reset by sw)
 * OLED pin 17 (BS0)   to Vss ground
 * OLED pin 18 (BS1)   to Vss ground
 * OLED pin 19 (BS2)   to Vss ground
 * OLED pin 20 (Vss)   to Vss ground
 *
 * Original example created by Newhaven Display International Inc.
 * Modified and adapted to Arduino Uno 30 Mar 2015 by Pasquale D'Antini
 * Modified 19 May 2015 by Pasquale D'Antini
 * Modified to use hardware SPI 1 April 2016 by Joakim Sandström
 * HW SPI transaction 3 April 2016 by Cris O.
 *
 * This example code is in the public domain.
 */

// inslude the SPI library:
#include <SPI.h>

/*
 * The SPI protocol allows for a range of transmission speeds ranging from 1Mhz to 100MHz.
 * SPI slaves vary in the maximum speed at which they can reliably work.
 * For a SPI chip rated up to 20 MHz, use 20000000.
 * NOTE:
 * Arduino Pro Mini (3.3 V / 8MHz) can only have SPI at 4 MHz as fastest speed, 1/2 the system clock speed.
 * Arduino UNO (5 V / 16MHz) can only have SPI at 8 MHz as fastest speed, 1/2 the system clock speed.
 */
// Transactional SPI configuration
// Set up SPI transaction method for all devices
// Set up the speed, data order and data mode
SPISettings NHD0420CW_A(8000000, LSBFIRST, SPI_MODE3); // 8 MHz
SPISettings NHD0420CW_B(4000000, LSBFIRST, SPI_MODE3); // 4 MHz

/* Multiple SPI devices use the same SPI SCK, MISO and MOSI signals but each device will need it's own SS pin. */
// set the Slave Select Pins, using two SPI devices, A and B.
const int CS_A_Pin = 10; // (1st device)
const int CS_B_Pin = 9; // (2nd device)

/* Slave Select Signal:
* Any digital pin can be used for a SS (slave select) signal.
* The SPI library does not control the SS signals,
* because devices differ on when this is used,
* whether it is held low for multiple transfers or for each individual transfer,
* and so on. Control SS with digitalWrite().
* However, the SS pin must either be configured as an output,
* or if it is an input, it must remain low during the SPI transfer.
* Unconfigured pins default to input, and a pin with no signal can easily "float"
* to random voltages due to electrical noise.
* Always configure the SS pin as an output, or make sure it remains low.
*
* Most SPI devices are designed to work together with others,
* where SCK, MISO, and MOSI are shared. Each chip needs a separate SS signal.
* Only the selected chip will communicate. The others ignore SCK and MOSI,
* and avoid driving MISO when they are not selected.
*/

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

// 1ST OLED
const byte ROW_N_1 = 4;                 // Number of display rows
const byte COLUMN_N_1 = 20;             // Number of display columns

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

byte new_line_1[4] = {0x80, 0xA0, 0xC0, 0xE0};               // DDRAM address for each line of the display
byte rows_1 = 0x08;                     // Display mode: 1/3 lines or 2/4 lines; default 2/4 (0x08)

// 2ND OLED
const byte ROW_N_2 = 4;                 // Number of display rows
const byte COLUMN_N_2 = 20;             // Number of display columns

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

byte new_line_2[4] = {0x80, 0xA0, 0xC0, 0xE0};               // DDRAM address for each line of the display
byte rows_2 = 0x08;                     // Display mode: 1/3 lines or 2/4 lines; default 2/4 (0x08)

// __
void command(byte c, byte device)                  // SUBROUTINE: PREPARES THE TRANSMISSION OF A COMMAND
{
  switch (device) {
    case 1:  // (1st device)
      SPI.beginTransaction(NHD0420CW_A);
      // take the CS pin low to select the chip:
      digitalWrite (CS_A_Pin, LOW); /* (most chips use LOW during the transfer) */
      SPI.transfer(0x1F);
      send_byte(c);                 // Transmits the byte
      // take the CS pin high to de-select the chip:
      digitalWrite (CS_A_Pin, HIGH);
      SPI.endTransaction();
      break;

    case 2: // (2nd device)
      SPI.beginTransaction(NHD0420CW_B);
      // take the CS pin low to select the chip:
      digitalWrite (CS_B_Pin, LOW); /* (most chips use LOW during the transfer) */
      SPI.transfer(0x1F);
      send_byte(c);                 // Transmits the byte
      // take the CS pin high to de-select the chip:
      digitalWrite (CS_B_Pin, HIGH);
      SPI.endTransaction();
      break;

    case 3:
      Serial.println("Error No device 3 specified");
      break;
    default:
      Serial.print("Error Unknown Device:");
      Serial.println(device);
      break;
  }
}
// _______________________________________________________________________________________

void data(byte d, byte device)
{
  switch (device) {
    case 1:  // (1st device)
      SPI.beginTransaction(NHD0420CW_A);
      // take the CS pin low to select the chip:
      digitalWrite (CS_A_Pin, LOW);
      SPI.transfer(0x5F);
      send_byte(d);
      // take the CS pin high to de-select the chip:
      digitalWrite (CS_A_Pin, HIGH);
      SPI.endTransaction();
      break;

    case 2: // (2nd device)
      SPI.beginTransaction(NHD0420CW_B);
      // take the CS pin low to select the chip:
      digitalWrite (CS_B_Pin, LOW); /* (most chips use LOW during the transfer) */
      SPI.transfer(0x5F);
      send_byte(d);
      // take the CS pin high to de-select the chip:
      digitalWrite (CS_B_Pin, HIGH);
      SPI.endTransaction();
      break;

    case 3:
      Serial.println("Error No device 3 specified");
      break;
    default:
      Serial.print("Error Unknown Device:");
      Serial.println(device);
      break;
  }
}
// _______________________________________________________________________________________

void send_byte(byte tx_b)
{
  //Split the bytes into two and pad the last four bits with 0s
  byte tx_b1 = tx_b & 0x0F;
  byte tx_b2 = (tx_b >> 4) & 0x0F;

  //Or together the bytes
  int tx_int = (tx_b2 << 8) | tx_b1;

  //transfer it
  SPI.transfer16(tx_int);
}

// _______________________________________________________________________________________

void output(byte device)                     // SUBROUTINE: DISPLAYS THE FOUR STRINGS, THEN THE SAME IN REVERSE ORDER
{
  // 1ST OLED ---------------------------------------------------------------------------------------
  if (device == 1) {
    unsigned long lastTime1 = 0;
    unsigned long temp1;
    byte r1 = 0;                        // Row index
    byte c1 = 0;                        // Column index

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

    for (r1 = 0; r1 < ROW_N_1; r1++)        // One row at a time,
    {
      command(new_line_1[r1], device);         //  moves the cursor to the first column of that line
      for (c1 = 0; c1 < COLUMN_N_1; c1++)   // One character at a time,
      {
        data(TEXT_1[r1][c1], device);            //  displays the correspondig string
      }
    }

    delay(2000);                       // Waits, only for visual effect purpose

    lastTime1 = millis();
    for (r1 = 0; r1 < ROW_N_1; r1++)        // One row at a time,
    {
      command(new_line_1[r1], device);           //  moves the cursor to the first column of that line
      for (c1 = 0; c1 < COLUMN_N_1; c1++)  // One character at a time,
      {
        data(TEXT_1[3 - r1][c1], device);        //  displays the correspondig string (in reverse order)
      }
    }
    temp1 = millis() - lastTime1;
    Serial.print("OLED 1: ");
    Serial.println(temp1);
  }

  // 2ND OLED -----------------------------------------------------------------------------------------
  if (device == 2) {
    unsigned long lastTime2 = 0;
    unsigned long temp2;
    byte r2 = 0;                        // Row index
    byte c2 = 0;                        // Column index

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

    for (r2 = 0; r2 < ROW_N_2; r2++)        // One row at a time,
    {
      command(new_line_2[r2], device);         //  moves the cursor to the first column of that line
      for (c2 = 0; c2 < COLUMN_N_2; c2++)   // One character at a time,
      {
        data(TEXT_2[r2][c2], device);            //  displays the correspondig string
      }
    }

    delay(2000);                       // Waits, only for visual effect purpose

    lastTime2 = millis();
    for (r2 = 0; r2 < ROW_N_2; r2++)        // One row at a time,
    {
      command(new_line_2[r2], device);           //  moves the cursor to the first column of that line
      for (c2 = 0; c2 < COLUMN_N_2; c2++)  // One character at a time,
      {
        data(TEXT_2[3 - r2][c2], device);        //  displays the correspondig string (in reverse order)
      }
    }
    temp2 = millis() - lastTime2;
    Serial.print("OLED 2: ");
    Serial.println(temp2);
  }
}
// _______________________________________________________________________________________

void blocks(byte device)                     // SUBROUTINE: FILLS THE ENTIRE DISPLAY WITH THE CHARACTER "BLOCK"
{
  // 1ST OLED ---------------------------------------------------------------------------------------
  if (device == 1) {
    byte r1 = 0;                        // Row index
    byte c1 = 0;                        // Column index

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

    for (r1 = 0; r1 < ROW_N_1; r1++)        // One row at a time,
    {
      command(new_line_1[r1], device);           //  moves the cursor to the first column of that line
      for (c1 = 0; c1 < COLUMN_N_1; c1++)  // One character at a time,
      {
        data(0xDB, device);                  //  displays the character 0xDB (block)
        delay(50);                   // Waits, only for visual effect purpose
      }
      delay(500);                     // Waits, only for visual effect purpose
    }
  }
  // 2ND OLED -----------------------------------------------------------------------------------------
  if (device == 2) {
    byte r2 = 0;                        // Row index
    byte c2 = 0;                        // Column index

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

    for (r2 = 0; r2 < ROW_N_2; r2++)        // One row at a time,
    {
      command(new_line_2[r2], device);           //  moves the cursor to the first column of that line
      for (c2 = 0; c2 < COLUMN_N_2; c2++)  // One character at a time,
      {
        data(0xDB, device);                  //  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)

  // set the Slave Select Pins as outputs:
  pinMode (CS_A_Pin, OUTPUT); // Pin 10
  pinMode (CS_B_Pin, OUTPUT); // Pin 9, optional 2ND device.
  // initialize SPI:
  SPI.begin();

  /* Deprecated SPI configuration
  Used by older versions of the SPI library, this method was not interrupt safe and
  depended on your sketch doing low-level SPI configuration management.
    SPI.setBitOrder(LSBFIRST);
    SPI.setClockDivider(SPI_CLOCK_DIV2);
    SPI.setDataMode(SPI_MODE3);
  */

  delayMicroseconds(200);            // Waits 200 us for stabilization purpose

  OledInit(1); // OLED init (1st device)
  OledInit(2); // OLED init (2nd device)

  Serial.begin(115200); //For performance measurement
}
// _______________________________________________________________________________________

void OledInit(byte device)
{
  // OLED init

  // 1ST OLED
  if (ROW_N_1 == 2 || ROW_N_1 == 4)
    rows_1 = 0x08;                    // Display mode: 2/4 lines
  else
    rows_1 = 0x00;                    // Display mode: 1/3 lines

  // 2ND OLED
  if (ROW_N_2 == 2 || ROW_N_2 == 4)
    rows_2 = 0x08;                    // Display mode: 2/4 lines
  else
    rows_2 = 0x00;                    // Display mode: 1/3 lines

  if (device == 1) {
    command(0x22 | rows_1, device); // Function set: extended command set (RE=1), lines #

    command(0x71, device);        // Function selection A:
    data(0x5C, device);           //  enable internal Vdd regulator at 5V I/O mode (def. value) (0x00 for disable, 2.8V I/O)
    command(0x20 | rows_1, device); // Function set: fundamental command set (RE=0) (exit from extended command set), lines #
    command(0x08, device);        // Display ON/OFF control: display off, cursor off, blink off (default values)
    command(0x22 | rows_1, device); // Function set: extended command set (RE=1), lines #
    command(0x79, device);        // OLED characterization: OLED command set enabled (SD=1)
    command(0xD5, device);        // Set display clock divide ratio/oscillator frequency:
    command(0x70, device);        //  divide ratio=1, frequency=7 (default values)
    command(0x78, device);        // OLED characterization: OLED command set disabled (SD=0) (exit from OLED command set)

    if (ROW_N_1 > 2)
      command(0x09, device);  // Extended function set (RE=1): 5-dot font, B/W inverting disabled (def. val.), 3/4 lines
    else
      command(0x08, device);  // Extended function set (RE=1): 5-dot font, B/W inverting disabled (def. val.), 1/2 lines

    command(0x06, device);        // Entry Mode set - COM/SEG direction: COM0->COM31, SEG99->SEG0 (BDC=1, BDS=0)
    command(0x72, device);        // Function selection B:
    data(0x0A, device);           //  ROM/CGRAM selection: ROM C, CGROM=250, CGRAM=6 (ROM=10, OPR=10)
    command(0x79, device);        // OLED characterization: OLED command set enabled (SD=1)
    command(0xDA, device);        // Set SEG pins hardware configuration:
    command(0x10, device);        //  alternative odd/even SEG pin, disable SEG left/right remap (default values)
    command(0xDC, device);        // Function selection C:
    command(0x00, device);        //  internal VSL, GPIO input disable
    command(0x81, device);        // Set contrast control:
    command(0x7F, device);        //  contrast=127 (default value)
    command(0xD9, device);        // Set phase length:
    command(0xF1, device);        //  phase2=15, phase1=1 (default: 0x78)
    command(0xDB, device);        // Set VCOMH deselect level:
    command(0x40, device);        //  VCOMH deselect level=1 x Vcc (default: 0x20=0,77 x Vcc)
    command(0x78, device);        // OLED characterization: OLED command set disabled (SD=0) (exit from OLED command set)
    command(0x20 | rows_1 , device); // Function set: fundamental command set (RE=0) (exit from extended command set), lines #
    command(0x01, device);        // Clear display
    delay(2);             // After a clear display, a minimum pause of 1-2 ms is required
    command(0x80, device);        // Set DDRAM address 0x00 in address counter (cursor home) (default value)
    command(0x0C, device);        // Display ON/OFF control: display ON, cursor off, blink off
    delay(250);           // Waits 250 ms for stabilization purpose after display on
  }

  if (device == 2) {
    command(0x22 | rows_2, device); // Function set: extended command set (RE=1), lines #
   /*i had to remove the comments cause of
    The message exceeds the maximum allowed length (20000 characters).*/
    command(0x71, device);
    data(0x5C, device);
    command(0x20 | rows_2, device);
    command(0x08, device);
    command(0x22 | rows_2, device);
    command(0x79, device);
    command(0xD5, device);
    command(0x70, device);
    command(0x78, device);

    if (ROW_N_2 > 2)
      command(0x09, device);
    else
      command(0x08, device);

    command(0x06, device);
    command(0x72, device);
    data(0x0A, device);
    command(0x79, device);
    command(0xDA, device);
    command(0x10, device);
    command(0xDC, device);
    command(0x00, device);
    command(0x81, device);
    command(0x7F, device);
    command(0xD9, device);
    command(0xF1, device);
    command(0xDB, device);
    command(0x40, device);
    command(0x78, device);
    command(0x20 | rows_2 , device);
    command(0x01, device);
    delay(2);
    command(0x80, device);
    command(0x0C, device);
    delay(250);
  }

  if (ROW_N_1 == 2)
    new_line_1[1] = 0xC0;

  if (ROW_N_2 == 2)
    new_line_2[1] = 0xC0;
}
// _______________________________________________________________________________________

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

Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: Paul_B on April 04, 2016, 08:09:36 AM
Awesome, thanks for sharing your code!
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: MSanders on May 25, 2016, 09:02:35 PM
Hi all,

I'm hoping someone might be able to assist.  I have just hooked up a new NHD0420CW-AG3 display to Arduino uno (compatible) and uploaded the I2C code directly from 'oldmaker' first post.  Works fine, except for screen banding.  The very first time the code was uploaded the screen had three vertical bands, which reduced to one after about 5 minutes. Now there is consistently two vertical bands, one at character 9 and the other at character 16.

I've also tried this with SPI code - same two vertical bands at the same position.

So, firstly, is this a software or hardware issue?

If software (somewhere in the initialization perhaps?), can someone assist in diagnosing the issue?

When replying please keep in mind that I am a relatively new hobbyist with only basic coding knowledge.  Complex responses will baffle my underqualified brain!
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: Saurabh_B on May 26, 2016, 07:50:35 AM
This sounds like it could be a hardware issue, would it be possible to post a picture of what you have on your display?
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: MSanders on May 27, 2016, 06:10:22 AM
After 3 days pouring over the US2066 datasheet I've made a few 'tweaks' to the code - and have made huge leaps in understanding what the code is doing.  I now don't seem to have any banding.  I'm not really confident my changes did a whole lot, they seem quite minor.

All changes occurred in the initialisation as follows:
command(0x7F) --> command(0xFF);  - increases contrast
command(0x40) --> command(0x30); - reduces Vcomh to 0.83, though I'm a little fuzzy as to what this does

I've also changed:
data(0x5C) --> data(0x00) - I want to run of 3.3v rather than 5v.  I hope this is correct?
Title: Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
Post by: MSanders on May 27, 2016, 06:20:38 AM
oh, I also changed the bitwise operator and removed the 'if' statement that set the number of rows. :
command(0x22 | 0x08) --> command(0x2A);

Again, I can't see how this should have changed anything!