Simple library for UC1701 based GLCD's

Dependents:   Opensmart_LCD_UC1701

With lots of fonts! Will include more in the future. A couple bitmaps have also been added.

UC1701.cpp

Committer:
Anaesthetix
Date:
2016-12-19
Revision:
5:7494bdca926b
Parent:
4:8da4c691643a

File content as of revision 5:7494bdca926b:

/**
 * This is a simple library for UC1701 controlled graphic LCD's. 
 * Written for a cheap OPEN-SMART 1.8" 128x64 display
 * See      http://www.dx.com/p/open-smart-1-8-128-64-lcd-display-breakout-module-w-blue-backlit-444694
 *
 * Written by:  Erik van de Coevering
 * With thanks to Tim Barr from whom I've reused some code
 * Use this code in whatever way you like, as long as it stays free of charge!
 */

#include "UC1701.h"

UC1701::UC1701(SPI &lcd, DigitalOut &lcd_cs, DigitalOut &lcd_cd)
{
    _lcd = &lcd;
    _lcd_cs = &lcd_cs;
    _lcd_cd = &lcd_cd;
}

void UC1701::init()
{
    _lcd_cs->write(1);
    _lcd->frequency(24000000);      // Abusing SPI to save some time.. 
    _lcd->format(8,3);
    _lcd_cs->write(0);              // enable SPI
    _lcd_cd->write(0);                  // COMMAND mode

    wait_ms(50);

    _lcd->write(0xE2);              // Reset
    _lcd->write(0x40);              // Set display start line to 0
    _lcd->write(0xA1);              // Set SEG direction
    _lcd->write(0xC0);              // Set COM direction
    _lcd->write(0xA2);              // Set bias = 1/9
    _lcd->write(0x2C);              // Boost ON
    _lcd->write(0x2E);              // Voltage regulator on
    _lcd->write(0x2F);              // Voltage follower on
    _lcd->write(0xF8);              // Set booster ratio
    _lcd->write(0x00);              
    _lcd->write(0x23);              // Set resistor ratio
    _lcd->write(0x81);              // Set contrast to
    _lcd->write(0x28);              // 40
    _lcd->write(0xEE);              // Set cursor update -> after write, column cursor will be updated (rows will not!)
    _lcd->write(0xAC);              // Disable static indicator
    _lcd->write(0x00);
    _lcd->write(0xA6);              // Disable inverse
    _lcd->write(0xAF);              // Display enable
    //_lcd->write(0xA5);            // display all points
    _lcd->write(0xA4);              // clear
    _lcd_cs->write(1);              // disable SPI
    _lcd_cd->write(1);              // DATA mode

}

void UC1701::setContrast(char contrast)
{
    _lcd_cs->write(0);              // enable SPI
    _lcd_cd->write(0);              // command mode
    _lcd->write(0x81);              // command to set contrast
    _lcd->write(contrast);          // set contrast
    _lcd_cs->write(1);
    _lcd_cd->write(1);
    }

void UC1701::setCursor(char column, char line)
{
    int i, j;
    column = column+4;

    i=(column&0xF0)>>4;
    j=column&0x0F;
    _lcd_cd->write(0);
    _lcd->write(0xb0+line);
    _lcd->write(0x10+i);
    _lcd->write(j);
    _lcd_cd->write(1);
}

void UC1701::clear()
{
    _lcd_cs->write(0);
    for(unsigned short j = 0; j < 8; j++) {
        UC1701::setCursor(0, j);
        for(unsigned short i = 0; i < 128 ; i++) {
            _lcd->write(0x00);
        }
    }

    UC1701::setCursor(0, 0);
    _lcd_cs->write(1);
}

// fill() only used to optimize the library. Using command 0xA5 is faster, if needed.
void UC1701::fill()
{
    _lcd_cs->write(0);
    _lcd_cd->write(1);

    for(unsigned short j = 0; j < 8; j++) {
        UC1701::setCursor(0, j);
        for(unsigned short i = 0; i < 128 ; i++) {
            _lcd->write(0xFF);
        }
    }

    UC1701::setCursor(0, 0);

    _lcd_cs->write(1);
}

void UC1701::writeText2d(char column, char page, const char font_address[96][8], const char *text, int size)
{
    _lcd_cs->write(0);
    UC1701::setCursor(column, page);
    for(int i=0; i<size; i++) {
        for(int a=0; a<8; a++) {
            _lcd->write((font_address[(text[i]-32)][a]));
        }
    }
    _lcd_cs->write(1);
}

void UC1701::writeText(char column, char page, const char *font_address, const char *text, const uint8_t size)
{
    // Position of character data in memory array
    uint16_t pos_array;
    // temporary column, page address, and column_cnt are used
    // to stay inside display area
    uint8_t i,y, column_cnt = 0;
    uint8_t count = 0;

    // font information, needed for calculation
    uint8_t start_code, last_code, width, page_height, bytes_p_char;

    uint8_t *txtbuffer;

    start_code   = font_address[2];  // get first defined character
    last_code    = font_address[3];  // get last defined character
    width        = font_address[4];  // width in pixel of one char
    page_height  = font_address[6];  // page count per char
    bytes_p_char = font_address[7];  // bytes per char

    _lcd_cs->write(0);  // Enable SPI
    _lcd_cd->write(1);  // Data mode

    if(page_height + page > LCDPAGES) //stay inside display area
        page_height = LCDPAGES - page;

    // The string is displayed character after character. If the font has more then one page,
    // the top page is printed first, then the next page and so on
    for(y = 0; y < page_height; y++) {
        txtbuffer = &_lcdbuffer[page*LCDWIDTH + column];
        column_cnt = 0;                 // clear column_cnt start point
        i = 0;
        while(( i < size) && ((column_cnt + column) < LCDWIDTH)) {
            if(text[i] < start_code || (uint8_t)text[i] > last_code) //make sure data is valid
                i++;
            else {
                // calculate position of ASCII character in font array
                // bytes for header + (ASCII - startcode) * bytes per char)
                pos_array = 8 + (uint8_t)(text[i++] - start_code) * bytes_p_char;

                // get the dot pattern for the part of the char to print
                pos_array += y*width;

                // stay inside display area
                if((column_cnt + width + column) > LCDWIDTH)
                    column_cnt = LCDWIDTH-width;

                // copy character data to buffer
                memcpy (txtbuffer+column_cnt,font_address+pos_array,width);
            }

            column_cnt += width;
        }
        UC1701::setCursor(column,page);  // set start position x and y

        do {
            _lcd->write(txtbuffer[count]);
            count++;
        } while ((count <= column_cnt));
    }

    _lcd_cs->write(1);  // Disable SPI

}

void UC1701::drawBitmap(const char *data)
{
    int cnt = 0;
    _lcd_cs->write(0);
    _lcd_cd->write(1);
    UC1701::setCursor(0,0);
    for(int row=0; row<8; row++) {
        UC1701::setCursor(0, row);
        for(int column=0; column<128; column++) {
            _lcd->write(data[cnt]);
            cnt++;
        }
    }
}

void UC1701::drawLineHor(char posx, char posy, char height, char width)
{
    char page, offset, offset2;
    char buffer[2] = {0xFF, 0xFF};

    _lcd_cs->write(0);
    _lcd_cd->write(1);

    if(width+posx > LCDWIDTH) width = (LCDWIDTH-posx); // keep inside display area

    page = posy/8;
    offset = posy - (page*8);
    buffer[0] = buffer[0] >> (8-height);
    buffer[0] = buffer[0] << offset;

    if((offset + height) > 8) {
        offset2 = ((offset+height)-8);
        buffer[1] = buffer[1] - (0xFF << (offset2));
    }

    UC1701::setCursor(posx, page);

    for(int i=0; i<width; i++) _lcd->write(buffer[0]);

    if(buffer[1] != 0xFF && (page+1) < 8) {         // only write if line takes up > 1 page & keep inside display area
        UC1701::setCursor(posx, (page+1));
        for(int i=0; i<width; i++) _lcd->write(buffer[1]);
    }
    _lcd_cs->write(1);
}

void UC1701::drawLineVert(char posx, char posy, char height, char width)
{
    char page, pagecount, offset, offset2;
    
    _lcd_cs->write(0);
    _lcd_cd->write(1);

    page = posy/8;
    pagecount = height/8;
    offset2 = height - (pagecount*8);

    UC1701::setCursor(posx, page);
    for(int i=0; i<width; i++) _lcd->write((0xFF>>offset));

    for(; pagecount > 1; pagecount--) {
        page++;
        UC1701::setCursor(posx, page);
        for(int i=0; i<width; i++) _lcd->write(0xFF);
    }

    UC1701::setCursor(posx, (page+1));
    for(int i=0; i<width; i++) _lcd->write((0xFF<<offset2));

    _lcd_cs->write(1);
}

void UC1701::clearBuffer(void)
{
    for(int i=0; i<(LCDWIDTH*LCDPAGES); i++) buff[i] = 0;
}

void UC1701::update(void)
{
    int cnt = 0;
    _lcd_cs->write(0);
    _lcd_cd->write(1);
    UC1701::setCursor(0,0);
    for(int row=0; row<8; row++) {
        UC1701::setCursor(0, row);
        for(int column=0; column<128; column++) {
            _lcd->write(buff[cnt]);
            cnt++;
        }
    }
    _lcd_cs->write(1);
}

void UC1701::drawbufferLineHor(char posx, char posy, char height, char width)
{
    char page, offset, offset2;
    int cursor;
    char buffer[2] = {0xFF, 0xFF};

    if(width+posx > LCDWIDTH) width = (LCDWIDTH-posx); // keep inside display area

    page = posy/8;
    offset = posy - (page*8);
    buffer[0] = buffer[0] >> (8-height);
    buffer[0] = buffer[0] << offset;

    if((offset + height) > 8) {
        offset2 = ((offset+height)-8);
        buffer[1] = buffer[1] - (0xFF << (offset2));
    }

    cursor = posx + (page*128);

    for(int i=0; i<width; i++) UC1701::buff[cursor+i] |= buffer[0];

    if(buffer[1] != 0xFF && (page+1) < 8) {         // only write if line takes up > 1 page & keep inside display area
        for(int i=0; i<width; i++) UC1701::buff[cursor+i+128] |= buffer[1];
    }
}

void UC1701::drawbufferLineVert(char posx, char posy, char height, char width)
{
    char page, pagecount, offset, offset2;
    int cursor;

    page = posy/8;
    pagecount = height/8;
    offset2 = height - (pagecount*8);
    cursor = posx + (page*128); // LCDWIDTH

    for(int i=0; i<width; i++) UC1701::buff[cursor+i] |= (0xFF>>offset);

    for(; pagecount > 1; pagecount--) {
        page++;
        cursor += 128;
        for(int i=0; i<width; i++) UC1701::buff[cursor+i] |= 0xFF;
    }

    cursor += 128;
    for(int i=0; i<width; i++) UC1701::buff[cursor+i] |= (0xFF >> offset2);
}