Graham Bloice / EAQVGAOLED
Revision:
0:ae3d20db48fc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EAQVGAOLED.cpp	Wed Feb 09 21:23:49 2011 +0000
@@ -0,0 +1,387 @@
+/* mbed library for driving the EA QVGA 2.8" OLED
+ * Copyright (c) Graham Bloice 2011
+ *
+ * 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 "EAQVGAOLED.h"
+#include "mbed.h"
+ 
+// Constants
+const unsigned int EAQVGAOLED_ID = 0x63D6; // The display controller ID
+
+// Local functions
+inline void orderCoords
+(
+    const uint16_t x0,
+    const uint16_t y0,
+    const uint16_t x1,
+    const uint16_t y1,
+    uint16_t &startX,
+    uint16_t &startY,
+    uint16_t &endX,
+    uint16_t &endY
+)
+{
+    // Order the drawing co-ords
+    if (x1 > x0) {
+        startX = x0;
+        endX = x1;
+    }
+    else {
+        startX = x1;
+        endX = x0;
+    }
+    if (y1 > y0) {
+        startY = y0;
+        endY = y1;
+    }
+    else {
+        startY = y1;
+        endY = y0;
+    }
+}
+
+EAQVGAOLED::EAQVGAOLED
+(
+    PinName mosi,
+    PinName miso,
+    PinName sclk,
+    PinName cs,
+    PinName reset,
+    PinName bl
+) : _spi(mosi, miso, sclk), _cs(cs), _reset(reset), _bl(bl)
+{
+    // Initialise the hardware
+    initHardware();
+    
+    // And reset the display
+    resetDisplay();
+}
+
+void EAQVGAOLED::pixel
+(
+    int x,
+    int y,
+    int colour
+)
+{
+    // Set the x and y positions via their registers, then the colour
+    writeDataRegister(0x20, x);
+    writeDataRegister(0x21, y);
+    writeDataRegister(0x22, colour);
+}
+
+void EAQVGAOLED::hLine
+(
+    const uint16_t x0,
+    const uint16_t y0,
+    const uint16_t x1,
+    const uint16_t colour
+)
+{
+    // Make sure we are drawing in the correct direction
+    uint16_t startPos;
+    uint16_t length; 
+    if (x1 > x0) {
+        startPos = x0;
+        length = x1 - x0;
+    }
+    else {
+        startPos = x1;
+        length = x0 - x1;
+    }
+    
+    // Now draw the line, the display is set to auto increment in x
+    movePen(startPos, y0);
+    for (uint16_t i = 0; i < length; i++) {
+        writeData(colour);
+    }
+}
+        
+void EAQVGAOLED::vLine
+(
+    uint16_t x0,
+    uint16_t y0,
+    uint16_t y1,
+    uint16_t colour
+)
+{
+    // Make sure we are drawing in the correct direction
+    uint16_t startPos;
+    uint16_t endPos; 
+    if (y1 > y0) {
+        startPos = y0;
+        endPos = y1;
+    }
+    else {
+        startPos = y1;
+        endPos = y0;
+    }
+    
+    // TODO This might be optimised by setting the Addressing mode bit AM to 1 (reg 03)
+    
+    // Now draw the line
+    for (uint16_t i = startPos; i < endPos; i++) {
+        pixel(x0, i, colour);
+    }
+}
+
+void EAQVGAOLED::rectangle
+(
+    const uint16_t x0,
+    const uint16_t y0,
+    const uint16_t x1,
+    const uint16_t y1,
+    uint16_t colour
+)
+{
+    // Order the drawing co-ords
+    uint16_t startX, startY, endX, endY;
+    orderCoords(x0, y0, x1, y1, startX, startY, endX, endY);    
+    
+    // Now draw the 4 lines required
+    hLine(startX, startY, endX, colour);
+    vLine(endX, startY, endY, colour);
+    hLine(startX, endY, endX, colour);
+    vLine(startX, startY, endY, colour);
+} 
+
+void EAQVGAOLED::fillRectangle
+(
+    const uint16_t x0,
+    const uint16_t y0,
+    const uint16_t x1,
+    const uint16_t y1,
+    uint16_t colour
+)
+{
+    // Order the drawing co-ords
+    uint16_t startX, startY, endX, endY;
+    orderCoords(x0, y0, x1, y1, startX, startY, endX, endY);    
+    
+    // Now draw the all lines required
+    for (uint16_t i = startY; i < endY; i++) {
+        hLine(startX, i, endX, colour);
+    }
+} 
+
+int EAQVGAOLED::_putc
+(
+    int value
+)
+{
+    switch (value) {
+    case CURSOR_CLS: // Clear the screen
+        cls();
+        break;
+    case CURSOR_UP:
+        if (_row == 0)
+            _row = rows();
+        else {
+            _row--;
+        }
+        break;
+    case CURSOR_DOWN:
+        if (_row == rows()) {
+            _row = 0;
+        }
+        else {
+            _row++;
+        }
+        break;
+    case CURSOR_LEFT:
+        if (_column == 0) {
+            _column = columns();
+        }
+        else {
+            _column--;
+        }
+        break;
+    case CURSOR_RIGHT:
+        if (_column == columns()) {
+            _column = 0;
+        }
+        else {
+            _column++;
+        }
+        break;
+    default:    
+        GraphicsDisplay::_putc(value);
+        break;
+    }
+    
+    return value;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Private functions                                                        */
+/*                                                                          */
+/****************************************************************************/
+
+/**
+ * Initialise the hardware required
+ *
+ */
+void EAQVGAOLED::initHardware(void)
+{
+    // Activate the display reset line
+    _reset = 0;
+    
+    // Turn the chip select and backlight off
+    _cs = 1;
+    _bl = 0;
+    
+    // Set the spi port for 8 bits, clk phase and polarity 0
+     _spi.format(8, 0);
+    // And frequency to 10MHz
+    _spi.frequency(10000000);
+    
+    // Wait for 10uS and release reset
+    wait_us(10);
+    _reset = 1;
+    
+    // Wait for 10ms to allow access to controller
+    wait_ms(10);
+}
+
+/**
+ * Reset the display controller
+ *
+ */
+bool EAQVGAOLED::resetDisplay(void)
+{
+    // Ensure we are connected to the correct hardware
+    unsigned int result = readDataRegister(0x0F);
+    /* Doesn't seem to wrk ??
+    if (EAQVGAOLED_ID != result)
+    {
+      return false;
+    }
+    */
+    
+    // Set the entry mode values for addessing and increment   
+    writeDataRegister(0x03, 0x130);
+    
+    // Set the standby off
+    writeDataRegister(0x10, 0);
+    
+    // Delay till the clocks come up
+    wait_ms(100);
+    
+    // Enable the backlight
+    _bl = 1;
+    
+    // Delay until power is steady
+    wait_ms(40);
+    
+    // Turn the display on
+    writeDataRegister(0x05, 1);
+    
+    return true;
+}
+
+/**
+ * Set the location of the pen
+ *
+ */
+void EAQVGAOLED::movePen
+(
+    const uint16_t x,
+    const uint16_t y
+)
+{
+    // Set x & y pos and select GRAM register
+    writeDataRegister(0x20, x);
+    writeDataRegister(0x21, y);
+    setRegisterIndex(0x22);
+}
+
+/**
+ * Read the value of a controller data register
+ *
+ * @param reg the register address to read
+ */
+uint16_t EAQVGAOLED::readDataRegister
+(
+    const uint8_t reg
+)
+{
+    //  Set the register index
+    setRegisterIndex(reg);
+
+    // Read the response
+    _cs = 0;
+    _spi.write(0x71);   // Command byte ID = 011100, RS = 0, R/W = 1
+    uint8_t msb = _spi.write(0);
+    uint8_t lsb = _spi.write(0);
+    _cs = 1;
+    
+    return (msb << 8) | lsb;
+}
+
+/**
+ * Write to a controller data register
+ *
+ * @param reg the register address to read
+ * @param data the data to write
+ */
+void EAQVGAOLED::writeDataRegister
+(
+    const uint8_t reg,
+    const uint16_t data
+)
+{
+    //  Set the register index
+    setRegisterIndex(reg);
+
+    // Write the data
+    writeData(data);
+}
+
+inline void EAQVGAOLED::writeData
+(
+    const uint16_t data
+)
+{
+    // Write the data
+    _cs = 0;
+    _spi.write(0x72);   // Command byte, ID = 011100, RS = 1, R/W = 0
+    _spi.write(data >> 8);
+    _spi.write(data & 0xFF);
+    _cs = 1;
+}
+
+/** Select a controller register
+ *
+ * @param reg register to select
+ */
+inline void EAQVGAOLED::setRegisterIndex
+(
+    const uint8_t reg
+)
+{
+    //  Write to the register selector (RS = 0)
+    _cs = 0;
+    _spi.write(0x70);   // Command byte ID = 011100, RS = 0, R/W = 0
+    _spi.write(0);
+    _spi.write(reg);    
+    _cs = 1;
+}