Library for Electronic Assembly DOG Displays

Hi all.
My first post here and just with a library. :slight_smile:

I’ve made a library for the DOG series of Electronic Assembly. Because it’s not a normal HD44780 controller. The library is written like the LCD4Bit library. And it’s one of my sources.

Datasheet of the Display http://www.lcd-module.de/eng/pdf/doma/dog-me.pdf
Datasheet of the Controller ST7036 http://www.lcd-module.de/eng/pdf/zubehoer/st7036.pdf

I’ll try to upload some pictures and the wiring diagram.

The Sketch:

// examples of the DOGM_LCD library

#include <DOGM_LCD.h>

// create an object with the type of your Display
// EA DOGM081x-A (1x8 chars)  -> 81
// EA DOGM162x-A (2x16 chars) -> 162
// ES DOGM163x-A (3x16 chars) -> 163
DOGM_LCD lcd = DOGM_LCD(163); 

int i;
int x;
char string[3];


void setup() { 
  lcd.init();
}

void loop() {
  // ##########
  lcd.gotoxy(2,1);
  lcd.printStr("Hello World!");
  delay(2000);
  
  // ##########  
  lcd.clear(); // clear the Display
  lcd.contrast(0); // set contrast to 0 (nothing to see)
  lcd.gotoxy(3,1);
  lcd.printStr("Fade in...");
  for (i=0; i<64; i++) {
    lcd.contrast(i);
    delay(50);
  }
  delay(2000);
  
  // ##########
  lcd.home(); // position of teh cursor at home (0,0)
  lcd.printStr("01234567890123456");

  lcd.gotoxy(0, 1);
  lcd.printStr("ABCDEFGHIJKLMNOP");

  lcd.gotoxy(0, 2);
  lcd.print(0x08); // print out some special chars
  lcd.print(0x09);
  lcd.print(0x0A);
  lcd.print(0x0B);
  lcd.print(0x0C);
  lcd.print(0x0D);
  lcd.print(0x0E);
  lcd.print(0x0F);
  lcd.print(0xF8);
  lcd.print(0xF9);
  lcd.print(0xFA);
  lcd.print(0xFB);
  lcd.print(0xFC);
  lcd.print(0xFD);
  lcd.print(0xFE);
  lcd.print(0xFF);
  
  delay(2000);
  
  for (i=63; i>=0; i--) {
    lcd.contrast(i);
    delay(50);
  }
  lcd.clear();
  lcd.contrast(32);
  
  // ##########
  for (x=0; x<100; x++) {
    itoa(x, string, 10);
    lcd.gotoxy(14,2);
    lcd.printStr(string);
    delay(50);
  }
}

The Header:

#ifndef DOGM_LCD_h
  #define DOGM_LCD_h

  #include <inttypes.h>

  class DOGM_LCD {
  public:
    DOGM_LCD(int type);
    void cmd_nibble(int nibble);
    void cmd(int value);
    void init();
    void clear();
    void home();
    void gotoxy(int x, int y);
    void printStr(char value[]);
    void print(int value);
    void contrast(int value);
  private:
    void pulse_enable();
    void chkbusy();
    void push_nibble(int nibble);
    void push_byte(int value);
  };
#endif

And the .cpp

/*
DOGM_LCD - v0.1 - 27.07.2008 - dasgrundprinzip.de

This is an Arduino library for the DOG series Display from Electronic Assembly.
http://www.lcd-module.de/deu/dog/dog.htm
Communication is 4-pin parallel mode. 

Sources:
- LCD4Bit v0.1 from neillzero (http://abstractplain.net Library)
- Datasheet of ST7036 controller (http://www.lcd-module.de/eng/pdf/zubehoer/st7036.pdf)

Tested with a DOGM163W-A (3x16 chars) on an Arduino Decimila and Arduino 0010 Alpha

Usage:
see the examples folder of this library distribution.

*/

// ########## includes ##########
#include "DOGM_LCD.h"
extern "C" {
  #include <stdio.h>            //not needed yet
  #include <string.h>            //needed for strlen()
  #include <inttypes.h>
  #include "WConstants.h"      //all things wiring / arduino
}

// ########## pin assignment ##########
int RS = 12;      // Register Select
int RW = 11;      // Read/Write
int En = 2;            // Enable

//DB should be an unseparated group of pins - because of lazy coding in push_nibble()
int DB[] = {7, 8, 9, 10};  // DB4 .. DB7


// ########## global variables ##########
int lcd_type = 81; // just a ini-value. The LCD-Type is changed in the DOGM_LCD sketch.

// If you want to save the RW-pin of the microcontroller, just switch it off and tie the RW-pin of the LCD to GROUND.
// The only time the RW-pin is used, is for checking the BusyFlag. When RW is deactivated we'll use a 5ms dealy instead checking the BusyFlag.
int USING_RW = false;





// The type variable is set in the sketch
DOGM_LCD::DOGM_LCD(int type) {
  lcd_type = type;
}

// a short (1us) impuls on the Enable-Pin to clock the Data into the LCD.
void DOGM_LCD::pulse_enable(){
  digitalWrite(En,LOW);
  delayMicroseconds(1);
  digitalWrite(En,HIGH);
  delayMicroseconds(1);
  digitalWrite(En,LOW);
}


// checking the Busy Flag (DB7=1 -> busy). Only when RW is activated. Otherwise a delay of 5ms.
void DOGM_LCD::chkbusy(){
  if (USING_RW) {
    int busy;

    // D4-D7 as input
    pinMode(DB[0],INPUT);
    pinMode(DB[1],INPUT);
    pinMode(DB[2],INPUT);
    pinMode(DB[3],INPUT);
  
    do {
      digitalWrite(RS, LOW);
      digitalWrite(RW, HIGH);
      digitalWrite(En,HIGH); // get high-nibble
      delayMicroseconds(1);
      busy = digitalRead(DB[3]); // get DB7(BusyFlag)
      digitalWrite(En,LOW);
      delayMicroseconds(1);

      pulse_enable(); // get low-nibble and ignore it
    }
    while (busy);

    // D4-D7 as output
    pinMode(DB[0],OUTPUT);
    pinMode(DB[1],OUTPUT);
    pinMode(DB[2],OUTPUT);
    pinMode(DB[3],OUTPUT);
  }
  else delay(5);
}

//push a nibble of data through the the LCD's DB4~7 pins, clocking with the Enable pin.
//We don't care what RS and RW are, here.
void DOGM_LCD::push_nibble(int value){
  int val_nibble = value & 0x0F;  //clean the value.  (unnecessary)

  for (int i=DB[0]; i <= DB[3]; i++) {
    digitalWrite(i,val_nibble & 01);
    val_nibble >>= 1;
  }
  pulse_enable();
}

//push a byte of data through the LCD's DB4~7 pins, in two steps, clocking each with the enable pin.
void DOGM_LCD::push_byte(int value){
  int val_lower = value & 0x0F;
  int val_upper = value >> 4;
  push_nibble(val_upper);
  push_nibble(val_lower);
}

// Register Select to LOW -> it's a command. Push the nibble
void DOGM_LCD::cmd_nibble(int nibble) {
  digitalWrite(RS, LOW);
  if (USING_RW) { digitalWrite(RW, LOW); }
  push_nibble(nibble);
}

// Register Select to LOW -> it's a command. Push the byte
void DOGM_LCD::cmd(int value) {
  chkbusy();

  digitalWrite(RS, LOW);
  if (USING_RW) { digitalWrite(RW, LOW); }
  push_byte(value);
}

// initializing the LCD
void DOGM_LCD::init () {
  pinMode(En,OUTPUT);
  pinMode(RS,OUTPUT);
  if (USING_RW) { pinMode(RW,OUTPUT); }
  pinMode(DB[0],OUTPUT);
  pinMode(DB[1],OUTPUT);
  pinMode(DB[2],OUTPUT);
  pinMode(DB[3],OUTPUT);

  delay(40);

  cmd_nibble(0x03);                   // FUNCTION SET            DL=1 - 8bit
  delay(2);
  cmd_nibble(0x03);                   // FUNCTION SET       DL=1 - 8bit
  delayMicroseconds(30);
  cmd_nibble(0x03);                   // FUNCTION SET       DL=1 - 8bit
  delayMicroseconds(30);
  chkbusy();
  cmd_nibble(0x02);                   // FUNCTION SET            DL=0 - 4bit
  delayMicroseconds(30);
  cmd(0x29);                              // FUNCTION SET            DL=0 / N=1 / DH=0 / IS2=0 / IS1=1
  delayMicroseconds(30);

  cmd(0x14);                              // bias
  delayMicroseconds(30);
  cmd(0x70);                              // contrast set
  delayMicroseconds(30);
  cmd(0x52);                              // power/ICON/contrast
  delayMicroseconds(30);
  cmd(0x6A);                              // follower control
  delayMicroseconds(30);

  cmd(0x0C);                              // DISPLAY ON
  delayMicroseconds(30);
  cmd(0x01);                              // CLEAR DISPLAY
  delay(2);
  cmd(0x06);                              // ENTRY MODE SET
  delayMicroseconds(30);
}

// Clear Screen
void DOGM_LCD::clear(){
  cmd(0x01);
  delay(2);
}

// Cursor to Home position 0,0
void DOGM_LCD::home(){
  cmd(0x02);
  delayMicroseconds(30);
}

// move cursor to position x,y (1st Row and 1st column is position 0,0)
// for a 163 display : x = 0..15   y = 0..2
void DOGM_LCD::gotoxy(int x, int y) {
  int addr = 0x80;
  if (y<1) addr = 0x80+x;
  else switch (lcd_type) {
    case 81:
        addr = 0x80+x;
        break;;
      case 162:
        if (y>0) addr = 0xC0+x;
        break;;
    case 163:
        if (y==1) addr = 0x90+x;
        else if (y>1) addr = 0xA0+x;
        break;;
  }
  cmd(addr);
}

… and the rest of the .cpp

// Register Select to HIGH -> it's a data. Push the byte. With this function it is possible to dispaly special chars.
void DOGM_LCD::print(int value) {
  digitalWrite(RS, HIGH);
  if (USING_RW) { digitalWrite(RW, LOW); }

  push_byte(value);
}

// print the given string to the LCD at the current cursor position.  overwrites, doesn't insert.
void DOGM_LCD::printStr(char msg[]) {
  uint8_t i;  //fancy int.  avoids compiler warning when comparing i with strlen()'s uint8_t
  for (i=0;i < strlen(msg);i++){
    print(msg[i]);
  }
}

// The only possibility to change the contrast of the display. There's no potentiometer to do that!
// The contrast is initialized to 32. The posible range is 0..63.
void DOGM_LCD::contrast (int value) {
  if ((value >= 0x00) && (value <= 0x3F)) {
    int val_lower = value & 0x0F;
    int val_upper = value >> 4;
    cmd(0x29); // FUNCTION SET
    cmd(0x70|val_lower);
    cmd(0x50|val_upper);
  }
}

Hi,
great this was on my task list, but never got beyond some (successful) tests.
I will try your code with my 2 Line display.

But here are already some hints :
If you have the time to do so, you should create a new page on the playground Arduino Playground - HomePage, write some documentation for it and upload the code to there.

For the device-selection in the constructor I would suggest adding 3 #define statements :

#define EA_DOGM081 81
#define EA_DOGM162 162
#define EA_DOGM163 163

DOGM_LCD lcd=DOGM_LCD(EA_DOGM163);

The link to the product-page points to the german version here is the english translation http://www.lcd-module.de/eng/dog/dog.htm

Eberhard

Here are some more hints, I hope they are helpful

I was curious to know if you compared the performance the library when using RW to check when the panel is ready vs a hard coded delay. My guess is that it takes much longer to execute the code that checks if the panel is ready than a hard coded 5ms delay used if USING_RW set false. So the panel will always be ready on the first read and the delay will be much more than 5ms. But I haven't actually tried it and would be happy to be proved wrong.

I realize the code was derived from the playground lcd4bit code but you can get some extra performance in your library by eliminating the 1us delays in pulse_enable(). The Enable pulse will be at least 4us long without any added delays because each digitalWrite takes around 2us.

pulse_enable is called a number of times for each character written so minimsing the delay should enhance the performance.

Hi wayoda,
would be interesting if I'm right with the adresses for the 2nd line. Where would you place the define statements? In the Arduino-Code or maybe in the header-file?

Hi mem,
I just tested your suggestions and commented out the 1us delay in the pulse_enable() ... working. And I commented out the 5ms delay.
void DOGM_LCD::chkbusy() {}
And it's working already. What I want to try is, to count the time during the do{...}while(busy) and display it on the LCD, or something like that.
But the next two days I'm away on a construction job (I hope you know what I mean - in german it's called "auf Montage sein"). So maybe on thursday or friday.

And the next step is to test the SPI-mode. And the documentation of course. And then I'll start my little project. ;D

Hm, I searched the Arduino site and unfortunately I only found this after I finished my first attempt at writing a library for the DOG-M displays.

The good side of this: I started off with SPI. So, if you would like, you could take my working SPI code and merge it into your library?

Here's the link to my github project:GitHub - halfbyte/lcddogmspi: ABANDONED PROJECT: An arduino library for the EA DOG-M LCD displays (an adaption of the LCD libraries available)

Can not find any prices on the DOG display, any hints?
Hope they are not to expensive, they are a great product.

Hi,

I received a price list from Electronic Assembly.
The price is good, hope it is ok to list prices at this forum.

Article no. / product type / price: | 1- | 25- | 100- pieces/EURO

EA DOGL128B-6 128x64 à 20,50 / 15,38 / 13,33 EUR, STN, blue negative
EA DOGL128E-6 128x64 à 20,50 / 15,38 / 13,33 EUR, STN, Y-green positive
EA DOGL128L-6 128x64 à 20,50 / 15,38 / 13,33 EUR, STN, reflektive, pos.
EA DOGL128S-6 128x64 à 20,50 / 15,38 / 13,33 EUR, FSTN, black negative
EA DOGL128W-6 128x64 à 20,50 / 15,38 / 13,33 EUR, FSTN, black positive

LED backlights:

LED68x51-W white à 15,50 / 11,63 / 10,08 EUR
LED68x51-G yellow-green à 6,50 / 4,88 / 4,23 EUR
LED68x51-B blue à 15,50 / 11,63 / 10,08 EUR
LED68x51-R red à 6,50 / 4,88 / 4,23 EUR LED68x51-A amber à 6,50 / 4,88 / 4,23 EUR
LED68x51-E green à 15,50 / 11,63 / 10,08 EUR
LED68x51-RGB multicolour à 24,50 / 18,38 / 15,93 EUR

accessory:

EA FL-20P socket à 1.50| 1.20| 1.05 EUR
2 pieces for each display
Touch Panel 128-2 will come soon
EA WF100-04S, connector à 1,50 / 1,13 / 0,98 EUR