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:
Thu Aug 28 09:36:13 2014 +0000
Parent:
1:47680ec5d783
Child:
3:7ef908e84ae1
Commit message:
Moved each test into separate classes.

Changed in this revision

BubbleDemo.cpp Show diff for this revision Revisions of this file
BubbleDemo.h Show diff for this revision Revisions of this file
DmTftLibrary.lib Show diff for this revision Revisions of this file
TestAcc.cpp Show annotated file Show diff for this revision Revisions of this file
TestAcc.h Show annotated file Show diff for this revision Revisions of this file
TestAudio.cpp Show annotated file Show diff for this revision Revisions of this file
TestAudio.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
TestFileSystemMCI.cpp Show annotated file Show diff for this revision Revisions of this file
TestFileSystemMCI.h Show annotated file Show diff for this revision Revisions of this file
TestFileSystemSPI.cpp Show annotated file Show diff for this revision Revisions of this file
TestFileSystemSPI.h Show annotated file Show diff for this revision Revisions of this file
TestJoystick.cpp Show annotated file Show diff for this revision Revisions of this file
TestJoystick.h Show annotated file Show diff for this revision Revisions of this file
TestRGBLed.cpp Show annotated file Show diff for this revision Revisions of this file
TestRGBLed.h Show annotated file Show diff for this revision Revisions of this file
TestShiftreg.cpp Show annotated file Show diff for this revision Revisions of this file
TestShiftreg.h Show annotated file Show diff for this revision Revisions of this file
TestTemperature.cpp Show annotated file Show diff for this revision Revisions of this file
TestTemperature.h Show annotated file Show diff for this revision Revisions of this file
TestTrimpot.cpp Show annotated file Show diff for this revision Revisions of this file
TestTrimpot.h Show annotated file Show diff for this revision Revisions of this file
TextLCD.lib Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/BubbleDemo.cpp	Wed Aug 27 14:24:59 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,171 +0,0 @@
-/******************************************************************************
- * Includes
- *****************************************************************************/
-
-#include "mbed.h"
-
-#include "BubbleDemo.h"
-#include "DmTftBase.h"
-#include "wchar.h"
-
-/******************************************************************************
- * Typedefs and defines
- *****************************************************************************/
-
-#define PI 3.1415926535897932384626433832795
-
-/* Red color mask, 565 mode */
-#define REDMASK       0xF800
-/* Red shift value, 565 mode */
-#define REDSHIFT      11
-/* Green color mask, 565 mode */
-#define GREENMASK     0x07E0
-/* Green shift value, 565 mode */
-#define GREENSHIFT    5
-/* Blue color mask, 565 mode */
-#define BLUEMASK      0x001F
-/* Blue shift value, 565 mode */
-#define BLUESHIFT     0
-
-/* Number of colors in 565 mode */
-#define NUM_COLORS    65536
-/* Number of red colors in 565 mode */
-#define RED_COLORS    0x20
-/* Number of green colors in 565 mode */
-#define GREEN_COLORS  0x40
-/* Number of blue colors in 565 mode */
-#define BLUE_COLORS   0x20
-
-/******************************************************************************
- * Local variables
- *****************************************************************************/
-
-
-/******************************************************************************
- * External variables
- *****************************************************************************/
-
-
-/******************************************************************************
- * Local functions
- *****************************************************************************/
-
-
-void BubbleDemo::initialize() {
- float radian;
- const float phase1 = 2 * PI / 3;
- const float phase2 = 4 * PI / 3;
-
- for(i = 0; i < NumBalls; i++) {
-  x[i] = this->windowX / 2;
-  y[i] = this->windowY / 2;
-  r[i] = i * 2 + 10;
-
-  oldX[i] = x[i];
-  oldY[i] = y[i];
-
-  velX[i] = 1;
-  velY[i] = 1;
-
-  radian = i * 2 * PI / NumBalls;
-  red[i] = cos(radian) * RED_COLORS / 2 + (RED_COLORS / 2 - 1);
-  green[i] = cos(radian + phase2) * GREEN_COLORS / 2 + (GREEN_COLORS / 2 - 1);
-  blue[i] = cos(radian + phase1) * BLUE_COLORS / 2 + (BLUE_COLORS / 2 - 1);
- }
-}
-
-void BubbleDemo::collision() {
- float disX = x[j] - x[i];
- float disY = y[j] - y[i];
- float d2 = disX * disX + disY * disY;
-
- if(d2 != 0) {
-  float rij = r[i] + r[j];
-  float rij2 = rij * rij;
-
-  if(d2 < rij2) {
-   float ii = (disX * velX[i] + disY * velY[i]) / d2;
-   float ji = (disX * velY[i] - disY * velX[i]) / d2;
-   float ij = (disX * velX[j] + disY * velY[j]) / d2;
-   float jj = (disX * velY[j] - disY * velX[j]) / d2;
-   float ratio = rij / sqrt(d2);
-
-   velX[i] = ij * disX - ii * disY;
-   velY[i] = ij * disY + ii * disX;
-   velX[j] = ji * disX - jj * disY;
-   velY[j] = ji * disY + jj * disX;
-
-   disX *= (ratio - 1) / 2;
-   disY *= (ratio - 1) / 2;
-
-   x[j] += disX;
-   y[j] += disY;
-   x[i] -= disX;
-   y[i] -= disY;
-  }
- }
-}
-
-void BubbleDemo::borders() {
- if(x[i] >= this->windowX - r[i] - 1) {
-  x[i] = this->windowX - r[i] - 1;
-  velX[i] = -velX[i];
- } else if(x[i] <= r[i]) {
-  x[i] = r[i];
-  velX[i] = -velX[i];
- }
-
- if(y[i] >= this->windowY - r[i] - 1) {
-  y[i] = this->windowY - r[i] - 1;
-  velY[i] = -velY[i];
- } else if(y[i] <= r[i]) {
-  y[i] = r[i];
-  velY[i] = -velY[i];
- }
-}
-
-void BubbleDemo::draw() {
- tft->drawCircle(oldX[i], oldY[i], r[i], BLACK);
- tft->drawCircle(x[i], y[i], r[i], (red[i] << REDSHIFT) + (green[i] << GREENSHIFT) + (blue[i] << BLUESHIFT));
-
- oldX[i] = x[i];
- oldY[i] = y[i];
-}
-
-
-/******************************************************************************
- * Public functions
- *****************************************************************************/
- 
-BubbleDemo::BubbleDemo(DmTftBase* display, uint16_t dispWidth, uint16_t dispHeight) {
-
-    this->windowX = dispWidth;
-    this->windowY = dispHeight;
-    tft = display;
-
-    initialize();
-}
-
-void BubbleDemo::run(uint32_t loops, uint32_t delayMs) {
-  
-    tft->clearScreen();
-
-    for(int32_t n=0;n<loops;n++) {
-
-        for(i = 0; i < NumBalls; i++) {
-            x[i] += velX[i];
-            y[i] += velY[i];
-            
-            for(j = i + 1; j < NumBalls; j++)
-                collision();
-                
-            borders();
-            
-            if((int)x[i] != (int)oldX[i] || (int)y[i] != (int)oldY[i])
-                draw();
-        }
-
-        wait_ms(delayMs);
-    }
-}
-
--- a/BubbleDemo.h	Wed Aug 27 14:24:59 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-
-#ifndef BUBBLEDEMO_H
-#define BUBBLEDEMO_H
-
-#include "DmTftBase.h"
-
-class BubbleDemo {
-public:
-
-    enum Constants {
-        NumBalls = 4 // 17
-    };
-
-    /** 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
-     */
-    BubbleDemo(DmTftBase* display, uint16_t dispWidth, uint16_t dispHeight);
-    
-    void run(uint32_t loops, uint32_t delayMs);
-
-private:
-    int32_t windowX;
-    int32_t windowY;
-    
-    DmTftBase* tft;
-    
-    uint8_t i;
-    uint8_t j;
-    
-    float x[NumBalls];
-    float y[NumBalls];
-    uint8_t r[NumBalls];
-    
-    float oldX[NumBalls];
-    float oldY[NumBalls];
-    
-    float velX[NumBalls];
-    float velY[NumBalls];
-    
-    uint8_t red[NumBalls];
-    uint8_t green[NumBalls];
-    uint8_t blue[NumBalls];
-    
-    
-    void initialize();
-    void collision();
-    void borders();
-    void draw();
-};
-
-#endif /* BUBBLEDEMO_H */
-
-
--- a/DmTftLibrary.lib	Wed Aug 27 14:24:59 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/displaymodule/code/DmTftLibrary/#d263094e666d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestAcc.cpp	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,173 @@
+/*
+ *  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 "TestAcc.h"
+#include "MMA7455.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+#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 ACC_THRESHOLD  (2)
+
+/******************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+/*
+   Prerequisites:
+ 
+   - For this test to work jumpers JP8 and JP9 on the LPC4088 Experiment Base Board
+     must both be in positions 1-2
+*/
+
+bool TestAcc::runTest() {
+    MMA7455 sensor(P0_27, P0_28);
+
+    // Initialize the accelerometer
+    if (!sensor.setMode(MMA7455::ModeMeasurement)) {
+        printf("Unable to set mode for MMA7455!\n");
+        return false;
+    }
+
+    // Calibrate it. It does not matter if it is on a level surface
+    // as this test is only interested in relative values.
+    if (!sensor.calibrate()) {
+        printf("Failed to calibrate MMA7455!\n");
+        return false;
+    }
+
+    int val[3] = {    0,    0,    0};
+    int max[3] = {-1000,-1000,-1000};
+    int min[3] = { 1000, 1000, 1000};
+    int i;
+    Timer t;
+    t.start();
+    
+    // Read the x, y and z values every 100ms for up to five seconds.
+    // When the accelerometer is working those values will sightly vary
+    // even if the board is still. When a ACC_THRESHOLD difference has
+    // been detected in each of the three axis the test is considered
+    // successful.
+    while (t.read() < 5) {
+        if (!sensor.read(val[0], val[1], val[2])) {
+            printf("Failed to read accelerometer data!\n");
+            return false;
+        }
+        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]) < ACC_THRESHOLD) {
+                break;
+            }
+            if (i == 2) {
+                printf("All three axis work\n");
+                return true;
+            }
+        }
+        wait(0.1);
+    }
+    printf("Accelerometer data invalid\n");
+    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]);
+    return false;
+}
+
+bool TestAcc::alternativeTest() {
+    MMA7455 sensor(P0_27, P0_28);
+
+    // Initialize the accelerometer
+    if (!sensor.setMode(MMA7455::ModeMeasurement)) {
+        printf("Unable to set mode for MMA7455!\n");
+        return false;
+    }
+
+    // Calibrate it. The board must be on a flat surface 
+    // during calibration!
+    if (!sensor.calibrate()) {
+        printf("Failed to calibrate MMA7455!\n");
+        return false;
+    }
+
+    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();
+    
+    // Read the x, y and z values every 100ms for up to ten seconds.
+    // Lift and tilt the board along all axis and look at the printed
+    // output. There are ACC_MIN_LIMIT and ACC_MAX_LIMIT limits and 
+    // as the value of an axis passes that limit it is printed and 
+    // if all six limits (min/max for x,y and z) are passed within the
+    // time limit the test is considered successful.
+    while ((t.read() < 10) && (done != 0x3f)) {
+        if (!sensor.read(x, y, z)) {
+            printf("Failed to read accelerometer data!\n");
+            return false;
+        }
+        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");
+    return (t.read() < 10);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestAcc.h	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,47 @@
+/*
+ *  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 TESTACC_H
+#define TESTACC_H
+
+
+/**
+ * Test the MMA7455 accelerometer sensor on the 
+ * LPC4088 Experiment Base Board
+ */
+class TestAcc {
+public:
+
+    /**
+     * Test the accelerometer
+     *
+     * @return true if the test was successful; otherwise false
+     */
+	bool runTest();
+
+    /**
+     * Alternative test of the accelerometer
+     *
+     * @return true if the test was successful; otherwise false
+     */
+    bool alternativeTest();
+
+private:
+
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestAudio.cpp	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,52 @@
+/*
+ *  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 "TestAudio.h"
+#include "WM8731.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+/******************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+/*
+   Prerequisites:
+ 
+   - For this test to work jumpers JP8 and JP9 on the LPC4088 Experiment Base Board
+     must both be in positions 1-2
+     
+   - MIC cable, Line OUT, Headphone...
+*/
+
+bool TestAudio::runTest() {
+    printf("Testing audio...\n");
+    WM8731 audio(P0_27, P0_28);
+    if (!audio.writeCmd(WM8731::REG_R15_RESET, 0x0000)) {
+        printf("Failed to send command to audio codec\n");
+        return false;
+    }
+    return true;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestAudio.h	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,40 @@
+/*
+ *  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 TESTAUDIO_H
+#define TESTAUDIO_H
+
+
+/**
+ * Test the WM8731 audio codec and the audio connectors on 
+ * the LPC4088 Experiment Base Board
+ */
+class TestAudio {
+public:
+
+    /**
+     * Test the audio
+     *
+     * @return true if the test was successful; otherwise false
+     */
+	bool runTest();
+
+private:
+
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestDisplay.cpp	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,264 @@
+/*
+ *  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"
+
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+#define LCD_CONFIGURATION \
+        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  (char*)"v1,cd0,c50,cc0,c30,d100,c31,d100,cd1,d10,o,c51,cc100"
+
+/******************************************************************************
+ * 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
+
+*/
+
+/* 
+   Test Description:
+
+   - The SDRAM is initialized and a framebuffer is allocated
+   - Display is initialized and a color bar (red-green-blue) is shown
+   - The user have 10 seconds to test display contrast by turning the
+     right trimpot on the board
+   - The touch calibration is started and the user must press each of
+     the four crosshairs that appear.
+   - After calibration the display can be drawn upon for 5 seconds.
+   
+   Any failed part test will abort the sequence
+*/
+
+TestDisplay::TestDisplay() : 
+    _lcdCfg(LCD_CONFIGURATION),
+    _lcdBoard(P0_27, P0_28),
+    _touch(P0_27, P0_28, P2_25) {
+        
+    if (sdram_init() == 1) {
+        printf("Failed to initialize SDRAM\n");
+        _framebuffer = 0;
+    } else {
+        _framebuffer = (uint32_t) malloc(_lcdCfg.width * _lcdCfg.height * 2);
+    }
+    _displayWorking = false;
+}
+
+TestDisplay::~TestDisplay() {
+    if (_framebuffer != 0) {
+        free((void*)_framebuffer);
+        _framebuffer = 0;
+    }
+}
+
+void TestDisplay::showStatus(bool success) {
+    if (_displayWorking) {
+        if (success) {
+            // Green cannot be memsetted so it will have to be the
+            // more manual way
+            uint16_t* p = (uint16_t*)_framebuffer;
+            for (int x = _lcdCfg.width; x > 0; x--) {
+                for (int y = _lcdCfg.height; y > 0; y--) {
+                    *p++ = 0x07e0;
+                }
+            }
+        } else {
+            // Red is possible to set directly as 0xe0e0 in RGB565 have
+            // only significant RED bits set.
+            memset((uint8_t*)_framebuffer, 0xe0, _lcdCfg.width * _lcdCfg.height * 2); // RED
+        }
+    }    
+}
+
+bool TestDisplay::runTest() {
+    bool testPassed = false;
+    do {
+        if (_framebuffer == 0) {
+            printf("Failed to allocate memory for framebuffer\n");
+            break;
+        }
+        
+        // Prepare framebuffer
+        drawBars();
+
+        EaLcdBoard::Result result = _lcdBoard.open(&_lcdCfg, LCD_INIT_STRING);
+        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;
+        }
+            
+        printf("Initialized. Control contrast with right trimpot (8 seconds)\n");
+        AnalogIn trimpot(p15);
+        Timer t;
+        t.start();
+        int delays = 0;
+        float last = -0.999;
+        while (t.read() < 8) {
+            float f = trimpot.read();
+            if (f != last) {
+                last = f;
+                _lcdBoard.setBC(100*f); // contrast is in 0..100 and analog value is 0.000..1.000
+            }
+            wait(0.1);
+            
+            // Countdown
+            if (delays%10 == 0) {
+                printf("%ds\n", (80-delays)/10);
+            }
+            delays++;
+        }
+        
+        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");
+            break;
+        }
+
+        printf("Calibrate display\n");
+        testPassed = calibrate_display();
+    } while(0);
+    
+    _displayWorking = testPassed;
+    return testPassed;
+}
+
+void TestDisplay::drawBars() {
+    uint16_t* p = (uint16_t*)_framebuffer;
+    int third = _lcdCfg.width/3;
+    for (int y = 0; y < _lcdCfg.height; y++) {
+        int x;
+        for (x = 0; x < third; x++) {
+            *p = 0xf800;
+            p++;
+        }
+        for (; x < 2*third; x++) {
+            *p = 0x07e0;
+            p++;
+        }
+        for (; x < _lcdCfg.width; x++) {
+            *p = 0x001f;
+            p++;
+        }
+    }
+}
+
+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 5 seconds
+        Timer t;
+        t.start();
+        TouchPanel::touchCoordinate_t tc;
+        while(t.read() < 6) {
+            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;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestDisplay.h	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,65 @@
+/*
+ *  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:
+
+    /**
+     * Create an interface to the display
+     */
+    TestDisplay();
+    ~TestDisplay();
+
+    /**
+     * Use the RED or GREEN LEDs to signal failure/success
+     */
+	void showStatus(bool success);
+
+    /**
+     * Test the display
+     *
+     * @return true if the test was successful; otherwise false
+     */
+	bool runTest();
+
+private:
+
+    void drawBars(); 
+    void calibrate_drawMarker(Graphics &g, uint16_t x, uint16_t y, bool erase);
+    bool calibrate_display();
+
+    LcdController::Config _lcdCfg;
+    EaLcdBoardGPIO _lcdBoard;
+    AR1021I2C _touch;
+
+    uint32_t _framebuffer;
+    bool _displayWorking;
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestFileSystemMCI.cpp	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,71 @@
+/*
+ *  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 "TestFileSystemMCI.h"
+#include "MCIFileSystem.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+
+/******************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+/*
+   Prerequisites:
+ 
+   - For this test to work jumpers JP1..JP6 on the LPC4088 Experiment Base Board
+     must all be in positions 1-2, that is closest to the center of the board.
+ 
+   - The uSD card must be formatted as FAT or FAT32, NTFS will not work.
+ 
+   - This test expects a file with the name message.txt to exist in the
+     root folder on the uSD card. The file must be at least 10 bytes in
+     size and the first bytes must be eatest2014
+*/
+
+bool TestFileSystemMCI::runTest() {
+    // 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];
+        int num = fread(buf, 1, sizeof(buf), fp);
+        if (num >= 10) {
+            buf[10] = '\0';
+            if (strcmp(buf, "eatest2014") == 0) {
+                printf("MCI SD Card works!\n");
+                fclose(fp);
+                return true;
+            }
+            printf("Invalid data read from /mci/message.txt\n");
+        }
+        printf("Failed to read >= 10 bytes from /mci/message.txt\n");
+    }
+    printf("Failed to open /mci/message.txt\n");
+    return false;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestFileSystemMCI.h	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,40 @@
+/*
+ *  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 TESTFILESYSTEMMCI_H
+#define TESTFILESYSTEMMCI_H
+
+
+/**
+ * Test the MCI interface to the uSD connector on the 
+ * LPC4088 Experiment Base Board
+ */
+class TestFileSystemMCI {
+public:
+
+    /**
+     * Test the MCI file system
+     *
+     * @return true if the test was successful; otherwise false
+     */
+	bool runTest();
+
+private:
+
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestFileSystemSPI.cpp	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,75 @@
+/*
+ *  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 "TestFileSystemSPI.h"
+#include "SDFileSystem.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+
+/******************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+/*
+   Prerequisites:
+ 
+   - For this test to work jumpers JP1..JP6 on the LPC4088 Experiment Base Board
+     must all be in positions 2-3, that is closest to the edge of the board.
+ 
+   - The uSD card must be formatted as FAT or FAT32, NTFS will not work.
+ 
+   - This test expects a file with the name message.txt to exist in the
+     root folder on the uSD card. The file must be at least 10 bytes in
+     size and the first bytes must be eatest2014
+*/
+
+bool TestFileSystemSPI::runTest() {
+    // The LPC4088 Experiment Base Board does not have the CardDetect signal
+    // available so it must be set to NC here to work.
+    SDFileSystem spifs(p5, p6, p7, p8, "spi"); // mosi, miso, sclk, cs
+
+    // This test expects a file with the name message.txt to exist in the
+    // root folder on the uSD card. The file must be at least 10 bytes in
+    // size and the first bytes must be eatest2014.
+    FILE* fp = fopen("/spi/message.txt", "r");
+    
+    if (fp != NULL) {
+        char buf[20];
+        int num = fread(buf, 1, sizeof(buf), fp);
+        if (num >= 10) {
+            buf[10] = '\0';
+            if (strcmp(buf, "eatest2014") == 0) {
+                printf("SPI SD Card works!\n");
+                fclose(fp);
+                return true;
+            }
+            printf("Invalid data read from /spi/message.txt\n");
+        }
+        printf("Failed to read >= 10 bytes from /spi/message.txt\n");
+    }
+    printf("Failed to open /spi/message.txt\n");
+    return false;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestFileSystemSPI.h	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,40 @@
+/*
+ *  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 TESTFILESYSTEMSPI_H
+#define TESTFILESYSTEMSPI_H
+
+
+/**
+ * Test the SPI interface to the uSD connector on the 
+ * LPC4088 Experiment Base Board
+ */
+class TestFileSystemSPI {
+public:
+
+    /**
+     * Test the SPI file system
+     *
+     * @return true if the test was successful; otherwise false
+     */
+	bool runTest();
+
+private:
+
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestJoystick.cpp	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,68 @@
+/*
+ *  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 "TestJoystick.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+#define TIMEOUT  (100)
+
+/******************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+bool TestJoystick::runTest() {
+    DigitalIn up(p32);
+    DigitalIn down(p38);
+    DigitalIn left(p39);
+    DigitalIn right(p37);
+    DigitalIn center(p31);
+
+    printf("Reading joystick for %d seconds...\n", TIMEOUT/10);  
+    printf("Move it in all directions and click it!\n");
+    uint16_t mask = 0;
+
+    for (int i = 0; i < TIMEOUT; i++) {
+        bool line = false;
+        if (up.read() == 0) { printf("UP ");        line = true; mask |= 0x01; }
+        if (down.read() == 0) { printf("DOWN ");    line = true; mask |= 0x02; }
+        if (left.read() == 0) { printf("LEFT ");    line = true; mask |= 0x04; }
+        if (right.read() == 0) { printf("RIGHT ");  line = true; mask |= 0x08; }
+        if (center.read() == 0) { printf("CENTER ");line = true; mask |= 0x10; }
+        if (line) {
+            printf("\n");
+        }
+        if (mask == 0x1F) {
+            printf("All directions tested. Done!\n");
+            return true;
+        }
+        wait(0.1);
+        if (i%10 == 0) {
+            printf("%ds\n", (TIMEOUT-i)/10);
+        }
+    }
+    printf("Failed to detect all joystick directions\n");
+    return false;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestJoystick.h	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,39 @@
+/*
+ *  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 TESTJOYSTICK_H
+#define TESTJOYSTICK_H
+
+
+/**
+ * Test the joystick on the LPC4088 Experiment Base Board
+ */
+class TestJoystick {
+public:
+
+    /**
+     * Test the joystick
+     *
+     * @return true if the test was successful; otherwise false
+     */
+	bool runTest();
+
+private:
+
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestRGBLed.cpp	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,157 @@
+/*
+ *  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 "TestRGBLed.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+#define LED_ON   0
+#define LED_OFF  1
+
+#define BUTTON_PRESSED   0
+#define BUTTON_RELEASED  1
+
+/******************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+TestRGBLed::TestRGBLed(PinName red, PinName green, PinName blue, PinName button) :
+    _redPin(red), _greenPin(green), _bluePin(blue), _button(button) {
+       
+    _button.mode(PullUp);
+}
+
+void TestRGBLed::showStartupPattern() {
+    // Have to create the DigitalOut instances here (as opposed to
+    // create them in the constructor) as some of the pins are shared 
+    // with other functionality on the LPC4088 Experiment Base Board
+    DigitalOut ledRed(_redPin);
+    DigitalOut ledGreen(_greenPin);
+    DigitalOut ledBlue(_bluePin);
+
+    ledRed = LED_OFF;
+    ledGreen = LED_OFF;
+    ledBlue = LED_OFF;
+
+    for(int i=0; i<10; i++)
+    {
+        ledRed = LED_ON;
+        wait(0.05);
+        ledRed = LED_OFF;
+        wait(0.05);
+    }
+    wait(0.5);
+    for(int i=0; i<10; i++)
+    {
+        ledGreen = LED_ON;
+        wait(0.05);
+        ledGreen = LED_OFF;
+        wait(0.05);
+    }
+    wait(0.5);
+    for(int i=0; i<10; i++)
+    {
+        ledBlue = LED_ON;
+        wait(0.05);
+        ledBlue = LED_OFF;
+        wait(0.05);
+    }
+    wait(0.5);    
+}
+
+void TestRGBLed::showStatus(bool success) {
+    // Have to create the DigitalOut instances here (as opposed to
+    // create them in the constructor) as some of the pins are shared 
+    // with other functionality on the LPC4088 Experiment Base Board
+    DigitalOut ledRed(_redPin);
+    DigitalOut ledGreen(_greenPin);
+    DigitalOut ledBlue(_bluePin);
+
+    ledRed = LED_OFF;
+    ledGreen = LED_OFF;
+    ledBlue = LED_OFF;
+    if (success) {
+        ledGreen = LED_ON;
+    } else {
+        ledRed = LED_ON;
+    }
+}
+
+void TestRGBLed::waitForButtonClick() {
+    // wait for button to be pressed
+    while(_button.read() == BUTTON_RELEASED);
+    
+    // small delay to avoid contact bounce
+    wait_ms(40);
+    
+    // wait for button to be released
+    while(_button.read() == BUTTON_PRESSED);
+}
+
+bool TestRGBLed::runTest() {
+    // Have to create the DigitalOut instances here (as opposed to
+    // create them in the constructor) as some of the pins are shared 
+    // with other functionality on the LPC4088 Experiment Base Board
+    DigitalOut ledRed(_redPin);
+    DigitalOut ledGreen(_greenPin);
+    DigitalOut ledBlue(_bluePin);
+
+    printf("LED Tests: All off. Press button to continue\n");
+    ledRed = LED_OFF;
+    ledGreen = LED_OFF;
+    ledBlue = LED_OFF;
+    waitForButtonClick();
+
+    printf("LED Tests: RED on. Press button to continue\n");
+    ledRed = LED_ON;
+    ledGreen = LED_OFF;
+    ledBlue = LED_OFF;
+    waitForButtonClick();
+
+    printf("LED Tests: GREEN on. Press button to continue\n");
+    ledRed = LED_OFF;
+    ledGreen = LED_ON;
+    ledBlue = LED_OFF;
+    waitForButtonClick();
+
+    printf("LED Tests: BLUE on. Press button to continue\n");
+    ledRed = LED_OFF;
+    ledGreen = LED_OFF;
+    ledBlue = LED_ON;
+    waitForButtonClick();
+
+    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;
+
+    return true;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestRGBLed.h	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,69 @@
+/*
+ *  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 TESTRGBLED_H
+#define TESTRGBLED_H
+
+
+/**
+ * Test the RGB LED on the LPC4088 Experiment Base Board
+ */
+class TestRGBLed {
+public:
+
+    /**
+     * Create an interface to the RGB LED
+     *
+     * @param red  Pin for the RED LED
+     * @param green Pin for the GREEN LED
+     * @param blue Pin for the BLUE LED
+     * @param button Pin for the User Button on the LPC4088 QuickStart Board
+     */
+    TestRGBLed(PinName red=p25, PinName green=p28, PinName blue=p26, PinName button=p23);
+
+    /**
+     * Blink in pattern to show test start
+     */
+	void showStartupPattern();
+
+    /**
+     * Use the RED or GREEN LEDs to signal failure/success
+     */
+	void showStatus(bool success);
+
+    /**
+     * Wait for the user to press and release the User Button on the
+     * LPC4088 QuickStart Board.
+     */
+	void waitForButtonClick();
+
+    /**
+     * Test the RGB LEDs
+     *
+     * @return true if the test was successful; otherwise false
+     */
+	bool runTest();
+
+private:
+
+    PinName _redPin;
+    PinName _greenPin;
+    PinName _bluePin;
+    DigitalIn _button;
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestShiftreg.cpp	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,80 @@
+/*
+ *  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 "TestShiftreg.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+
+/******************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+TestShiftreg::TestShiftreg(PinName mosi, PinName miso, PinName sclk, PinName cs) :
+    _spi(mosi, miso, sclk), _cs(cs) {
+        
+    _cs = 1; // to get it in a known state
+    output(0x00);
+}
+
+bool TestShiftreg::runTest() {
+    output(0x1);
+    wait(0.1);
+    output(0x2);
+    wait(0.1);
+    output(0x4);
+    wait(0.1);
+    output(0x8);
+    wait(0.1);
+    output(0x10);
+    wait(0.1);
+    output(0x20);
+    wait(0.1);
+    output(0x40);
+    wait(0.1);
+    output(0x80);
+    wait(0.1);
+    output(0x40);
+    wait(0.1);
+    output(0x20);
+    wait(0.1);
+    output(0x10);
+    wait(0.1);
+    output(0x8);
+    wait(0.1);
+    output(0x4);
+    wait(0.1);
+    output(0x2);
+    wait(0.1);
+    output(0x1);
+    wait(0.1);
+    output(0x0);
+    return true;
+}
+
+void TestShiftreg::output(uint8_t value) {
+    _cs = 0;
+    _spi.write(value);
+    _cs = 1;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestShiftreg.h	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,53 @@
+/*
+ *  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 TESTSHIFTREG_H
+#define TESTSHIFTREG_H
+
+
+/**
+ * Test the shift register and the LEDs connected to it on 
+ * the LPC4088 Experiment Base Board
+ */
+class TestShiftreg {
+public:
+    
+    /**
+     * Create an interface to the shift register
+     *
+     */
+    TestShiftreg(PinName mosi=p5, PinName miso=p6, PinName sclk=p7, PinName cs=p30);
+
+    /**
+     * Test the shift register
+     *
+     * @return true if the test was successful; otherwise false
+     */
+	bool runTest();
+
+    /**
+     * Set a value in the shift register
+     */
+    void output(uint8_t value);
+
+private:
+    
+    SPI _spi;
+    DigitalOut _cs;
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestTemperature.cpp	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,78 @@
+/*
+ *  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 "TestTemperature.h"
+#include "LM75B.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+#define MIN_TEMP  (15.0f)
+#define MAX_TEMP  (45.0f)
+
+/******************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+/*
+   Prerequisites:
+ 
+   - For this test to work jumpers JP8 and JP9 on the LPC4088 Experiment Base Board
+     must both be in positions 1-2
+*/
+
+bool TestTemperature::runTest() {
+    //Create an LM75B object at 0x92/0x93 (ADDRESS_1)
+    LM75B sensor(P0_27, P0_28, LM75B::ADDRESS_1);
+
+    printf("Testing LM75 temperature sensor...\n");
+
+    // Test waits up to 5 seconds, sampling the temperature twice per second,
+    // for the sensor to produce a value in the MIN_TEMP to MAX_TEMP range.
+    
+    if (sensor.open()) {
+        printf("LM75 Device detected!\n");
+ 
+        int i = 10;
+        while (i--) {
+            float f = (float)sensor;
+
+            printf("Temp = %.3f\n", f);
+ 
+            if ((f >= MIN_TEMP) && (f <= MAX_TEMP)) {
+                printf("Temp in %.3f..%.3f range - test passed\n", MIN_TEMP, MAX_TEMP);
+                return true;
+            }
+            
+            //Sleep for 0.5 seconds
+            wait(0.5);
+        }
+        if (i == 0) {
+            printf("LM75 No temp in range %.3f..%.3f!\n", MIN_TEMP, MAX_TEMP);
+        }
+    } else {
+        printf("LM75 Device not detected!\n");
+    }  
+    return false;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestTemperature.h	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,40 @@
+/*
+ *  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 TESTTEMPERATURE_H
+#define TESTTEMPERATURE_H
+
+
+/**
+ * Test the LM75 temperature sensor on the 
+ * LPC4088 Experiment Base Board
+ */
+class TestTemperature {
+public:
+
+    /**
+     * Test the temperature sensor
+     *
+     * @return true if the test was successful; otherwise false
+     */
+	bool runTest();
+
+private:
+
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestTrimpot.cpp	Thu Aug 28 09:36:13 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.
+ */
+
+/******************************************************************************
+ * Includes
+ *****************************************************************************/
+
+#include "mbed.h"
+#include "TestTrimpot.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+#define MIN_VALUE  (0.010f)
+#define MAX_VALUE  (0.990f)
+
+/******************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+bool TestTrimpot::runTest() {
+    AnalogIn trimpot(p15);
+    bool min = false;
+    bool max = false;
+
+    printf("Reading trimpot for 5 seconds...\n");  
+
+    // Reads the analog value of the right trimpot every 100ms for
+    // up to five seconds or until both end limit have been reached.
+    for (int i = 0; i < 50; i++) {
+        float f = trimpot.read();
+        printf("Trimpot = %.3f\n", f);
+        if (f < MIN_VALUE) {
+            min = true;
+        } else if (f > MAX_VALUE) {
+            max = true;
+        }
+        if (min && max) {
+            printf("Test passed\n");
+            return true;
+        }
+
+        wait(0.1);
+    }
+    printf("Trimpot does not reach limits (%.3f - %.3f)!\n", MIN_VALUE, MAX_VALUE);
+    return false;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestTrimpot.h	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,39 @@
+/*
+ *  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 TESTTRIMPOT_H
+#define TESTTRIMPOT_H
+
+
+/**
+ * Test the right trimpot on the LPC4088 Experiment Base Board
+ */
+class TestTrimpot {
+public:
+
+    /**
+     * Test the trimpot
+     *
+     * @return true if the test was successful; otherwise false
+     */
+	bool runTest();
+
+private:
+
+};
+
+#endif
+
--- a/TextLCD.lib	Wed Aug 27 14:24:59 2014 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/wim/code/TextLCD/#59c4b8f648d4
--- a/main.cpp	Wed Aug 27 14:24:59 2014 +0000
+++ b/main.cpp	Thu Aug 28 09:36:13 2014 +0000
@@ -3,625 +3,32 @@
  *****************************************************************************/
 #include "mbed.h"
 
-#include "MCIFileSystem.h"
-#include "SDFileSystem.h"
-#include "LM75B.h"
-#include "MMA7455.h"
-#include "WM8731.h"
-#include "TextLCD.h"
-#include "DmTftHX8353C.h"
-#include "BubbleDemo.h"
-#include "AR1021I2C.h"
-#include "Graphics.h"
-
-#include "LcdController.h"
-#include "EaLcdBoardGPIO.h"
-#include "sdram.h"
+#include "TestRGBLed.h"
+#include "TestFileSystemMCI.h"
+#include "TestFileSystemSPI.h"
+#include "TestAcc.h"
+#include "TestTemperature.h"
+#include "TestTrimpot.h"
+#include "TestJoystick.h"
+#include "TestAudio.h"
+#include "TestShiftreg.h"
+#include "TestDisplay.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
-
-#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)
 
 /******************************************************************************
  * Local variables
  *****************************************************************************/
 
 DigitalOut myled(LED1);
-DigitalIn  button(p23);
-
-SPI shiftreg(p5, p6, p7);  // mosi, miso, sclk,
-DigitalOut shiftregCS(p30);
-
-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];
-    int num = fread(buf, 1, sizeof(buf), fp);
-    if (num >= 10) {
-      buf[10] = '\0';
-      if (strcmp(buf, "eatest2014") == 0) {
-        printf("MCI SD Card works!\n");
-        fclose(fp);
-        return;
-      }
-      handleError(STATE_ERR_MCIFS, "Invalid data read from /mci/message.txt\n");
-    }
-    handleError(STATE_ERR_MCIFS, "Failed to read >= 10 bytes from /mci/message.txt\n");
-  }
-  handleError(STATE_ERR_MCIFS, "Failed to open /mci/message.txt\n");
-}  
-
-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];
-    int num = fread(buf, 1, sizeof(buf), fp);
-    if (num >= 10) {
-      buf[10] = '\0';
-      if (strcmp(buf, "eatest2014") == 0) {
-        printf("SPI SD Card works!\n");
-        fclose(fp);
-        return;
-      }
-      handleError(STATE_ERR_SPIFS, "Invalid data read from /spi/message.txt\n");
-    }
-    handleError(STATE_ERR_SPIFS, "Failed to read >= 10 bytes from /spi/message.txt\n");
-  }
-  handleError(STATE_ERR_SPIFS, "Failed to open /spi/message.txt\n");
-}  
-
-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
-  if (!sensor.setMode(MMA7455::ModeMeasurement)) {
-     handleError(STATE_ERR_ACC, "Unable to set mode for MMA7455!\n");
-  }
-  
-  printf("Put on flat surface and press button to calibrate!\n");
-  while (button.read() != BUTTON_PRESSED) {}
-  while (button.read() == BUTTON_PRESSED) {}
-    
-  if (!sensor.calibrate()) {
-     handleError(STATE_ERR_ACC, "Failed to calibrate MMA7455!\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() < 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} %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", 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");
-    }  
-}
-
-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++) {
-    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)
-{
-    shiftregCS = 0;  
-    shiftreg.write(val);
-    shiftregCS = 1;
-}
-static void test_shiftreg()
-{
-   outputShiftReg(0x1);
-   wait(0.1);
-   outputShiftReg(0x2);
-   wait(0.1);
-   outputShiftReg(0x4);
-   wait(0.1);
-   outputShiftReg(0x8);
-   wait(0.1);
-   outputShiftReg(0x10);
-   wait(0.1);
-   outputShiftReg(0x20);
-   wait(0.1);
-   outputShiftReg(0x40);
-   wait(0.1);
-   outputShiftReg(0x80);
-   wait(0.1);
-   outputShiftReg(0x40);
-   wait(0.1);
-   outputShiftReg(0x20);
-   wait(0.1);
-   outputShiftReg(0x10);
-   wait(0.1);
-   outputShiftReg(0x8);
-   wait(0.1);
-   outputShiftReg(0x4);
-   wait(0.1);
-   outputShiftReg(0x2);
-   wait(0.1);
-   outputShiftReg(0x1);
-   wait(0.1);
-   outputShiftReg(0x0);
-}
-    
-
-static void test_joystick()
-{
-  DigitalIn up(p32);//p39);
-  DigitalIn down(p38);//p32);
-  DigitalIn left(p39);//p38);
-  DigitalIn right(p37);
-  DigitalIn center(p31);
-
-  printf("Reading joystick for 10 seconds or all directions...\n");  
-  uint16_t mask = 0;
-
-  for (int i = 0; i < 100; i++) {
-    bool line = false;
-    if (up.read() == 0) { printf("UP ");        line = true; mask |= 0x01; }
-    if (down.read() == 0) { printf("DOWN ");    line = true; mask |= 0x02; }
-    if (left.read() == 0) { printf("LEFT ");    line = true; mask |= 0x04; }
-    if (right.read() == 0) { printf("RIGHT ");  line = true; mask |= 0x08; }
-    if (center.read() == 0) { printf("CENTER ");line = true; mask |= 0x10; }
-    if (line) {
-      printf("\n");
-    }
-    if (mask == 0x1F) {
-        printf("All directions tested. Done!\n");
-        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("LED Tests: All off. Press button to continue\n");
-  *ledRed = LED_OFF;
-  *ledGreen = LED_OFF;
-  *ledBlue = LED_OFF;
-  waitForButtonClick();
-
-  printf("LED Tests: RED on. Press button to continue\n");
-  *ledRed = LED_ON;
-  *ledGreen = LED_OFF;
-  *ledBlue = LED_OFF;
-  waitForButtonClick();
-  
-  printf("LED Tests: GREEN on. Press button to continue\n");
-  *ledRed = LED_OFF;
-  *ledGreen = LED_ON;
-  *ledBlue = LED_OFF;
-  waitForButtonClick();
-  
-  printf("LED Tests: BLUE on. Press button to continue\n");
-  *ledRed = LED_OFF;
-  *ledGreen = LED_OFF;
-  *ledBlue = LED_ON;
-  waitForButtonClick();
-  
-  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");
-    }
-}
-
-static void test_TextLCD()
-{
-    SPI spi_lcd(p5, p6, p7); // MOSI, MISO, SCLK
-    TextLCD_SPI lcd(&spi_lcd, p30, TextLCD::LCD16x2); // SPI bus, CS pin, LCD Type ok
-    
-    lcd.cls();
-    lcd.locate(0, 0);
-    lcd.putc('E');
-    lcd.putc('m');
-    lcd.putc('b');
-    lcd.putc('e');
-    lcd.putc('d');
-    lcd.putc('d');
-    lcd.putc('e');
-    lcd.putc('d');
-    lcd.putc(' ');
-    lcd.putc('A');
-    lcd.putc('r');
-    lcd.putc('t');
-    lcd.putc('i');
-    lcd.putc('s');
-    lcd.putc('t');
-    lcd.putc('s');
-    lcd.putc('!');
-    lcd.setCursor(TextLCD::CurOff_BlkOn);
-}
-
-static void test_DisplayModule()
-{
-    // Test of DM-TFT18-101 display (http://www.displaymodule.com/collections/featured-modules/products/dm-tft18-101)
-    DmTftHX8353C tft(p5, p7, p30, p17, p16); // mosi, clk, cs, dc, rst
-    tft.init();
-    
-    BubbleDemo bubbleDemo(&tft, tft.width(), tft.height());
-    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)
 {
@@ -640,59 +47,71 @@
            "Build Date: " __DATE__ " at " __TIME__ "\n"
            "\n");
     
-    shiftregCS = 1;    
-    button.mode(PullUp);
+    // run all tests
+    int failed = 0;
     
-    resetLEDs();
-      
-    outputShiftReg(0x0);
+    TestRGBLed rgb;
+    TestFileSystemMCI mcifs;
+    TestAcc acc;
+//    TestFileSystemSPI spifs;
+    TestTemperature temp;
+    TestTrimpot trim;
+    TestJoystick joy;
+    TestAudio audio;
+    TestShiftreg shift;
+    TestDisplay display;
+    
+    //startup flash behaviour
+    rgb.showStartupPattern();
+    
+    if (!mcifs.runTest()) {
+        failed++;
+    }
+
+//    if (!spifs.runTest()) {
+//        failed++;
+//    }
     
-     //startup flash behaviour
-     for(int i=0; i<10; i++)
-     {
-       *ledRed = LED_ON;
-       wait(0.05);
-       *ledRed = LED_OFF;
-       wait(0.05);
-     }
-     wait(1.0);
-     for(int i=0; i<10; i++)
-     {
-       *ledGreen = LED_ON;
-       wait(0.05);
-       *ledGreen = LED_OFF;
-       wait(0.05);
-     }
-     wait(1.0);
-     for(int i=0; i<10; i++)
-     {
-       *ledBlue = LED_ON;
-       wait(0.05);
-       *ledBlue = LED_OFF;
-       wait(0.05);
-     }
-     wait(1.0);    
+    if (!acc.runTest()) {
+        failed++;
+    }
+
+    if (!temp.runTest()) {
+        failed++;
+    }
+    
+    if (!trim.runTest()) {
+        failed++;
+    }
 
-    test_micro_sd_card_mci();
-    resetLEDs(); // MCI interface disables the RGB LED
-//    test_micro_sd_card_spi();
-    test_acc();
-    test_lm75();
-    test_trimpot();
-    test_joystick();
-    test_rgb();
-    test_audio();
-    //test_TextLCD();
-    //test_DisplayModule();
+    if (!joy.runTest()) {
+        failed++;
+    }
+    
+    if (!rgb.runTest()) {
+        failed++;
+    }
+
+    if (!audio.runTest()) {
+        failed++;
+    }
 
-    test_Display();
-     
-    showTestResult();
-     
-    //waitForButtonClick();
+    if (!display.runTest()) {
+        failed++;
+    }
+    
+    if (failed == 0) {
+        printf("\n\n---\nTest PASSED\n\n");
+        printf("NOTE: The display as well as the shift register LEDs\n"
+               "      must be manually checked as well\n\n");
+    } else {
+        printf("\n\n---\nTest FAILED  (%d failed parts)\n\n", failed);
+    }
+    rgb.showStatus(failed == 0);
+    display.showStatus(failed == 0);
 
     while(1) {
-        test_shiftreg();
+        shift.runTest();
         myled = 1;
         wait(0.2);
         myled = 0;