SG12864A

Dependents:   SG12864A_TestProgram

SG12864A.cpp

Committer:
shintamainjp
Date:
2010-08-10
Revision:
5:4d86043f7942
Parent:
4:200d1ea4e76e

File content as of revision 5:4d86043f7942:

/**
 * SG12864A Graphics LCD module driver class (Version 0.0.1)
 *
 * Copyright (C) 2010 Shinichiro Nakamura (CuBeatSystems)
 * http://shinta.main.jp/
 *
 * See also ...
 * http://mbed.org/users/shintamainjp/notebook/sg12864asunlike-display-graphics-lcd-driver/
 */

#include "SG12864A.h"

#define setPixel(x,y) buffer[((COLUMNS * 2)* ((y) / 8)) + (x)] |= (1 << ((y) % 8))
#define unsetPixel(x,y) buffer[((COLUMNS * 2)* ((y) / 8)) + (x)] &= ~(1 << ((y) % 8))
#define swap(a,b) {int c=a;a=b;b=c;}

const uint8_t SG12864A::font5x7_data[] = {
    0x00, 0x00, 0x00, 0x00, 0x00, // (white space)
    0x00, 0x00, 0x5F, 0x00, 0x00, // !
    0x00, 0x07, 0x00, 0x07, 0x00, // "
    0x14, 0x7F, 0x14, 0x7F, 0x14, // #
    0x24, 0x2A, 0x7F, 0x2A, 0x12, // $
    0x23, 0x13, 0x08, 0x64, 0x62, // %
    0x36, 0x49, 0x55, 0x22, 0x50, // &
    0x00, 0x05, 0x03, 0x00, 0x00, // '
    0x00, 0x1C, 0x22, 0x41, 0x00, // (
    0x00, 0x41, 0x22, 0x1C, 0x00, // )
    0x08, 0x2A, 0x1C, 0x2A, 0x08, // *
    0x08, 0x08, 0x3E, 0x08, 0x08, // +
    0x00, 0x50, 0x30, 0x00, 0x00, // ,
    0x08, 0x08, 0x08, 0x08, 0x08, // -
    0x00, 0x60, 0x60, 0x00, 0x00, // .
    0x20, 0x10, 0x08, 0x04, 0x02, // /
    0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
    0x00, 0x42, 0x7F, 0x40, 0x00, // 1
    0x42, 0x61, 0x51, 0x49, 0x46, // 2
    0x21, 0x41, 0x45, 0x4B, 0x31, // 3
    0x18, 0x14, 0x12, 0x7F, 0x10, // 4
    0x27, 0x45, 0x45, 0x45, 0x39, // 5
    0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
    0x01, 0x71, 0x09, 0x05, 0x03, // 7
    0x36, 0x49, 0x49, 0x49, 0x36, // 8
    0x06, 0x49, 0x49, 0x29, 0x1E, // 9
    0x00, 0x36, 0x36, 0x00, 0x00, // :
    0x00, 0x56, 0x36, 0x00, 0x00, // ;
    0x00, 0x08, 0x14, 0x22, 0x41, // <
    0x14, 0x14, 0x14, 0x14, 0x14, // =
    0x41, 0x22, 0x14, 0x08, 0x00, // >
    0x02, 0x01, 0x51, 0x09, 0x06, // ?
    0x32, 0x49, 0x79, 0x41, 0x3E, // @
    0x7E, 0x11, 0x11, 0x11, 0x7E, // A
    0x7F, 0x49, 0x49, 0x49, 0x36, // B
    0x3E, 0x41, 0x41, 0x41, 0x22, // C
    0x7F, 0x41, 0x41, 0x22, 0x1C, // D
    0x7F, 0x49, 0x49, 0x49, 0x41, // E
    0x7F, 0x09, 0x09, 0x01, 0x01, // F
    0x3E, 0x41, 0x41, 0x51, 0x32, // G
    0x7F, 0x08, 0x08, 0x08, 0x7F, // H
    0x00, 0x41, 0x7F, 0x41, 0x00, // I
    0x20, 0x40, 0x41, 0x3F, 0x01, // J
    0x7F, 0x08, 0x14, 0x22, 0x41, // K
    0x7F, 0x40, 0x40, 0x40, 0x40, // L
    0x7F, 0x02, 0x04, 0x02, 0x7F, // M
    0x7F, 0x04, 0x08, 0x10, 0x7F, // N
    0x3E, 0x41, 0x41, 0x41, 0x3E, // O
    0x7F, 0x09, 0x09, 0x09, 0x06, // P
    0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
    0x7F, 0x09, 0x19, 0x29, 0x46, // R
    0x46, 0x49, 0x49, 0x49, 0x31, // S
    0x01, 0x01, 0x7F, 0x01, 0x01, // T
    0x3F, 0x40, 0x40, 0x40, 0x3F, // U
    0x1F, 0x20, 0x40, 0x20, 0x1F, // V
    0x7F, 0x20, 0x18, 0x20, 0x7F, // W
    0x63, 0x14, 0x08, 0x14, 0x63, // X
    0x03, 0x04, 0x78, 0x04, 0x03, // Y
    0x61, 0x51, 0x49, 0x45, 0x43, // Z
    0x00, 0x00, 0x7F, 0x41, 0x41, // [
    0x02, 0x04, 0x08, 0x10, 0x20, // /
    0x41, 0x41, 0x7F, 0x00, 0x00, // ]
    0x04, 0x02, 0x01, 0x02, 0x04, // ^
    0x40, 0x40, 0x40, 0x40, 0x40, // _
    0x00, 0x01, 0x02, 0x04, 0x00, // `
    0x20, 0x54, 0x54, 0x54, 0x78, // a
    0x7F, 0x48, 0x44, 0x44, 0x38, // b
    0x38, 0x44, 0x44, 0x44, 0x20, // c
    0x38, 0x44, 0x44, 0x48, 0x7F, // d
    0x38, 0x54, 0x54, 0x54, 0x18, // e
    0x08, 0x7E, 0x09, 0x01, 0x02, // f
    0x08, 0x14, 0x54, 0x54, 0x3C, // g
    0x7F, 0x08, 0x04, 0x04, 0x78, // h
    0x00, 0x44, 0x7D, 0x40, 0x00, // i
    0x20, 0x40, 0x44, 0x3D, 0x00, // j
    0x00, 0x7F, 0x10, 0x28, 0x44, // k
    0x00, 0x41, 0x7F, 0x40, 0x00, // l
    0x7C, 0x04, 0x18, 0x04, 0x78, // m
    0x7C, 0x08, 0x04, 0x04, 0x78, // n
    0x38, 0x44, 0x44, 0x44, 0x38, // o
    0x7C, 0x14, 0x14, 0x14, 0x08, // p
    0x08, 0x14, 0x14, 0x18, 0x7C, // q
    0x7C, 0x08, 0x04, 0x04, 0x08, // r
    0x48, 0x54, 0x54, 0x54, 0x20, // s
    0x04, 0x3F, 0x44, 0x40, 0x20, // t
    0x3C, 0x40, 0x40, 0x20, 0x7C, // u
    0x1C, 0x20, 0x40, 0x20, 0x1C, // v
    0x3C, 0x40, 0x30, 0x40, 0x3C, // w
    0x44, 0x28, 0x10, 0x28, 0x44, // x
    0x0C, 0x50, 0x50, 0x50, 0x3C, // y
    0x44, 0x64, 0x54, 0x4C, 0x44, // z
    0x00, 0x08, 0x36, 0x41, 0x00, // {
    0x00, 0x00, 0x7F, 0x00, 0x00, // |
    0x00, 0x41, 0x36, 0x08, 0x00, // }
    0x08, 0x08, 0x2A, 0x1C, 0x08, // ->
    0x08, 0x1C, 0x2A, 0x08, 0x08  // <-
};

SG12864A::SG12864A(PinName di,
                   PinName rw,
                   PinName en,
                   PinName db0,
                   PinName db1,
                   PinName db2,
                   PinName db3,
                   PinName db4,
                   PinName db5,
                   PinName db6,
                   PinName db7,
                   PinName cs1,
                   PinName cs2,
                   PinName res)
        :
        ioDI(di),
        ioRW(rw),
        ioEN(en),
        ioDB(db0, db1, db2, db3, db4, db5, db6, db7),
        ioCS1(cs1),
        ioCS2(cs2),
        ioRES(res) {
    bufferClear();
    setDirectionToWrite();
}

SG12864A::~SG12864A() {
}

void SG12864A::bufferPush(void) {
    for (uint8_t i = 0; i < PAGES; i++) {
        // CS1
        setPageAddress(SG12864A::CS1, i);
        setColumnAddress(SG12864A::CS1, 0);
        for (uint8_t j = 0; j < COLUMNS; j++) {
            writeData(CS1, buffer[0 + ((COLUMNS * 2) * i) + j]);
        }
        // CS2
        setPageAddress(SG12864A::CS2, i);
        setColumnAddress(SG12864A::CS2, 0);
        for (uint8_t j = 0; j < COLUMNS; j++) {
            writeData(CS2, buffer[COLUMNS + ((COLUMNS * 2) * i) + j]);
        }
    }
}

void SG12864A::bufferPull(void) {
}

void SG12864A::bufferClear(bool reverse) {
    for (int i = 0; i < sizeof(buffer); i++) {
        if (reverse) {
            buffer[i] = 0xFF;
        } else {
            buffer[i] = 0x00;
        }
    }
}

void SG12864A::bufferDrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, bool reverse) {
    /*
     * Bresenham's line algorithm
     */
    bool steep = abs(y2 - y1) > abs(x2 - x1);
    if (steep) {
        swap(x1, y1);
        swap(x2, y2);
    }
    if (x1 > x2) {
        swap(x1, x2);
        swap(y1, y2);
    }
    int deltax = x2 - x1;
    int deltay = abs(y2 - y1);
    int error = deltax / 2;
    int ystep;
    int y = y1;
    if (y1 < y2) {
        ystep = 1;
    } else {
        ystep = -1;
    }
    for (int x = x1; x <= x2; x++) {
        if (steep) {
            if (reverse) {
                unsetPixel(y, x);
            } else {
                setPixel(y, x);
            }
        } else {
            if (reverse) {
                unsetPixel(x, y);
            } else {
                setPixel(x, y);
            }
        }
        error = error - deltay;
        if (error < 0) {
            y = y + ystep;
            error = error + deltax;
        }
    }
}

void SG12864A::bufferDrawBox(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, bool reverse) {
    for (int x = x1; x <= x2; x++) {
        if (reverse) {
            unsetPixel(x, y1);
            unsetPixel(x, y2);
        } else {
            setPixel(x, y1);
            setPixel(x, y2);
        }
    }
    for (int y = y1; y <= y2; y++) {
        if (reverse) {
            unsetPixel(x1, y);
            unsetPixel(x2, y);
        } else {
            setPixel(x1, y);
            setPixel(x2, y);
        }
    }
}

void SG12864A::bufferFillBox(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, bool reverse) {
    for (int x = x1; x <= x2; x++) {
        for (int y = y1; y <= y2; y++) {
            if (reverse) {
                unsetPixel(x, y);
            } else {
                setPixel(x, y);
            }
        }
    }
}

void SG12864A::bufferDrawString(uint8_t x, uint8_t y, char * str, bool reverse) {
    char *p = str;
    int cnt = 0;
    while (*p) {
        bufferDrawChar(x + (FONT_X * cnt), y, *p, reverse);
        p++;
        cnt++;
    }
}

void SG12864A::bufferDrawChar(uint8_t x, uint8_t y, char c, bool reverse) {
    if ((FONT_MIN_CODE <= c) &&(c <= FONT_MAX_CODE)) {
        int aofs = (c - FONT_MIN_CODE) * FONT_X;
        for (int i = 0; i < FONT_X; i++) {
            uint8_t pat = font5x7_data[aofs + i];
            for (int j = 0; j < FONT_Y; j++) {
                if (pat & (1 << j)) {
                    if (reverse) {
                        unsetPixel(x + i, y + j);
                    } else {
                        setPixel(x + i, y + j);
                    }
                } else {
                    if (reverse) {
                        setPixel(x + i, y + j);
                    } else {
                        unsetPixel(x + i, y + j);
                    }
                }
            }
        }
    } else {
        for (int i = 0; i < FONT_X; i++) {
            uint8_t pat = (i % 2) ? 0x55 : 0xAA;
            for (int j = 0; j < FONT_Y; j++) {
                if (pat & (1 << j)) {
                    if (reverse) {
                        unsetPixel(x + i, y + j);
                    } else {
                        setPixel(x + i, y + j);
                    }
                } else {
                    if (reverse) {
                        setPixel(x + i, y + j);
                    } else {
                        unsetPixel(x + i, y + j);
                    }
                }
            }
        }
    }
}

void SG12864A::bufferDrawCheckbox(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, bool state, bool reverse) {
    bufferDrawBox(x1, y1, x2, y2, reverse);
    if (state) {
        bufferDrawLine(x1, y1, x2, y2, reverse);
        bufferDrawLine(x1, y2, x2, y1, reverse);
    }
}

void SG12864A::bufferDrawProgressbar(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, int min, int max, int value, bool reverse) {
    bufferDrawBox(x1, y1, x2, y2, reverse);
    if ((value < min) || (max < value)) {
        return;
    }
    int tmp_max = max - min;
    int tmp_val = value - min;
    int pix = ((x2 - x1) * tmp_val) / tmp_max;
    bufferFillBox(x1 + 1, y1 + 1, x1 + pix - 1, y2 - 1, reverse);
}

/**
 * High Level Interface.
 *
 * Reset display module.
 */
void SG12864A::reset(void) {
    reset(true);
    wait_ms(200);
    reset(false);
    wait_ms(200);

    setDisplayOnOff(SG12864A::CS1, true);
    setDisplayOnOff(SG12864A::CS2, true);
    setDisplayStartLine(SG12864A::CS1, 0);
    setDisplayStartLine(SG12864A::CS2, 0);
    setPageAddress(SG12864A::CS1, 0);
    setPageAddress(SG12864A::CS2, 0);
    setColumnAddress(SG12864A::CS1, 0);
    setColumnAddress(SG12864A::CS2, 0);
}

/**
 * High Level Interface.
 *
 * Clear display module.
 */
void SG12864A::clear(void) {
    for (uint8_t page = 0; page < PAGES; page++) {
        for (uint8_t column = 0; column < COLUMNS; column++) {
            // CS1
            setPageAddress(SG12864A::CS1, page);
            setColumnAddress(SG12864A::CS1, column);
            writeData(CS1, 0x00);
            // CS2
            setPageAddress(SG12864A::CS2, page);
            setColumnAddress(SG12864A::CS2, column);
            writeData(CS2, 0x00);
        }
    }
    // CS1
    setPageAddress(SG12864A::CS1, 0);
    setColumnAddress(SG12864A::CS1, 0);
    writeData(CS1, 0x00);
    // CS2
    setPageAddress(SG12864A::CS2, 0);
    setColumnAddress(SG12864A::CS2, 0);
    writeData(CS2, 0x00);
}

/**
 * Middle Level Interface.
 *
 * Set display on/off.
 *
 * @param t Target (CS1, CS2).
 * @param on ON/OFF (true, false).
 */
void SG12864A::setDisplayOnOff(Target t, bool on) {
    setDirectionToWrite();
    uint8_t c = 0x3e | (on ? 0x01 : 0x00);
    write(t, SG12864A::Instruction, c);
    wait_us(1);
}

/**
 * Middle Level Interface.
 *
 * Set display start line.
 *
 * @param t Target (CS1, CS2).
 * @param addr Display start line (0-63).
 */
void SG12864A::setDisplayStartLine(Target t, uint8_t addr) {
    setDirectionToWrite();
    uint8_t c = 0xc0 | (addr & 0x3f);
    write(t, SG12864A::Instruction, c);
    wait_us(1);
}

/**
 * Middle Level Interface.
 *
 * Set page address.
 *
 * @param t Target (CS1, CS2).
 * @param addr Page address(0-7).
 */
void SG12864A::setPageAddress(Target t, uint8_t addr) {
    setDirectionToWrite();
    uint8_t c = 0xb8 | (addr & 0x07);
    write(t, SG12864A::Instruction, c);
    wait_us(1);
}

/**
 * Middle Level Interface.
 *
 * Set column address.
 *
 * @param t Target. (CS1, CS2)
 * @param addr Column address (0-63).
 */
void SG12864A::setColumnAddress(Target t, uint8_t addr) {
    setDirectionToWrite();
    uint8_t c = 0x40 | (addr & 0x3f);
    write(t, SG12864A::Instruction, c);
    wait_us(1);
}

/**
 * Middle Level Interface.
 */
void SG12864A::readStatus(Target t, uint8_t *c) {
    setDirectionToRead();
    read(t, SG12864A::Instruction, c);
    wait_us(1);
}

/**
 * Middle Level Interface.
 */
void SG12864A::writeData(Target t, uint8_t c) {
    setDirectionToWrite();
    write(t, SG12864A::Data, c);
    wait_us(1);
}

/**
 * Middle Level Interface.
 */
void SG12864A::readData(Target t, uint8_t *c) {
    setDirectionToRead();
    read(t, SG12864A::Data, c);
    wait_us(1);
}

/**
 * Low Level Interface.
 */
void SG12864A::setDirectionToRead() {
    ioDB.input();
    ioRW = 1;
}

/**
 * Low Level Interface.
 */
void SG12864A::setDirectionToWrite() {
    ioDB.output();
    ioRW = 0;
}

/**
 * Low Level Interface.
 */
void SG12864A::write(Target t, Mode m, uint8_t c) {
    switch (t) {
        case CS1:
            ioCS1 = 1;
            ioCS2 = 0;
            break;
        case CS2:
            ioCS1 = 0;
            ioCS2 = 1;
            break;
    }
    switch (m) {
        case Data:
            ioDI = 1;
            break;
        case Instruction:
            ioDI = 0;
            break;
    }
    ioDB = c;
    wait_us(1);
    ioEN = 1;
    wait_us(1);
    ioEN = 0;
    wait_us(5);
}

/**
 * Low Level Interface.
 */
void SG12864A::read(Target t, Mode m, uint8_t *c) {
    // TODO
}

/**
 * Low Level Interface.
 */
void SG12864A::reset(bool b) {
    if (b) {
        ioRES = 0;
    } else {
        ioRES = 1;
    }
}