Newhaven Display Forum

Newhaven Products => OLEDs => Topic started by: cody on April 18, 2014, 05:04:42 PM

Title: NHD-0216KZW-AG5 Font Tables in 4-bit Mode
Post by: cody on April 18, 2014, 05:04:42 PM
Hi, I've used the NHD-0216KZW-AG5 in 8-bit mode using the Western European 2 font table. It has performed as expected in 8-bit mode.

In a new design, I am using the 4-bit mode.

As long as I never change the font table, it works properly (albeit with the wrong character displayed). Whenever I try to change the font table, the display begins showing characters that are not in any font table, and eventually stops updating all together. I have to set the font table back to English/Japanese and then remove and re-apply power to the LCD to get the display operating again.

Any ideas as to where I'm going wrong?
Title: Re: NHD-0216KZW-AG5 Font Tables in 4-bit Mode
Post by: Michael_L on April 21, 2014, 03:43:14 PM
Can you send the part of your code that is changing the font table?
Title: Re: NHD-0216KZW-AG5 Font Tables in 4-bit Mode
Post by: cody on May 06, 2014, 12:41:16 PM
Sorry for the late reply, here is the C++ class that I'm using.

I gave up trying to get the font table to change, and instead used custom characters. However, I ran into a small issue there as well. I was unable program use the first custom character (character 0x00). I just shifted to using characters 0x01 to 0x03 and it worked fine.

Code: (c++) [Select]
/*
The MIT License (MIT)

Copyright (c) 2014 Cody Browne

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef _LCD_HPP_
#define _LCD_HPP_

#include <stdint.h>

template< class HW >
class LCD {
public:
static const uint16_t WIDTH = 16;
static const uint16_t CHARHEIGHT = 8;
private:
enum {
CMD_CLEAR_DISPLAY = 0x01
, CMD_RETURN_HOME = 0x02
, CMD_SET_ENTRY_MODE = 0x04
, CMD_SET_DISPLAY = 0x08
, CMD_SET_SHIFT = 0x10
, CMD_SET_FUNCTION = 0x28
, CMD_SET_CGRAM_ADDRESS = 0x40
, CMD_SET_DDRAM_ADDRESS = 0x80
, ENTRY_MODE_INCREMENT = 0x02
, ENTRY_MODE_DECREMENT = 0x00
, ENTRY_MODE_SHIFT = 0x01
, ENTRY_MODE_DONTSHIFT = 0x00
, DISPLAY_ON = 0x04
, DISPLAY_OFF = 0x00
, DISPLAY_CURSOR_ON = 0x02
, DISPLAY_CURSOR_OFF = 0x00
, DISPLAY_CURSOR_BLINK = 0x01
, DISPLAY_CURSOR_SOLID = 0x00
, SHIFT_DISPLAY = 0x08
, SHIFT_CURSOR = 0x00
, SHIFT_LEFT = 0x00
, SHIFT_RIGHT = 0x04
, FUNCTION_FT_ENGLISH_JAPANESE = 0x00
, FUNCTION_FT_WESTERN_EUROPE_1 = 0x01
, FUNCTION_FT_ENGLISH_RUSSIAN = 0x02
, FUNCTION_FT_WESTERN_EUROPE_2 = 0x03
, FUNCTION_DL_8BIT = 0x10
, FUNCTION_DL_4BIT = 0x00
, DDRAM_LINE2 = 0x40
};

static uint8_t _displayMode;

static void _probe( void );
static void _write( uint8_t data );
public:
static void Init( void );
static void Clear( void );
static void On( void );
static void Off( void );
static void GoL1( void );
static void GoL2( void );
static void Puts( const uint8_t* str );
static void PutAll( const uint8_t* line1 , const uint8_t* line2 );
static void Putc( uint8_t c );
static void SetCursor( bool ison , bool isblinking = true );
static void MakeCharacter( uint8_t value , const uint8_t* data , uint16_t data_lenght );
};
template< class HW>
uint8_t LCD< HW >::_displayMode;

template< class HW >
void LCD< HW >::PutAll( const uint8_t* line1 , const uint8_t* line2 ){
GoL1();
Puts( line1 );
GoL2();
Puts( line2 );
}
template< class HW >
void LCD< HW >::_probe( void ){
HW::template E<true>();
HW::template E<false>();
}
template< class HW >
void LCD< HW >::_write( uint8_t data ){
HW::SetNibble( data >> 4 );
_probe();
HW::SetNibble( data );
_probe();
}
template< class HW >
void LCD< HW >::Init( void ){
HW::Init();

// Start in command mode.
HW::template RS<false>();
HW::template RW<false>();

// Wake the LCD up in 8-bit mode.
HW::SetNibble( 0x3 );
_probe();
HW::Delay_ms( 100 );

// Wake the LCD up again in 8-bit mode.
HW::SetNibble( 0x3 );
_probe();
HW::Delay_ms( 10 );

// Set 4-bit mode.
HW::SetNibble( 0x2 );
_probe();
HW::Delay_ms( 10 );

// Set 4-bit mode with font table.
//FUNCTION_FT_ENGLISH_JAPANESE
//FUNCTION_FT_WESTERN_EUROPE_2
_write(
CMD_SET_FUNCTION
| FUNCTION_DL_4BIT
| FUNCTION_FT_ENGLISH_JAPANESE
);
HW::Delay_ms( 10 );

// Turn of display and cursor
_displayMode =
CMD_SET_DISPLAY
| DISPLAY_OFF
;
_write( _displayMode );
HW::Delay_ms( 1 );

// Set incrementing address without shifting the display.
_write(
CMD_SET_ENTRY_MODE
| ENTRY_MODE_INCREMENT
| ENTRY_MODE_DONTSHIFT
);
HW::Delay_ms( 1 );
}
template< class HW >
void LCD< HW >::MakeCharacter( uint8_t value , const uint8_t* data , uint16_t data_length ){
_write( 0x40 | ( value << 3 ) );
HW::Delay_ms( 1 );
HW::template RS<true>();
uint16_t i;
for( i = 0; i < data_length; ++i ){
_write( data[ i ] );
HW::Delay_ms( 1 );
}
while( i < CHARHEIGHT ){
_write( 0x00 );
HW::Delay_ms( 1 );
++i;
}
HW::template RS<false>();
_write( 0x80 );
HW::Delay_ms( 1 );
}
template< class HW >
void LCD< HW >::Puts( const uint8_t* str ){
// Set LCD control lines to write character data.
HW::template RS<true>();
HW::template RW<false>();

// Write the string out, limiting the maximum size of the string.
for( uint16_t i = 0; i < WIDTH; ++i ){
if( *str == '\0' ){
// Null termination reached.
break;
}
Putc( *str );
++str;
}
}
template< class HW >
void LCD< HW >::On( void ){
_displayMode |= DISPLAY_ON;
HW::template RS<false>();
HW::template RW<false>();
_write( _displayMode );
HW::Delay_ms( 1 );
}
template< class HW >
void LCD< HW >::Off( void ){
_displayMode &= ~DISPLAY_ON;
HW::template RS<false>();
HW::template RW<false>();
_write( _displayMode );
HW::Delay_ms( 1 );
}
template< class HW >
void LCD< HW >::SetCursor( bool ison , bool isblinking ){
if( ison ){
_displayMode |= DISPLAY_CURSOR_ON;
if( isblinking ){
_displayMode |= DISPLAY_CURSOR_BLINK;
}
else {
_displayMode &= ~DISPLAY_CURSOR_BLINK;
}
}
else {
_displayMode &= ~ DISPLAY_CURSOR_ON;
}
HW::template RS<false>();
HW::template RW<false>();
_write( _displayMode );
HW::Delay_ms( 1 );
}
template< class HW >
void LCD< HW >::Clear( void ){
HW::template RS<false>();
HW::template RW<false>();
_write( CMD_CLEAR_DISPLAY );
HW::Delay_ms( 3 );
}
template< class HW >
void LCD< HW >::GoL1( void ){
HW::template RS<false>();
HW::template RW<false>();
_write( CMD_SET_DDRAM_ADDRESS );
HW::Delay_ms( 1 );
}
template< class HW >
void LCD< HW >::GoL2( void ){
HW::template RS<false>();
HW::template RW<false>();
_write( CMD_SET_DDRAM_ADDRESS | DDRAM_LINE2 );
HW::Delay_ms( 1 );
}
template< class HW >
void LCD< HW >::Putc( uint8_t c ){
HW::template RS<true>();
HW::template RW<false>();
_write( c );
HW::Delay_ms( 1 );
}
#endif /* _LCD_HPP_ */
Title: Re: NHD-0216KZW-AG5 Font Tables in 4-bit Mode
Post by: cody on May 28, 2014, 02:23:42 PM
Anyone able to take a look at this?
Title: Re: NHD-0216KZW-AG5 Font Tables in 4-bit Mode
Post by: Michael_L on May 29, 2014, 11:41:57 AM
I have successfully modified my code to select that font table you are trying to use in 4-bit mode and have shared it below:

Code: [Select]
//---------------------------------------------------------
/*
NHD_0216KZW_uno4bit.ino
Program for writing to Newhaven Display 2 x 16 Character OLED (4-bit, 6800 mode)

(c)2014 Mike LaVine - Newhaven Display International, LLC.

        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation; either version 2 of the License, or
        (at your option) any later version.

        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
*/
//---------------------------------------------------------

// The 4 bit data bus is connected to PORTD[3..0] of the Arduino Uno

int RS =  9;    // RS signal connected to digital pin 9 of Arduino Uno
int RW =  10;    // R/W signal connected to digital pin 10 of Arduino Uno
int  E =  11;    // E signal connected to digital pin 11 of Arduino Uno

const char text1[] = {"Newhaven Display"};
const char text2[] = {" 2x16 Char OLED "};

void toggle()
{
   digitalWrite(E, HIGH);
   delay(1);
   digitalWrite(E, LOW);
}

void command(char c)

   PORTD = (c>>4);
   digitalWrite(RS, LOW);
   toggle();
   PORTD = c;
   toggle();
}

void data(char d)
{
   PORTD = (d>>4);
   digitalWrite(RS, HIGH);
   toggle();
   PORTD = d;
   toggle();
}

void disp()
{
   int i;
   delay(50);
   command(0x02);  //Home Command  [Set DDRAM address to Line 1 position 1]
   delay(5);
   for (i=0;i<20;i++)
   {
      data(text1[i]);
   }
   command(0xC0);  //Second Line  [Set DDRAM address to Line 2 position 1]
   for (i=0;i<20;i++)
   {
      //data(text2[i]);
      data(0xF0+i);  //to prove western european table 2 is selected
   }
}

void writeCGRAM()
{
   command(0x40);    //first CGRAM position
   data(0x00);
   data(0x00);
   data(0x0F);
   data(0x14);
   data(0x14);
   data(0x14);
   data(0x14);
   data(0x0F);
}

void setup()         //runs first at power on
{
   DDRD = 0xFF;    //set PORTD (data bus) as output
   PORTD = 0x00;   //initialize PORTD to 0x00
   DDRB = 0xFF;    //set PORTB (control lines) as output
   PORTB = 0x00;   //initialize PORTB to 0x00
   
   /////////////////////Initialization Start///////////////////////
   PORTD = 0x2;        //extra leading nibble for 4-bit mode
   toggle();
   command(0x2B);      //4-bit mode, western european table 2
   command(0x08);      //display OFF
   command(0x01);      //clear display
   delay(5);
   command(0x06);      //entry mode set
   command(0x02);      //return home
   command(0x0C);      //display ON
   delay(10);
   //////////////////////Initialization End////////////////////////
}

void loop()         //main loop

  disp();
  delay(2000);    //2 seconds delay
  command(0x01);  //clear display
  delay(5);       //5 milliseconds delay
  writeCGRAM();   //write custom character to CGRAM (sideways 'A')
  command(0x02);  //Home Command  [Set DDRAM address to Line 1 position 1]
  data(0x00);     //display custom char at CGRAM location 0x00 (sideways 'A')
  delay(3000);    //3 seconds delay
}

I've also successfully wrote a custom sideways 'A' to the CGRAM's first location 0x00.

Please also take special note of the extra leading nibble in the initialization, as you will see undesirable results on the display if this is not present.
Title: Re: NHD-0216KZW-AG5 Font Tables in 4-bit Mode
Post by: cody on May 29, 2014, 01:26:15 PM
Thank you, I'll work though your code as soon as I get a change.