Graphical demo for the LPC4088 Experiment Base Board with one of the Display Expansion Kits. This demo shows a number of dots projected on a rotating sphere.

Dependencies:   EALib mbed

Files at this revision

API Documentation at this revision

Comitter:
embeddedartists
Date:
Fri Oct 03 13:15:25 2014 +0000
Commit message:
First version

Changed in this revision

AR1021I2C.cpp Show annotated file Show diff for this revision Revisions of this file
AR1021I2C.h Show annotated file Show diff for this revision Revisions of this file
EALib.lib Show annotated file Show diff for this revision Revisions of this file
EaLcdBoardGPIO.cpp Show annotated file Show diff for this revision Revisions of this file
EaLcdBoardGPIO.h Show annotated file Show diff for this revision Revisions of this file
GlobeDemo.cpp Show annotated file Show diff for this revision Revisions of this file
GlobeDemo.h Show annotated file Show diff for this revision Revisions of this file
Graphics.cpp Show annotated file Show diff for this revision Revisions of this file
Graphics.h Show annotated file Show diff for this revision Revisions of this file
TestDisplay.cpp Show annotated file Show diff for this revision Revisions of this file
TestDisplay.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 79b286950b60 AR1021I2C.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AR1021I2C.cpp	Fri Oct 03 13:15:25 2014 +0000
@@ -0,0 +1,560 @@
+/*
+ *  Copyright 2013 Embedded Artists AB
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/******************************************************************************
+ * Includes
+ *****************************************************************************/
+
+#include "mbed.h"
+#include "mbed_debug.h"
+
+#include "AR1021I2C.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+#define AR1021_REG_TOUCH_THRESHOLD        (0x02)
+#define AR1021_REG_SENS_FILTER            (0x03)
+#define AR1021_REG_SAMPLING_FAST          (0x04)
+#define AR1021_REG_SAMPLING_SLOW          (0x05)
+#define AR1021_REG_ACC_FILTER_FAST        (0x06)
+#define AR1021_REG_ACC_FILTER_SLOW        (0x07)
+#define AR1021_REG_SPEED_THRESHOLD        (0x08)
+#define AR1021_REG_SLEEP_DELAY            (0x0A)
+#define AR1021_REG_PEN_UP_DELAY           (0x0B)
+#define AR1021_REG_TOUCH_MODE             (0x0C)
+#define AR1021_REG_TOUCH_OPTIONS          (0x0D)
+#define AR1021_REG_CALIB_INSETS           (0x0E)
+#define AR1021_REG_PEN_STATE_REPORT_DELAY (0x0F)
+#define AR1021_REG_TOUCH_REPORT_DELAY     (0x11)
+
+
+#define AR1021_CMD_GET_VERSION                 (0x10)
+#define AR1021_CMD_ENABLE_TOUCH                (0x12)
+#define AR1021_CMD_DISABLE_TOUCH               (0x13)
+#define AR1021_CMD_CALIBRATE_MODE              (0x14)
+#define AR1021_CMD_REGISTER_READ               (0x20)
+#define AR1021_CMD_REGISTER_WRITE              (0x21)
+#define AR1021_CMD_REGISTER_START_ADDR_REQUEST (0x22)
+#define AR1021_CMD_REGISTER_WRITE_TO_EEPROM    (0x23)
+#define AR1021_CMD_EEPROM_READ                 (0x28)
+#define AR1021_CMD_EEPROM_WRITE                (0x29)
+#define AR1021_CMD_EEPROM_WRITE_TO_REGISTERS   (0x2B)
+
+#define AR1021_RESP_STAT_OK           (0x00)
+#define AR1021_RESP_STAT_CMD_UNREC    (0x01)
+#define AR1021_RESP_STAT_HDR_UNREC    (0x03)
+#define AR1021_RESP_STAT_TIMEOUT      (0x04)
+#define AR1021_RESP_STAT_CANCEL_CALIB (0xFC)
+
+
+#define AR1021_ERR_NO_HDR      (-1000)
+#define AR1021_ERR_INV_LEN     (-1001)
+#define AR1021_ERR_INV_RESP    (-1002)
+#define AR1021_ERR_INV_RESPLEN (-1003)
+#define AR1021_ERR_TIMEOUT     (-1004)
+
+// bit 7 is always 1 and bit 0 defines pen up or down
+#define AR1021_PEN_MASK (0x81)
+
+#define AR1021_NUM_CALIB_POINTS (4)
+
+#define AR1021_ADDR  (0x4D << 1)
+
+#define AR1021_TIMEOUT     1000        //how many ms to wait for responce 
+#define AR1021_RETRY          5        //how many times to retry sending command 
+
+#define AR1021_MIN(__a, __b) (((__a)<(__b))?(__a):(__b))
+
+
+AR1021I2C::AR1021I2C(PinName sda, PinName scl, PinName siq) :
+_i2c(sda, scl), _siq(siq), _siqIrq(siq)
+{
+    _i2c.frequency(200000);
+
+    // default calibration inset is 25 -> (25/2 = 12.5%)
+    _inset = 25;
+
+    // make sure _calibPoint has an invalid value to begin with
+    // correct value is set in calibrateStart()
+    _calibPoint = AR1021_NUM_CALIB_POINTS+1;
+
+    _x = 0;
+    _y = 0;
+    _pen = 0;
+
+    _initialized = false;
+}
+
+
+bool AR1021I2C::read(touchCoordinate_t &coord) {
+
+    if (!_initialized) return false;
+
+    coord.x = _x * _width/4095;
+    coord.y = _y * _height/4095;
+    coord.z = _pen;
+
+    return true;
+}
+
+
+bool AR1021I2C::init(uint16_t width, uint16_t height) {
+    int result = 0;
+    bool ok = false;
+    int attempts = 0;
+
+    _width = width;
+    _height = height;
+
+    while (1) {
+
+        do {
+            // disable touch
+            result = cmd(AR1021_CMD_DISABLE_TOUCH, NULL, 0, NULL, 0);
+            if (result != 0) {
+                debug("disable touch failed (%d)\n", result);
+                break;
+            }
+
+            char regOffset = 0;
+            int regOffLen = 1;
+            result = cmd(AR1021_CMD_REGISTER_START_ADDR_REQUEST, NULL, 0,
+                    &regOffset, &regOffLen);
+            if (result != 0) {
+                debug("register offset request failed (%d)\n", result);
+                break;
+            }
+
+            // enable calibrated coordinates
+            //                  high, low address,                        len,  value
+            char toptions[4] = {0x00, AR1021_REG_TOUCH_OPTIONS+regOffset, 0x01, 0x01};
+            result = cmd(AR1021_CMD_REGISTER_WRITE, toptions, 4, NULL, 0);
+            if (result != 0) {
+                debug("register write request failed (%d)\n", result);
+                break;
+            }
+
+            // save registers to eeprom
+            result = cmd(AR1021_CMD_REGISTER_WRITE_TO_EEPROM, NULL, 0, NULL, 0);
+            if (result != 0) {
+                debug("register write to eeprom failed (%d)\n", result);
+                break;
+            }
+
+            // enable touch
+            result = cmd(AR1021_CMD_ENABLE_TOUCH, NULL, 0, NULL, 0);
+            if (result != 0) {
+                debug("enable touch failed (%d)\n", result);
+                break;
+            }
+
+            _siqIrq.rise(this, &AR1021I2C::readTouchIrq);
+
+            _initialized = true;
+            ok = true;
+
+        } while(0);
+
+        if (ok) break;
+
+        // try to run the initialize sequence at most 2 times
+        if(++attempts >= 2) break;
+    }
+
+
+    return ok;
+}
+
+bool AR1021I2C::calibrateStart() {
+    bool ok = false;
+    int result = 0;
+    int attempts = 0;
+
+    if (!_initialized) return false;
+
+    _siqIrq.rise(NULL);
+
+    while(1) {
+
+        do {
+            // disable touch
+            result = cmd(AR1021_CMD_DISABLE_TOUCH, NULL, 0, NULL, 0);
+            if (result != 0) {
+                debug("disable touch failed (%d)\n", result);
+                break;
+            }
+
+            char regOffset = 0;
+            int regOffLen = 1;
+            result = cmd(AR1021_CMD_REGISTER_START_ADDR_REQUEST, NULL, 0,
+                    &regOffset, &regOffLen);
+            if (result != 0) {
+                debug("register offset request failed (%d)\n", result);
+                break;
+            }
+
+            // set insets
+            // enable calibrated coordinates
+            //                high, low address,                       len,  value
+            char insets[4] = {0x00, AR1021_REG_CALIB_INSETS+regOffset, 0x01, _inset};
+            result = cmd(AR1021_CMD_REGISTER_WRITE, insets, 4, NULL, 0);
+            if (result != 0) {
+                debug("register write request failed (%d)\n", result);
+                break;
+            }
+
+            // calibration mode
+            char calibType = 4;
+            result = cmd(AR1021_CMD_CALIBRATE_MODE, &calibType, 1, NULL, 0, false);
+            if (result != 0) {
+                debug("calibration mode failed (%d)\n", result);
+                break;
+            }
+
+            _calibPoint = 0;
+            ok = true;
+
+        } while(0);
+
+        if (ok) break;
+
+        // try to run the calibrate mode sequence at most 2 times
+        if (++attempts >= 2) break;
+    }
+
+    return ok;
+}
+
+bool AR1021I2C::getNextCalibratePoint(uint16_t* x, uint16_t* y) {
+
+    if (!_initialized) return false;
+    if (x == NULL || y == NULL) return false;
+
+    int xInset = (_width * _inset / 100) / 2;
+    int yInset = (_height * _inset / 100) / 2;
+
+    switch(_calibPoint) {
+    case 0:
+        *x = xInset;
+        *y = yInset;
+        break;
+    case 1:
+        *x = _width - xInset;
+        *y = yInset;
+        break;
+    case 2:
+        *x = _width - xInset;
+        *y = _height - yInset;
+        break;
+    case 3:
+        *x = xInset;
+        *y = _height - yInset;
+        break;
+    default:
+        return false;
+    }
+
+    return true;
+}
+
+bool AR1021I2C::waitForCalibratePoint(bool* morePoints, uint32_t timeout) {
+    int result = 0;
+    bool ret = false;
+
+    if (!_initialized) return false;
+
+    do {
+        if (morePoints == NULL || _calibPoint >= AR1021_NUM_CALIB_POINTS) {
+            break;
+        }
+
+        // wait for response
+        result = waitForCalibResponse(timeout);
+        if (result != 0) {
+            debug("wait for calibration response failed (%d)\n", result);
+            break;
+        }
+
+        _calibPoint++;
+        *morePoints = (_calibPoint < AR1021_NUM_CALIB_POINTS);
+
+
+        // no more points -> enable touch
+        if (!(*morePoints)) {
+
+            // wait for calibration data to be written to eeprom
+            // before enabling touch
+            result = waitForCalibResponse(timeout);
+            if (result != 0) {
+                debug("wait for calibration response failed (%d)\n", result);
+                break;
+            }
+
+
+            // clear chip-select since calibration is done;
+//            _cs = 1;
+
+            result = cmd(AR1021_CMD_ENABLE_TOUCH, NULL, 0, NULL, 0);
+            if (result != 0) {
+                debug("enable touch failed (%d)\n", result);
+                break;
+            }
+
+            _siqIrq.rise(this, &AR1021I2C::readTouchIrq);
+        }
+
+        ret = true;
+
+    } while (0);
+
+
+
+    if (!ret) {
+        // make sure to set chip-select off in case of an error
+//        _cs = 1;
+        // calibration must restart if an error occurred
+        _calibPoint = AR1021_NUM_CALIB_POINTS+1;
+    }
+
+
+
+    return ret;
+}
+
+int AR1021I2C::cmd(char cmd, char* data, int len, char* respBuf, int* respLen,
+        bool setCsOff) {
+
+    int ret = 0;
+    int readLen = (respLen == NULL) ? 0 : *respLen;
+    for (int attempt = 1; attempt <= AR1021_RETRY; attempt++) {
+        if (attempt > 1) {
+            wait_ms(50);
+        }
+
+        // command request
+        // ---------------
+        // 0x00 0x55 len cmd data
+        // 0x00 = protocol command byte
+        // 0x55 = header
+        // len = data length + cmd (1)
+        // data = data to send
+
+        _i2c.start(); 
+        _i2c.write(AR1021_ADDR);                   //send write address 
+        _i2c.write(0x00); 
+        _i2c.write(0x55);                          //header 
+        _i2c.write(len+1);                         //message length 
+        _i2c.write(cmd);
+        for (int i = 0; i < len; i++) {
+            _i2c.write(data[i]);
+        }
+        wait_us(60);
+        _i2c.stop();
+     
+        // wait for response (siq goes high when response is available)
+        Timer t;
+        t.start();
+        while(_siq.read() != 1 && t.read_ms() < AR1021_TIMEOUT);
+        
+        if (t.read_ms() < AR1021_TIMEOUT) {
+        
+            // command response
+            // ---------------
+            // 0x55 len status cmd data
+            // 0x55 = header
+            // len = number of bytes following the len byte (i.e. including the status&cmd)
+            // status = status
+            // cmd = command ID
+            // data = data to receive
+            _i2c.start();
+            _i2c.write(AR1021_ADDR + 1);        //send read address 
+            char header = _i2c.read(1);         //header should always be 0x55
+            if (header != 0x55) {
+                ret = AR1021_ERR_NO_HDR;
+                continue;
+            }
+            char length = _i2c.read(1);         //data length
+            if (length < 2) {
+                ret = AR1021_ERR_INV_LEN;       //must have at least status and command bytes
+                continue;
+            }
+            length -= 2;
+            if (length > readLen) {
+                ret = AR1021_ERR_INV_LEN;       //supplied buffer is not enough
+                continue;
+            }
+
+            char status = _i2c.read(1);         //command status
+            char usedCmd;
+            if (readLen <= 0) {
+                usedCmd = _i2c.read(0);         //no data => read command byte + NACK
+            } else {
+                usedCmd = _i2c.read(1);         //which command
+
+                //we need to send a NACK on the last read. 
+                int i;
+                for (i = 0; i < (length-1); i++) {
+                    respBuf[i] = _i2c.read(1);
+                }
+                respBuf[i] = _i2c.read(0);      //last returned data byte + NACK
+            }
+            _i2c.stop();
+            
+            
+            if (status != AR1021_RESP_STAT_OK) {
+                ret = -status;
+                continue;
+            }
+            if (usedCmd != cmd) {
+                ret = AR1021_ERR_INV_RESP;
+                continue;
+            }
+            
+            // success
+            ret = 0;
+            break;
+            
+        } else {
+            ret = AR1021_ERR_TIMEOUT;
+            continue;
+        }
+    }
+
+    return ret;
+}
+
+int AR1021I2C::waitForCalibResponse(uint32_t timeout) {
+    Timer t;
+    int ret = 0;
+
+    t.start();
+
+    // wait for siq
+    while (_siq.read() != 1 &&
+            (timeout == 0 || (uint32_t)t.read_ms() < (int)timeout));
+
+
+    do {
+
+        if (timeout >  0 && (uint32_t)t.read_ms() >= timeout) {
+            ret = AR1021_ERR_TIMEOUT;
+            break;
+        }
+
+        // command response
+        // ---------------
+        // 0x55 len status cmd data
+        // 0x55 = header
+        // len = number of bytes following the len byte (should be 2)
+        // status = status
+        // cmd = command ID
+        _i2c.start();
+        _i2c.write(AR1021_ADDR + 1);        //send read address 
+        char header = _i2c.read(1);         //header should always be 0x55  
+        char length = _i2c.read(1);         //data length
+
+        if (header != 0x55) {
+            ret = AR1021_ERR_NO_HDR;
+            break;
+        }
+        if (length < 2) {
+            ret = AR1021_ERR_INV_LEN;
+            break;
+        }
+        char status = _i2c.read(1);         //status
+        char cmd    = _i2c.read(0);         //command, should be NACK'ed
+        _i2c.stop();
+        if (status != AR1021_RESP_STAT_OK) {
+            ret = -status;
+            break;
+        }
+        if (cmd != AR1021_CMD_CALIBRATE_MODE) {
+            ret = AR1021_ERR_INV_RESP;
+            break;
+        }
+        
+        // success
+        ret = 0;
+
+    } while (0);
+
+    return ret;
+}
+
+
+void AR1021I2C::readTouchIrq() {
+    while(_siq.read() == 1) {
+
+        // touch coordinates are sent in a 5-byte data packet
+        _i2c.start();
+        _i2c.write(AR1021_ADDR + 1);        //send read address 
+        int pen = _i2c.read(1);
+        int xlo = _i2c.read(1);
+        int xhi = _i2c.read(1);
+        int ylo = _i2c.read(1);
+        int yhi = _i2c.read(0);
+        _i2c.stop();
+        
+        // pen down
+        if ((pen&AR1021_PEN_MASK) == (1<<7|1<<0)) {
+            _pen = 1;
+        }
+        // pen up
+        else if ((pen&AR1021_PEN_MASK) == (1<<7)){
+            _pen = 0;
+        }
+        // invalid value
+        else {
+            continue;
+        }
+
+        _x = ((xhi<<7)|xlo);
+        _y = ((yhi<<7)|ylo);
+    }
+}
+
+bool AR1021I2C::info(int* verHigh, int* verLow, int* resBits, int* type)
+{
+    char buff[3] = {0,0,0};
+    int read = 3;
+    int res = cmd(AR1021_CMD_GET_VERSION, NULL, 0, buff, &read);
+    if (res == 0) {
+        *verHigh = buff[0];
+        *verLow = buff[1];
+        switch(buff[2] & 3) {
+            case 0:   
+                *resBits = 8;
+                break;
+            case 1:   
+                *resBits = 10;
+                break;
+            case 2:   
+                *resBits = 12;
+                break;
+            case 3:   
+                *resBits = 12;
+                break;
+            default:
+                res = 25;
+                printf("Invalid resolution %d\n", buff[2]&3);
+                break;
+        }
+        *type = buff[2]>>2;
+    }
+    return (res == 0);
+}
diff -r 000000000000 -r 79b286950b60 AR1021I2C.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AR1021I2C.h	Fri Oct 03 13:15:25 2014 +0000
@@ -0,0 +1,77 @@
+/*
+ *  Copyright 2013 Embedded Artists AB
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#ifndef AR1021I2C_H
+#define AR1021I2C_H
+
+#include "TouchPanel.h"
+
+/**
+ * Microchip Touch Screen Controller (AR1021).
+ *
+ * Please note that this touch panel has an on-board storage for
+ * calibration data. Once a successful calibration has been performed
+ * it is not needed to do additional calibrations since the stored
+ * calibration data will be used.
+ */
+class AR1021I2C : public TouchPanel {
+public:
+
+
+    /**
+     * Constructor
+     *
+     * @param mosi I2C SDA pin
+     * @param miso I2C SCL pin
+     * @param siq interrupt pin
+     */
+    AR1021I2C(PinName sda, PinName scl, PinName siq);
+
+    bool info(int* verHigh, int* verLow, int* resBits, int* type);
+
+    virtual bool init(uint16_t width, uint16_t height);
+    virtual bool read(touchCoordinate_t &coord);
+    virtual bool calibrateStart();
+    virtual bool getNextCalibratePoint(uint16_t* x, uint16_t* y);
+    virtual bool waitForCalibratePoint(bool* morePoints, uint32_t timeout);
+
+private:
+
+
+    I2C _i2c;
+    DigitalIn _siq;
+    InterruptIn _siqIrq;
+    bool _initialized;
+
+
+    int32_t _x;
+    int32_t _y;
+    int32_t _pen;
+
+    uint16_t _width;
+    uint16_t _height;
+    uint8_t _inset;
+
+    int _calibPoint;
+
+
+    int cmd(char cmd, char* data, int len, char* respBuf, int* respLen, bool setCsOff=true);
+    int waitForCalibResponse(uint32_t timeout);
+    void readTouchIrq();
+};
+
+#endif
+
diff -r 000000000000 -r 79b286950b60 EALib.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EALib.lib	Fri Oct 03 13:15:25 2014 +0000
@@ -0,0 +1,1 @@
+https://mbed.org/users/embeddedartists/code/EALib/#b3a179cc3d88
diff -r 000000000000 -r 79b286950b60 EaLcdBoardGPIO.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EaLcdBoardGPIO.cpp	Fri Oct 03 13:15:25 2014 +0000
@@ -0,0 +1,96 @@
+/*
+ *  Copyright 2013 Embedded Artists AB
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/******************************************************************************
+ * Includes
+ *****************************************************************************/
+
+#include "mbed.h"
+#include "EaLcdBoardGPIO.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+
+EaLcdBoardGPIO::EaLcdBoardGPIO(PinName sda, PinName scl)
+  : EaLcdBoard(sda, scl), /*pinWP(P4_15),*/ pin3v3(P2_0), pin5v(P2_21), pinDE(P2_11), pinContrast(P2_1)
+{
+  pinContrast.period_ms(10);
+  setWriteProtect(true);
+  set3V3Signal(false);
+  set5VSignal(false);
+  setDisplayEnableSignal(false);
+  setBacklightContrast(0);
+}
+
+
+void EaLcdBoardGPIO::setWriteProtect(bool enable)
+{  
+    // Not Applicable
+}
+
+void EaLcdBoardGPIO::set3V3Signal(bool enabled) { //P2.0 L=3.3V on
+    if (enabled) {
+        pin3v3 = 0;
+    } else {
+        pin3v3 = 1;
+    }
+}
+
+void EaLcdBoardGPIO::set5VSignal(bool enabled) { //P2.21 H=5V on
+    if (enabled) {
+        pin5v = 1;
+    } else {
+        pin5v = 0;
+    }
+}
+
+void EaLcdBoardGPIO::setDisplayEnableSignal(bool enabled) { //P2.11 H=enabled
+    LPC_IOCON->P2_11 &= ~7; /* GPIO2[11]  @ P2.11 */
+    if (enabled) {
+        pinDE = 1;
+    } else {
+        pinDE = 0;
+    }
+}
+
+void EaLcdBoardGPIO::setBacklightContrast(uint32_t value) { //P2.1, set to 4.30 for now
+#if 0    
+    LPC_IOCON->P2_1 &= ~7; /* GPIO2[1]  @ P2.1 */
+  if (value > 50) {
+      pinContrast = 1;
+  } else {
+      pinContrast = 0;
+  }
+#else
+    uint32_t tmp = LPC_IOCON->P2_1;
+    tmp &= ~7;
+    tmp |= 1;
+    LPC_IOCON->P2_1 = tmp; /* PWM2[1]  @ P2.1 */
+    float f = value;
+    pinContrast = f/100.0f;
+#endif
+  
+//    if (value > 100) return;
+
+//    pca9532_setBlink0Duty(100-value);
+//    pca9532_setBlink0Period(0);
+//    pca9532_setBlink0Leds(LCDB_CTRL_BL_C);
+}
+
+
+
diff -r 000000000000 -r 79b286950b60 EaLcdBoardGPIO.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EaLcdBoardGPIO.h	Fri Oct 03 13:15:25 2014 +0000
@@ -0,0 +1,50 @@
+/*
+ *  Copyright 2013 Embedded Artists AB
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#ifndef EALCDBOARDGPIO_H
+#define EALCDBOARDGPIO_H
+
+#include "EaLcdBoard.h"
+
+/** An interface to Embedded Artists LCD Boards
+ *
+ */
+class EaLcdBoardGPIO : public EaLcdBoard {
+public:
+
+    EaLcdBoardGPIO(PinName sda, PinName scl);
+
+    void setBC(uint32_t val) { setBacklightContrast(val); };
+
+protected:
+    virtual void setWriteProtect(bool enable);
+    virtual void set3V3Signal(bool enabled);
+    virtual void set5VSignal(bool enabled);
+    virtual void setDisplayEnableSignal(bool enabled);
+    virtual void setBacklightContrast(uint32_t value);
+
+private:
+    //DigitalOut pinWP;
+    DigitalOut pin3v3;
+    DigitalOut pin5v;
+    DigitalOut pinDE;
+    //DigitalOut pinContrast;
+    PwmOut pinContrast;
+};
+
+#endif
+
+
diff -r 000000000000 -r 79b286950b60 GlobeDemo.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GlobeDemo.cpp	Fri Oct 03 13:15:25 2014 +0000
@@ -0,0 +1,396 @@
+/******************************************************************************
+ * Includes
+ *****************************************************************************/
+
+#include "mbed.h"
+
+#include "LcdController.h"
+#include "EaLcdBoard.h"
+#include "GlobeDemo.h"
+
+#include <math.h>
+
+//#include "wchar.h"
+
+/******************************************************************************
+ * Typedefs and defines
+ *****************************************************************************/
+
+#define NUM_OF_DOTS 50
+
+/******************************************************************************
+ * Local variables
+ *****************************************************************************/
+
+
+/******************************************************************************
+ * External variables
+ *****************************************************************************/
+
+/******************************************************************************
+ * Local functions
+ *****************************************************************************/
+
+// Vertex structure
+typedef struct
+{
+#ifdef USE_FLOAT
+  float x, y, z;
+#else
+  long x, y, z;
+#endif
+}tVertex;
+
+// Transformed vertices
+tVertex *gRVtx;
+
+#ifdef USE_FLOAT
+// Original vertices
+static tVertex *gVtx;
+#else
+static const tVertex gVtx[NUM_OF_DOTS] = {
+{-21585, 17597, -17265},
+{28493, -7790, 14183},
+{13031, 27845, 11338},
+{10822, 29162, -10304},
+{19517, -25865, -4876},
+{1283, 30949, -10687},
+{-23097, 12297, 19723},
+{-17162, 1188, 27888},
+{-29007, -1547, 15163},
+{-8182, -31729, -197},
+{11599, -28575, -11073},
+{25963, 12182, 15850},
+{106, 10547, -31023},
+{-24312, 3053, -21755},
+{9966, -18803, -24916},
+{17598, -6037, -26973},
+{23321, 17149, -15353},
+{-3265, 8867, -31376},
+{-23639, 13701, 18087},
+{-2433, -22123, -24049},
+{21284, -11349, -22179},
+{-21407, 24683, -2486},
+{-32011, -4336, 5495},
+{-20191, 22605, 12450},
+{14752, -23540, 17376},
+{-8961, -17292, -26351},
+{-18078, 13561, -23727},
+{10730, -23639, 19994},
+{-18718, 17555, 20376},
+{13626, -22837, 19144},
+{-24695, -19036, -10073},
+{11935, 22275, 20859},
+{-2182, -28801, -15474},
+{21428, -21867, -11678},
+{-19601, 21558, -14991},
+{24512, 10876, -18830},
+{12385, 27881, 11956},
+{26982, 15618, -10088},
+{-16954, 19591, 20061},
+{-6027, 22699, -22850},
+{5453, 28825, -14598},
+{-20155, -16252, -20083},
+{-15962, 11757, -26089},
+{-29175, -11289, -9750},
+{-15370, 604, -28933},
+{26009, 19868, -1575},
+{24722, -17277, -12806},
+{-4527, 25836, -19639},
+{-22224, 10442, 21697},
+{-10388, 24393, -19255}};
+#endif
+
+unsigned short GlobeDemo::isqrt(unsigned long a) const {
+    unsigned long temp;
+    long e;
+    unsigned long x = 0;
+    if((a & 0xffff0000) != 0)
+        x = 444 + a / 26743;
+    else if((a & 0xff00) != 0)
+        x = 21 + a / 200;
+    else
+        x = 1 + a / 12;
+    do{
+        temp = a / x;
+        e = (x - temp) / 2;
+        x = (x + temp) / 2;
+    }
+    while(e != 0);
+    return (unsigned short)x;
+}
+
+short GlobeDemo::_sin(short y) const {
+    static short s1 = 0x6487;
+    static short s3 = 0x2951;
+    static short s5 = 0x4f6;
+    long z, prod, sum;
+
+    z = ((long)y * y) >> 12;
+    prod = (z * s5) >> 16;
+    sum = s3 - prod;
+    prod = (z * sum) >> 16;
+    sum = s1 - prod;
+
+    // for better accuracy, round here
+    return (short)((y * sum) >> 13);
+ }
+
+short GlobeDemo::_cos(short y) const {
+    static short c0 = 0x7fff;
+    static short c2 = 0x4eea;
+    static short c4 = 0x0fc4;
+    long z, prod, sum;
+    z = ((long)y * y) >> 12;
+    prod = (z * c4) >> 16;
+    sum = c2 - prod;
+
+    // for better accuracy, round here
+    prod = (z * sum) >> 15;
+    return (short)(c0 - prod);
+}
+
+short GlobeDemo::isine(short x) const {
+    unsigned short n = (((unsigned short)x + 0x2000) >> 14) & 0x3;
+    x -= n * 0x4000;
+    switch(n){
+        case 0:
+            return _sin(x);
+        case 1:
+            return _cos(x);
+        case 2:
+            return - _sin(x);
+        case 3:
+            return  - _cos(x);
+    }
+    return 0;
+ }
+
+
+short GlobeDemo::icosine(short x) const {
+    return isine(x + 0x4000);
+ }
+
+void GlobeDemo::initialize()
+{
+//  gVtx = (tVertex*)malloc(sizeof(tVertex) * NUM_OF_DOTS);
+  gRVtx = (tVertex*)malloc(sizeof(tVertex) * NUM_OF_DOTS);
+
+#ifdef USE_FLOAT
+  int i;
+  for (i = 0; i < NUM_OF_DOTS; i++)
+  {
+    gVtx[i].x = (rand() % 32768) - 16384.0f;
+    gVtx[i].y = (rand() % 32768) - 16384.0f;
+    gVtx[i].z = (rand() % 32768) - 16384.0f;
+    float len = (float)sqrt(gVtx[i].x * gVtx[i].x + 
+                            gVtx[i].y * gVtx[i].y + 
+                            gVtx[i].z * gVtx[i].z);
+    if (len != 0)
+    {
+      gVtx[i].x /= len;
+      gVtx[i].y /= len;
+      gVtx[i].z /= len;
+    }
+  }
+#endif
+}
+
+#ifdef USE_FLOAT
+void GlobeDemo::rotate_z(float angle)
+{
+  float ca = (float)cos(angle);
+  float sa = (float)sin(angle);
+  int i;
+  for (i = 0; i < NUM_OF_DOTS; i++)
+  {
+    float x = gRVtx[i].x * ca - gRVtx[i].y * sa;
+    float y = gRVtx[i].x * sa + gRVtx[i].y * ca;
+    gRVtx[i].x = x;
+    gRVtx[i].y = y;
+  }
+}
+
+void GlobeDemo::rotate_y(float angle)
+{
+  float ca = (float)cos(angle);
+  float sa = (float)sin(angle);
+  int i
+  for (i = 0; i < NUM_OF_DOTS; i++)
+  {
+    float z = gRVtx[i].z * ca - gRVtx[i].x * sa;
+    float x = gRVtx[i].z * sa + gRVtx[i].x * ca;
+    gRVtx[i].z = z;
+    gRVtx[i].x = x;
+  }
+}
+#else
+void GlobeDemo::rotate_z(uint32_t angle)
+{
+  uint32_t i;
+  long x,y,ca,sa;
+
+  ca = icosine(angle);
+  sa = isine(angle);
+  for (i = 0; i < NUM_OF_DOTS; i++)
+  {
+    x = (gRVtx[i].x * ca - gRVtx[i].y * sa) / 0x7fff;
+    y = (gRVtx[i].x * sa + gRVtx[i].y * ca) / 0x7fff;
+    gRVtx[i].x = x;
+    gRVtx[i].y = y;
+  }
+}
+
+void GlobeDemo::rotate_y(uint32_t angle)
+{
+  uint32_t i;
+  long x,z,ca,sa;
+
+  ca = icosine(angle);
+  sa = isine(angle);
+  for (i = 0; i < NUM_OF_DOTS; i++)
+  {
+    z = (gRVtx[i].z * ca - gRVtx[i].x * sa) / 0x7fff;
+    x = (gRVtx[i].z * sa + gRVtx[i].x * ca) / 0x7fff;
+    gRVtx[i].z = z;
+    gRVtx[i].x = x;
+  }
+}
+#endif
+
+#if 0
+void GlobeDemo::rotate_x(float angle)
+{
+  float ca = (float)cos(angle);
+  float sa = (float)sin(angle);
+  int i;
+  for (i = 0; i < NUM_OF_DOTS; i++)
+  {
+    float y = gRVtx[i].y * ca - gRVtx[i].z * sa;
+    float z = gRVtx[i].y * sa + gRVtx[i].z * ca;
+    gRVtx[i].y = y;
+    gRVtx[i].z = z;
+  }
+}
+#endif
+
+void GlobeDemo::render(uint32_t idx)
+{
+  uint32_t i;
+#ifdef USE_FLOAT
+  float rotz;
+  float roty;
+#else
+  uint32_t rotz;
+  uint32_t roty;
+#endif
+
+ static uint8_t cnt=0;
+
+  if (cnt == 0)
+  {
+    cnt = 1;
+    pFrmBuf = pFrmBuf1;
+  }
+  else if (cnt == 1)
+  {
+    cnt = 2;
+    pFrmBuf = pFrmBuf2;
+  }
+  else
+  {
+    cnt = 0;
+    pFrmBuf = pFrmBuf3;
+  }
+
+  graphics.setFrameBuffer(pFrmBuf);
+
+  // rendering here
+  memset((void*)(pFrmBuf), BACKGROUND_COLOR, this->windowX * this->windowY * 2);
+
+//  lcd_fillcircle(myLcdHnd, WIDTH / 2, HEIGHT / 2, HEIGHT / 4, LARGE_CIRCLE_COLOR);
+  graphics.put_circle(this->windowX / 2, this->windowY / 2, LARGE_CIRCLE_COLOR, this->windowY / 4, 1);
+
+  memcpy(gRVtx, gVtx, sizeof(tVertex) * NUM_OF_DOTS);
+
+#ifdef USE_FLOAT
+  rotz = idx /*tick*/ * 0.0005f;
+  roty = idx /*tick*/ * 0.0020f;
+#else
+  rotz = idx /*tick*/ * 50*5;
+  roty = idx /*tick*/ * 200*5;
+#endif
+  rotate_y(roty);
+  rotate_z(rotz);
+
+  for (i = 0; i < NUM_OF_DOTS; i++)
+  {
+    uint16_t c = SMALL_CIRCLE_FRONT_COLOR;
+
+    if (gRVtx[i].z < 0)
+      c = SMALL_CIRCLE_BACK_COLOR;
+#if 0
+    lcd_point(myLcdHnd,
+              (int)((gRVtx[i].x * (HEIGHT / 4)) / 0x7fff + WIDTH  / 2),
+              (int)((gRVtx[i].y * (HEIGHT / 4)) / 0x7fff + HEIGHT / 2),
+              c);
+#else
+//    lcd_fillcircle(myLcdHnd,
+//                   (int)((gRVtx[i].x * (HEIGHT / 4)) / 0x7fff + WIDTH / 2),
+//                   (int)((gRVtx[i].y * (HEIGHT / 4)) / 0x7fff + HEIGHT / 2),
+//                   2,
+//                   c);
+    graphics.put_circle((int)((gRVtx[i].x * (this->windowY / 4)) / 0x7fff + this->windowX / 2), (int)((gRVtx[i].y * (this->windowY / 4)) / 0x7fff + this->windowY / 2), c, 2, 1);
+
+#endif
+  } 
+#ifdef USE_FLOAT
+  lcd_fillcircle(myLcdHnd,
+                 (int)((WIDTH / 3) * cos(rotz) + WIDTH / 2),
+                 (int)((WIDTH / 3) * sin(rotz) + HEIGHT / 2),
+                 6,
+                 SMALL_CIRCLE_FRONT_COLOR);
+#else
+//  lcd_fillcircle(myLcdHnd,
+//                 (int)(((HEIGHT / 3) * icosine(rotz))/0x7fff + WIDTH / 2),
+//                 (int)(((HEIGHT / 3) * isine(rotz))  /0x7fff + HEIGHT / 2),
+//                 7,
+//                 SMALL_CIRCLE_FRONT_COLOR);
+    graphics.put_circle((int)(((this->windowY / 3) * icosine(rotz))/0x7fff + this->windowX / 2), (int)(((this->windowY / 3) * isine(rotz))  /0x7fff + this->windowY / 2), SMALL_CIRCLE_FRONT_COLOR, 7, 1);
+#endif
+}
+
+
+/******************************************************************************
+ * Public functions
+ *****************************************************************************/
+GlobeDemo::GlobeDemo(uint8_t *pFrameBuf, uint16_t dispWidth, uint16_t dispHeight) 
+    : graphics((uint16_t *)pFrameBuf, dispWidth, dispHeight) {
+
+    this->windowX = dispWidth;
+    this->windowY = dispHeight;
+    this->pFrmBuf  = (uint16_t *)pFrameBuf;
+    this->pFrmBuf1 = (uint16_t *)pFrameBuf;
+    this->pFrmBuf2 = (uint16_t *)((uint32_t)pFrameBuf + dispWidth*dispHeight*2);
+    this->pFrmBuf3 = (uint16_t *)((uint32_t)pFrameBuf + dispWidth*dispHeight*4);
+
+    initialize();
+}
+
+void GlobeDemo::run(EaLcdBoardGPIO& lcdBoard, uint32_t loops, uint32_t delayMs) {
+
+  printf("GlobeDemo, %d loops, %dms delay\n", loops, delayMs);
+  
+    for(int32_t n=0;n<loops;n++) {
+    
+        //render globe
+        render(n);
+    
+        //update framebuffer
+        lcdBoard.setFrameBuffer((uint32_t)this->pFrmBuf);
+
+        wait_ms(delayMs);
+    }
+    free(gRVtx);
+}
+
diff -r 000000000000 -r 79b286950b60 GlobeDemo.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GlobeDemo.h	Fri Oct 03 13:15:25 2014 +0000
@@ -0,0 +1,64 @@
+
+#ifndef GLOBEDEMO_H
+#define GLOBEDEMO_H
+
+#include "Graphics.h"
+#include "GFXFb.h"
+#include "EaLcdBoardGPIO.h"
+
+class GlobeDemo {
+public:
+
+    /** Set the address of the frame buffer to use.
+     *
+     *  It is the content of the frame buffer that is shown on the
+     *  display. All the drawing on the frame buffer can be done
+     *  'offline' and whenever it should be shown this function
+     *  can be called with the address of the offline frame buffer.
+     *
+     *  @param pFrameBuf  Pointer to the frame buffer, which must be
+     *                    3 times as big as the frame size (for tripple
+     *                    buffering).
+     *         dispWidth  The width of the display (in pixels).
+     *         dispHeight The height of the display (in pixels).
+     *         loops      Number of loops in the demo code.
+     *         delayMs    Delay in milliseconds between schreen updates.
+     *
+     *  @returns
+     *       none
+     */
+    GlobeDemo(uint8_t *pFrameBuf, uint16_t dispWidth, uint16_t dispHeight);
+    
+    void run(EaLcdBoardGPIO& lcdBoard, uint32_t loops, uint32_t delayMs);
+
+private:
+    enum Constants {
+        BACKGROUND_COLOR         = BLACK,
+        LARGE_CIRCLE_COLOR       = 0x39e7, //DARK_GRAY
+        SMALL_CIRCLE_FRONT_COLOR = WHITE,
+        SMALL_CIRCLE_BACK_COLOR  = 0x7bef, //LIGHT_GRAY
+    };
+
+    int32_t windowX;
+    int32_t windowY;
+    uint16_t *pFrmBuf;
+    uint16_t *pFrmBuf1;
+    uint16_t *pFrmBuf2;
+    uint16_t *pFrmBuf3;
+    
+    Graphics graphics;
+    
+    unsigned short isqrt(unsigned long a) const;
+    short _sin(short y) const;
+    short _cos(short y) const;
+    short isine(short x) const;
+    short icosine(short x) const;
+    void rotate_z(uint32_t angle);
+    void rotate_y(uint32_t angle);
+    void initialize();
+    void render(uint32_t idx);
+
+};
+
+#endif /* GLOBEDEMO_H */
+
diff -r 000000000000 -r 79b286950b60 Graphics.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Graphics.cpp	Fri Oct 03 13:15:25 2014 +0000
@@ -0,0 +1,241 @@
+
+#include "mbed.h"
+#include "Graphics.h"
+
+
+Graphics::Graphics(uint16_t *pFrmBuf, uint16_t dispWidth, uint16_t dispHeight)
+{
+	this->windowX = dispWidth;
+	this->windowY = dispHeight;
+	this->pFrmBuf = pFrmBuf;
+}
+
+void Graphics::setFrameBuffer( uint16_t *pFrmBuf )
+{
+	this->pFrmBuf = pFrmBuf;
+}
+
+int32_t Graphics::abs(int32_t v1) const
+{
+   if (v1 > 0)
+     return v1;
+
+  return -v1;
+}
+
+/***********************************************************************
+ *
+ * Function: swim_put_line_raw
+ *
+ * Purpose: Draw a line on the physical display
+ *
+ * Processing:
+ *     See function.
+ *
+ * Parameters:
+ *     win : Window identifier
+ *     x1  : Physical X position of X line start
+ *     y1  : Physical Y position of Y line start
+ *     x2  : Physical X position of X line end
+ *     y2  : Physical Y position of Y line end
+ *
+ * Outputs: None
+ *
+ * Returns: Nothing
+ *
+ * Notes: None
+ *
+ **********************************************************************/
+void Graphics::put_line(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int16_t color)
+{
+    int32_t e2, sx, sy, dx, dy, err;
+    
+    /* calculate delta_x and delta_y */
+    dx = abs(x2 - x1);
+    dy = abs(y2 - y1);
+
+    /* set the direction for the step for both x and y, and
+       initialize the error */
+    if (x1 < x2)
+        sx = 1;
+    else
+        sx = -1;
+
+    if (y1 < y2)
+        sy = 1;
+    else
+        sy = -1;
+
+    err = dx - dy;
+   
+    while (1)
+    {
+        if ((x1 >= 0) && (x1 < this->windowX) && 
+            (y1 >= 0) && (y1 < this->windowY))
+            this->pFrmBuf[x1 + (this->windowX*y1)] = color;
+
+        if ((x1 == x2) && (y1 == y2))
+            return;
+
+        e2 = 2 * err;
+        if (e2 > -dy)
+        {
+            err -= dy;
+            x1 += sx;
+        }
+        if (e2 < dx)
+        {
+            err += dx;
+            y1 += sy;
+        }
+    }
+}
+
+/***********************************************************************
+ *
+ * Function: plot4points
+ *
+ * Purpose:
+ *
+ * Processing:
+ *     See function.
+ *
+ * Parameters:
+ *     win    : Window identifier
+ *     cx     :
+ *     cy     :
+ *     x      :
+ *     y      :
+ *     Filled :
+ *
+ * Outputs: None
+ *
+ * Returns: Nothing
+ *
+ * Notes: None
+ *
+ **********************************************************************/
+void Graphics::plot4points( int32_t cx, int32_t cy, int32_t x, int32_t y, int16_t color, int32_t Filled )
+   {
+   int16_t x0, x1, y0, y1;
+
+   y0 = cy + y;
+   y1 = cy - y;
+   if( Filled )
+      {
+      for( x0=cx - x; x0<=cx + x; x0++ )
+         {
+         if ((x0>=0) && (x0<this->windowX) && (y0>=0) && (y0<this->windowY))
+            this->pFrmBuf[x0 + (this->windowX*y0)] = color;
+         if ((x0>=0) && (x0<this->windowX) && (y1>=0) && (y1<this->windowY))
+            this->pFrmBuf[x0 + (this->windowX*y1)] = color;
+         }
+      }
+   else
+      {
+      x0 = cx + x;
+      x1 = cx - x;
+      if ((x0>=0) && (x0<this->windowX) && (y0>=0) && (y0<this->windowY))
+         this->pFrmBuf[x0 + (this->windowX*y0)] = color;
+      if ((x != 0) && 
+          (x1>=0) && (x1<this->windowX) && (y0>=0) && (y0<this->windowY))
+         this->pFrmBuf[x1 + (this->windowX*y0)] = color;
+      if ((y != 0) &&
+          (x0>=0) && (x0<this->windowX) && (y1>=0) && (y1<this->windowY))
+         this->pFrmBuf[x0 + (this->windowX*y1)] = color;
+      if ((x != 0 && y != 0) &&
+          (x1>=0) && (x1<this->windowX) && (y1>=0) && (y1<this->windowY))
+         this->pFrmBuf[x1 + (this->windowX*y1)] = color;
+      }
+   }
+
+/***********************************************************************
+ *
+ * Function: plot8points
+ *
+ * Purpose:
+ *
+ * Processing:
+ *     See function.
+ *
+ * Parameters:
+ *     win    : Window identifier
+ *     cx     :
+ *     cy     :
+ *     x      :
+ *     y      :
+ *     Filled :
+ *
+ * Outputs: None
+ *
+ * Returns: Nothing
+ *
+ * Notes: None
+ *
+ **********************************************************************/
+void Graphics::plot8points( int32_t cx, int32_t cy, int32_t x, int32_t y, int16_t color, int32_t Filled )
+   {
+   plot4points( cx, cy, x, y, color, Filled );
+   if (x != y)
+      plot4points( cx, cy, y, x, color, Filled );
+   }
+
+/***********************************************************************
+ *
+ * Function: swim_put_circle
+ *
+ * Purpose:
+ *
+ * Processing:
+ *     See function.
+ *
+ * Parameters:
+ *     win    : Window identifier
+ *     cx     :
+ *     cy     :
+ *     radius :
+ *     Filled :
+ *
+ * Outputs: None
+ *
+ * Returns: Nothing
+ *
+ * Notes: None
+ *
+ **********************************************************************/
+void Graphics::put_circle( int32_t cx, int32_t cy, int16_t color, int32_t radius, int32_t Filled )
+   {
+   int32_t Error = -radius;
+   int16_t x = radius;
+   int16_t y = 0;
+
+   while( x >= y )
+      {
+      plot8points( cx, cy, x, y, color, Filled );
+
+      Error += y;
+      ++y;
+      Error += y;
+
+      if( Error >= 0 )
+         {
+         --x;
+         Error -= x;
+         Error -= x;
+         }
+      }
+   }
+
+void Graphics::put_dot( int32_t cx, int32_t cy, int16_t color )
+{
+  int size = 1;
+  for (int y1 = cy - size; y1 <= (cy + size); y1++) {
+    for (int x1 = cx - size; x1 <= (cx + size); x1++) {
+      if ((x1 >= 0) && (x1 < this->windowX) && (y1 >= 0) && (y1 < this->windowY)) {
+          this->pFrmBuf[x1 + (this->windowX*y1)] = color;
+      }
+    }
+  }
+}
+
+
diff -r 000000000000 -r 79b286950b60 Graphics.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Graphics.h	Fri Oct 03 13:15:25 2014 +0000
@@ -0,0 +1,29 @@
+
+#ifndef GRAPHICS_H
+#define GRAPHICS_H
+
+class Graphics {
+public:
+
+	Graphics(uint16_t *pFrmBuf, uint16_t dispWidth, uint16_t dispHeight);
+
+	void setFrameBuffer( uint16_t *pFrmBuf );
+	void put_line(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int16_t color);
+    void put_circle( int32_t cx, int32_t cy, int16_t color, int32_t radius, int32_t Filled );
+    void put_dot( int32_t cx, int32_t cy, int16_t color );
+
+protected:
+	uint16_t windowX;
+	uint16_t windowY;
+	uint16_t *pFrmBuf;
+	
+    int32_t abs(int32_t v1) const;
+    
+    virtual void plot4points( int32_t cx, int32_t cy, int32_t x, int32_t y, int16_t color, int32_t Filled );
+    void plot8points( int32_t cx, int32_t cy, int32_t x, int32_t y, int16_t color, int32_t Filled );
+    
+};
+
+#endif
+
+
diff -r 000000000000 -r 79b286950b60 TestDisplay.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestDisplay.cpp	Fri Oct 03 13:15:25 2014 +0000
@@ -0,0 +1,216 @@
+/*
+ *  Copyright 2013 Embedded Artists AB
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/******************************************************************************
+ * Includes
+ *****************************************************************************/
+
+#include "mbed.h"
+#include "TestDisplay.h"
+#include "sdram.h"
+
+#include "GlobeDemo.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+#define LCD_CONFIGURATION_43 \
+        40,                         /* horizontalBackPorch */ \
+        5,                          /* horizontalFrontPorch */ \
+        2,                          /* hsync */ \
+        480,                        /* width */ \
+        8,                          /* verticalBackPorch */ \
+        8,                          /* verticalFrontPorch */ \
+        2,                          /* vsync */ \
+        272,                        /* height */ \
+        false,                      /* invertOutputEnable */ \
+        false,                      /* invertPanelClock */ \
+        true,                       /* invertHsync */ \
+        true,                       /* invertVsync */ \
+        1,                          /* acBias */ \
+        LcdController::Bpp_16_565,  /* bpp */ \
+        9000000,                    /* optimalClock */ \
+        LcdController::Tft,         /* panelType */ \
+        false                       /* dualPanel */
+
+#define LCD_INIT_STRING_43  (char*)"v1,cd0,c50,cc0,c30,d100,c31,d100,cd1,d10,o,c51,cc100"
+
+#define LCD_CONFIGURATION_50 \
+        46,                         /* horizontalBackPorch */ \
+        20,                          /* horizontalFrontPorch */ \
+        2,                          /* hsync */ \
+        800,                        /* width */ \
+        23,                          /* verticalBackPorch */ \
+        10,                          /* verticalFrontPorch */ \
+        3,                          /* vsync */ \
+        480,                        /* height */ \
+        false,                      /* invertOutputEnable */ \
+        false,                      /* invertPanelClock */ \
+        true,                       /* invertHsync */ \
+        true,                       /* invertVsync */ \
+        1,                          /* acBias */ \
+        LcdController::Bpp_16_565,  /* bpp */ \
+        30000000,                   /* optimalClock */ \
+        LcdController::Tft,         /* panelType */ \
+        false                       /* dualPanel */
+
+#define LCD_INIT_STRING_50  (char*)"v1,cc0,c31,d50,o,d200,c51,cc100"
+
+#define MY_ABS(__a)  (((__a) < 0) ? -(__a) : (__a))
+
+/******************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+/*
+   Prerequisites:
+ 
+   - A display must be connected to the LPC4088 Experiment Base Board
+     with the FPC connector
+
+   - The touch controller uses the I2C bus so for this test to work 
+     jumpers JP8 and JP9 on the LPC4088 Experiment Base Board must 
+     both be in positions 1-2
+
+*/
+
+TestDisplay::TestDisplay(WhichDisplay which) : 
+    _initStr(NULL),
+    _lcdCfg(NULL),
+    _lcdBoard(P0_27, P0_28),
+    _touch(P0_27, P0_28, P2_25) {
+    
+    switch (which) {
+        case TFT_5:
+            _lcdCfg = new LcdController::Config(LCD_CONFIGURATION_50);
+            _initStr = LCD_INIT_STRING_50;
+            break;
+        case TFT_4_3:
+            _lcdCfg = new LcdController::Config(LCD_CONFIGURATION_43);
+            _initStr = LCD_INIT_STRING_43;
+            break;
+        default:
+            mbed_die();
+    }
+            
+    if (sdram_init() == 1) {
+        printf("Failed to initialize SDRAM\n");
+        _framebuffer = 0;
+    } else {
+        _framebuffer = (uint32_t) malloc(_lcdCfg->width * _lcdCfg->height * 2 * 3); // 2 is for 16 bit color, 3 is the number of buffers
+        if (_framebuffer != 0) {
+            memset((uint8_t*)_framebuffer, 0, _lcdCfg->width * _lcdCfg->height * 2 * 3);
+        }
+    }
+}
+
+TestDisplay::~TestDisplay() {
+    if (_framebuffer != 0) {
+        free((void*)_framebuffer);
+        _framebuffer = 0;
+    }
+}
+
+bool TestDisplay::runTest() {
+    do {
+        if (_framebuffer == 0) {
+            printf("Failed to allocate memory for framebuffer\n");
+            break;
+        }
+        
+        EaLcdBoard::Result result = _lcdBoard.open(_lcdCfg, _initStr);
+        if (result != EaLcdBoard::Ok) {
+            printf("Failed to open display, error %d\n", result);
+            break;
+        }
+
+        result = _lcdBoard.setFrameBuffer(_framebuffer);
+        if (result != EaLcdBoard::Ok) {
+            printf("Failed to set framebuffer, error %d\n", result);
+            break;
+        }
+        
+        GlobeDemo globeDemo((uint8_t *)_framebuffer, _lcdCfg->width, _lcdCfg->height);
+        while (1) {
+            globeDemo.run(_lcdBoard, 400, 30);
+        }
+    } while(0);
+    
+    return false;
+}
+
+void TestDisplay::calibrate_drawMarker(Graphics &g, uint16_t x, uint16_t y, bool erase) {
+    uint16_t color = (erase ? 0x0000 : 0xffff);
+    g.put_line(x-15, y, x+15, y, color);
+    g.put_line(x, y-15, x, y+15, color);
+    g.put_circle(x, y, color, 10, false);
+}
+
+bool TestDisplay::calibrate_display() {
+    bool morePoints = true;
+    uint16_t x, y;
+    int point = 0;
+    Graphics g((uint16_t*)_framebuffer, _lcdCfg->width, _lcdCfg->height);
+    
+    do {
+        if (!_touch.init(_lcdCfg->width, _lcdCfg->height)) {
+            printf("Failed to initialize touch controller\n");
+            break;
+        }
+        if (!_touch.calibrateStart()) {
+            printf("Failed to start calibration\n");
+            break;
+        }  
+        while (morePoints) {
+            if (point++ > 0) {
+                // erase old location
+                calibrate_drawMarker(g, x, y, true);
+            }
+            if (!_touch.getNextCalibratePoint(&x, &y)) {
+                printf("Failed to get calibration point\n");
+                break;
+            }
+            calibrate_drawMarker(g, x, y, false);
+            if (!_touch.waitForCalibratePoint(&morePoints, 0)) {
+                printf("Failed to get user click\n");
+                break;
+            }
+        }
+        if (morePoints) {
+            // aborted calibration due to error(s)
+            break;
+        }
+
+        // erase old location
+        calibrate_drawMarker(g, x, y, true);
+
+        // allow user to draw for 5999 seconds
+        Timer t;
+        t.start();
+        TouchPanel::touchCoordinate_t tc;
+        while(t.read() < 6000) {
+            if (_touch.read(tc)) {
+                //printf("TC: x,y,z = {%5d, %5d, %5d}\n", tc.x, tc.y, tc.z);
+                if (tc.z) {
+                    g.put_dot(tc.x, tc.y, 0xffff);
+                }
+            }
+        }
+    } while(0);
+    
+    return !morePoints;
+}
diff -r 000000000000 -r 79b286950b60 TestDisplay.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestDisplay.h	Fri Oct 03 13:15:25 2014 +0000
@@ -0,0 +1,63 @@
+/*
+ *  Copyright 2013 Embedded Artists AB
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+#ifndef TESTDISPLAY_H
+#define TESTDISPLAY_H
+
+#include "AR1021I2C.h"
+#include "Graphics.h"
+#include "LcdController.h"
+#include "EaLcdBoardGPIO.h"
+
+/**
+ * Test the display connected with a FPC cable to the LPC4088 Experiment Base Board
+ * as well as the AR1021 touch sensor on the board.
+ */
+class TestDisplay {
+public:
+	enum WhichDisplay {
+		TFT_5,    // 5" display
+		TFT_4_3,  // 4.3" display
+	};
+
+    /**
+     * Create an interface to the display
+     */
+    TestDisplay(WhichDisplay which);
+    ~TestDisplay();
+
+    /**
+     * Test the display
+     *
+     * @return true if the test was successful; otherwise false
+     */
+	bool runTest();
+
+private:
+
+    void calibrate_drawMarker(Graphics &g, uint16_t x, uint16_t y, bool erase);
+    bool calibrate_display();
+
+	char* _initStr;
+    LcdController::Config* _lcdCfg;
+    EaLcdBoardGPIO _lcdBoard;
+    AR1021I2C _touch;
+
+    uint32_t _framebuffer;
+};
+
+#endif
+
diff -r 000000000000 -r 79b286950b60 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Oct 03 13:15:25 2014 +0000
@@ -0,0 +1,46 @@
+/******************************************************************************
+ * Includes
+ *****************************************************************************/
+#include "mbed.h"
+
+#include "TestDisplay.h"
+
+/******************************************************************************
+ * Typedefs and defines
+ *****************************************************************************/
+
+
+/******************************************************************************
+ * Local variables
+ *****************************************************************************/
+
+DigitalOut myled(LED1);
+
+/******************************************************************************
+ * Local functions
+ *****************************************************************************/
+
+/*
+ * Test program for the 4.3" and 5" displays. This test is supposed to run
+ * on a LPC4088QSB board on an LPC4088 Experiment Base Board.
+ */
+
+
+int main() {
+    printf("\n"
+           "---\n"
+           "Display Demo Program for 4.3 and 5 inch display on the LPC4088 Experiment Base Board\n"
+           "Build Date: " __DATE__ " at " __TIME__ "\n"
+           "\n");
+
+    //TestDisplay display(TestDisplay::TFT_4_3);
+    TestDisplay display(TestDisplay::TFT_5);
+    display.runTest();
+    
+    while(1) {
+        myled = 1;
+        wait(0.2);
+        myled = 0;
+        wait(0.2);
+    }
+}
diff -r 000000000000 -r 79b286950b60 mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Fri Oct 03 13:15:25 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/552587b429a1
\ No newline at end of file