Library for New Haven NHD_0420DZW OLED

Revision:
0:91420dff6791
--- /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;
+}