Author Topic: NHD0420CW-Ax3 display with Arduino Uno - Tutorials  (Read 11785 times)

Chris O.

  • Jr. Member
  • **
  • Posts: 35
  • Karma: 5
    • View Profile
Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
« Reply #15 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
}


Paul_B

  • Administrator
  • Sr. Member
  • *****
  • Posts: 248
  • Karma: 16
    • View Profile
Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
« Reply #16 on: April 04, 2016, 08:09:36 AM »
Awesome, thanks for sharing your code!

MSanders

  • Newbie
  • *
  • Posts: 3
  • Karma: 0
    • View Profile
Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
« Reply #17 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!

Saurabh_B

  • Administrator
  • Hero Member
  • *****
  • Posts: 356
  • Karma: 10
    • View Profile
Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
« Reply #18 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?

MSanders

  • Newbie
  • *
  • Posts: 3
  • Karma: 0
    • View Profile
Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
« Reply #19 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?

MSanders

  • Newbie
  • *
  • Posts: 3
  • Karma: 0
    • View Profile
Re: NHD0420CW-Ax3 display with Arduino Uno - Tutorials
« Reply #20 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!

 

Blank Display on NHD‐C0220BiZ‐FS(RGB)‐FBW‐3VM

Started by SteveCBoard Character LCDs

Replies: 5
Views: 4584
Last post November 23, 2017, 10:40:50 AM
by tolikkk
NHD‐C12864A1Z‐FSW‐FBW‐HTT display clears after draw

Started by EdAverillBoard Graphic LCDs

Replies: 9
Views: 5733
Last post November 23, 2017, 09:20:46 PM
by tolikkk
NHD‐4.3‐480272EF‐ATXL#‐CTP | FAN5333 | BBB | Nothing on the Display

Started by Alias_AliasBoard TFTs

Replies: 1
Views: 3437
Last post September 25, 2015, 03:09:24 PM
by Paul_B
NHD-0420DZW-AG5 - Display "sometimes" shows only 2 lines

Started by stylonurusBoard OLEDs

Replies: 5
Views: 5599
Last post June 18, 2014, 10:09:49 AM
by Michael_L
NHD-C0220BiZ Sometimes Ignoring "Clear Display" Command

Started by dstoverBoard Character LCDs

Replies: 2
Views: 3767
Last post March 27, 2014, 05:41:27 PM
by Michael_L