Test mode for NHD-0420CW-xxx displays?

Comments

8 comments

  • LoyalServant

    Ok, so a colleague remembered that he gave his son an Arduino a couple years ago.


    We were able to get a demo program running on the Arduino so now I have to figure out why we can't get this working with our code.
    At least we have something that works to probe to death.

    0
  • Saurabh_B

    Would you be able to share some more information about your code:

    -  Are you sending the data via. SPI or I2C?
    - What are the voltage levels for your devices?

    Would you also be able to provide how you are sending the data to these displays from the Cyclone 2? (Bit Format)

    0
  • LoyalServant

    I can't share anything on that because it's proprietary.. one of the things that makes this a little hard when asking for help.
    We are looking for a display to work in an existing product and the physical dimensions of this display fit the bill.

    We went simple - For now we are just trying to get it to work on one on our Atmel prototyping boards.
    We see it working with the Arduino example and just trying to sort out what exactly it's doing in the bowels.
    Tons of overhead in the Arduino code and I suspect that we are looking at timing issues because that.

    But, we are still scratching our heads.
    Tomorrow is another day.
    Might have better luck. Who knows.

    0
  • LoyalServant

    Because I just can't put it down....

    Some test code below... ideas what's being fouled up on the bus?


    #define F_CPU 20000000UL

    #include <avr/io.h>
    #include <util/delay.h>

    const uint8_t ROW_N = 4;                 // Number of display rows
    const uint8_t COLUMN_N = 20;             // Number of display columns
    const uint8_t SLAVE2W = 0x3C;            // Display I2C address, in 7-bit form: 0x3C if SA0=LOW, 0x3D if SA0=HIGH
    uint8_t new_line[4] = {0x80, 0xA0, 0xC0, 0xE0};               // DDRAM address for each line of the display
    uint8_t rows = 0x08;                     // Display mode: 1/3 lines or 2/4 lines; default 2/4 (0x08)
    uint8_t tx_packet[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; // Packet to be transmitted (max 20 bytes)

    void i2c_init(void)
    {
    TWSR = 0;
    TWBR = ((F_CPU / 100000L) - 16) / 2;
    //TWBR =  0xC0;
    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
    }

    void i2c_begin(void)
    {
    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);
    while (!(TWCR & _BV(TWINT)));
    }

    void i2c_end(void)
    {
    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO);
    }

    void i2c_write(uint8_t data)
    {
    TWDR = data;
    TWCR = _BV(TWINT) | _BV(TWEN);
    while (!(TWCR & _BV(TWINT)));
    }

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

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

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

    void initlcd(void)                      // INITIAL SETUP
    {

    _delay_us(200);            // Waits 200 us for stabilization purpose
    i2c_init();      // Initiate the Wire library and join the I2C bus as a master
    _delay_ms(10);         // Waits 10 ms for stabilization purpose

    if (ROW_N == 2 || ROW_N == 4)
    rows = 0x08;                    // Display mode: 2/4 lines
    else
    rows = 0x00;                    // Display mode: 1/3 lines

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

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

    command(0x06);        // Entry Mode set - COM/SEG direction: COM0->COM31, SEG99->SEG0 (BDC=1, BDS=0)
    command(0x72);        // Function selection B:
    data(0x0A);           //  ROM/CGRAM selection: ROM C, CGROM=250, CGRAM=6 (ROM=10, OPR=10)
    command(0x79);        // OLED characterization: OLED command set enabled (SD=1)
    command(0xDA);        // Set SEG pins hardware configuration:
    command(0x10);        //  alternative odd/even SEG pin, disable SEG left/right remap (default values)
    command(0xDC);        // Function selection C:
    command(0x00);        //  internal VSL, GPIO input disable
    command(0x81);        // Set contrast control:
    command(0x7F);        //  contrast=127 (default value)
    command(0xD9);        // Set phase length:
    command(0xF1);        //  phase2=15, phase1=1 (default: 0x78)
    command(0xDB);        // Set VCOMH deselect level:
    command(0x40);        //  VCOMH deselect level=1 x Vcc (default: 0x20=0,77 x Vcc)
    command(0x78);        // OLED characterization: OLED command set disabled (SD=0) (exit from OLED command set)
    command(0x20 | rows); // Function set: fundamental command set (RE=0) (exit from extended command set), lines #
    command(0x01);        // Clear display
    _delay_ms(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_ms(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 blocks(void)                     // SUBROUTINE: FILLS THE ENTIRE DISPLAY WITH THE CHARACTER "BLOCK"
    {
    uint8_t r = 0;                        // Row index
    uint8_t c = 0;                        // Column index

    command(0x01);                     // Clear display (and cursor home)
    _delay_ms(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_ms(10);                   // Waits, only for visual effect purpose
    }
    _delay_ms(100);                     // Waits, only for visual effect purpose
    }
    }

    int main(void)
    {
    i2c_init();

    initlcd();

        /* Replace with your application code */
        while (1)
        {
    blocks();
        }
    }
    0
  • LoyalServant

    Wanted to post the solution to the above....
    Spotted by an AVRFreaks member.

    The address needed to be shifted to the left by 1 bit.
    I do indeed have egg on my face  

    Fixed code:

    void send_packet(uint8_t x)              // SUBROUTINE: SEND TO THE DISPLAY THE x BYTES STORED IN tx_packet
    {
    uint8_t ix = 0;                       // Bytes index

    uint8_t address = 0;
    address |= SLAVE2W << 1;

    i2c_begin();
    i2c_write(address);   // Begin the transmission via I2C to the display with the given address
    for(ix=0; ix<x; ix++)              // One byte at a time,
    {
    i2c_write(tx_packet[ix]);      //  queue bytes for transmission
    }
    i2c_end();            // Transmits the bytes that were queued
    }
    « Last Edit: May 05, 2016, 10:36:24 PM by LoyalServant »
    0
  • Saurabh_B

    Hi,
    Glad to see you have it figured out.
    For this controller the I²C address will be 7-bits wide, and the 8th-bit (LSB) will determine whether you are reading from or writing to the display.

    0
  • LoyalServant
    Hi,

    Glad to see you have it figured out.
    For this controller the I²C address will be 7-bits wide, and the 8th-bit (LSB) will determine whether you are reading from or writing to the display.
     


    Yeah we missed that teensy little bit (no pun intended) in our other code as well.
    That leads me to another question regarding mounting...
    Why are the boards castellated? The full holes would have been nice.
    We can still mount it just that it makes it a tad interesting.

    0
  • Saurabh_B

    We wanted to minimize the overall size of the display. This helped reduce the overall size.

    0

Please sign in to leave a comment.