Library for New Haven NHD_0420DZW OLED

Files at this revision

API Documentation at this revision

Comitter:
JackB
Date:
Wed Oct 26 12:19:43 2016 +0000
Commit message:
Library for New Haven NHD_0420DZW OLED

Changed in this revision

NHD_0420DZW_OLED.cpp Show annotated file Show diff for this revision Revisions of this file
NHD_0420DZW_OLED.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 91420dff6791 NHD_0420DZW_OLED.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NHD_0420DZW_OLED.cpp	Wed Oct 26 12:19:43 2016 +0000
@@ -0,0 +1,308 @@
+/**
+* @file NHD_0420DZW_OLED.cpp
+* @brief This C++ file contains the functions to interface the New Haven
+* NHD_0420DZW display using a 4-wire software spi bus bus.
+* 10-bit SPI operation, ie spi.format(10, 3), does not work with Nucleo-F746ZG,
+* it remains 8-bit, so unfortunately I had to do bit banging
+* @author Jack Berkhout
+*
+* @date 2016-10-21
+*/
+#include "NHD_0420DZW_OLED.h"
+#include "mbed.h"
+
+NHD_0420DZW_OLED::NHD_0420DZW_OLED(PinName sdi, PinName sdo, PinName scl, PinName csb, const char *name) : 
+  Stream(name), _lcd_sdi(sdi), _lcd_sdo(sdo), _lcd_scl(scl), _lcd_csb(csb)
+//  TextDisplay(name), _lcd_sdi(sdi), _lcd_sdo(sdo), _lcd_scl(scl), _lcd_csb(csb)
+{
+    _lcd_csb = 1;
+    _lcd_scl = 1;
+    _lcd_sdi = 0;
+    
+    // --- claim ---
+    _row = 0;
+    _column = 0;
+    if (name == NULL) {
+        _path = NULL;
+    } else {
+        _path = new char[strlen(name) + 2];
+        sprintf(_path, "/%s", name);
+    }
+    // -------------
+        
+    init();
+}
+
+void NHD_0420DZW_OLED::init(void)
+{
+    writeCommand(LCD_FUNCTION_SET);
+    writeCommand(LCD_DISPLAY_OFF);
+    writeCommand(LCD_CLEAR_DISPLAY);
+    writeCommand(LCD_CURSOR_INCR);
+    writeCommand(LCD_RETURN_HOME);
+    writeCommand(LCD_DISPLAY_ON);
+
+    // custom characters
+    // In the character generator RAM, the user can rewrite character patterns
+    // For 5x8 dots, eight character patterns can be written
+    // Store custom chars in LCD's CGRAM
+    writeCommand(LCD_CGRAM(1));
+    char CharacterBytes[] = CHARACTERBYTES;
+    for (unsigned char Index = 0; Index < sizeof(CharacterBytes); Index++) {
+        writeData(CharacterBytes[Index]);
+    }
+}
+
+void NHD_0420DZW_OLED::cls(void)
+{
+    writeCommand(LCD_CLEAR_DISPLAY);   // Clear display
+}
+
+void NHD_0420DZW_OLED::cursorHome(void)
+{
+    writeCommand(LCD_RETURN_HOME);   // Clear display
+}
+
+void NHD_0420DZW_OLED::writeCharacter(int column, int row, int c)
+{
+    locate(column, row);
+    writeData(c);
+}
+
+void NHD_0420DZW_OLED::writeCharacter(char c)
+{
+    writeData((int)c);
+}
+
+void NHD_0420DZW_OLED::writeString(char *charString)
+{
+    uint8_t length = strlen(charString);
+    for (uint8_t i = 0; i < length; i++) {
+        writeCharacter(charString[i]);
+    }
+}
+
+void NHD_0420DZW_OLED::writeString(int row, char *charString)
+{
+    locate(0, row);
+    writeString(charString);
+}
+
+void NHD_0420DZW_OLED::writeString(int column, int row, char *charString)
+{
+    locate(column, row);
+    writeString(charString);
+}
+
+void NHD_0420DZW_OLED::clearLine(int row)
+{
+    int length = LCD_NUMBER_OF_CHARACTERS;
+    locate(0, row);
+    while(length--) {
+        writeCharacter(' ');
+    }
+    locate(0, row);
+}
+
+void NHD_0420DZW_OLED::clearRegion(int column, int row, int length)
+{
+    locate(column, row);
+    while(length--) {
+        writeCharacter(' ');
+    }
+    locate(column, row);
+}
+
+void NHD_0420DZW_OLED::locate(int column, int row)
+{
+    if ((column > LCD_NUMBER_OF_CHARACTERS) || (row > LCD_NUMBER_OF_LINES))
+    {
+        return;
+    }
+    else
+    {
+        switch (row) {
+            case 0:
+                writeCommand(LCD_LINE_1 + column);   /* command - position cursor at 0x00 (0x80 + 0x00 ) */
+                break;
+            case 1:
+                writeCommand(LCD_LINE_2 + column);   /* command - position cursor at 0x40 (0x80 + 0x00 ) */
+                break;
+            case 2:
+                writeCommand(LCD_LINE_3 + column);   /* command - position cursor at 0x40 (0x80 + 0x00 ) */
+                break;
+            case 3:
+                writeCommand(LCD_LINE_4 + column);   /* command - position cursor at 0x40 (0x80 + 0x00 ) */
+                break;
+            default:
+                writeCommand(LCD_LINE_1 + column);   /* command - position cursor at 0x00 (0x80 + 0x00 ) */
+                break;
+        }
+    }
+}
+
+void NHD_0420DZW_OLED::drawBar(int column, int row, int Value, int Max)
+{
+  int Count = 0;
+  int Characters = Max / 5;
+  if (Value > Max)
+    Value = Max;
+  locate(column, row);
+  // Print the characters
+  while (Count < Characters)
+  {
+    if ((Value >= 6) && (Value <= Max))
+      writeData('\6');  // *****
+    else
+    if ((Value == 0) || (Value > Max))
+      writeData('\1');  // .....
+    else
+      writeData(Value+1);  // ***..
+    Value -= 5;
+    Count++;
+  }
+}
+
+void NHD_0420DZW_OLED::writeCommand(int data)
+{
+    waitBusy();
+    writeSerial(LCD_COMMAND, LCD_WRITE, data);
+}
+
+void NHD_0420DZW_OLED::writeData(int data)
+{
+//    waitBusy();
+    writeSerial(LCD_DATA, LCD_WRITE, data);
+}
+
+int NHD_0420DZW_OLED::readAddress(void)
+{
+    writeSerial(LCD_COMMAND, LCD_READ, 0x00);   // Dummy read
+    return (serialData(LCD_COMMAND, LCD_READ, 0x00, 0x00) >> 3) & 0x7F;
+}
+
+void NHD_0420DZW_OLED::waitBusy(void)
+{
+    while (readBusyFlag());
+}
+
+int NHD_0420DZW_OLED::readBusyFlag(void)
+{
+    return (serialInstruction(LCD_COMMAND, LCD_READ, 0x00, 0x00) >> 10);
+}
+
+void NHD_0420DZW_OLED::writeSerial(int rs, int rw, int data)
+{
+    // CSB ---|_________________________________________|----
+    // SCL -----|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|------
+    // SDI .....|RS0|RW0|D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 |....
+    // SDO .............|D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 |....
+    // RS=1: Data
+    // RS=0: Command <---
+    // RW=1: Read
+    // RW=0: Write <---
+    if (rs > 0) {
+        data |= LCD_RS_BIT_MASK;
+    }
+    if (rw > 0) {
+        data |= LCD_Rw_BIT_MASK;
+    }
+
+    selectSerial(true);
+    clockSerial(data, 10);
+    selectSerial(false);
+}
+
+int NHD_0420DZW_OLED::serialInstruction(int rs, int rw, int data1, int data2)
+{
+    // CSB ---|_________________________________________________________________________________|----
+    // SCL -----|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|------
+    // SDI .....|RS0|RW1|D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 |RS |RW |D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 |....
+    // SDO .............|D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 |D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 |D7 |D6 |....
+    // RS=1: Data
+    // RS=0: Command <---
+    // RW=1: Read <---
+    // RW=0: Write
+    // Read Bussy Flag & Address BF AC6 AC5 AC4 AC3 AC2 AC1 AC0
+    if (rs > 0) {
+        data1 |= LCD_RS_BIT_MASK;
+        data2 |= LCD_RS_BIT_MASK;
+    }
+    if (rw > 0) {
+        data1 |= LCD_Rw_BIT_MASK;
+        data2 |= LCD_Rw_BIT_MASK;
+    }
+
+    selectSerial(true);
+    clockSerial(data1, 10);
+    int data = clockSerial(data2, 10);
+    selectSerial(false);
+    return data;
+}
+
+int NHD_0420DZW_OLED::serialData(int rs, int rw, int data1, int data2)
+{
+    // CSB ---|_________________________________________________________________________________|----
+    // SCL -----|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|-|_|------
+    // SDI .....|RS1|RW1|D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 |RS |RW |D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 |....
+    // SDO .............|D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 |D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 |D7 |D6 |....
+    // RS=1: Data <---
+    // RS=0: Command
+    // RW=1: Read <---
+    // RW=0: Write
+    // Read data from CGRAM or DDRAM
+    if (rs > 0) {
+        data1 |= LCD_RS_BIT_MASK;
+    }
+    if (rw > 0) {
+        data1 |= LCD_Rw_BIT_MASK;
+    }
+
+    selectSerial(true);
+    clockSerial(data1, 10);
+    int data = clockSerial(data2, 8);
+    selectSerial(false);
+    return data;
+}
+
+int NHD_0420DZW_OLED::clockSerial(int dataOut, int bits)
+{
+    int dataIn = 0;
+    for (int bit = bits; bit > 0; bit--) {
+        _lcd_scl = 0;
+        if ((dataOut & (1 << (bit-1))) == 0) {
+            _lcd_sdi = 0;
+        } else {
+            _lcd_sdi = 1;
+        }
+//        wait_us(LCD_CLOCK_PULSE_LENGTH);
+        _lcd_scl = 1;
+        dataIn |= _lcd_sdo;
+        dataIn <<= 1;
+//        wait_us(LCD_CLOCK_PULSE_LENGTH);
+    }
+    return dataIn;
+}
+
+void NHD_0420DZW_OLED::selectSerial(bool select)
+{
+    if (select)
+        _lcd_csb = 0;
+    else
+        _lcd_csb = 1;
+//    wait_us(LCD_CLOCK_PULSE_LENGTH);
+}
+
+bool NHD_0420DZW_OLED::claim (FILE *stream) {
+    if ( _path == NULL) {
+        fprintf(stderr, "claim requires a name to be given in the instantioator of the TextDisplay instance!\r\n");
+        return false;
+    }
+    if (freopen(_path, "w", stream) == NULL) {
+        // Failed, should not happen
+        return false;
+    }
+    // make sure we use line buffering
+    setvbuf(stdout, NULL, _IOLBF, LCD_NUMBER_OF_CHARACTERS);
+    return true;
+} 
diff -r 000000000000 -r 91420dff6791 NHD_0420DZW_OLED.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NHD_0420DZW_OLED.h	Wed Oct 26 12:19:43 2016 +0000
@@ -0,0 +1,139 @@
+#ifndef _NHD_0420DZW_OLED_H_
+#define _NHD_0420DZW_OLED_H_
+
+/**
+* @file NHD_0420DZW_OLED.h
+* @brief this header file will contain the definitions to interface the New Haven
+* NHD-0420DZW-AY5 display using a 4-wire software spi bus bus.
+* @author Jack Berkhout
+*
+* @date 2016-10-21
+*/
+
+/**
+* Class for the New Haven NHD-0420DZW-AY5 SPI LCD 4x20
+* @author Jack Berkhout
+* @date 2016-10-21
+*/
+
+#include "mbed.h"
+//#include "TextDisplay.h"
+
+#define LCD_COMMAND 0
+#define LCD_DATA    1
+#define LCD_WRITE   0
+#define LCD_READ    1
+
+#define LCD_CLEAR_DISPLAY   0x01
+#define LCD_RETURN_HOME     0x02
+#define LCD_CURSOR_INCR     0x06
+#define LCD_DISPLAY_OFF     0x08
+#define LCD_DISPLAY_ON      0x0C
+#define LCD_FUNCTION_SET    0x38
+#define LCD_BUSSY_FLAG      0x80
+#define LCD_NUMBER_OF_CHARACTERS 20
+#define LCD_NUMBER_OF_LINES       4
+
+#define LCD_LINE_1 0x80
+#define LCD_LINE_2 0xC0
+#define LCD_LINE_3 0x94
+#define LCD_LINE_4 0xD4
+
+#define LCD_CLOCK_PULSE_LENGTH 1
+#define LCD_RS_BIT_MASK 0x0200
+#define LCD_Rw_BIT_MASK 0x0100
+
+/* set CGRAM addr */
+#define LCD_CGRAM(n)        (0x40 + ((n) << 3))
+// *.... 16
+// **... 24
+// ***.. 28
+// ****. 30
+// ***** 31
+// *..*. 18
+// *..*. 18
+// .***. 14
+
+//#define CHARACTERBYTES { \
+//     0,  0,  0,  0,  0,  0,  0,  0, \
+//    16, 16, 16, 16, 16, 16, 16, 16, \
+//    24, 24, 24, 24, 24, 24, 24, 24, \
+//    28, 28, 28, 28, 28, 28, 28, 28, \
+//    30, 30, 30, 30, 30, 30, 30, 30, \
+//    31, 31, 31, 31, 31, 31, 31, 31, \
+//     1,  1,  1,  1,  1,  1,  1,  1 \
+//}
+
+#define CHARACTERBYTES { \
+     0,  0,  0,  0,  0,  0,  0,  0, \
+     0,  0,  0,  16,  16, 0, 0, 0, \
+     0,  0,  0,  24,  24, 0, 0, 0, \
+     0,  0,  0,  28,  28, 0, 0, 0, \
+     0,  0,  0,  30,  30, 0, 0, 0, \
+     0,  0,  0,  31,  31, 0, 0, 0, \
+     0,  0,  0,  0,  0,  0,  0,  0, \
+     0,  0,  0,  0,  0,  0,  0,  0 \
+}
+
+//class NHD_0420DZW_OLED {
+class NHD_0420DZW_OLED : public Stream {
+public:
+    /**
+    * @brief Create a new Class to interface to an NH-0216K3Z-NSW-BBW 2x16 Character LCD from New Haven
+    **/
+    NHD_0420DZW_OLED(PinName mosi, PinName miso, PinName sck, PinName cs, const char *name);
+
+    void init(void);
+
+    void cls(void);
+    void cursorHome(void);
+    
+    void writeCharacter(int column, int row, int c);
+    void writeCharacter(char character);
+    void writeString(char *charString);
+    void writeString(int y, char *charString);
+    void writeString(int x, int y, char *charString);
+    void clearLine(int y);
+    void clearRegion(int x, int y, int length);
+    void locate(int X, int Y);
+    void drawBar(int X, int Y, int Value, int Max);
+
+    virtual bool claim (FILE *stream);
+
+private:
+    DigitalOut _lcd_csb;
+    DigitalOut _lcd_scl;
+    DigitalOut _lcd_sdi;
+    DigitalIn  _lcd_sdo;  
+
+    void writeCommand(int data);
+    void writeData(int data);
+    int readAddress(void);
+    void waitBusy(void);
+    int readBusyFlag(void);
+    void writeSerial(int rs, int rw, int data);
+    int serialInstruction(int rs, int rw, int data1, int data2);
+    int serialData(int rs, int rw, int data1, int data2);
+    int clockSerial(int dataOut, int bits);
+    void selectSerial(bool select);
+
+// https://developer.mbed.org/users/4180_1/notebook/how-to-get-printf-to-work-in-a-new-display-driver-/
+//and add this to the end of the class
+protected:
+    //used by printf - supply a new _putc virtual function for the new device
+    virtual int _putc(int c) {
+        writeData(c); //your new LCD put to print an ASCII character on LCD
+        return 0;
+    };
+//assuming no reads from LCD
+    virtual int _getc() {
+        return -1;
+    }
+
+    // character location
+    uint16_t _column;
+    uint16_t _row;
+    char *_path;
+
+};
+#endif
\ No newline at end of file