Aitendo OLED device driver library.

Dependents:   AitendoOLED_TestProgram

AitendoOLED.cpp

Committer:
shintamainjp
Date:
2010-12-19
Revision:
2:74c60a959299
Parent:
1:4b819d5ea905

File content as of revision 2:74c60a959299:

/**
 * =============================================================================
 * Aitendo OLED device driver library. (Version 0.0.2)
 *
 * [The product]
 * OLED-2P-095BWNN-SPI : http://www.aitendo.co.jp/product/2099
 * ALO-095BWNN-J9      : http://www.aitendo.co.jp/product/1449
 *
 * [References]
 * http://serdisplib.sourceforge.net/ser/doc/Treiber_IC-SSD1332_OLED_96x64_COLOR.pdf
 * =============================================================================
 * Copyright (c) 2010 Shinichiro Nakamura (CuBeatSystems)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 * =============================================================================
 */
#include "AitendoOLED.h"

#define RES_ENA()       io_res = 0
#define RES_DIS()       io_res = 1
#define CS_ENA()        io_cs = 0
#define CS_DIS()        io_cs = 1
#define DC_CMD()        io_dc = 0
#define DC_DAT()        io_dc = 1
#define SPI_WRITE(a)    io_spi.write((a))
#define SPI_READ()      io_spi.write(0x00)
#define WAIT_US(a)      wait_us((a))
#define swap(a,b) {int c=a;a=b;b=c;}

/**
 * Create.
 *
 * @param pin_mosi MOSI.
 * @param pin miso MISO.
 * @param pin_sclk SCLK.
 * @param pin_res RES.
 * @param pin_cs CS.
 * @param pin_dc DC.
 */
AitendoOLED::AitendoOLED(
    PinName pin_mosi,
    PinName pin_miso,
    PinName pin_sclk,
    PinName pin_res,
    PinName pin_cs,
    PinName pin_dc)
        :
        io_spi(pin_mosi, pin_miso, pin_sclk),
        io_res(pin_res),
        io_cs(pin_cs),
        io_dc(pin_dc) {
    io_spi.format(8, 0);
#if 0
    io_spi.frequency(4000000);
#else
    io_spi.frequency(40000000);
#endif
    reset();
}

/**
 * Dispose.
 */
AitendoOLED::~AitendoOLED() {
}

/**
 * Draw pixel.
 *
 * @param x X.
 * @param y Y.
 * @param c Color.
 */
void AitendoOLED::drawPixel(int x, int y, Color c) {
    setColumnAddress(x, x);
    setRowAddress(y, y);
    c.b = c.b >> 3;
    c.g = c.g >> 2;
    c.r = c.r >> 3;
    writeData((((c.b << 3) & 0xF8) | ((c.g >> 3) & 0x07)));
    writeData((((c.g << 5) & 0xE0) | ((c.r >> 0) & 0x1F)));
}

/**
 * Draw line.
 *
 * @param x1 X1.
 * @param y1 Y1.
 * @param x2 X2.
 * @param y2 Y2.
 * @param c Color.
 */
void AitendoOLED::drawLine(int x1, int y1, int x2, int y2, Color c) {
#if 0
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0x21);
    SPI_WRITE(x1);
    SPI_WRITE(y1);
    SPI_WRITE(x2);
    SPI_WRITE(y2);
    SPI_WRITE(c.b >> 3);
    SPI_WRITE(c.g >> 2);
    SPI_WRITE(c.r >> 3);
    CS_DIS();
    WAIT_US(100);
#else
    /*
     * 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) {
            drawPixel(y, x, c);
        } else {
            drawPixel(x, y, c);
        }
        error = error - deltay;
        if (error < 0) {
            y = y + ystep;
            error = error + deltax;
        }
    }
#endif
}

/**
 * Fill box.
 *
 * @param x1 X1.
 * @param y1 Y1.
 * @param x2 X2.
 * @param y2 Y2.
 * @param c1 Color1.
 * @param c2 Color2.
 */
void AitendoOLED::fillBox(int x1, int y1, int x2, int y2, Color c1, Color c2) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0x22);
    SPI_WRITE(x1);
    SPI_WRITE(y1);
    SPI_WRITE(x2);
    SPI_WRITE(y2);
    SPI_WRITE(c1.b >> 3);
    SPI_WRITE(c1.g >> 2);
    SPI_WRITE(c1.r >> 3);
    SPI_WRITE(c2.b >> 3);
    SPI_WRITE(c2.g >> 2);
    SPI_WRITE(c2.r >> 3);
    CS_DIS();
    WAIT_US(400);
}

/**
 * Copy.
 *
 * @param x1 X1.
 * @param y1 Y1.
 * @param x2 X2.
 * @param y2 Y2.
 * @param nx X of the destination.
 * @param ny Y of the destination.
 */
void AitendoOLED::copy(int x1, int y1, int x2, int y2, int nx, int ny) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0x23);
    SPI_WRITE(x1);
    SPI_WRITE(y1);
    SPI_WRITE(x2);
    SPI_WRITE(y2);
    SPI_WRITE(nx);
    SPI_WRITE(ny);
    CS_DIS();
    WAIT_US(400);
}

/**
 * Darker.
 *
 * @param x1 X1.
 * @param y1 Y1.
 * @param x2 X2.
 * @param y2 Y2.
 */
void AitendoOLED::darker(int x1, int y1, int x2, int y2) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0x24);
    SPI_WRITE(x1);
    SPI_WRITE(y1);
    SPI_WRITE(x2);
    SPI_WRITE(y2);
    CS_DIS();
    WAIT_US(400);
}

/**
 * Clear.
 *
 * @param x1 X1.
 * @param y1 Y1.
 * @param x2 X2.
 * @param y2 Y2.
 */
void AitendoOLED::clear(int x1, int y1, int x2, int y2) {
#if 1
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0x25);
    SPI_WRITE(x1);
    SPI_WRITE(y1);
    SPI_WRITE(x2);
    SPI_WRITE(y2);
    CS_DIS();
    WAIT_US(400);
#else
    AitendoOLED::Color c;
    c.r = 0x00;
    c.g = 0x00;
    c.b = 0x00;
    for (int x = x1; x <= x2; x++) {
        for (int y = y1; y <= y2; y++) {
            drawPixel(x, y, c);
        }
    }
#endif
}

/**
 * Reset.
 */
void AitendoOLED::reset() {

    RES_ENA();
    WAIT_US(200 * 1000);
    RES_DIS();
    WAIT_US(200 * 1000);

    setDisplayOnOff(false);
    setRowAddress(0, 63);
    setColumnAddress(0, 95);
    setRemapAndDataFormat(0x70);
    setDisplayStartLine(0);
    setDisplayOffset(0);
    setDisplayMode(AitendoOLED::NormalDisplay);
    setMultiplexRatio(0x3f);
    setMasterCurrentControl(0x8f);
    setPowerSavingMode(0x00);
    setPhasePeriod(0x74);
    setDisplayClockDivideRatio(0xD0);
    setSecondPreChargeSpeedForColorA(0x80);
    setSecondPreChargeSpeedForColorB(0x80);
    setSecondPreChargeSpeedForColorC(0x80);
    setPreChargeLevelForColorA(0x3F);
    setPreChargeLevelForColorB(0x3F);
    setPreChargeLevelForColorC(0x3F);
    setVCOMH(0x3E);
    setMasterCurrentControl(0x0F);
    // A:Blue, B:Green, C:Red
    setContrastForColorA(0x80);
    setContrastForColorB(0x80);
    setContrastForColorC(0x80);
    setMode(true, false);
    setDisplayOnOff(true);
}

/**
 * Write data.
 *
 * @param data Data.
 */
void AitendoOLED::writeData(uint8_t data) {
    DC_DAT();
    CS_ENA();
    SPI_WRITE(data);
    CS_DIS();
}

/**
 * Set mode.
 *
 * @param fillrect Fill the rectangle.
 * @param revcopy Reverse copy.
 */
void AitendoOLED::setMode(bool fillrect, bool revcopy) {
    uint8_t val = 0x00;
    if (fillrect) {
        val |= 1 << 0;
    }
    if (revcopy) {
        val |= 1 << 4;
    }
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0x26);
    SPI_WRITE(val);
    CS_DIS();
}

/**
 * Set column address.
 *
 * @param start Start address. (0-95)
 * @param end End address. (0-95)
 */
void AitendoOLED::setColumnAddress(int start, int end) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0x15);
    SPI_WRITE(start);
    SPI_WRITE(end);
    CS_DIS();
}

/**
 * Set row address.
 *
 * @param start Start address. (0-63)
 * @param end End address. (0-63)
 */
void AitendoOLED::setRowAddress(int start, int end) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0x75);
    SPI_WRITE(start);
    SPI_WRITE(end);
    CS_DIS();
}

/**
 * Set contrast for Color A.
 *
 * @param contrast Contrast. (Default:0x80)
 */
void AitendoOLED::setContrastForColorA(int contrast) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0x81);
    SPI_WRITE(contrast);
    CS_DIS();
}

/**
 * Set contrast for Color B.
 *
 * @param contrast Contrast. (Default:0x80)
 */
void AitendoOLED::setContrastForColorB(int contrast) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0x82);
    SPI_WRITE(contrast);
    CS_DIS();
}

/**
 * Set contrast for Color C.
 *
 * @param contrast Contrast. (Default:0x80)
 */
void AitendoOLED::setContrastForColorC(int contrast) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0x83);
    SPI_WRITE(contrast);
    CS_DIS();
}

/**
 * Set master current control value.
 *
 * @param current Current value. (0x00-0x0F)
 */
void AitendoOLED::setMasterCurrentControl(int current) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0x87);
    SPI_WRITE(current);
    CS_DIS();
}

/**
 * Set remapping mode and the data format.
 *
 * @param mode See the document.
 */
void AitendoOLED::setRemapAndDataFormat(int mode) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0xA0);
    SPI_WRITE(mode);
    CS_DIS();
}

/**
 * Set display start line.
 *
 * @param line Start line number. (0-63)
 */
void AitendoOLED::setDisplayStartLine(int line) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0xA1);
    SPI_WRITE(line);
    CS_DIS();
}

/**
 * Set display offset line.
 *
 * @param offset Offset line number. (0-63)
 */
void AitendoOLED::setDisplayOffset(int offset) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0xA2);
    SPI_WRITE(offset);
    CS_DIS();
}

/**
 * Set display mode.
 *
 * @param mode Display mode.
 */
void AitendoOLED::setDisplayMode(DisplayMode mode) {
    int val = 0;
    switch (mode) {
        case NormalDisplay:
            val = 0xA4;
            break;
        case EntireDisplayOn:
            val = 0xA5;
            break;
        case EntireDisplayOff:
            val = 0xA6;
            break;
        case InverseDisplay:
            val = 0xA7;
            break;
        default:
            break;
    }
    if (val != 0) {
        DC_CMD();
        CS_ENA();
        SPI_WRITE(val);
        CS_DIS();
    }
}

/**
 * Set multiplex ratio.
 *
 * @param ratio Ratio.
 */
void AitendoOLED::setMultiplexRatio(int ratio) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0xA8);
    SPI_WRITE(ratio);
    CS_DIS();
}

/**
 * Set display on/off.
 *
 * @param on On.
 */
void AitendoOLED::setDisplayOnOff(bool on) {
    if (on) {
        DC_CMD();
        CS_ENA();
        SPI_WRITE(0xAF);
        CS_DIS();
    } else {
        DC_CMD();
        CS_ENA();
        SPI_WRITE(0xAE);
        CS_DIS();
    }
}

/**
 * Set gray scale table.
 *
 * @param p A pointer to the look up table.
 */
void AitendoOLED::setGrayScaleTable(gray_scale_table_t *p) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0xB8);
    for (int i = 0; i < 32; i++) {
        SPI_WRITE(p->data[i]);
    }
    CS_DIS();
}

/**
 * NOP.
 */
void AitendoOLED::nop() {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0xE3);
    CS_DIS();
}

/**
 * Set power saving mode.
 *
 * @param value Value. (0x00:None, 0x12:power saving)
 */
void AitendoOLED::setPowerSavingMode(int value) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0xB0);
    SPI_WRITE(value);
    CS_DIS();
}

/**
 * Set phase period.
 *
 * @param value Value. (Default:0x74)
 */
void AitendoOLED::setPhasePeriod(int value) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0xB1);
    SPI_WRITE(value);
    CS_DIS();
}

/**
 * Set display clock divide ratio.
 *
 * @param value Value. (Default:0x00)
 */
void AitendoOLED::setDisplayClockDivideRatio(int value) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0xB3);
    SPI_WRITE(value);
    CS_DIS();
}

/**
 * Set second pre-charge speed for color A.
 *
 * @param value Value.
 */
void AitendoOLED::setSecondPreChargeSpeedForColorA(int value) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0x8A);
    SPI_WRITE(value);
    CS_DIS();
}

/**
 * Set second pre-charge speed for color B.
 *
 * @param value Value.
 */
void AitendoOLED::setSecondPreChargeSpeedForColorB(int value) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0x8B);
    SPI_WRITE(value);
    CS_DIS();
}

/**
 * Set second pre-charge speed for color C.
 *
 * @param value Value.
 */
void AitendoOLED::setSecondPreChargeSpeedForColorC(int value) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0x8C);
    SPI_WRITE(value);
    CS_DIS();
}

/**
 * Set pre charge level for color A.
 *
 * @param value The value.
 */
void AitendoOLED::setPreChargeLevelForColorA(int value) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0xBB);
    SPI_WRITE(value);
    CS_DIS();
}

/**
 * Set pre charge level for color B.
 *
 * @param value The value.
 */
void AitendoOLED::setPreChargeLevelForColorB(int value) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0xBC);
    SPI_WRITE(value);
    CS_DIS();
}

/**
 * Set pre charge level for color C.
 *
 * @param value The value.
 */
void AitendoOLED::setPreChargeLevelForColorC(int value) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0xBD);
    SPI_WRITE(value);
    CS_DIS();
}

/**
 * Set VCOMH.
 *
 * @param value VCOMH value. (0x00:0.43 * Vref, 0x3F:0x83 * Vref)
 */
void AitendoOLED::setVCOMH(int value) {
    DC_CMD();
    CS_ENA();
    SPI_WRITE(0xBE);
    SPI_WRITE(value);
    CS_DIS();
}

/**
 * Read the status register.
 *
 * @return the value. (0x80:CommandLock)
 */
uint8_t AitendoOLED::readStatusRegister() {
    uint8_t s;
    DC_CMD();
    CS_ENA();
    s = SPI_READ();
    CS_DIS();
    return s;
}