Library for New Haven NHD_0420DZW OLED

NHD_0420DZW_OLED.cpp

Committer:
JackB
Date:
2016-10-26
Revision:
0:91420dff6791

File content as of revision 0:91420dff6791:

/**
* @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;
}