Production Test Program (PTP) for the LPC4088 Experiment Base Board

Dependencies:   EALib I2S LM75B SDFileSystem mbed

Files at this revision

API Documentation at this revision

Comitter:
embeddedartists
Date:
Wed Aug 27 14:24:59 2014 +0000
Parent:
0:0d5190d379d3
Child:
2:2f4b7535ceb3
Commit message:
Got the display and touch to work. Only audio tests missing

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
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
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AR1021I2C.cpp	Wed Aug 27 14:24:59 2014 +0000
@@ -0,0 +1,562 @@
+/*
+ *  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 
+
+
+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;
+    char buff[10];
+    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
+            // 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  
+            char length = _i2c.read(1);         //data length
+
+            //we need to send a NACK on the last read. 
+            int i;
+            for (i = 0; i < (length-1); i++) {
+                buff[i] = _i2c.read(1);
+            }
+            buff[i] = _i2c.read(0);             //last returned data byte             
+            _i2c.stop();
+            
+            
+            if (header != 0x55) {
+                ret = AR1021_ERR_NO_HDR;
+                continue;
+            }
+            if (length < 2) {
+                ret = AR1021_ERR_INV_LEN;
+                continue;
+            }
+            if (buff[0] != AR1021_RESP_STAT_OK) {
+                ret = -buff[0];
+                continue;
+            }
+            if (buff[1] != cmd) {
+                ret = AR1021_ERR_INV_RESP;
+                continue;
+            }
+            
+            // copy data into response
+            if (respLen != NULL && respBuf != NULL) {
+                if ((length - 2) > *respLen) {
+                    // respBuf too small, only copy what fits
+                    for (i = 0; i < *respLen; i++) {
+                        respBuf[i] = buff[i+2];
+                    }
+                } else {
+                    // respBuf large enough, copy all
+                    for (i = 0; i < (length-2); i++) {
+                        respBuf[i] = buff[i+2];
+                    }
+                    *respLen = (length-2);
+                }
+            }
+            
+            // 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);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AR1021I2C.h	Wed Aug 27 14:24:59 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
+
--- a/EALib.lib	Mon Aug 25 13:15:27 2014 +0000
+++ b/EALib.lib	Wed Aug 27 14:24:59 2014 +0000
@@ -1,1 +1,1 @@
-https://mbed.org/users/embeddedartists/code/EALib/#529fb3f8f88b
+https://mbed.org/users/embeddedartists/code/EALib/#b3a179cc3d88
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EaLcdBoardGPIO.cpp	Wed Aug 27 14:24:59 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);
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EaLcdBoardGPIO.h	Wed Aug 27 14:24:59 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
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Graphics.cpp	Wed Aug 27 14:24:59 2014 +0000
@@ -0,0 +1,242 @@
+
+#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;
+      }
+    }
+  }
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Graphics.h	Wed Aug 27 14:24:59 2014 +0000
@@ -0,0 +1,68 @@
+
+#ifndef GRAPHICS_H
+#define GRAPHICS_H
+
+/**
+ * LcdController example
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "LcdController.h"
+ *
+ * LcdController::Config innolux(
+ *        45,
+ *        17,
+ *        2,
+ *        800,
+ *        22,
+ *        22,
+ *        2,
+ *        480,
+ *        false,
+ *        false,
+ *        true,
+ *        true,
+ *        true,
+ *        LcdController::Bpp_16_565,
+ *        36000000,
+ *        LcdController::Tft,
+ *        false);
+ *
+ * int main(void) {
+ *    LcdController lcd;
+ *
+ *    lcd.open(&innolux);
+ *    lcd.setFrameBuffer(frameBuffer);
+ *    lcd.setPower(true);
+ *
+ *    // draw on the frame buffer
+ *    ...
+ * }
+ * @endcode
+ */
+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
+
+
+
--- a/main.cpp	Mon Aug 25 13:15:27 2014 +0000
+++ b/main.cpp	Wed Aug 27 14:24:59 2014 +0000
@@ -11,18 +11,72 @@
 #include "TextLCD.h"
 #include "DmTftHX8353C.h"
 #include "BubbleDemo.h"
+#include "AR1021I2C.h"
+#include "Graphics.h"
+
+#include "LcdController.h"
+#include "EaLcdBoardGPIO.h"
+#include "sdram.h"
 
 /******************************************************************************
  * Typedefs and defines
  *****************************************************************************/
 
+#define ACC_XMIN  (1<<0)  
+#define ACC_XMAX  (1<<1)  
+#define ACC_YMIN  (1<<2)  
+#define ACC_YMAX  (1<<3)  
+#define ACC_ZMIN  (1<<4)  
+#define ACC_ZMAX  (1<<5)  
+  
+#define ACC_MIN_LIMIT  (-50)
+#define ACC_MAX_LIMIT  ( 50)
+
 #define BUTTON_PRESSED   0
 #define BUTTON_RELEASED  1
 
 #define LED_ON   0
 #define LED_OFF  1
 
-#define handleError(__a, __b)  printf("Error: %s\n", (__b)); mbed_die()
+#if 0
+    // Enters eternal loop
+    #define handleError(__a, __b) do { \
+        printf("Error " #__a ": %s\n", (__b)); \
+        resetLEDs(); \
+        ledRed = LED_ON; \
+        ledGreen = LED_OFF; \
+        ledBlue = LED_OFF; \
+        mbed_die(); \
+    } while(0)
+    
+    #define showTestResult() do {} while(0)   // Never used in this setup
+#else
+    bool allTestsPassed = true;
+    // Leaves error handling to the end of the program
+    #define handleError(__a, __b) do { \
+        printf("Error " #__a ": %s\n", (__b)); \
+        resetLEDs(); \
+        *ledRed = LED_ON; \
+        *ledGreen = LED_OFF; \
+        *ledBlue = LED_OFF; \
+        allTestsPassed = false; \
+        return; \
+    } while(0)
+    
+    #define showTestResult() do { \
+        resetLEDs(); \
+        *ledRed = LED_OFF; \
+        *ledGreen = LED_OFF; \
+        *ledBlue = LED_OFF; \
+        if (allTestsPassed) { \
+            printf("\n\nTest Result: PASSED\n\n"); \
+            *ledGreen = LED_ON; \
+        } else { \
+            printf("\n\nTest Result: FAILED\n\n"); \
+            *ledRed = LED_ON; \
+        } \
+    } while(0)
+#endif
 
 #define waitForButtonClick()  do {while(button.read() == BUTTON_RELEASED); while(button.read() == BUTTON_PRESSED);} while(false)
 
@@ -30,25 +84,47 @@
  * Local variables
  *****************************************************************************/
 
-//MCIFileSystem mcifs("mci");//, P4_16);
-SDFileSystem spifs(p5, p6, p7, p8, "spi"); // mosi, miso, sclk, cs
-
 DigitalOut myled(LED1);
 DigitalIn  button(p23);
 
 SPI shiftreg(p5, p6, p7);  // mosi, miso, sclk,
 DigitalOut shiftregCS(p30);
 
-DigitalOut ledRed(p25);
-DigitalOut ledGreen(p28);
-DigitalOut ledBlue(p26);
+DigitalOut* ledRed = NULL;
+DigitalOut* ledGreen = NULL;
+DigitalOut* ledBlue = NULL;
 
 /******************************************************************************
  * Local functions
  *****************************************************************************/
 
+static void resetLEDs()
+{
+    // Some peripherals may interfer with the RGB LED and as a result it
+    // may be needed to reinitialize them so that PIN is again an GPIO.
+    if (ledRed != NULL) {
+        delete ledRed;
+    }
+    if (ledGreen != NULL) {
+        delete ledGreen;
+    }
+    if (ledBlue != NULL) {
+        delete ledBlue;
+    }
+    ledRed = new DigitalOut(p25);
+    ledGreen = new DigitalOut(p28);
+    ledBlue = new DigitalOut(p26);
+
+    *ledRed = LED_OFF;
+    *ledGreen = LED_OFF;
+    *ledBlue = LED_OFF;
+}
+
 static void test_micro_sd_card_mci()
 {
+  // The LPC4088 Experiment Base Board does not have the CardDetect signal
+  // available so it must be set to NC here to work.
+  MCIFileSystem mcifs("mci", NC);
   FILE* fp = fopen("/mci/message.txt", "r");
   if (fp != NULL) {
     char buf[20];
@@ -69,6 +145,7 @@
 
 static void test_micro_sd_card_spi()
 {
+  SDFileSystem spifs(p5, p6, p7, p8, "spi"); // mosi, miso, sclk, cs
   FILE* fp = fopen("/spi/message.txt", "r");
   if (fp != NULL) {
     char buf[20];
@@ -89,6 +166,52 @@
 
 static void test_acc()
 {
+#if 1
+  MMA7455 sensor(P0_27, P0_28);
+  
+  //Try to initialize the accelerometer
+  if (!sensor.setMode(MMA7455::ModeMeasurement)) {
+     handleError(STATE_ERR_ACC, "Unable to set mode for MMA7455!\n");
+  }
+  
+  if (!sensor.calibrate()) {
+     handleError(STATE_ERR_ACC, "Failed to calibrate MMA7455!\n");
+  }
+
+  int val[3] = {    0,    0,    0};
+  int max[3] = {-1000,-1000,-1000};
+  int min[3] = { 1000, 1000, 1000};
+  int i;
+  Timer t;
+  t.start();
+  while (t.read() < 5) {
+    if (!sensor.read(val[0], val[1], val[2])) {
+      handleError(STATE_ERR_ACC, "Failed to read accelerometer data!\n");
+    }
+    printf("ACC: x,y,z = {%5d, %5d, %5d}\n", val[0], val[1], val[2]);
+    for (i = 0; i < 3; i++) {
+      if (val[i] < min[i]) {
+        min[i] = val[i];
+      }
+      if (val[i] > max[i]) {
+        max[i] = val[i];
+      }
+    }
+    for (i = 0; i < 3; i++) {
+      if ((max[i] - min[i]) < 2) {
+        break;
+      }
+      if (i == 2) {
+        printf("All three axis work\n");
+        return;
+      }
+    }
+    wait(0.1);
+  }
+  printf("Not enough variation X {%d..%d}, Y {%d..%d}, Z {%d..%d}!\n",
+              min[0], max[0], min[1], max[1], min[2], max[2]);
+  handleError(STATE_ERR_ACC, "Accelerometer data invalid\n");
+#else
   MMA7455 sensor(P0_27, P0_28);
   
   //Try to initialize the accelerometer
@@ -104,37 +227,73 @@
      handleError(STATE_ERR_ACC, "Failed to calibrate MMA7455!\n");
   }
   
-  printf("Printing values for the next 5 seconds...\n");
+  printf("Now tilt the board in all directions (max 10 seconds)...\n");
   int x=0, y=0, z=0;
+  uint8_t done = 0;
+  char msg[30] = {0};
   
   Timer t;
   t.start();
-  while (t.read() < 6) {
+  while ((t.read() < 10) && (done != 0x3f)) {
     if (!sensor.read(x, y, z)) {
       handleError(STATE_ERR_ACC, "Failed to read accelerometer data!\n");
     }
-    printf("ACC: x,y,z = {%5d, %5d, %5d}\n", x, y, z);
+    printf("ACC: x,y,z = {%5d, %5d, %5d} %s\n", x, y, z, msg);
+    if ((x < ACC_MIN_LIMIT) && !(done & ACC_XMIN)) {
+        done |= ACC_XMIN;
+        printf("Tilted XMIN\n");
+    } else if ((x > ACC_MAX_LIMIT) && !(done & ACC_XMAX)) {
+        done |= ACC_XMAX;
+        printf("Tilted XMAX\n");
+    }
+    if ((y < ACC_MIN_LIMIT) && !(done & ACC_YMIN)) {
+        done |= ACC_YMIN;
+        printf("Tilted YMIN\n");
+    } else if ((y > ACC_MAX_LIMIT) && !(done & ACC_YMAX)) {
+        done |= ACC_YMAX;
+        printf("Tilted XMAX\n");
+    }
+    if ((z < ACC_MIN_LIMIT) && !(done & ACC_ZMIN)) {
+        done |= ACC_ZMIN;
+        printf("Tilted ZMIN\n");
+    } else if ((z > ACC_MAX_LIMIT) && !(done & ACC_ZMAX)) {
+        done |= ACC_ZMAX;
+        printf("Tilted ZMAX\n");
+    }
+    wait(0.1);
   }
   printf("Done with ACC tests!\n");
+#endif
 }
 
 static void test_lm75()
 {
   //Create an LM75B object at 0x92/0x93 (ADDRESS_1)
   LM75B sensor(P0_27, P0_28, LM75B::ADDRESS_1);
-  
+
+  printf("Testing LM75 temperature sensor...\n");
+    
     //Try to open the LM75B
     if (sensor.open()) {
         printf("LM75 Device detected!\n");
  
         int i = 10;
         while (i--) {
+            float f = (float)sensor;
             //Print the current temperature
-            printf("Temp = %.3f\n", (float)sensor);
+            printf("Temp = %.3f\n", f);
  
+            if ((f >= 15) && (f <= 45)) {
+                printf("Temp in 15..45 range - test passed\n");
+                break;
+            }
+            
             //Sleep for 0.5 seconds
             wait(0.5);
         }
+        if (i == 0) {
+            handleError(STATE_ERR_LM75, "LM75 No temp in range 15..45!\n");
+        }
     } else {
         handleError(STATE_ERR_LM75, "LM75 Device not detected!\n");
     }  
@@ -143,13 +302,27 @@
 static void test_trimpot()
 {
   AnalogIn trimpot(p15);
+  bool min = false;
+  bool max = false;
 
   printf("Reading trimpot for 5 seconds...\n");  
 
   for (int i = 0; i < 50; i++) {
-    printf("Trimpot = %.3f\n", trimpot.read());
+    float f = trimpot.read();
+    printf("Trimpot = %.3f\n", f);
+    if (f < 0.01f) {
+        min = true;
+    } else if (f > 0.99f) {
+        max = true;
+    }
+    if (min && max) {
+        printf("Test passed\n");
+        return;
+    }
+    
     wait(0.1);
-  }  
+  }
+  handleError(STATE_ERR_TRIMPOT, "Trimpot does not reach limits (0.01 - 0.99)!\n");
 }
 
 static void outputShiftReg(uint8_t val)
@@ -217,47 +390,57 @@
     }
     if (mask == 0x1F) {
         printf("All directions tested. Done!\n");
-        break;
+        return;
     }
     wait(0.1);
-  }  
+    if (i%10 == 0) {
+      printf("%ds\n", (100-i)/10);
+    }
+  }
+  handleError(STATE_ERR_JOYSTICK, "Failed to detect all joystick directions\n");
 }
 
 static void test_rgb()
 {
-  printf("All off. Press button to continue\n");
-  ledRed = LED_OFF;
-  ledGreen = LED_OFF;
-  ledBlue = LED_OFF;
+  printf("LED Tests: All off. Press button to continue\n");
+  *ledRed = LED_OFF;
+  *ledGreen = LED_OFF;
+  *ledBlue = LED_OFF;
   waitForButtonClick();
 
-  printf("RED on. Press button to continue\n");
-  ledRed = LED_ON;
-  ledGreen = LED_OFF;
-  ledBlue = LED_OFF;
+  printf("LED Tests: RED on. Press button to continue\n");
+  *ledRed = LED_ON;
+  *ledGreen = LED_OFF;
+  *ledBlue = LED_OFF;
   waitForButtonClick();
   
-  printf("GREEN on. Press button to continue\n");
-  ledRed = LED_OFF;
-  ledGreen = LED_ON;
-  ledBlue = LED_OFF;
+  printf("LED Tests: GREEN on. Press button to continue\n");
+  *ledRed = LED_OFF;
+  *ledGreen = LED_ON;
+  *ledBlue = LED_OFF;
   waitForButtonClick();
   
-  printf("BLUE on. Press button to continue\n");
-  ledRed = LED_OFF;
-  ledGreen = LED_OFF;
-  ledBlue = LED_ON;
+  printf("LED Tests: BLUE on. Press button to continue\n");
+  *ledRed = LED_OFF;
+  *ledGreen = LED_OFF;
+  *ledBlue = LED_ON;
   waitForButtonClick();
   
-  printf("All on. Press button to continue\n");
-  ledRed = LED_OFF;
-  ledGreen = LED_OFF;
-  ledBlue = LED_OFF;
+  printf("LED Tests: All on. Press button to continue\n");
+  *ledRed = LED_ON;
+  *ledGreen = LED_ON;
+  *ledBlue = LED_ON;
   waitForButtonClick();
+
+  // Turn them off again
+  *ledRed = LED_OFF;
+  *ledGreen = LED_OFF;
+  *ledBlue = LED_OFF;
 }
 
 static void test_audio()
 {
+    printf("Testing audio...\n");
     WM8731 audio(P0_27, P0_28);
     if (!audio.writeCmd(WM8731::REG_R15_RESET, 0x0000)) {
         handleError(STATE_ERR_AUDIO, "Failed to send command to audio codec\n");
@@ -301,45 +484,197 @@
     bubbleDemo.run(750, 20);
 }
 
+static void drawBars(int w, int h, uint32_t frameBuf)
+{
+    uint16_t* p = (uint16_t*)frameBuf;
+    int third = w/3;
+    for (int y = 0; y < h; y++) {
+        int x;
+        for (x = 0; x < third; x++) {
+            *p = 0xf800;
+            p++;
+        }
+        for (; x < 2*third; x++) {
+            *p = 0x07e0;
+            p++;
+        }
+        for (; x < w; x++) {
+            *p = 0x001f;
+            p++;
+        }
+    }
+}
+
+static void 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);
+}
+
+static void calibrate_display(TouchPanel* tp, uint32_t framebuffer, LcdController::Config &lcd)
+{
+  bool morePoints = true;
+  uint16_t x, y;
+  int point = 0;
+  Graphics g((uint16_t*)framebuffer, lcd.width, lcd.height);
+  if (!tp->init(lcd.width, lcd.height)) {
+    handleError(STATE_ERR_TOUCH, "Failed to initialize touch controller\n");
+  }
+  if (!tp->calibrateStart()) {
+    handleError(STATE_ERR_TOUCH, "Failed to start calibration\n");
+  }  
+  while (morePoints) {
+    if (point++ > 0) {
+      // erase old location
+      calibrate_drawMarker(g, x, y, true);
+    }
+    if (!tp->getNextCalibratePoint(&x, &y)) {
+      handleError(STATE_ERR_TOUCH, "Failed to get calibration point\n");
+    }
+      calibrate_drawMarker(g, x, y, false);
+    if (!tp->waitForCalibratePoint(&morePoints, 0)) {
+      handleError(STATE_ERR_TOUCH, "Failed to get user click\n");
+    }
+  }
+  
+  // erase old location
+  calibrate_drawMarker(g, x, y, true);
+  
+  // allow user to draw for 5 seconds
+  Timer t;
+  t.start();
+  TouchPanel::touchCoordinate_t tc;
+  while(t.read() < 6) {
+    if (tp->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);
+      }
+    }
+  }
+}
+
+static void test_Display()
+{
+    if (sdram_init() == 1) {
+        handleError(STATE_ERR_MEM, "Failed to initialize SDRAM\n");
+    }
+    
+    // Test of display attached with FPC connector, 0.5mm pitch
+    EaLcdBoard::Result result;
+    LcdController::Config lcdCfg(40, 5, 2, 480, 8, 8, 2, 272, false, false, true, true, 1, LcdController::Bpp_16_565, 9000000, LcdController::Tft, false);
+    char* initStr = "v1,cd0,c50,cc0,c30,d100,c31,d100,cd1,d10,o,c51,cc100";
+    EaLcdBoardGPIO lcdBoard(P0_27, P0_28);
+    int num = lcdCfg.width * lcdCfg.height * 2;
+    
+    uint32_t frameBuf = (uint32_t) malloc(num);
+    if (frameBuf == 0) {
+        handleError(STATE_ERR_MEM, "Failed to allocate memory for framebuffer\n");
+    }
+    drawBars(lcdCfg.width, lcdCfg.height, frameBuf);
+
+    result = lcdBoard.open(&lcdCfg, initStr);
+    if (result != EaLcdBoard::Ok) {
+        printf("Error Code: %d\n", result);
+        handleError(STATE_ERR_MEM, "Failed to open display\n");
+    }
+
+    result = lcdBoard.setFrameBuffer(frameBuf);
+    if (result != EaLcdBoard::Ok) {
+        printf("Error Code: %d\n", result);
+        handleError(STATE_ERR_MEM, "Failed to set framebuffer\n");
+    }
+        
+    printf("Initialized. Control contrast with right trimpot (8 seconds)\n");
+    AnalogIn trimpot(p15);
+    Timer t;
+    t.start();
+    int delays = 0;
+    float last = -0.365;
+    while (t.read() < 8) {
+        float f = trimpot.read();
+        if (f != last) {
+            last = f;
+            lcdBoard.setBC(100*f);
+        }
+        wait(0.1);
+        if (delays%10 == 0) {
+            printf("%ds\n", (80-delays)/10);
+        }
+        delays++;
+    }
+    
+    AR1021I2C touch(P0_27, P0_28, P2_25);
+    int vh,vl,r,ty;
+    if (touch.info(&vh,&vl,&r,&ty)) {
+        printf("Touch info: v%d.%d, %d-bit resolution, type 0x%x\n", vh, vl, r, ty);
+    } else {
+        printf("Failed to read touch information\n");
+    }
+
+    printf("Calibrate display\n");
+    calibrate_display(&touch, frameBuf, lcdCfg);
+    if (allTestsPassed) {
+        memset((uint8_t*)frameBuf, 0x03, num); // GREEN
+    } else {
+        memset((uint8_t*)frameBuf, 0xe0, num); // RED
+    }
+}
+
+static void setupSerial(int baudrate)
+{
+    // This works because both the default serial (used by printf) and the s instance
+    // (used by s.printf) would use the same underlying UART code so setting the baudrate
+    // in one affects the other.
+    Serial s(USBTX, USBRX);
+    s.baud(baudrate);
+}
+
 int main() {
-    printf("hello! " __DATE__ " at " __TIME__ "\n");
+    setupSerial(115200);
+    printf("\n"
+           "---\n"
+           "Production Test Program: LPC4088 Experiment Base Board\n"
+           "Build Date: " __DATE__ " at " __TIME__ "\n"
+           "\n");
     
     shiftregCS = 1;    
     button.mode(PullUp);
     
-    ledRed = LED_OFF;
-    ledGreen = LED_OFF;
-    ledBlue = LED_OFF;
+    resetLEDs();
       
     outputShiftReg(0x0);
     
      //startup flash behaviour
      for(int i=0; i<10; i++)
      {
-       ledRed = LED_ON;
+       *ledRed = LED_ON;
        wait(0.05);
-       ledRed = LED_OFF;
+       *ledRed = LED_OFF;
        wait(0.05);
      }
      wait(1.0);
      for(int i=0; i<10; i++)
      {
-       ledGreen = LED_ON;
+       *ledGreen = LED_ON;
        wait(0.05);
-       ledGreen = LED_OFF;
+       *ledGreen = LED_OFF;
        wait(0.05);
      }
      wait(1.0);
      for(int i=0; i<10; i++)
      {
-       ledBlue = LED_ON;
+       *ledBlue = LED_ON;
        wait(0.05);
-       ledBlue = LED_OFF;
+       *ledBlue = LED_OFF;
        wait(0.05);
      }
      wait(1.0);    
 
-    //test_micro_sd_card_mci();
+    test_micro_sd_card_mci();
+    resetLEDs(); // MCI interface disables the RGB LED
 //    test_micro_sd_card_spi();
     test_acc();
     test_lm75();
@@ -349,7 +684,12 @@
     test_audio();
     //test_TextLCD();
     //test_DisplayModule();
-    waitForButtonClick();
+
+    test_Display();
+     
+    showTestResult();
+     
+    //waitForButtonClick();
 
     while(1) {
         test_shiftreg();