Text console library for ST7565 graphics LCD controller over SPI interface.

Dependents:   TextLCD_ST7565SPI_Test OpPanel_Offline OpPanel_Offline_cmake_gcc_arm_NUCLEO_F303RENew

TextLCD_ST7565SPI.cpp

Committer:
kayekss
Date:
2015-05-25
Revision:
2:5a627a1745f2
Parent:
1:a32310f5dab1

File content as of revision 2:5a627a1745f2:

// ==================================================== Mar 03 2015, kayeks ==
// TextLCD_ST7565SPI.cpp
// ===========================================================================
// Text console library for ST7565 graphics LCD controller over SPI interface.

#include <string.h>
#include "TextLCD_ST7565SPI.h"

const uint8_t TextLCD_ST7565SPI::FONT_5X7[128][5] = {
    // 00h..07h
    { 0x77, 0x55, 0x55, 0x55, 0x77 },  // unimplemented NUL
    { 0x77, 0x52, 0x52, 0x52, 0x76 },  // unimplemented SOH
    { 0x77, 0x54, 0x57, 0x51, 0x77 },  // unimplemented STX
    { 0x77, 0x51, 0x56, 0x51, 0x77 },  // unimplemented ETX
    { 0x71, 0x57, 0x55, 0x55, 0x71 },  // unimplemented EOT
    { 0x77, 0x51, 0x57, 0x54, 0x77 },  // unimplemented ENQ
    { 0x77, 0x55, 0x57, 0x54, 0x77 },  // unimplemented ACK
    { 0x74, 0x54, 0x52, 0x51, 0x77 },  // unimplemented BEL
    // 08h..0Fh
    { 0x77, 0x55, 0x57, 0x55, 0x77 },  // unimplemented BS
    { 0x77, 0x51, 0x57, 0x55, 0x77 },  // unimplemented HT
    { 0x75, 0x57, 0x55, 0x55, 0x77 },  // unimplemented LF
    { 0x77, 0x55, 0x55, 0x57, 0x74 },  // unimplemented VT
    { 0x77, 0x54, 0x54, 0x54, 0x77 },  // unimplemented FF
    { 0x77, 0x55, 0x55, 0x57, 0x71 },  // unimplemented CR
    { 0x77, 0x54, 0x57, 0x54, 0x77 },  // unimplemented SO
    { 0x74, 0x54, 0x57, 0x54, 0x77 },  // unimplemented SI
    // 10h..17h
    { 0x77, 0x25, 0x25, 0x25, 0x67 },  // unimplemented DLE
    { 0x77, 0x22, 0x22, 0x22, 0x66 },  // unimplemented DC1
    { 0x77, 0x24, 0x27, 0x21, 0x67 },  // unimplemented DC2
    { 0x77, 0x21, 0x26, 0x21, 0x67 },  // unimplemented DC3
    { 0x71, 0x27, 0x25, 0x25, 0x61 },  // unimplemented DC4
    { 0x77, 0x21, 0x27, 0x24, 0x67 },  // unimplemented NAK
    { 0x77, 0x25, 0x27, 0x24, 0x67 },  // unimplemented SYN
    { 0x74, 0x24, 0x22, 0x21, 0x67 },  // unimplemented ETB
    // 18h..1Fh
    { 0x77, 0x25, 0x27, 0x25, 0x67 },  // unimplemented CAN
    { 0x77, 0x21, 0x27, 0x25, 0x67 },  // unimplemented EM
    { 0x75, 0x27, 0x25, 0x25, 0x67 },  // unimplemented SUB
    { 0x77, 0x25, 0x25, 0x27, 0x64 },  // unimplemented ESC
    { 0x77, 0x24, 0x24, 0x24, 0x67 },  // unimplemented FS
    { 0x77, 0x25, 0x25, 0x27, 0x61 },  // unimplemented GS
    { 0x77, 0x24, 0x27, 0x24, 0x67 },  // unimplemented RS
    { 0x74, 0x24, 0x27, 0x24, 0x67 },  // unimplemented US
    // 20h..27h
    { 0x00, 0x00, 0x00, 0x00, 0x00 },  // SPC
    { 0x00, 0x00, 0x7d, 0x00, 0x00 },  // !
    { 0x00, 0x60, 0x00, 0x60, 0x00 },  // "
    { 0x22, 0x7f, 0x22, 0x7f, 0x22 },  // #
    { 0x32, 0x49, 0x7f, 0x49, 0x26 },  // $
    { 0x72, 0x54, 0x7f, 0x15, 0x27 },  // %
    { 0x36, 0x49, 0x75, 0x02, 0x0d },  // &
    { 0x00, 0x20, 0x40, 0x00, 0x00 },  // '
    // 28h..2Fh
    { 0x00, 0x00, 0x00, 0x3e, 0x41 },  // (
    { 0x41, 0x3e, 0x00, 0x00, 0x00 },  // )
    { 0x14, 0x08, 0x3e, 0x08, 0x14 },  // *
    { 0x08, 0x08, 0x3e, 0x08, 0x08 },  // +
    { 0x00, 0x01, 0x02, 0x00, 0x00 },  // ,
    { 0x08, 0x08, 0x08, 0x08, 0x08 },  // -
    { 0x00, 0x00, 0x01, 0x00, 0x00 },  // .
    { 0x00, 0x03, 0x1c, 0x60, 0x00 },  // /
    // 30h..37h
    { 0x3e, 0x41, 0x49, 0x41, 0x3e },  // 0
    { 0x00, 0x41, 0x7f, 0x01, 0x00 },  // 1
    { 0x27, 0x49, 0x49, 0x49, 0x31 },  // 2
    { 0x42, 0x41, 0x51, 0x51, 0x6e },  // 3
    { 0x0e, 0x12, 0x22, 0x7f, 0x02 },  // 4
    { 0x72, 0x51, 0x51, 0x51, 0x4e },  // 5
    { 0x3e, 0x51, 0x51, 0x51, 0x0e },  // 6
    { 0x40, 0x40, 0x47, 0x58, 0x60 },  // 7
    // 38h..3Fh
    { 0x36, 0x49, 0x49, 0x49, 0x36 },  // 8
    { 0x38, 0x45, 0x45, 0x45, 0x3e },  // 9
    { 0x00, 0x00, 0x12, 0x00, 0x00 },  // :
    { 0x00, 0x01, 0x12, 0x00, 0x00 },  // ;
    { 0x00, 0x08, 0x14, 0x22, 0x41 },  // <
    { 0x14, 0x14, 0x14, 0x14, 0x14 },  // =
    { 0x41, 0x22, 0x14, 0x08, 0x00 },  // >
    { 0x20, 0x40, 0x45, 0x48, 0x30 },  // ?
    // 40h..47h
    { 0x3e, 0x41, 0x5d, 0x55, 0x3c },  // @
    { 0x0f, 0x34, 0x44, 0x34, 0x0f },  // A
    { 0x7f, 0x49, 0x49, 0x49, 0x36 },  // B
    { 0x3e, 0x41, 0x41, 0x41, 0x22 },  // C
    { 0x7f, 0x41, 0x41, 0x41, 0x3e },  // D
    { 0x7f, 0x49, 0x49, 0x49, 0x41 },  // E
    { 0x7f, 0x48, 0x48, 0x48, 0x40 },  // F
    { 0x3e, 0x41, 0x49, 0x49, 0x2e },  // G
    // 48h..4Fh
    { 0x7f, 0x08, 0x08, 0x08, 0x7f },  // H
    { 0x00, 0x41, 0x7f, 0x41, 0x00 },  // I
    { 0x02, 0x01, 0x01, 0x41, 0x7e },  // J
    { 0x7f, 0x08, 0x14, 0x22, 0x41 },  // K
    { 0x7f, 0x01, 0x01, 0x01, 0x01 },  // L
    { 0x7f, 0x20, 0x1c, 0x20, 0x7f },  // M
    { 0x7f, 0x20, 0x10, 0x08, 0x7f },  // N
    { 0x3e, 0x41, 0x41, 0x41, 0x3e },  // O
    // 50h..57h
    { 0x7f, 0x48, 0x48, 0x48, 0x30 },  // P
    { 0x3e, 0x41, 0x45, 0x42, 0x3d },  // Q
    { 0x7f, 0x48, 0x4c, 0x4a, 0x31 },  // R
    { 0x32, 0x49, 0x49, 0x49, 0x26 },  // S
    { 0x40, 0x40, 0x7f, 0x40, 0x40 },  // T
    { 0x7e, 0x01, 0x01, 0x01, 0x7e },  // U
    { 0x78, 0x06, 0x01, 0x06, 0x78 },  // V
    { 0x7e, 0x01, 0x1e, 0x01, 0x7e },  // W
    // 58h..5Fh
    { 0x63, 0x14, 0x08, 0x14, 0x63 },  // X
    { 0x60, 0x10, 0x0f, 0x10, 0x60 },  // Y
    { 0x43, 0x45, 0x49, 0x51, 0x61 },  // Z
    { 0x00, 0x00, 0x00, 0x7f, 0x41 },  // [
    { 0x00, 0x60, 0x1c, 0x03, 0x00 },  // backslash
    { 0x41, 0x7f, 0x00, 0x00, 0x00 },  // ]
    { 0x00, 0x20, 0x40, 0x20, 0x00 },  // ^
    { 0x01, 0x01, 0x01, 0x01, 0x01 },  // _
    // 60h..67h
    { 0x00, 0x00, 0x40, 0x20, 0x00 },  // `
    { 0x02, 0x15, 0x15, 0x15, 0x0f },  // a
    { 0x7f, 0x11, 0x11, 0x11, 0x0e },  // b
    { 0x0e, 0x11, 0x11, 0x11, 0x0a },  // c
    { 0x0e, 0x11, 0x11, 0x11, 0x7f },  // d
    { 0x0e, 0x15, 0x15, 0x15, 0x0c },  // e
    { 0x00, 0x08, 0x3f, 0x48, 0x48 },  // f
    { 0x08, 0x15, 0x15, 0x15, 0x1e },  // g
    // 68h..6Fh
    { 0x7f, 0x10, 0x10, 0x10, 0x0f },  // h
    { 0x00, 0x10, 0x5f, 0x00, 0x00 },  // i
    { 0x01, 0x11, 0x5e, 0x00, 0x00 },  // j
    { 0x00, 0x7f, 0x04, 0x0a, 0x11 },  // k
    { 0x00, 0x40, 0x7f, 0x00, 0x00 },  // l
    { 0x1f, 0x10, 0x1f, 0x10, 0x0f },  // m
    { 0x1f, 0x10, 0x10, 0x10, 0x0f },  // n
    { 0x0e, 0x11, 0x11, 0x11, 0x0e },  // o
    // 70h..77h
    { 0x1f, 0x12, 0x12, 0x12, 0x0c },  // p
    { 0x0c, 0x12, 0x12, 0x12, 0x1f },  // q
    { 0x1f, 0x08, 0x10, 0x10, 0x10 },  // r
    { 0x09, 0x15, 0x15, 0x15, 0x12 },  // s
    { 0x00, 0x3e, 0x11, 0x11, 0x00 },  // t
    { 0x1e, 0x01, 0x01, 0x01, 0x1f },  // u
    { 0x18, 0x06, 0x01, 0x06, 0x18 },  // v
    { 0x1e, 0x01, 0x0e, 0x01, 0x1e },  // w
    // 78h..7Fh
    { 0x11, 0x0a, 0x04, 0x0a, 0x11 },  // x
    { 0x18, 0x05, 0x05, 0x05, 0x1e },  // y
    { 0x11, 0x13, 0x15, 0x19, 0x11 },  // z
    { 0x00, 0x00, 0x08, 0x7f, 0x41 },  // {
    { 0x00, 0x00, 0x7f, 0x00, 0x00 },  // |
    { 0x41, 0x7f, 0x08, 0x00, 0x00 },  // }
    { 0x08, 0x10, 0x18, 0x08, 0x10 },  // ~ 
    { 0x44, 0x44, 0x77, 0x44, 0x77 }   // unimplemented DEL
};

TextLCD_ST7565SPI::TextLCD_ST7565SPI(PinName mosi, PinName sck, PinName cs,
                                     PinName rs, PinName rst,
                                     uint8_t columns, uint8_t rows)
:
    _rs(rs),
    _rst(rst),
    _spi(mosi, NC, sck),
    _cs(cs)
{
    // Allocate line buffer
    _columns = columns;
    _rows = rows;
    _lineBuffer = new uint8_t*[_rows];
    for (uint8_t i = 0; i < _rows; i++) {
        _lineBuffer[i] = new uint8_t[_columns];
    }
    
    // Initialize SPI
    _spi.format(8, 0);
    
    // Initialize pins
    _rs = 0;
    _rst = 1;
    _cs = 1;
    
    reset();
}

TextLCD_ST7565SPI::~TextLCD_ST7565SPI() {
    for (uint8_t i = 0; i < _rows; i++) {
        delete[] _lineBuffer[i];
    }
    delete[] _lineBuffer;
}

void TextLCD_ST7565SPI::reset() {
    wait_ms(10);
    _rst = 0;
    wait_ms(10);
    _rst = 1;
}

void TextLCD_ST7565SPI::clear() {
    for (uint8_t j = 7; j <= 7; j--) {
        setPage(j);
        setColumn(0);
        for (uint8_t i = 0; i < 132; i++) {
            data(0x00);
        }
    }
}

void TextLCD_ST7565SPI::init(uint8_t v0, uint8_t contrast, Bias bias) {
    command(INTERNAL_RESET);
    wait_ms(5);
    
    command(DISPLAY_ON);
    command(PCTRL_BOOSTER_ON | PCTRL_REGULATOR_ON | PCTRL_VFOLLOWER_ON);
    command(V0_INTERNAL_R_0 + (v0 & 0x07));
    command(ELECTRONIC_VOL_MODE);
    if (contrast == 0) {
        contrast = 1;
    }
    command(ELECTRONIC_VOL_1 - 1 + (contrast & 0x3f));
    switch (bias) {
    case Bias1_7:
        command(BIAS_1_7);
        break;
    case Bias1_9:
        command(BIAS_1_9);
    }
    command(COMMON_ASCENDING);
    command(SEGMENT_ASCENDING);
    command(ENTIRE_DISPLAY_OFF);
    command(INVERT_DISPLAY_OFF);
    command(COMMON_OFFSET);
    cls();
}

void TextLCD_ST7565SPI::cls() {
    clear();
    for (uint8_t j = 0; j < _rows; j++) {
        memset(_lineBuffer[j], ' ', _columns);
    }
    _column = 0;
    _row = 0;
}

void TextLCD_ST7565SPI::locate(uint8_t column, uint8_t row) {
    if (column < _columns && row < _rows) {
        setPage(_rows - row - 1);
        setColumn(6 * column);
        _column = column;
        _row = row;
    }
}

int TextLCD_ST7565SPI::_putc(int c) {
    switch (c) {
    case '\r':  // Carriage return
        _column = 0;
        locate(_column, _row);
        break;
    case '\n':  // Line feed
        if (_row == _rows - 1) {
            shiftUp();
        } else {
            _row++;
        }
        break;
    case '\f':  // Form feed
        // Clear screen
        cls();
        break;
    default:
        // Break line if the cursor reaches end
        if (_column == _columns) {
            if (_row == _rows - 1) {
                shiftUp();
            } else {
                _row++;
            }
            _column = 0;
        }
        locate(_column, _row);
        for (uint8_t k = 0; k < 5; k++) {
            data(FONT_5X7[c][k]);
        }
        data(0x00);
        _lineBuffer[_row][_column] = c;
        _column++;
        break;
    }
    return 0;
}

int TextLCD_ST7565SPI::_getc() {
    return 0;
}

void TextLCD_ST7565SPI::shiftUp() {
    // Move line buffer content
    for (uint8_t j = 0; j < _rows - 1; j++) {
        memcpy(_lineBuffer[j], _lineBuffer[j + 1], _columns);
    }
    // Clear last line
    memset(_lineBuffer[_rows - 1], ' ', _columns);
    
    // Redraw
    for (uint8_t j = 0; j < _rows; j++) {
        locate(0, j);
        for (uint8_t i = 0; i < _columns; i++) {
            for (uint8_t k = 0; k < 5; k++) {
                data(FONT_5X7[_lineBuffer[j][i]][k]);
            }
            data(0x00);
        }
    }
}

void TextLCD_ST7565SPI::setPage(uint8_t page) {
    if (page < 16) {
        command(0xb0 | page);
    }
}

void TextLCD_ST7565SPI::setColumn(uint8_t column) {
    command(0x10 | (column >> 4));
    command(column & 0x0f);
}

void TextLCD_ST7565SPI::command(uint8_t c) {
    _rs = 0;
    _cs = 0;
    _spi.write(c);
    _cs = 1;
}

void TextLCD_ST7565SPI::data(uint8_t d) {
    _rs = 1;
    _cs = 0;
    _spi.write(d);
    _cs = 1;
}