NHD0420CW-Ax3 display with Arduino Uno - Tutorials

Comments

20 comments

  • oldmaker

    Tutorial 2 - display connected to Arduino Uno via 8-bit 6800 parallel interface:

    /*
     * 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
    }
    0
  • oldmaker

    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:

    /*
     * 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
    }
    0
  • oldmaker

    Tutorial 4 - display connected to Arduino Uno via SPI interface:

    /*
     * 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
    }

     

     

    « Last Edit: May 19, 2015, 04:40:59 AM  »
    0
  • Michael_L

    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.

    ;)

    0
  • oldmaker

    Thank you very much, Michael.
    I did so many tests and attempts that I didn't see I had swapped two lines  
    Code fixed and post updated.
    Thanks again.

     

    « Last Edit: April 22, 2015, 04:09:02 PM  »
    0
  • macsboost

    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.

    0
  • oldmaker

    The complete pinout is reported in the comment text at the beginning of each tutorial.
    The examples are all tested with two Newhaven display.

    0
  • macsboost

    thanks!  too many sleepless nights!

    0
  • Rage441

    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?

    0
  • Paul_B

    Please try this code, let me know if the contrast changes.

    https://github.com/NewhavenDisplay/NHD_US2066

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

    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); 
      }
    }

     

    « Last Edit: December 06, 2016, 02:19:13 PM by Michael_L »
    0
  • Paul_B

    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.

    https://newhavendisplay.com/content/app_notes/US2066.pdf 

    Hope this helps ;)

    0
  • Rage441

    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?

    0
  • Saurabh_B

    Hi,

    Would you be able to post the code snipped of how you are adjusting the contrast?

    0
  • Morne

    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 satisfied 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.

    /*
     * 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
    }

     

    0
  • Chris O.

    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.

    /*
     * 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
    }
    0
  • Paul_B

    Awesome, thanks for sharing your code!

    0
  • MSanders

    Hi all,
    I'm hoping someone might be able to assist.  I have just hooked up a new NHD-0420CW-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!

    0
  • Saurabh_B

    This sounds like it could be a hardware issue, would it be possible to post a picture of what you have on your display?

    0
  • MSanders
    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?
    0
  • MSanders

    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!

    0

Please sign in to leave a comment.