The wait in mci_WaitForEvent will delay all card transactions.

Dependencies:   FATFileSystem

Fork of EALib by EmbeddedArtists AB

Files at this revision

API Documentation at this revision

Comitter:
embeddedartists
Date:
Thu Sep 26 06:37:02 2013 +0000
Child:
1:f3ef2b577bf6
Commit message:
First version

Changed in this revision

Adafruit_GFX.cpp Show annotated file Show diff for this revision Revisions of this file
Adafruit_GFX.h Show annotated file Show diff for this revision Revisions of this file
EaLcdBoard.cpp Show annotated file Show diff for this revision Revisions of this file
EaLcdBoard.h Show annotated file Show diff for this revision Revisions of this file
GFXFb.cpp Show annotated file Show diff for this revision Revisions of this file
GFXFb.h Show annotated file Show diff for this revision Revisions of this file
LcdController.cpp Show annotated file Show diff for this revision Revisions of this file
LcdController.h Show annotated file Show diff for this revision Revisions of this file
MCIFileSystem.cpp Show annotated file Show diff for this revision Revisions of this file
MCIFileSystem.h Show annotated file Show diff for this revision Revisions of this file
QSPIFileSystem.cpp Show annotated file Show diff for this revision Revisions of this file
QSPIFileSystem.h Show annotated file Show diff for this revision Revisions of this file
TSC2046.cpp Show annotated file Show diff for this revision Revisions of this file
TSC2046.h Show annotated file Show diff for this revision Revisions of this file
glcdfont.c Show annotated file Show diff for this revision Revisions of this file
gpdma.cpp Show annotated file Show diff for this revision Revisions of this file
gpdma.h Show annotated file Show diff for this revision Revisions of this file
sdram.cpp Show annotated file Show diff for this revision Revisions of this file
sdram.h Show annotated file Show diff for this revision Revisions of this file
spifi_rom_api.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Adafruit_GFX.cpp	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,479 @@
+/*
+This is the core graphics library for all our displays, providing a common
+set of graphics primitives (points, lines, circles, etc.).  It needs to be
+paired with a hardware-specific library for each display device we carry
+(to handle the lower-level functions).
+
+Adafruit invests time and resources providing this open source code, please
+support Adafruit & open-source hardware by purchasing products from Adafruit!
+
+Copyright (c) 2013 Adafruit Industries.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+- Redistributions of source code must retain the above copyright notice,
+  this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mbed.h"
+#include "Adafruit_GFX.h"
+#include "glcdfont.c"
+#ifdef __AVR__
+#include <avr/pgmspace.h>
+#else
+#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
+#endif
+
+Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h):
+WIDTH(w), HEIGHT(h)
+{
+    _width    = WIDTH;
+    _height   = HEIGHT;
+    rotation  = 0;
+    cursor_y  = cursor_x    = 0;
+    textsize  = 1;
+    textcolor = textbgcolor = 0xFFFF;
+    wrap      = true;
+}
+
+// Draw a circle outline
+void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r,
+        uint16_t color) {
+    int16_t f = 1 - r;
+    int16_t ddF_x = 1;
+    int16_t ddF_y = -2 * r;
+    int16_t x = 0;
+    int16_t y = r;
+
+    drawPixel(x0  , y0+r, color);
+    drawPixel(x0  , y0-r, color);
+    drawPixel(x0+r, y0  , color);
+    drawPixel(x0-r, y0  , color);
+
+    while (x<y) {
+        if (f >= 0) {
+            y--;
+            ddF_y += 2;
+            f += ddF_y;
+        }
+        x++;
+        ddF_x += 2;
+        f += ddF_x;
+
+        drawPixel(x0 + x, y0 + y, color);
+        drawPixel(x0 - x, y0 + y, color);
+        drawPixel(x0 + x, y0 - y, color);
+        drawPixel(x0 - x, y0 - y, color);
+        drawPixel(x0 + y, y0 + x, color);
+        drawPixel(x0 - y, y0 + x, color);
+        drawPixel(x0 + y, y0 - x, color);
+        drawPixel(x0 - y, y0 - x, color);
+    }
+}
+
+void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0,
+        int16_t r, uint8_t cornername, uint16_t color) {
+    int16_t f     = 1 - r;
+    int16_t ddF_x = 1;
+    int16_t ddF_y = -2 * r;
+    int16_t x     = 0;
+    int16_t y     = r;
+
+    while (x<y) {
+        if (f >= 0) {
+            y--;
+            ddF_y += 2;
+            f     += ddF_y;
+        }
+        x++;
+        ddF_x += 2;
+        f     += ddF_x;
+        if (cornername & 0x4) {
+            drawPixel(x0 + x, y0 + y, color);
+            drawPixel(x0 + y, y0 + x, color);
+        }
+        if (cornername & 0x2) {
+            drawPixel(x0 + x, y0 - y, color);
+            drawPixel(x0 + y, y0 - x, color);
+        }
+        if (cornername & 0x8) {
+            drawPixel(x0 - y, y0 + x, color);
+            drawPixel(x0 - x, y0 + y, color);
+        }
+        if (cornername & 0x1) {
+            drawPixel(x0 - y, y0 - x, color);
+            drawPixel(x0 - x, y0 - y, color);
+        }
+    }
+}
+
+void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r,
+        uint16_t color) {
+    drawFastVLine(x0, y0-r, 2*r+1, color);
+    fillCircleHelper(x0, y0, r, 3, 0, color);
+}
+
+// Used to do circles and roundrects
+void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
+        uint8_t cornername, int16_t delta, uint16_t color) {
+
+    int16_t f     = 1 - r;
+    int16_t ddF_x = 1;
+    int16_t ddF_y = -2 * r;
+    int16_t x     = 0;
+    int16_t y     = r;
+
+    while (x<y) {
+        if (f >= 0) {
+            y--;
+            ddF_y += 2;
+            f     += ddF_y;
+        }
+        x++;
+        ddF_x += 2;
+        f     += ddF_x;
+
+        if (cornername & 0x1) {
+            drawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
+            drawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
+        }
+        if (cornername & 0x2) {
+            drawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
+            drawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
+        }
+    }
+}
+
+// Bresenham's algorithm - thx wikpedia
+void Adafruit_GFX::drawLine(int16_t x0, int16_t y0,
+        int16_t x1, int16_t y1,
+        uint16_t color) {
+    int16_t steep = abs(y1 - y0) > abs(x1 - x0);
+    if (steep) {
+        swap(x0, y0);
+        swap(x1, y1);
+    }
+
+    if (x0 > x1) {
+        swap(x0, x1);
+        swap(y0, y1);
+    }
+
+    int16_t dx, dy;
+    dx = x1 - x0;
+    dy = abs(y1 - y0);
+
+    int16_t err = dx / 2;
+    int16_t ystep;
+
+    if (y0 < y1) {
+        ystep = 1;
+    } else {
+        ystep = -1;
+    }
+
+    for (; x0<=x1; x0++) {
+        if (steep) {
+            drawPixel(y0, x0, color);
+        } else {
+            drawPixel(x0, y0, color);
+        }
+        err -= dy;
+        if (err < 0) {
+            y0 += ystep;
+            err += dx;
+        }
+    }
+}
+
+// Draw a rectangle
+void Adafruit_GFX::drawRect(int16_t x, int16_t y,
+        int16_t w, int16_t h,
+        uint16_t color) {
+    drawFastHLine(x, y, w, color);
+    drawFastHLine(x, y+h-1, w, color);
+    drawFastVLine(x, y, h, color);
+    drawFastVLine(x+w-1, y, h, color);
+}
+
+void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y,
+        int16_t h, uint16_t color) {
+    // Update in subclasses if desired!
+    drawLine(x, y, x, y+h-1, color);
+}
+
+void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y,
+        int16_t w, uint16_t color) {
+    // Update in subclasses if desired!
+    drawLine(x, y, x+w-1, y, color);
+}
+
+void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
+        uint16_t color) {
+    // Update in subclasses if desired!
+    for (int16_t i=x; i<x+w; i++) {
+        drawFastVLine(i, y, h, color);
+    }
+}
+
+void Adafruit_GFX::fillScreen(uint16_t color) {
+    fillRect(0, 0, _width, _height, color);
+}
+
+// Draw a rounded rectangle
+void Adafruit_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w,
+        int16_t h, int16_t r, uint16_t color) {
+    // smarter version
+    drawFastHLine(x+r  , y    , w-2*r, color); // Top
+    drawFastHLine(x+r  , y+h-1, w-2*r, color); // Bottom
+    drawFastVLine(x    , y+r  , h-2*r, color); // Left
+    drawFastVLine(x+w-1, y+r  , h-2*r, color); // Right
+    // draw four corners
+    drawCircleHelper(x+r    , y+r    , r, 1, color);
+    drawCircleHelper(x+w-r-1, y+r    , r, 2, color);
+    drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
+    drawCircleHelper(x+r    , y+h-r-1, r, 8, color);
+}
+
+// Fill a rounded rectangle
+void Adafruit_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w,
+        int16_t h, int16_t r, uint16_t color) {
+    // smarter version
+    fillRect(x+r, y, w-2*r, h, color);
+
+    // draw four corners
+    fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
+    fillCircleHelper(x+r    , y+r, r, 2, h-2*r-1, color);
+}
+
+// Draw a triangle
+void Adafruit_GFX::drawTriangle(int16_t x0, int16_t y0,
+        int16_t x1, int16_t y1,
+        int16_t x2, int16_t y2, uint16_t color) {
+    drawLine(x0, y0, x1, y1, color);
+    drawLine(x1, y1, x2, y2, color);
+    drawLine(x2, y2, x0, y0, color);
+}
+
+// Fill a triangle
+void Adafruit_GFX::fillTriangle ( int16_t x0, int16_t y0,
+        int16_t x1, int16_t y1,
+        int16_t x2, int16_t y2, uint16_t color) {
+
+    int16_t a, b, y, last;
+
+    // Sort coordinates by Y order (y2 >= y1 >= y0)
+    if (y0 > y1) {
+        swap(y0, y1); swap(x0, x1);
+    }
+    if (y1 > y2) {
+        swap(y2, y1); swap(x2, x1);
+    }
+    if (y0 > y1) {
+        swap(y0, y1); swap(x0, x1);
+    }
+
+    if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing
+        a = b = x0;
+        if(x1 < a)      a = x1;
+        else if(x1 > b) b = x1;
+        if(x2 < a)      a = x2;
+        else if(x2 > b) b = x2;
+        drawFastHLine(a, y0, b-a+1, color);
+        return;
+    }
+
+    int16_t
+    dx01 = x1 - x0,
+    dy01 = y1 - y0,
+    dx02 = x2 - x0,
+    dy02 = y2 - y0,
+    dx12 = x2 - x1,
+    dy12 = y2 - y1,
+    sa   = 0,
+    sb   = 0;
+
+    // For upper part of triangle, find scanline crossings for segments
+    // 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1
+    // is included here (and second loop will be skipped, avoiding a /0
+    // error there), otherwise scanline y1 is skipped here and handled
+    // in the second loop...which also avoids a /0 error here if y0=y1
+    // (flat-topped triangle).
+    if(y1 == y2) last = y1;   // Include y1 scanline
+    else         last = y1-1; // Skip it
+
+    for(y=y0; y<=last; y++) {
+        a   = x0 + sa / dy01;
+        b   = x0 + sb / dy02;
+        sa += dx01;
+        sb += dx02;
+        /* longhand:
+    a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
+    b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
+         */
+        if(a > b) swap(a,b);
+        drawFastHLine(a, y, b-a+1, color);
+    }
+
+    // For lower part of triangle, find scanline crossings for segments
+    // 0-2 and 1-2.  This loop is skipped if y1=y2.
+    sa = dx12 * (y - y1);
+    sb = dx02 * (y - y0);
+    for(; y<=y2; y++) {
+        a   = x1 + sa / dy12;
+        b   = x0 + sb / dy02;
+        sa += dx12;
+        sb += dx02;
+        /* longhand:
+    a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
+    b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
+         */
+        if(a > b) swap(a,b);
+        drawFastHLine(a, y, b-a+1, color);
+    }
+}
+
+void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
+        const uint8_t *bitmap, int16_t w, int16_t h,
+        uint16_t color) {
+
+    int16_t i, j, byteWidth = (w + 7) / 8;
+
+    for(j=0; j<h; j++) {
+        for(i=0; i<w; i++ ) {
+            if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
+                drawPixel(x+i, y+j, color);
+            }
+        }
+    }
+}
+
+
+size_t Adafruit_GFX::write(uint8_t c) {
+    if (c == '\n') {
+        cursor_y += textsize*8;
+        cursor_x  = 0;
+    } else if (c == '\r') {
+        // skip em
+    } else {
+        drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize);
+        cursor_x += textsize*6;
+        if (wrap && (cursor_x > (_width - textsize*6))) {
+            cursor_y += textsize*8;
+            cursor_x = 0;
+        }
+    }
+
+    return 1;
+
+}
+
+// Draw a character
+void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
+        uint16_t color, uint16_t bg, uint8_t size) {
+
+    if((x >= _width)            || // Clip right
+            (y >= _height)           || // Clip bottom
+            ((x + 6 * size - 1) < 0) || // Clip left
+            ((y + 8 * size - 1) < 0))   // Clip top
+        return;
+
+    for (int8_t i=0; i<6; i++ ) {
+        uint8_t line;
+        if (i == 5)
+            line = 0x0;
+        else
+            line = pgm_read_byte(font+(c*5)+i);
+        for (int8_t j = 0; j<8; j++) {
+            if (line & 0x1) {
+                if (size == 1) // default size
+                    drawPixel(x+i, y+j, color);
+                else {  // big size
+                    fillRect(x+(i*size), y+(j*size), size, size, color);
+                }
+            } else if (bg != color) {
+                if (size == 1) // default size
+                    drawPixel(x+i, y+j, bg);
+                else {  // big size
+                    fillRect(x+i*size, y+j*size, size, size, bg);
+                }
+            }
+            line >>= 1;
+        }
+    }
+}
+
+void Adafruit_GFX::setCursor(int16_t x, int16_t y) {
+    cursor_x = x;
+    cursor_y = y;
+}
+
+void Adafruit_GFX::setTextSize(uint8_t s) {
+    textsize = (s > 0) ? s : 1;
+}
+
+void Adafruit_GFX::setTextColor(uint16_t c) {
+    // For 'transparent' background, we'll set the bg
+    // to the same as fg instead of using a flag
+    textcolor = textbgcolor = c;
+}
+
+void Adafruit_GFX::setTextColor(uint16_t c, uint16_t b) {
+    textcolor   = c;
+    textbgcolor = b;
+}
+
+void Adafruit_GFX::setTextWrap(bool w) {
+    wrap = w;
+}
+
+uint8_t Adafruit_GFX::getRotation(void) {
+    return rotation;
+}
+
+void Adafruit_GFX::setRotation(uint8_t x) {
+    rotation = (x & 3);
+    switch(rotation) {
+    case 0:
+    case 2:
+        _width  = WIDTH;
+        _height = HEIGHT;
+        break;
+    case 1:
+    case 3:
+        _width  = HEIGHT;
+        _height = WIDTH;
+        break;
+    }
+}
+
+// Return the size of the display (per current rotation)
+int16_t Adafruit_GFX::width(void) {
+    return _width;
+}
+
+int16_t Adafruit_GFX::height(void) {
+    return _height;
+}
+
+void Adafruit_GFX::invertDisplay(bool i) {
+    // Do nothing, must be subclassed if supported
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Adafruit_GFX.h	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,79 @@
+#ifndef _ADAFRUIT_GFX_H
+
+
+#define swap(a, b) { int16_t t = a; a = b; b = t; }
+
+class Adafruit_GFX {
+
+ public:
+
+  Adafruit_GFX(int16_t w, int16_t h); // Constructor
+
+  // This MUST be defined by the subclass:
+  virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0;
+
+  // These MAY be overridden by the subclass to provide device-specific
+  // optimized code.  Otherwise 'generic' versions are used.
+  virtual void
+    drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color),
+    drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color),
+    drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color),
+    drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color),
+    fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color),
+    fillScreen(uint16_t color),
+    invertDisplay(bool i);
+
+  // These exist only with Adafruit_GFX (no subclass overrides)
+  void
+    drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color),
+    drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
+      uint16_t color),
+    fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color),
+    fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
+      int16_t delta, uint16_t color),
+    drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
+      int16_t x2, int16_t y2, uint16_t color),
+    fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
+      int16_t x2, int16_t y2, uint16_t color),
+    drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
+      int16_t radius, uint16_t color),
+    fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
+      int16_t radius, uint16_t color),
+    drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap,
+      int16_t w, int16_t h, uint16_t color),
+    drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color,
+      uint16_t bg, uint8_t size),
+    setCursor(int16_t x, int16_t y),
+    setTextColor(uint16_t c),
+    setTextColor(uint16_t c, uint16_t bg),
+    setTextSize(uint8_t s),
+    setTextWrap(bool w),
+    setRotation(uint8_t r);
+
+
+  virtual size_t write(uint8_t);
+
+  int16_t
+    height(void),
+    width(void);
+
+  uint8_t getRotation(void);
+
+ protected:
+  const int16_t
+    WIDTH, HEIGHT;   // This is the 'raw' display w/h - never changes
+  int16_t
+    _width, _height, // Display w/h as modified by current rotation
+    cursor_x, cursor_y;
+  uint16_t
+    textcolor, textbgcolor;
+  uint8_t
+    textsize,
+    rotation;
+  bool
+    wrap; // If set, 'wrap' text at right edge of display
+};
+
+#endif // _ADAFRUIT_GFX_H
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EaLcdBoard.cpp	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,602 @@
+
+#include "mbed.h"
+#include "EaLcdBoard.h"
+
+#define LCDB_MAGIC 0xEA01CDAE
+
+
+#define LCDB_PCA9532_I2C_ADDR    (0x64 << 1)
+
+/* PCA9532 registers*/
+#define LCDB_PCA9532_INPUT0   0x00
+#define LCDB_PCA9532_INPUT1   0x01
+#define LCDB_PCA9532_PSC0     0x02
+#define LCDB_PCA9532_PWM0     0x03
+#define LCDB_PCA9532_PSC1     0x04
+#define LCDB_PCA9532_PWM1     0x05
+#define LCDB_PCA9532_LS0      0x06
+#define LCDB_PCA9532_LS1      0x07
+#define LCDB_PCA9532_LS2      0x08
+#define LCDB_PCA9532_LS3      0x09
+#define LCDB_PCA9532_AUTO_INC 0x10
+
+#define LCDB_LS_MODE_ON     0x01
+#define LCDB_LS_MODE_BLINK0 0x02
+#define LCDB_LS_MODE_BLINK1 0x03
+
+#define LCDB_CTRL_3V3     0x0001
+#define LCDB_CTRL_5V      0x0002
+#define LCDB_CTRL_DISP_EN 0x0010
+#define LCDB_CTRL_BL_EN   0x0080
+#define LCDB_CTRL_BL_C    0x0100
+#define LCDB_EEPROM_WP    0x8000
+
+#define LCDB_EEPROM_I2C_ADDR  (0x56 << 1)
+#define LCDB_EEPROM_PAGE_SIZE     32
+#define LCDB_EEPROM_TOTAL_SIZE  8192
+
+/*
+ * Set which sequence string version that is supported
+ */
+#define LCDB_SEQ_VER 1
+
+#ifndef MIN
+#define MIN(x, y) (((x)<(y))?(x):(y))
+#endif
+
+#define EA_LCD_TMP_BUFFER_SZ 256
+static char* eaLcdTmpBuffer[EA_LCD_TMP_BUFFER_SZ];
+
+
+/* Structure containing the parameters for the LCD panel as stored on LCD Board */
+
+/* LCD display types */
+typedef enum {
+    TFT = 0,   /* standard TFT */
+    ADTFT,     /* advanced TFT */
+    HRTFT,     /* highly reflective TFT */
+    MONO_4BIT, /* 4-bit mono */
+    MONO_8BIT, /* 8-bit mono */
+    CSTN       /* color STN */
+} nxp_lcd_panel_t;
+
+typedef struct {
+    uint8_t         h_back_porch;         /* Horizontal back porch in clocks */
+    uint8_t         h_front_porch;        /* Horizontal front porch in clocks */
+    uint8_t         h_sync_pulse_width;   /* HSYNC pulse width in clocks */
+    uint16_t        pixels_per_line;      /* Pixels per line (horizontal resolution) */
+    uint8_t         v_back_porch;         /* Vertical back porch in clocks */
+    uint8_t         v_front_porch;        /* Vertical front porch in clocks */
+    uint8_t         v_sync_pulse_width;   /* VSYNC pulse width in clocks */
+    uint16_t        lines_per_panel;      /* Lines per panel (vertical resolution) */
+    uint8_t         invert_output_enable; /* Invert output enable, 1 = invert*/
+    uint8_t         invert_panel_clock;   /* Invert panel clock, 1 = invert*/
+    uint8_t         invert_hsync;         /* Invert HSYNC, 1 = invert */
+    uint8_t         invert_vsync;         /* Invert VSYNC, 1 = invert */
+    uint8_t         ac_bias_frequency;    /* AC bias frequency in clocks */
+    uint8_t         bits_per_pixel;       /* Maximum bits per pixel the display supports */
+    uint32_t        optimal_clock;        /* Optimal clock rate (Hz) */
+    nxp_lcd_panel_t lcd_panel_type;       /* LCD panel type */
+    uint8_t         dual_panel;           /* Dual panel, 1 = dual panel display */
+} nxp_lcd_param_t;
+
+static uint32_t str_to_uint(char* str, uint32_t len);
+
+EaLcdBoard::EaLcdBoard(PinName sda, PinName scl) : _i2c(sda, scl) {
+    _blink0Shadow = 0;
+    _blink1Shadow = 0;
+    _ledStateShadow = 0;
+    _lcdPwrOn = false;
+}
+
+EaLcdBoard::Result EaLcdBoard::open(LcdController::Config* cfg, char* initSeq) {
+
+    EaLcdBoard::Result result = Ok;
+
+    // load LCD configuration from storage
+    if (cfg == NULL) {
+        result = getLcdConfig(&_cfg);
+        cfg = &_cfg;
+    }
+
+    // load init sequence from storage
+    if (result == Ok && initSeq == NULL) {
+        result = getInitSeq((char*)eaLcdTmpBuffer, EA_LCD_TMP_BUFFER_SZ);
+        initSeq = (char*)eaLcdTmpBuffer;
+    }
+
+    if (result != Ok) {
+        return result;
+    }
+
+    return parseInitString(initSeq, cfg);
+}
+
+EaLcdBoard::Result EaLcdBoard::close() {
+    int r = 0;
+
+    do {
+        r = lcdCtrl.setPower(false);
+        if (r != 0) break;
+
+        _lcdPwrOn = false;
+
+        r = lcdCtrl.close();
+    } while(0);
+
+    if (r != 0) {
+        return LcdAccessError;
+    }
+
+    return Ok;
+}
+
+EaLcdBoard::Result EaLcdBoard::setFrameBuffer(uint32_t address) {
+    int r = 0;
+
+    do {
+
+        // begin by powering on the display
+        if (!_lcdPwrOn) {
+            r = lcdCtrl.setPower(true);
+            if (r != 0) break;
+
+            _lcdPwrOn = true;
+        }
+
+        // activate specified frame buffer
+        r = lcdCtrl.setFrameBuffer(address);
+        if (r != 0) break;
+
+    } while(0);
+
+    if (r != 0) {
+        return LcdAccessError;
+    }
+
+
+    return Ok;
+}
+
+EaLcdBoard::Result EaLcdBoard::getLcdConfig(LcdController::Config* cfg) {
+    store_t h;
+
+    nxp_lcd_param_t lcdParam;
+
+    getStore(&h);
+
+    if (h.magic != LCDB_MAGIC) {
+        return InvalidStorage;
+    }
+
+    eepromRead((uint8_t*)&lcdParam, h.lcdParamOff,
+            (h.initOff-h.lcdParamOff));
+
+    cfg->horizontalBackPorch  = lcdParam.h_back_porch;
+    cfg->horizontalFrontPorch = lcdParam.h_front_porch;
+    cfg->hsync                = lcdParam.h_sync_pulse_width;
+    cfg->width                = lcdParam.pixels_per_line;
+    cfg->verticalBackPorch    = lcdParam.v_back_porch;
+    cfg->verticalFrontPorch   = lcdParam.v_front_porch;
+    cfg->vsync                = lcdParam.v_sync_pulse_width;
+    cfg->height               = lcdParam.lines_per_panel;
+    cfg->invertOutputEnable   = (lcdParam.invert_output_enable == 1);
+    cfg->invertPanelClock     = (lcdParam.invert_panel_clock == 1);
+    cfg->invertHsync          = (lcdParam.invert_hsync == 1);
+    cfg->invertVsync          = (lcdParam.invert_vsync == 1);
+    cfg->acBias               = lcdParam.ac_bias_frequency;
+    cfg->bpp = LcdController::Bpp_16_565;
+    cfg->optimalClock         = lcdParam.optimal_clock;
+    cfg->panelType            = (LcdController::LcdPanel)lcdParam.lcd_panel_type;
+    cfg->dualPanel            = (lcdParam.dual_panel == 1);
+
+    return Ok;
+}
+
+EaLcdBoard::Result EaLcdBoard::getDisplayName(char* buf, int len) {
+    store_t h;
+
+    getStore(&h);
+
+    if (h.magic != LCDB_MAGIC) {
+        return InvalidStorage;
+    }
+
+    if (len < NameBufferSize) {
+        return BufferTooSmall;
+    }
+
+    strncpy(buf, (char*)h.lcd_name, NameBufferSize);
+
+    return Ok;
+}
+
+EaLcdBoard::Result EaLcdBoard::getDisplayMfg(char* buf, int len) {
+    store_t h;
+
+    getStore(&h);
+
+    if (h.magic != LCDB_MAGIC) {
+        return InvalidStorage;
+    }
+
+    if (len < NameBufferSize) {
+        return BufferTooSmall;
+    }
+
+    strncpy(buf, (char*)h.lcd_mfg, NameBufferSize);
+
+    return Ok;
+}
+
+EaLcdBoard::Result EaLcdBoard::getInitSeq(char* buf, int len) {
+    store_t h;
+
+    getStore(&h);
+
+    if (h.magic != LCDB_MAGIC) {
+        return InvalidStorage;
+    }
+
+    if ((h.pdOff-h.initOff) > len) {
+        return BufferTooSmall;
+    }
+
+    eepromRead((uint8_t*)buf, h.initOff,
+            (h.pdOff-h.initOff));
+
+    return Ok;
+}
+
+EaLcdBoard::Result EaLcdBoard::getPowerDownSeq(char* buf, int len) {
+    store_t h;
+
+    getStore(&h);
+
+    if (h.magic != LCDB_MAGIC) {
+        return InvalidStorage;
+    }
+
+    if ((h.tsOff-h.pdOff) > len) {
+        return BufferTooSmall;
+    }
+
+    eepromRead((uint8_t*)buf, h.pdOff,
+            (h.tsOff-h.pdOff));
+
+    return Ok;
+}
+
+EaLcdBoard::Result EaLcdBoard::getStore(store_t* store) {
+    int num = 0;
+
+    if (store == NULL) return InvalidArgument;
+
+    num = eepromRead((uint8_t*)store, 0, sizeof(store_t));
+    if (num < (int)sizeof(store_t)) {
+        return InvalidStorage;
+    }
+
+    return Ok;
+}
+
+// ###########################
+// An EEPROM is used for persistent storage
+// ###########################
+
+int EaLcdBoard::eepromRead(uint8_t* buf, uint16_t offset, uint16_t len) {
+    int i = 0;
+    char off[2];
+
+    if (len > LCDB_EEPROM_TOTAL_SIZE || offset+len > LCDB_EEPROM_TOTAL_SIZE) {
+        return -1;
+    }
+
+    off[0] = ((offset >> 8) & 0xff);
+    off[1] = (offset & 0xff);
+
+    _i2c.write(LCDB_EEPROM_I2C_ADDR, (char*)off, 2);
+    for ( i = 0; i < 0x2000; i++);
+    _i2c.read(LCDB_EEPROM_I2C_ADDR, (char*)buf, len);
+
+    return len;
+}
+
+int EaLcdBoard::eepromWrite(uint8_t* buf, uint16_t offset, uint16_t len) {
+    int16_t written = 0;
+    uint16_t wLen = 0;
+    uint16_t off = offset;
+    uint8_t tmp[LCDB_EEPROM_PAGE_SIZE+2];
+
+    if (len > LCDB_EEPROM_TOTAL_SIZE || offset+len > LCDB_EEPROM_TOTAL_SIZE) {
+        return -1;
+    }
+
+    wLen = LCDB_EEPROM_PAGE_SIZE - (off % LCDB_EEPROM_PAGE_SIZE);
+    wLen = MIN(wLen, len);
+
+    while (len) {
+        tmp[0] = ((off >> 8) & 0xff);
+        tmp[1] = (off & 0xff);
+        memcpy(&tmp[2], (void*)&buf[written], wLen);
+        _i2c.write(LCDB_EEPROM_I2C_ADDR, (char*)tmp, wLen+2);
+
+        // delay to wait for a write cycle
+        //eepromDelay();
+        wait_ms(1);
+
+        len     -= wLen;
+        written += wLen;
+        off     += wLen;
+
+        wLen = MIN(LCDB_EEPROM_PAGE_SIZE, len);
+    }
+
+    return written;
+}
+
+// ###########################
+// string parsing (initialization and power down strings)
+// ###########################
+
+EaLcdBoard::Result EaLcdBoard::parseInitString(char* str, LcdController::Config* cfg) {
+    char* c = NULL;
+    uint32_t len = 0;
+    Result result = Ok;
+
+    if (str == NULL) {
+        return InvalidCommandString;
+    }
+
+    while(*str != '\0') {
+
+        // skip whitespaces
+        while(*str == ' ') {
+            str++;
+        }
+
+        c = str;
+
+        // find end of command
+        while(*str != ',' && *str != '\0') {
+            str++;
+        }
+
+        len = (str-c);
+
+        if (*str == ',') {
+            str++;
+        }
+
+        switch (*c++) {
+
+        case 'v':
+            result = checkVersion(c, len-1);
+            break;
+
+            // sequence control command (pca9532)
+        case 'c':
+            execSeqCtrl(c, len-1);
+            break;
+
+            // delay
+        case 'd':
+            execDelay(c, len-1);
+            break;
+
+            // open lcd (init LCD controller)
+        case 'o':
+
+            if (cfg != NULL) {
+
+                if (lcdCtrl.open(cfg) != 0) {
+                    result = LcdAccessError;
+                }
+            }
+
+            else {
+                result = InvalidArgument;
+            }
+
+            break;
+
+        }
+
+        if (result != Ok) {
+            break;
+        }
+
+
+    }
+
+
+    return result;
+}
+
+EaLcdBoard::Result EaLcdBoard::checkVersion(char* v, uint32_t len) {
+    uint32_t ver = str_to_uint(v, len);
+
+    if (ver > LCDB_SEQ_VER) {
+        return VersionNotSupported;
+    }
+
+    return Ok;
+}
+
+EaLcdBoard::Result EaLcdBoard::execDelay(char* del, uint32_t len) {
+    wait_ms(str_to_uint(del, len));
+
+    return Ok;
+}
+
+EaLcdBoard::Result EaLcdBoard::execSeqCtrl(char* cmd, uint32_t len) {
+
+    switch (*cmd++) {
+
+    // display enable
+    case 'd':
+        setDisplayEnableSignal(*cmd == '1');
+        break;
+
+        // backlight contrast
+    case 'c':
+        setBacklightContrast(str_to_uint(cmd, len));
+        break;
+
+        // 3v3 enable
+    case '3':
+        set3V3Signal(*cmd == '1');
+        break;
+
+        // 5v enable
+    case '5':
+        set5VSignal(*cmd == '1');
+        break;
+    }
+
+    return Ok;
+}
+
+// ###########################
+// PCA9532 is used as a control inteface to the display.
+// voltages can be turned on/off and backlight can be controlled.
+// ###########################
+
+// Helper function to set LED states
+void EaLcdBoard::setLsStates(uint16_t states, uint8_t* ls, uint8_t mode)
+{
+#define IS_LED_SET(bit, x) ( ( ((x) & (bit)) != 0 ) ? 1 : 0 )
+
+    int i = 0;
+
+    for (i = 0; i < 4; i++) {
+
+        ls[i] |= ( (IS_LED_SET(0x0001, states)*mode << 0)
+                | (IS_LED_SET(0x0002, states)*mode << 2)
+                | (IS_LED_SET(0x0004, states)*mode << 4)
+                | (IS_LED_SET(0x0008, states)*mode << 6) );
+
+        states >>= 4;
+    }
+}
+
+void EaLcdBoard::setLeds(void)
+{
+    uint8_t buf[5];
+    uint8_t ls[4] = {0,0,0,0};
+    uint16_t states = _ledStateShadow;
+
+    // LEDs in On/Off state
+    setLsStates(states, ls, LCDB_LS_MODE_ON);
+
+    // set the LEDs that should blink
+    setLsStates(_blink0Shadow, ls, LCDB_LS_MODE_BLINK0);
+    setLsStates(_blink1Shadow, ls, LCDB_LS_MODE_BLINK1);
+
+    buf[0] = LCDB_PCA9532_LS0 | LCDB_PCA9532_AUTO_INC;
+    buf[1] = ls[0];
+    buf[2] = ls[1];
+    buf[3] = ls[2];
+    buf[4] = ls[3];
+
+    _i2c.write(LCDB_PCA9532_I2C_ADDR, (char*)buf, 5);
+}
+
+void EaLcdBoard::pca9532_setLeds (uint16_t ledOnMask, uint16_t ledOffMask)
+{
+    // turn off leds
+    _ledStateShadow &= (~(ledOffMask) & 0xffff);
+
+    // ledOnMask has priority over ledOffMask
+    _ledStateShadow |= ledOnMask;
+
+    // turn off blinking
+    _blink0Shadow &= (~(ledOffMask) & 0xffff);
+    _blink1Shadow &= (~(ledOffMask) & 0xffff);
+
+    setLeds();
+}
+
+void EaLcdBoard::pca9532_setBlink0Period(uint8_t period)
+{
+    uint8_t buf[2];
+
+    buf[0] = LCDB_PCA9532_PSC0;
+    buf[1] = period;
+
+    _i2c.write(LCDB_PCA9532_I2C_ADDR, (char*)buf, 2);
+}
+
+void EaLcdBoard::pca9532_setBlink0Duty(uint8_t duty)
+{
+    uint8_t buf[2];
+    uint32_t tmp = duty;
+    if (tmp > 100) {
+        tmp = 100;
+    }
+
+    tmp = (255 * tmp)/100;
+
+    buf[0] = LCDB_PCA9532_PWM0;
+    buf[1] = tmp;
+
+    _i2c.write(LCDB_PCA9532_I2C_ADDR, (char*)buf, 2);
+}
+
+void EaLcdBoard::pca9532_setBlink0Leds(uint16_t ledMask)
+{
+    _blink0Shadow |= ledMask;
+    setLeds();
+}
+
+void EaLcdBoard::set3V3Signal(bool enabled) {
+    if (enabled) {
+        pca9532_setLeds(LCDB_CTRL_3V3, 0);
+    } else {
+        pca9532_setLeds(0, LCDB_CTRL_3V3);
+    }
+}
+
+void EaLcdBoard::set5VSignal(bool enabled) {
+    if (enabled) {
+        pca9532_setLeds(LCDB_CTRL_5V, 0);
+    } else {
+        pca9532_setLeds(0, LCDB_CTRL_5V);
+    }
+}
+
+void EaLcdBoard::setDisplayEnableSignal(bool enabled) {
+    if (!enabled) {
+        pca9532_setLeds(LCDB_CTRL_DISP_EN, 0);
+    } else {
+        pca9532_setLeds(0, LCDB_CTRL_DISP_EN);
+    }
+}
+
+void EaLcdBoard::setBacklightContrast(uint32_t value) {
+
+    if (value > 100) return;
+
+    pca9532_setBlink0Duty(100-value);
+    pca9532_setBlink0Period(0);
+    pca9532_setBlink0Leds(LCDB_CTRL_BL_C);
+}
+
+
+// convert string to integer
+static uint32_t str_to_uint(char* str, uint32_t len)
+{
+    uint32_t val = 0;
+
+    while(len > 0 && *str <= '9' && *str >= '0') {
+        val = (val * 10) + (*str - '0');
+        str++;
+        len--;
+    }
+
+    return val;
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EaLcdBoard.h	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,161 @@
+
+#ifndef EALCDBOARD_H
+#define EALCDBOARD_H
+
+#include "LcdController.h"
+
+/** An interface to Embedded Artists LCD Boards
+ *
+ */
+class EaLcdBoard {
+public:
+
+    enum Result {
+        Ok = 0,
+        InvalidCommandString,
+        InvalidArgument,
+        InvalidStorage,
+        BufferTooSmall,
+        VersionNotSupported,
+        LcdAccessError
+    };
+
+    enum Constants {
+        NameBufferSize = 30
+    };
+
+    /** Create an interface to an Embedded Artists LCD Board
+     *
+     * @param sda I2C data line pin
+     * @param scl I2C clock line pin
+     */
+    EaLcdBoard(PinName sda, PinName scl);
+
+    /** Open the interface and start initialization.
+     *
+     * @param cfg initialize with a given LCD configuration. If this argument is
+     *            NULL the LCD configuration will be retrieved from persistent
+     *            storage on the LCD Board.
+     * @param initSeq the initialization string. If this argument is NULL the
+     *            initialization string will be retrieved from persistent
+     *            storage on the LCD Board.
+     *
+     * @returns the result of the operation
+     */
+    Result open(LcdController::Config* cfg, char* initSeq);
+
+    /** Close the interface
+     *
+     * @returns the result of the operation
+     */
+    Result close();
+
+    /** Set and activate 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 address Memory address of the frame buffer
+     *
+     * @returns the result of the operation
+     */
+    Result setFrameBuffer(uint32_t address);
+
+    /** Get the LCD configuration stored in persistent storage on the LCD Board
+     *
+     *  @param cfg pointer to a configuration object. Parameters are copied to
+     *  this object.
+     *
+     * @returns the result of the operation
+     */
+    Result getLcdConfig(LcdController::Config* cfg);
+
+    /** Get the display name stored in persistent storage on the LCD Board
+     *
+     *  @param buf buffer to which the name will be copied
+     *  @param len size of the buffer in bytes
+     *
+     * @returns the result of the operation
+     */
+    Result getDisplayName(char* buf, int len);
+
+    /** Get the display manufacturer stored in persistent storage on the
+     *  LCD Board
+     *
+     *  @param buf buffer to which the name will be copied
+     *  @param len size of the buffer in bytes
+     *
+     * @returns the result of the operation
+     */
+    Result getDisplayMfg(char* buf, int len);
+
+    /** Get the initialization sequence stored in persistent storage on the
+     *  LCD Board
+     *
+     *  @param buf buffer to which the string will be copied
+     *  @param len size of the buffer in bytes
+     *
+     * @returns the result of the operation
+     */
+    Result getInitSeq(char* buf, int len);
+
+    /** Get the power down sequence stored in persistent storage on the
+     *  LCD Board
+     *
+     *  @param buf buffer to which the string will be copied
+     *  @param len size of the buffer in bytes
+     *
+     * @returns the result of the operation
+     */
+    Result getPowerDownSeq(char* buf, int len);
+
+
+private:
+
+    typedef struct {
+        uint32_t magic;        // magic number
+        uint8_t lcd_name[NameBufferSize]; // LCD name
+        uint8_t lcd_mfg[NameBufferSize]; // manufacturer name
+        uint16_t lcdParamOff;  // offset to LCD parameters
+        uint16_t initOff;      // offset to init sequence string
+        uint16_t pdOff;        // offset to power down sequence string
+        uint16_t tsOff;        // offset to touch parameters
+        uint16_t end;          // end offset
+    } store_t;
+
+    Result getStore(store_t* store);
+
+    int eepromRead(uint8_t* buf, uint16_t offset, uint16_t len);
+    int eepromWrite(uint8_t* buf, uint16_t offset, uint16_t len);
+
+    Result parseInitString(char* str, LcdController::Config* cfg);
+    Result checkVersion(char* v, uint32_t len);
+    Result execDelay(char* del, uint32_t len);
+    Result execSeqCtrl(char* cmd, uint32_t len);
+
+    void setLsStates(uint16_t states, uint8_t* ls, uint8_t mode);
+    void setLeds(void);
+    void pca9532_setLeds (uint16_t ledOnMask, uint16_t ledOffMask);
+    void pca9532_setBlink0Period(uint8_t period);
+    void pca9532_setBlink0Duty(uint8_t duty);
+    void pca9532_setBlink0Leds(uint16_t ledMask);
+
+    void set3V3Signal(bool enabled);
+    void set5VSignal(bool enabled);
+    void setDisplayEnableSignal(bool enabled);
+    void setBacklightContrast(uint32_t value);
+
+    I2C _i2c;
+    LcdController::Config _cfg;
+    LcdController lcdCtrl;
+    uint16_t _blink0Shadow;
+    uint16_t _blink1Shadow;
+    uint16_t _ledStateShadow;
+    bool _lcdPwrOn;
+};
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GFXFb.cpp	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,94 @@
+#include "mbed.h"
+#include "GFXFb.h"
+
+
+GFXFb::GFXFb(uint16_t w, uint16_t h, uint16_t* fb) : Adafruit_GFX(w, h) {
+    _fb = fb;
+}
+
+
+void GFXFb::drawPixel(int16_t x, int16_t y, uint16_t color) {
+    if (_fb == 0) return;
+
+    if (x < 0 || x >= width() || y < 0 || y >= height()) return;
+
+    *(_fb + x + y*_width ) = color;
+}
+
+void GFXFb::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
+    int16_t y2 = y + h - 1;
+
+    if (y < 0) y = 0;
+    if (y2 >= _height) y2 = _height-1;
+
+    if (_fb == 0) return;
+    if (x < 0 || x >= _width || y >= _height || y2 < y) return;
+
+    uint16_t* f = (_fb + x + y*_width);
+    while(y <= y2) {
+
+        *f = color;
+        f += _width;
+        y++;
+    }
+
+}
+
+void GFXFb::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
+    int16_t x2 = x + w - 1;
+
+    if (x < 0) x = 0;
+    if (x2 >= _width) x2 = _width-1;
+
+    if (_fb == 0) return;
+    if (x >= _width || x2 < x || y < 0 || y >= _height) return;
+
+    uint16_t* f = (_fb + x + y*_width);
+    while(x <= x2) {
+
+        *f++ = color;
+        x++;
+    }
+
+}
+
+
+void GFXFb::fillScreen(uint16_t color) {
+
+    if (_fb == 0) return;
+
+    int len = _width*_height;
+    for (int i = 0; i < len; i++) {
+        *(_fb+i) = color;
+    }
+}
+
+void GFXFb::writeString(const char* s) {
+    if (s == NULL) return;
+
+    while(*s != 0) {
+        write(*s);
+        s++;
+    }
+}
+
+int16_t GFXFb::getStringWidth(const char* s) {
+    // the default font in GFX is 6 pixels in width
+    int chWidth = 6*textsize;
+    int sz = 0;
+
+    while(*s != 0) {
+        sz += chWidth;
+        s++;
+    }
+
+    return sz;
+}
+
+int16_t GFXFb::getStringHeight(const char* s) {
+    (void)s;
+    // the default font in GFX is 8 pixels in height
+    return 8;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GFXFb.h	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,100 @@
+
+#ifndef GFXFB_H
+#define GFXFB_H
+
+#include "Adafruit_GFX.h"
+
+#define BLACK         0x0000
+/* Light gray color, 565 mode */
+#define LIGHTGRAY     0X7BEF
+/* Dark gray color, 565 mode */
+#define DARKGRAY      0x39E7
+/* White color, 565 mode */
+#define WHITE         0xffff
+/* Red color, 565 mode */
+#define RED           0xF800
+/* Green color, 565 mode */
+#define GREEN         0x07E0
+/* Blue color, 565 mode */
+#define BLUE          0x001F
+/* Magenta color, 565 mode */
+#define MAGENTA       (RED | BLUE)
+/* Cyan color, 565 mode */
+#define CYAN          (GREEN | BLUE)
+/* Yellow color, 565 mode */
+#define YELLOW        (RED | GREEN)
+/* Light red color, 565 mode */
+#define LIGHTRED      0x7800
+/* Light green color, 565 mode */
+#define LIGHTGREEN    0x03E0
+/* Light blue color, 565 mode */
+#define LIGHTBLUE     0x000F
+/* Light magenta color, 565 mode */
+#define LIGHTMAGENTA  (LIGHTRED | LIGHTBLUE)
+/* Light cyan color, 565 mode */
+#define LIGHTCYAN     (LIGHTGREEN | LIGHTBLUE)
+/* Light yellow color, 565 mode */
+#define LIGHTYELLOW   (LIGHTRED | LIGHTGREEN)
+
+/**
+ * Graphical library based on Adafruit's GFX using a Frame buffer.
+ */
+class GFXFb : public Adafruit_GFX {
+public:
+
+    /** Create an interface to the GFX graphical library
+     *
+     * @param w width of the display
+     * @param h height of the display
+     * @param fb frame buffer that will be used by the graphical library. Can
+     * be set by calling setFb instead.
+     */
+    GFXFb(uint16_t w, uint16_t h, uint16_t* fb = 0);
+
+    virtual void drawPixel(int16_t x, int16_t y, uint16_t color);
+    virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
+    virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
+    virtual void fillScreen(uint16_t color);
+
+    /** Associate a frame buffer with the graphical library.
+     *  All drawing requests will be performed on the frame buffer.
+     *
+     * @param fb frame buffer that will be used by the graphical library
+     */
+    void setFb(uint16_t* fb) {_fb = fb;}
+
+    /** Get the frame buffer associated with the graphical library.
+     *
+     * @returns the frame buffer associated with the graphical library.
+     */
+    uint16_t* getFb() {return _fb;}
+
+    /** Write a null-terminated string
+     *
+     * @param s the string to write on the display
+     */
+    void writeString(const char* s);
+
+    /** Get the width in pixels of the given string.
+     *
+     * @param s width will be calculated on this string
+     * @returns the width in pixels of the string
+     */
+    int16_t getStringWidth(const char* s);
+
+    /** Get the height in pixels of the given string.
+     *
+     * @param s height will be calculated on this string
+     * @returns the height in pixels of the string
+     */
+    int16_t getStringHeight(const char* s);
+
+
+private:
+
+    uint16_t* _fb;
+};
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LcdController.cpp	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,437 @@
+
+#include "mbed.h"
+#include "LcdController.h"
+
+#undef _SBF
+#define _SBF(p,v) (((uint32_t)(v)) << (p))
+
+#undef _BITMASK
+#define _BITMASK(field_width) (_BIT(field_width) - 1)
+
+#undef _BIT
+#define _BIT(p) (((uint32_t)(1)) << (p))
+
+/***********************************************************************
+ * Color LCD controller horizontal axis plane control register definitions
+ **********************************************************************/
+
+/* LCD controller horizontal axis plane control register pixels per line */
+#define CLCDC_LCDTIMING0_PPL_WIDTH 6
+#define CLCDC_LCDTIMING0_PPL(n) _SBF(2, (((n) / 16) - 1) & _BITMASK(CLCDC_LCDTIMING0_PPL_WIDTH))
+/* LCD controller horizontal axis plane control register HSYNC pulse width */
+#define CLCDC_LCDTIMING0_HSW_WIDTH 8
+#define CLCDC_LCDTIMING0_HSW(n) _SBF(8, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING0_HSW_WIDTH))
+/* LCD controller horizontal axis plane control register horizontal front porch */
+#define CLCDC_LCDTIMING0_HFP_WIDTH 8
+#define CLCDC_LCDTIMING0_HFP(n) _SBF(16, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING0_HFP_WIDTH))
+/* LCD controller horizontal axis plane control register horizontal back porch */
+#define CLCDC_LCDTIMING0_HBP_WIDTH 8
+#define CLCDC_LCDTIMING0_HBP(n) _SBF(24, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING0_HBP_WIDTH))
+
+/***********************************************************************
+ * Color LCD controller vertical axis plane control register definitions
+ **********************************************************************/
+
+/* LCD controller vertical axis plane control register lines per panel */
+#define CLCDC_LCDTIMING1_LPP_WIDTH 10
+#define CLCDC_LCDTIMING1_LPP(n) _SBF(0, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING1_LPP_WIDTH))
+/* LCD controller vertical axis plane control register VSYNC pulse width */
+#define CLCDC_LCDTIMING1_VSW_WIDTH 6
+#define CLCDC_LCDTIMING1_VSW(n) _SBF(10, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING1_VSW_WIDTH))
+/* LCD controller vertical axis plane control register vertical front porch */
+#define CLCDC_LCDTIMING1_VFP_WIDTH 8
+#define CLCDC_LCDTIMING1_VFP(n) _SBF(16, (n) & _BITMASK(CLCDC_LCDTIMING1_VFP_WIDTH))
+/* LCD controller vertical axis plane control register vertical back porch */
+#define CLCDC_LCDTIMING1_VBP_WIDTH 8
+#define CLCDC_LCDTIMING1_VBP(n) _SBF(24, (n) & _BITMASK(CLCDC_LCDTIMING1_VBP_WIDTH))
+
+/***********************************************************************
+ * Color LCD controller clock and signal polarity control register definitions
+ **********************************************************************/
+
+/* LCD controller clock and signal polarity control register panel clock divisor low*/
+#define CLCDC_LCDTIMING2_PCD_LO_WIDTH 5
+#define CLCDC_LCDTIMING2_PCD_LO(n) _SBF(0, ((n) - 2) & _BITMASK(CLCDC_LCDTIMING2_PCD_LO_WIDTH))
+/* LCD controller clock and signal polarity control register clock select */
+#define CLCDC_LCDTIMING2_CLKSEL _BIT(5)
+/* LCD controller clock and signal polarity control register AC bias pin frequency */
+#define CLCDC_LCDTIMING2_ACB_WIDTH 5
+#define CLCDC_LCDTIMING2_ACB(n) _SBF(6, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING2_ACB_WIDTH))
+/* LCD controller clock and signal polarity control register invert VSYNC */
+#define CLCDC_LCDTIMING2_IVS    _BIT(11)
+/* LCD controller clock and signal polarity control register invert HSYNC */
+#define CLCDC_LCDTIMING2_IHS    _BIT(12)
+/* LCD controller clock and signal polarity control register invert plane clock */
+#define CLCDC_LCDTIMING2_IPC    _BIT(13)
+/* LCD controller clock and signal polarity control register invert output enable */
+#define CLCDC_LCDTIMING2_IOE    _BIT(14)
+/* LCD controller clock and signal polarity control register clocks per line */
+#define CLCDC_LCDTIMING2_CPL_WIDTH 10
+#define CLCDC_LCDTIMING2_CPL(n) _SBF(16, (n) & _BITMASK(CLCDC_LCDTIMING2_CPL_WIDTH))
+/* LCD controller clock and signal polarity control register bypass pixel clock divider */
+#define CLCDC_LCDTIMING2_BCD    _BIT(26)
+/* LCD controller clock and signal polarity control register panel clock divisor high*/
+#define CLCDC_LCDTIMING2_PCD_HI_WIDTH 5
+#define CLCDC_LCDTIMING2_PCD_HI(n) _SBF((27 - CLCDC_LCDTIMING2_PCD_LO_WIDTH), ((n) - 2) & _SBF(CLCDC_LCDTIMING2_PCD_LO_WIDTH, _BITMASK(CLCDC_LCDTIMING2_PCD_HI_WIDTH)))
+
+
+/***********************************************************************
+ * Color LCD controller control register definitions
+ **********************************************************************/
+
+/* LCD control enable bit */
+#define CLCDC_LCDCTRL_ENABLE    (1<<0)
+/* LCD control 1 bit per pixel bit field */
+#define CLCDC_LCDCTRL_BPP1      (0 << 1)
+/* LCD control 2 bits per pixel bit field */
+#define CLCDC_LCDCTRL_BPP2      (1 << 1)
+/* LCD control 4 bits per pixel bit field */
+#define CLCDC_LCDCTRL_BPP4      (2 << 1)
+/* LCD control 8 bits per pixel bit field */
+#define CLCDC_LCDCTRL_BPP8      (3 << 1)
+/* LCD control 16 bits per pixel bit field */
+#define CLCDC_LCDCTRL_BPP16     (4 << 1)
+/* LCD control 24 bits per pixel bit field */
+#define CLCDC_LCDCTRL_BPP24     (5 << 1)
+/* LCD control 16 bits (5:6:5 mode) per pixel bit field */
+#define CLCDC_LCDCTRL_BPP16_565_MODE (6 << 1)
+/* LCD control 12 bits (4:4:4 mode) per pixel bit field */
+#define CLCDC_LCDCTRL_BPP12_444_MODE (7 << 1)
+/* LCD control mono select bit */
+#define CLCDC_LCDCTRL_BW_COLOR  (0 << 4)
+#define CLCDC_LCDCTRL_BW_MONO   (1 << 4)
+/* LCD controler TFT select bit */
+#define CLCDC_LCDCTRL_TFT       (1 << 5)
+/* LCD control monochrome LCD has 4-bit/8-bit select bit */
+#define CLCDC_LCDCTRL_MON8      (1 << 6)
+/* LCD control dual panel select bit */
+#define CLCDC_LCDCTRL_DUAL      (1 << 7)
+/* LCD control RGB or BGR format select bit */
+#define CLCDC_LCDCTRL_RGB       (0 << 8)
+#define CLCDC_LCDCTRL_BGR       (1 << 8)
+/* LCD control big-endian byte order select bit */
+#define CLCDC_LCDCTRL_BEBO      (1 << 9)
+/* LCD control big-endian pixel order within a byte select bit */
+#define CLCDC_LCDCTRL_BEPO      (1 << 10)
+/* LCD control power enable bit */
+#define CLCDC_LCDCTRL_PWR       (1 << 11)
+/* LCD control VCOMP interrupt is start of VSYNC */
+#define CLCDC_LCDCTRL_VCOMP_VS  (0 << 12)
+/* LCD control VCOMP interrupt is start of back porch */
+#define CLCDC_LCDCTRL_VCOMP_BP  (1 << 12)
+/* LCD control VCOMP interrupt is start of active video */
+#define CLCDC_LCDCTRL_VCOMP_AV  (2 << 12)
+/* LCD control VCOMP interrupt is start of front porch */
+#define CLCDC_LCDCTRL_VCOMP_FP  (3 << 12)
+/* LCD control watermark level is 8 or more words free bit */
+#define CLCDC_LCDCTRL_WATERMARK (1 << 16)
+
+
+
+bool LcdController::_lcdControllerUsed = false;
+
+LcdController::LcdController() {
+  _opened = false;
+}
+
+int LcdController::open(LcdController::Config* cfg) {
+    if (_lcdControllerUsed) return 1;
+    if (cfg == NULL) return 1;
+
+    // enable power for LCD controller
+    LPC_SC->PCONP |= 0x00000001;
+
+    pinConfig();
+    init(cfg);
+
+    // only one instance at a time is allowed to be used
+    _lcdControllerUsed = true;
+    _opened = true;
+
+    return 0;
+}
+
+int LcdController::close() {
+
+    if (!_opened) return 1;
+
+    if (_lcdControllerUsed) {
+
+        // disable power for LCD controller
+        LPC_SC->PCONP &= ~(0x00000001);
+
+        _lcdControllerUsed = false;
+        _opened = false;
+    }
+
+
+    return 0;
+}
+
+int LcdController::setFrameBuffer(uint32_t address) {
+    if (!_opened) return 1;
+
+    LPC_LCD->UPBASE = address;
+
+    return 0;
+}
+
+int LcdController::setPower(bool on) {
+    if (!_opened) return 1;
+
+    if (on) {
+        LPC_LCD->CTRL |= CLCDC_LCDCTRL_ENABLE;
+        LPC_LCD->CTRL |= CLCDC_LCDCTRL_PWR;
+    }
+    else {
+        LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_PWR;
+        LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_ENABLE;
+    }
+
+    return 0;
+}
+
+void LcdController::init(LcdController::Config* cfg) {
+    uint32_t tmp, i;
+
+    // Disable the display in case it is on
+    LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_ENABLE;
+
+    // Generate the horizontal axis plane control word
+    tmp = (CLCDC_LCDTIMING0_PPL(cfg->width) |
+            CLCDC_LCDTIMING0_HSW(cfg->hsync) |
+            CLCDC_LCDTIMING0_HFP(cfg->horizontalFrontPorch) |
+            CLCDC_LCDTIMING0_HBP(cfg->horizontalBackPorch));
+    LPC_LCD->TIMH = tmp;
+
+    // Generate the vertical axis plane control word
+    tmp = (CLCDC_LCDTIMING1_LPP(cfg->height) |
+            CLCDC_LCDTIMING1_VSW(cfg->vsync) |
+            CLCDC_LCDTIMING1_VFP(cfg->verticalFrontPorch) |
+            CLCDC_LCDTIMING1_VBP(cfg->verticalBackPorch));
+    LPC_LCD->TIMV = tmp;
+
+    // Generate the clock and signal polarity control word
+    if(cfg->acBias != 0)
+    {
+        /* STN panel has AC bias value */
+        tmp = CLCDC_LCDTIMING2_ACB(cfg->acBias);
+    }
+    else
+    {
+        tmp = 0;
+    }
+
+    if (cfg->invertOutputEnable)
+    {
+        tmp |= CLCDC_LCDTIMING2_IOE;
+    }
+
+    if (cfg->invertPanelClock)
+    {
+        tmp |= CLCDC_LCDTIMING2_IPC;
+    }
+
+    if (cfg->invertHsync)
+    {
+        tmp |= CLCDC_LCDTIMING2_IHS;
+    }
+
+    if (cfg->invertVsync)
+    {
+        tmp |= CLCDC_LCDTIMING2_IVS;
+    }
+
+    // Compute clocks per line based on panel type
+    switch (cfg->panelType)
+    {
+    case Mono_4Bit:
+        // Clocks per line is a quarter of pixels per line
+        tmp = tmp | CLCDC_LCDTIMING2_CPL((cfg->width / 4) - 1);
+        break;
+
+    case Mono_8Bit:
+        // Clocks per line is an eighth of pixels per line
+        tmp = tmp | CLCDC_LCDTIMING2_CPL((cfg->width / 8) - 1);
+        break;
+
+    case ColorStn:
+        // CSTN Clocks per line (* 3 / 8)
+        tmp = tmp | CLCDC_LCDTIMING2_CPL(((cfg->width * 3) / 8) - 1);
+        break;
+
+    case Tft:
+    case AdTft:
+    case HrTft:
+    default:
+        // Clocks per line and pixels per line are the same
+        tmp = tmp | CLCDC_LCDTIMING2_CPL(cfg->width - 1);
+        break;
+    }
+
+    // clock
+    tmp = tmp | getClockDivisor(cfg->optimalClock);
+
+    LPC_LCD->POL = tmp;
+
+    // Skip line end control word - just set to 0x0
+    LPC_LCD->LE = 0x00000000;
+
+    // Default with all interrupts of
+    LPC_LCD->INTMSK = 0x00000000;
+
+
+    switch(cfg->bpp) {
+    case Bpp_1:
+        tmp = CLCDC_LCDCTRL_BPP1;
+        break;
+    case Bpp_2:
+        tmp = CLCDC_LCDCTRL_BPP2;
+        break;
+    case Bpp_4:
+        tmp = CLCDC_LCDCTRL_BPP4;
+        break;
+    case Bpp_8:
+        tmp = CLCDC_LCDCTRL_BPP8;
+        break;
+    case Bpp_16:
+        tmp = CLCDC_LCDCTRL_BPP16;
+        break;
+    case Bpp_24:
+        tmp = CLCDC_LCDCTRL_BPP24;
+        break;
+    case Bpp_16_565:
+        tmp = CLCDC_LCDCTRL_BPP16_565_MODE;
+        break;
+    case Bpp_12_444:
+        tmp = CLCDC_LCDCTRL_BPP12_444_MODE;
+        break;
+    default:
+        tmp = CLCDC_LCDCTRL_BPP16_565_MODE;
+        break;
+    }
+
+    // red and blue swapped
+    tmp |= CLCDC_LCDCTRL_BGR;
+
+    switch (cfg->panelType)
+    {
+    case AdTft:
+    case HrTft:
+    case Tft:
+        tmp |= CLCDC_LCDCTRL_TFT;
+        break;
+
+    case Mono_4Bit:
+        tmp |= CLCDC_LCDCTRL_BW_MONO;
+        break;
+
+    case Mono_8Bit:
+        tmp |= (CLCDC_LCDCTRL_MON8 | CLCDC_LCDCTRL_BW_MONO);
+        break;
+
+    case ColorStn:
+        ;
+        break;
+
+    default:
+        // Unsupported panel type
+        break;
+    }
+
+    // Dual panel operation
+    if (cfg->dualPanel)
+    {
+        tmp |= CLCDC_LCDCTRL_DUAL;
+    }
+
+    LPC_LCD->CTRL = tmp;
+
+    // clear the palette (color is black )
+    for (i = 0; i < sizeof(LPC_LCD->PAL)/sizeof(LPC_LCD->PAL[0]); i++)
+    {
+        LPC_LCD->PAL[i] = 0;
+    }
+
+    LPC_SC->LCD_CFG = 0x0;
+
+}
+
+void LcdController::pinConfig() {
+
+    LPC_IOCON->P0_4 |= 7; /* LCD_VD_0 @ P0.4 */
+    LPC_IOCON->P0_5 |= 7; /* LCD_VD_1 @ P0.5 */
+    LPC_IOCON->P0_6 |= 7; /* LCD_VD_8 @ P0.6 */
+    LPC_IOCON->P0_7 |= 7; /* LCD_VD_9 @ P0.7 */
+    LPC_IOCON->P0_8 |= 7; /* LCD_VD_16 @ P0.8 */
+    LPC_IOCON->P0_9 |= 7; /* LCD_VD_17 @ P0.9 */
+    LPC_IOCON->P0_10 |= 7; /* LCD_VD_5 @ P0.10 */  /* LPC4088 */
+
+#ifdef LPC4088_OEM
+    LPC_IOCON->P1_20 |= 7; /* LCD_VD_10 @ P1.20 */
+    LPC_IOCON->P1_23 |= 7; /* LCD_VD_13 @ P1.23 */
+    LPC_IOCON->P1_24 |= 7; /* LCD_VD_14 @ P1.24 */
+#else
+    LPC_IOCON->P0_11 |= 7; /* LCD_VD_10 @ P0.11 */
+    LPC_IOCON->P0_19 |= 7; /* LCD_VD_13 @ P0.19 */
+    LPC_IOCON->P0_20 |= 7; /* LCD_VD_14 @ P0.20 */
+#endif
+
+    LPC_IOCON->P1_21 |= 7; /* LCD_VD_11 @ P1.21 */
+    LPC_IOCON->P1_22 |= 7; /* LCD_VD_12 @ P1.22 */
+
+    LPC_IOCON->P1_25 |= 7; /* LCD_VD_15 @ P1.25 */
+    LPC_IOCON->P1_26 |= 7; /* LCD_VD_20 @ P1.26 */
+    LPC_IOCON->P1_27 |= 7; /* LCD_VD_21 @ P1.27 */
+    LPC_IOCON->P1_28 |= 7; /* LCD_VD_22 @ P1.28 */
+    LPC_IOCON->P1_29 |= 7; /* LCD_VD_23 @ P1.29 */
+
+    LPC_IOCON->P2_0 |= 7; /* LCD_PWR @ P2.0 */
+    LPC_IOCON->P2_1 |= 7; /* LCD_LE  @ P2.1 */
+    LPC_IOCON->P2_2 |= 7; /* LCD_DCLK @ P2.2 */
+    LPC_IOCON->P2_3 |= 7; /* LCD_FP @ P2.3 */
+    LPC_IOCON->P2_4 |= 7; /* LCD_ENAB_M @ P2.4 */
+    LPC_IOCON->P2_5 |= 7; /* LCD_LP @ P2.5 */
+    LPC_IOCON->P2_6 |= 7; /* LCD_VD_4 @ P2.6 */
+    //LPC_IOCON->P2_7 |= 7; /* LCD_VD_5 @ P2.7 */  /* LPC4088 */
+    LPC_IOCON->P2_8 |= 7; /* LCD_VD_6 @ P2.8 */
+    LPC_IOCON->P2_9 |= 7; /* LCD_VD_7 @ P2.9 */
+
+    LPC_IOCON->P2_11 |= 7; /* LCD_CLKIN @ P2.11 */
+    LPC_IOCON->P2_12 |= 5; /* LCD_VD_3 @ P2.12 Signal marked as LCD_VD_18 on base board, but shall carry the LCD_VD_3 signal */
+    LPC_IOCON->P2_13 |= 7; /* LCD_VD_19 @ P2.13 */
+}
+
+uint32_t LcdController::getClockDivisor(int clock) {
+    uint32_t pixel_div, tmp = 0;
+    uint32_t clk;
+
+    clk = SystemCoreClock;
+
+    // Find closest clock divider to get clock rate
+    pixel_div = 1;
+    while (((clk / pixel_div) > clock) && (pixel_div <= 0x3F))
+    {
+      pixel_div++;
+    }
+
+    if (pixel_div <= 1)
+    {
+      // Pixel clock divider is 1, skip divider logic
+      tmp = CLCDC_LCDTIMING2_BCD;
+    }
+    else
+    {
+      // Add in new divider
+      pixel_div -= 2;
+
+      tmp |= (((pixel_div >> 0) & 0x1F)
+             | (((pixel_div >> 5) & 0x1F) << 27));
+    }
+
+    return tmp;
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LcdController.h	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,215 @@
+
+#ifndef LCDCONTROLLER_H
+#define LCDCONTROLLER_H
+
+/**
+ * A LCD controller interface
+ *
+ * @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 LcdController {
+public:
+
+    enum LcdPanel {
+        Tft = 0,    // standard TFT
+        AdTft,      // advanced TFT
+        HrTft,      // highly reflective TFT
+        Mono_4Bit,  // 4-bit mono
+        Mono_8Bit,  // 8-bit mono
+        ColorStn    // Color STN
+    };
+
+    enum BitsPerPixel {
+        Bpp_1 = 0,
+        Bpp_2,
+        Bpp_4,
+        Bpp_8,
+        Bpp_16,
+        Bpp_24,
+        Bpp_16_565,
+        Bpp_12_444
+    };
+
+    /**
+     * LCD configuration
+     */
+    class Config {
+    public:
+
+        /** Create an empty LCD configuration object
+         *
+         */
+        Config() {
+        }
+
+        /** Create a LCD configuration object with specified values
+         *
+         *  @param horizontalBackPorch Horizontal back porch in clocks
+         *  @param horizontalFrontPorch Horizontal front porch in clocks
+         *  @param hsync HSYNC pulse width in clocks
+         *  @param width width of display in pixels
+         *  @param verticalBackPorch vertical back porch in clocks
+         *  @param verticalFrontPorch vertical front porch in clocks
+         *  @param vsync VSYNC pulse width in clocks
+         *  @param height height of display in pixels
+         *  @param invertOutputEnable true to invert output enable
+         *  @param invertPanelClock true to invert panel clock
+         *  @param invertHsync true to invert HSYNC
+         *  @param invertVsync true to invert VSYNC
+         *  @param acBias AC bias frequency in clocks
+         *  @param bpp bits per pixel
+         *  @param optimalClock optimal clock rate (Hz)
+         *  @param panelType LCD panel type
+         *  @param dualPanel true if it is a dual panel display
+         */
+        Config(int horizontalBackPorch,
+                int horizontalFrontPorch,
+                int hsync,
+                int width,
+                int verticalBackPorch,
+                int verticalFrontPorch,
+                int vsync,
+                int height,
+                bool invertOutputEnable,
+                bool invertPanelClock,
+                bool invertHsync,
+                bool invertVsync,
+                int acBias,
+                BitsPerPixel bpp,
+                int optimalClock,
+                LcdPanel panelType,
+                bool dualPanel) {
+
+            this->horizontalBackPorch = horizontalBackPorch;
+            this->horizontalFrontPorch = horizontalFrontPorch;
+            this->hsync = hsync;
+            this->width = width;
+            this->verticalBackPorch = verticalBackPorch;
+            this->verticalFrontPorch = verticalFrontPorch;
+            this->vsync = vsync;
+            this->height = height;
+            this->invertOutputEnable = invertOutputEnable;
+            this->invertPanelClock = invertPanelClock;
+            this->invertHsync = invertHsync;
+            this->invertVsync = invertVsync;
+            this->acBias = acBias;
+            this->bpp = bpp;
+            this->optimalClock = optimalClock;
+            this->panelType = panelType;
+            this->dualPanel = dualPanel;
+        }
+
+        int horizontalBackPorch;
+        int horizontalFrontPorch;
+        int hsync;
+        int width;
+        int verticalBackPorch;
+        int verticalFrontPorch;
+        int vsync;
+        int height;
+        bool invertOutputEnable;
+        bool invertPanelClock;
+        bool invertHsync;
+        bool invertVsync;
+        int acBias;
+        BitsPerPixel bpp;
+        int optimalClock;
+        LcdPanel panelType;
+        bool dualPanel;
+    };
+
+    /** Create a LCD controller interface
+     *
+     */
+    LcdController();
+
+    /** Open and initialize the LCD controller with the given LCD configuration
+     *
+     *  @param cfg LCD configuration
+     *
+     *  @returns
+     *       0 on success
+     *       1 on failure
+     */
+    int open(LcdController::Config* cfg);
+
+    /** Close the LCD controller
+     *
+     *  @returns
+     *       0 on success
+     *       1 on failure
+     */
+    int close();
+
+    /** Set and activate 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 address Memory address of the frame buffer
+     *
+     *  @returns
+     *       0 on success
+     *       1 on failure
+     */
+    int setFrameBuffer(uint32_t address);
+
+    /** Turn on/off the power to the display.
+     *
+     *  @param on true to turn on, false to turn off
+     *
+     *  @returns
+     *       0 on success
+     *       1 on failure
+     */
+    int setPower(bool on);
+
+
+private:
+
+    bool _opened;
+    static bool _lcdControllerUsed;
+
+    void init(LcdController::Config* cfg);
+    void pinConfig();
+    uint32_t getClockDivisor(int clock);
+};
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MCIFileSystem.cpp	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,1810 @@
+
+/******************************************************************************
+ * Includes
+ *****************************************************************************/
+
+#include "MCIFileSystem.h"
+#include "mbed_debug.h"
+
+#include "diskio.h" //STA_* defines
+#include "gpdma.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+#define MCI_DBG             0
+
+#define CMD_TIMEOUT                  (0x10000)
+
+#define DATA_TIMER_VALUE_R           (SDC_TRAN_CLOCK_RATE / 4)    // 250ms
+#define DATA_TIMER_VALUE_W           (SDC_TRAN_CLOCK_RATE)    // 1000ms
+#define ACQUIRE_DELAY       (0.100f)      /*!< inter-command acquire oper condition delay in seconds */
+
+#define SYSCTL_CLOCK_SDC    (1<<28)
+
+/**
+ * @brief SDC Clear Register bit definitions
+ */
+/** Clear all status flag*/
+#define SDC_CLEAR_ALL       ((uint32_t) 0x7FF)
+
+/*
+ * SDMMC Card bus clock rate definitions
+ */
+/** Card bus clock in Card Identification Mode */
+#define SDC_IDENT_CLOCK_RATE         (400000)  /* 400KHz */
+/** Card bus clock in Data Transfer Mode */
+#define SDC_TRAN_CLOCK_RATE        (20000000)  /* 20MHz */
+
+/**
+ * @brief SDC Power Control Register bit definitions
+ */
+/** SD_CMD Output Control */
+#define SDC_PWR_OPENDRAIN       (((uint32_t) 1) << 6)
+
+/**
+ * @brief SDC Command Register bit definitions
+ */
+/** SDC Command Register Bitmask */
+#define SDC_COMMAND_BITMASK     ((uint32_t) 0x7FF)
+/** SDC Command Index Bitmask */
+#define SDC_COMMAND_INDEX_BITMASK   ((uint32_t) 0x3F)
+/** Set SDC Command Index */
+#define SDC_COMMAND_INDEX(n)        ((uint32_t) n & 0x3F)
+/** No response is expected */
+#define SDC_COMMAND_NO_RSP          (((uint32_t) 0 ) << 6)
+/** Short response is expected */
+#define SDC_COMMAND_SHORT_RSP       (((uint32_t) 1 ) << 6)
+/** Long response is expected */
+#define SDC_COMMAND_LONG_RSP        (((uint32_t) 3 ) << 6)
+/** Response bit mask */
+#define SDC_COMMAND_RSP_BITMASK     (((uint32_t) 3 ) << 6)
+/** Mark that command timer is disabled and CPSM waits for interrupt request */
+#define SDC_COMMAND_INTERRUPT       (((uint32_t) 1 ) << 8)
+/** Mark that CPSM waits for CmdPend before starting sending a command*/
+#define SDC_COMMAND_PENDING     (((uint32_t) 1 ) << 9)
+/** Enable CPSM */
+#define SDC_COMMAND_ENABLE          (((uint32_t) 1 ) << 10)
+
+/**
+ * @brief SDC Command Response Register bit definitions
+ */
+/** SDC Command Response value */
+#define SDC_RESPCOMMAND_VAL(n)      ((uint32_t) n & 0x3F)
+
+/*
+ * SD/MMC Response type definitions
+ */
+#define CMDRESP_NONE_TYPE       (SDC_COMMAND_NO_RSP)
+#define CMDRESP_R1_TYPE         (SDC_COMMAND_SHORT_RSP)
+#define CMDRESP_R1b_TYPE        (SDC_COMMAND_SHORT_RSP)
+#define CMDRESP_R2_TYPE         (SDC_COMMAND_LONG_RSP)
+#define CMDRESP_R3_TYPE         (SDC_COMMAND_SHORT_RSP)
+#define CMDRESP_R6_TYPE         (SDC_COMMAND_SHORT_RSP)
+#define CMDRESP_R7_TYPE         (SDC_COMMAND_SHORT_RSP)
+
+/*
+ * SD command values (Command Index, Response)
+ */
+#define SD_GO_IDLE_STATE           (SDC_COMMAND_INDEX(MMC_GO_IDLE_STATE) | CMDRESP_NONE_TYPE | SDC_COMMAND_INTERRUPT)  /*!< GO_IDLE_STATE(MMC) or RESET(SD) */
+#define SD_CMD1_SEND_OP_COND       (SDC_COMMAND_INDEX(MMC_SEND_OP_COND) | CMDRESP_R3_TYPE | 0)          /*!< SEND_OP_COND(MMC) or ACMD41(SD) */
+#define SD_CMD2_ALL_SEND_CID       (SDC_COMMAND_INDEX(MMC_ALL_SEND_CID) | CMDRESP_R2_TYPE | 0)          /*!< ALL_SEND_CID */
+#define SD_CMD3_SET_RELATIVE_ADDR  (SDC_COMMAND_INDEX(MMC_SET_RELATIVE_ADDR) | CMDRESP_R1_TYPE | 0)        /*!< SET_RELATE_ADDR */
+#define SD_CMD3_SEND_RELATIVE_ADDR (SDC_COMMAND_INDEX(SD_SEND_RELATIVE_ADDR) | CMDRESP_R6_TYPE | 0)        /*!< SEND_RELATE_ADDR */
+#define SD_CMD7_SELECT_CARD        (SDC_COMMAND_INDEX(MMC_SELECT_CARD) | CMDRESP_R1b_TYPE | 0)          /*!< SELECT/DESELECT_CARD */
+#define SD_CMD8_SEND_IF_COND       (SDC_COMMAND_INDEX(SD_CMD8) | CMDRESP_R7_TYPE | 0)              /*!< SEND_IF_COND */
+#define SD_CMD9_SEND_CSD           (SDC_COMMAND_INDEX(MMC_SEND_CSD) | CMDRESP_R2_TYPE | 0)            /*!< SEND_CSD */
+#define SD_CMD12_STOP_TRANSMISSION (SDC_COMMAND_INDEX(MMC_STOP_TRANSMISSION) | CMDRESP_R1_TYPE | 0)        /*!< STOP_TRANSMISSION */
+#define SD_CMD13_SEND_STATUS       (SDC_COMMAND_INDEX(MMC_SEND_STATUS) | CMDRESP_R1_TYPE | 0)          /*!< SEND_STATUS */
+
+/* Block-Oriented Read Commands (class 2) */
+#define SD_CMD16_SET_BLOCKLEN      (SDC_COMMAND_INDEX(MMC_SET_BLOCKLEN) | CMDRESP_R1_TYPE | 0)          /*!< SET_BLOCK_LEN */
+#define SD_CMD17_READ_SINGLE_BLOCK (SDC_COMMAND_INDEX(MMC_READ_SINGLE_BLOCK) | CMDRESP_R1_TYPE | 0)        /*!< READ_SINGLE_BLOCK */
+#define SD_CMD18_READ_MULTIPLE_BLOCK (SDC_COMMAND_INDEX(MMC_READ_MULTIPLE_BLOCK) | CMDRESP_R1_TYPE | 0)      /*!< READ_MULTIPLE_BLOCK */
+
+/* Block-Oriented Write Commands (class 4) */
+#define SD_CMD24_WRITE_BLOCK       (SDC_COMMAND_INDEX(MMC_WRITE_BLOCK) | CMDRESP_R1_TYPE | 0)          /*!< WRITE_BLOCK */
+#define SD_CMD25_WRITE_MULTIPLE_BLOCK (SDC_COMMAND_INDEX(MMC_WRITE_MULTIPLE_BLOCK) | CMDRESP_R1_TYPE | 0)    /*!< WRITE_MULTIPLE_BLOCK */
+
+/* Erase Commands (class 5) */
+#define SD_CMD32_ERASE_WR_BLK_START (SDC_COMMAND_INDEX(SD_ERASE_WR_BLK_START) | CMDRESP_R1_TYPE | 0)      /*!< ERASE_WR_BLK_START */
+#define SD_CMD33_ERASE_WR_BLK_END   (SDC_COMMAND_INDEX(SD_ERASE_WR_BLK_END) | CMDRESP_R1_TYPE | 0)        /*!< ERASE_WR_BLK_END */
+#define SD_CMD38_ERASE              (SDC_COMMAND_INDEX(SD_ERASE) | CMDRESP_R1b_TYPE | 0)            /*!< ERASE */
+
+/* Application-Specific Commands (class 8) */
+#define SD_CMD55_APP_CMD           (SDC_COMMAND_INDEX(MMC_APP_CMD) | CMDRESP_R1_TYPE | 0)            /*!< APP_CMD */
+#define SD_ACMD6_SET_BUS_WIDTH     (SDC_COMMAND_INDEX(SD_APP_SET_BUS_WIDTH) | CMDRESP_R1_TYPE | 0)        /*!< SET_BUS_WIDTH */
+#define SD_ACMD13_SEND_SD_STATUS   (SDC_COMMAND_INDEX(MMC_SEND_STATUS) | CMDRESP_R1_TYPE | 0)          /*!< SEND_SD_STATUS */
+#define SD_ACMD41_SD_SEND_OP_COND  (SDC_COMMAND_INDEX(SD_APP_OP_COND) | CMDRESP_R3_TYPE | 0)          /*!< SD_SEND_OP_COND */
+
+/**
+ * @brief SDC Interrupt Mask Register bit definitions
+ */
+/** Mask CmdCrcFail flag.*/
+#define SDC_MASK0_CMDCRCFAIL     (((uint32_t) 1 ) << 0)
+/** Mask DataCrcFail flag. */
+#define SDC_MASK0_DATACRCFAIL     (((uint32_t) 1 ) << 1)
+/** Mask CmdTimeOut flag. */
+#define SDC_MASK0_CMDTIMEOUT     (((uint32_t) 1 ) << 2)
+/** Mask DataTimeOut flag. */
+#define SDC_MASK0_DATATIMEOUT     (((uint32_t) 1 ) << 3)
+/** Mask TxUnderrun flag. */
+#define SDC_MASK0_TXUNDERRUN     (((uint32_t) 1 ) << 4)
+/** Mask RxOverrun flag. */
+#define SDC_MASK0_RXOVERRUN     (((uint32_t) 1 ) << 5)
+/** Mask CmdRespEnd flag. */
+#define SDC_MASK0_CMDRESPEND     (((uint32_t) 1 ) << 6)
+/** Mask CmdSent flag.*/
+#define SDC_MASK0_CMDSENT     (((uint32_t) 1 ) << 7)
+/** Mask DataEnd flag.*/
+#define SDC_MASK0_DATAEND     (((uint32_t) 1 ) << 8)
+/** Mask StartBitErr flag.*/
+#define SDC_MASK0_STARTBITERR     (((uint32_t) 1 ) << 9)
+/** Mask DataBlockEnd flag.*/
+#define SDC_MASK0_DATABLOCKEND     (((uint32_t) 1 ) << 10)
+/** Mask CmdActive flag.*/
+#define SDC_MASK0_CMDACTIVE     (((uint32_t) 1 ) << 11)
+/** Mask TxActive flag.*/
+#define SDC_MASK0_TXACTIVE     (((uint32_t) 1 ) << 12)
+/** Mask RxActive flag.*/
+#define SDC_MASK0_RXACTIVE     (((uint32_t) 1 ) << 13)
+/** Mask TxFifoHalfEmpty flag.*/
+#define SDC_MASK0_TXFIFOHALFEMPTY     (((uint32_t) 1 ) << 14)
+/** Mask RxFifoHalfFull flag.*/
+#define SDC_MASK0_RXFIFOHALFFULL     (((uint32_t) 1 ) << 15)
+/** Mask TxFifoFull flag.*/
+#define SDC_MASK0_TXFIFOFULL     (((uint32_t) 1 ) << 16)
+/** Mask RxFifoFull flag.*/
+#define SDC_MASK0_RXFIFOFULL     (((uint32_t) 1 ) << 17)
+/** Mask TxFifoEmpty flag.*/
+#define SDC_MASK0_TXFIFOEMPTY     (((uint32_t) 1 ) << 18)
+/** Mask RxFifoEmpty flag.*/
+#define SDC_MASK0_RXFIFOEMPTY     (((uint32_t) 1 ) << 19)
+/** Mask TxDataAvlbl flag.*/
+#define SDC_MASK0_TXDATAAVLBL     (((uint32_t) 1 ) << 20)
+/** Mask RxDataAvlbl flag.*/
+#define SDC_MASK0_RXDATAAVLBL     (((uint32_t) 1 ) << 21)
+/** CMD error interrupt mask */
+#define SDC_MASK0_CMDERR    (SDC_MASK0_CMDCRCFAIL | SDC_MASK0_CMDTIMEOUT | SDC_MASK0_STARTBITERR)
+/** Data Transmit Error interrupt mask */
+#define SDC_MASK0_TXDATAERR    (SDC_MASK0_DATACRCFAIL | SDC_MASK0_DATATIMEOUT | SDC_MASK0_TXUNDERRUN | SDC_MASK0_STARTBITERR)
+/** Data Receive Error interrupt mask */
+#define SDC_MASK0_RXDATAERR    (SDC_MASK0_DATACRCFAIL | SDC_MASK0_DATATIMEOUT | SDC_MASK0_RXOVERRUN | SDC_MASK0_STARTBITERR)
+/** Data Transfer interrupt mask*/
+#define SDC_MASK0_DATA    (SDC_MASK0_DATAEND | SDC_MASK0_DATABLOCKEND )
+
+/**
+ * @brief SDC Clock Control Register bit definitions
+ */
+/** SDC Clock Control Register Bitmask */
+#define SDC_CLOCK_BITMASK       ((uint32_t) 0xFFF)
+/** SDC Clock Divider Bitmask */
+#define SDC_CLOCK_CLKDIV_BITMASK    (((uint32_t) 0xFF ) << 0)
+/** Set SDC Clock Divide value */
+#define SDC_CLOCK_CLKDIV(n)     (((uint32_t) (n & 0x0FF)) << 0)
+
+/**
+ * @brief SDC Status Register bit definitions
+ */
+/** Command Response received (CRC check failed) */
+#define SDC_STATUS_CMDCRCFAIL     (((uint32_t) 1 ) << 0)
+/** Data block sent/received (CRC check failed). */
+#define SDC_STATUS_DATACRCFAIL     (((uint32_t) 1 ) << 1)
+/** Command response timeout.. */
+#define SDC_STATUS_CMDTIMEOUT     (((uint32_t) 1 ) << 2)
+/** Data timeout. */
+#define SDC_STATUS_DATATIMEOUT     (((uint32_t) 1 ) << 3)
+/** Transmit FIFO underrun error. */
+#define SDC_STATUS_TXUNDERRUN     (((uint32_t) 1 ) << 4)
+/** Receive FIFO overrun error. */
+#define SDC_STATUS_RXOVERRUN     (((uint32_t) 1 ) << 5)
+/** Command response received (CRC check passed). */
+#define SDC_STATUS_CMDRESPEND     (((uint32_t) 1 ) << 6)
+/** Command sent (no response required).*/
+#define SDC_STATUS_CMDSENT     (((uint32_t) 1 ) << 7)
+/** Data end (data counter is zero).*/
+#define SDC_STATUS_DATAEND     (((uint32_t) 1 ) << 8)
+/** Start bit not detected on all data signals in wide bus mode..*/
+#define SDC_STATUS_STARTBITERR     (((uint32_t) 1 ) << 9)
+/** Data block sent/received (CRC check passed).*/
+#define SDC_STATUS_DATABLOCKEND     (((uint32_t) 1 ) << 10)
+/** Command transfer in progress.*/
+#define SDC_STATUS_CMDACTIVE     (((uint32_t) 1 ) << 11)
+/** Data transmit in progress.*/
+#define SDC_STATUS_TXACTIVE     (((uint32_t) 1 ) << 12)
+/** Data receive in progress.*/
+#define SDC_STATUS_RXACTIVE     (((uint32_t) 1 ) << 13)
+/** Transmit FIFO half empty.*/
+#define SDC_STATUS_TXFIFOHALFEMPTY     (((uint32_t) 1 ) << 14)
+/** Receive FIFO half full.*/
+#define SDC_STATUS_RXFIFOHALFFULL     (((uint32_t) 1 ) << 15)
+/** Transmit FIFO full.*/
+#define SDC_STATUS_TXFIFOFULL     (((uint32_t) 1 ) << 16)
+/** Receive FIFO full.*/
+#define SDC_STATUS_RXFIFOFULL     (((uint32_t) 1 ) << 17)
+/** Transmit FIFO empty.*/
+#define SDC_STATUS_TXFIFOEMPTY     (((uint32_t) 1 ) << 18)
+/** Receive FIFO empty.*/
+#define SDC_STATUS_RXFIFOEMPTY     (((uint32_t) 1 ) << 19)
+/** Data available in transmit FIFO.*/
+#define SDC_STATUS_TXDATAAVLBL     (((uint32_t) 1 ) << 20)
+/** Data available in receive FIFO.*/
+#define SDC_STATUS_RXDATAAVLBL     (((uint32_t) 1 ) << 21)
+/** Command Error Status */
+#define SDC_STATUS_CMDERR    (SDC_STATUS_CMDCRCFAIL | SDC_STATUS_CMDTIMEOUT | SDC_STATUS_STARTBITERR)
+/** Data Error Status */
+#define SDC_STATUS_DATAERR    (SDC_STATUS_DATACRCFAIL | SDC_STATUS_DATATIMEOUT | SDC_STATUS_TXUNDERRUN \
+                 | SDC_STATUS_RXOVERRUN | SDC_STATUS_STARTBITERR)
+/** FIFO Status*/
+#define SDC_STATUS_FIFO    (SDC_STATUS_TXFIFOHALFEMPTY | SDC_STATUS_RXFIFOHALFFULL \
+              | SDC_STATUS_TXFIFOFULL  | SDC_STATUS_RXFIFOFULL \
+              | SDC_STATUS_TXFIFOEMPTY | SDC_STATUS_RXFIFOEMPTY \
+              | SDC_STATUS_DATABLOCKEND)
+
+/** Data Transfer Status*/
+#define SDC_STATUS_DATA    (SDC_STATUS_DATAEND )
+
+/**
+ * @brief SDC Data Control Register bit definitions
+ */
+/** SDC Data Control Register Bitmask */
+#define SDC_DATACTRL_BITMASK        ((uint32_t) 0xFF)
+/** Enable Data Transfer */
+#define SDC_DATACTRL_ENABLE             (((uint32_t) 1 ) << 0)
+/** Mark that Data is transfer from card to controller */
+#define SDC_DATACTRL_DIR_FROMCARD       (((uint32_t) 1 ) << 1)
+/** Mark that Data is transfer from controller to card */
+#define SDC_DATACTRL_DIR_TOCARD         ((uint32_t) 0)
+/** Mark that the transfer mode is Stream Data Transfer */
+#define SDC_DATACTRL_XFER_MODE_STREAM   (((uint32_t) 1 ) << 2)
+/** Mark that the transfer mode is Block Data Transfer */
+#define SDC_DATACTRL_XFER_MODE_BLOCK    ((uint32_t) 0)
+/** Enable DMA */
+#define SDC_DATACTRL_DMA_ENABLE         (((uint32_t) 1 ) << 3)
+/** Set Data Block size */
+#define SDC_DATACTRL_BLOCKSIZE(n)       (((uint32_t) (n & 0x0F) ) << 4)
+/** Get Data Block size value */
+#define SDC_DATACTRL_BLOCKSIZE_VAL(n)   (((uint32_t) 1) << n)
+
+/**
+ * @brief OCR Register definitions
+ */
+/** Support voltage range 2.7-3.6 */
+#define SDC_OCR_27_36               ((uint32_t) 0x00FF8000)
+/** Card power up status bit */
+#define SDC_OCR_IDLE                (((uint32_t) 1) << 31)
+#define SDC_OCR_BUSY                (((uint32_t) 0) << 31)
+
+
+/* SD/MMC commands - this matrix shows the command, response types, and
+   supported card type for that command.
+   Command                 Number Resp  SD  MMC
+   ----------------------- ------ ----- --- ---
+   Reset (go idle)         CMD0   NA    x   x
+   Send op condition       CMD1   R3        x
+   All send CID            CMD2   R2    x   x
+   Send relative address   CMD3   R1        x
+   Send relative address   CMD3   R6    x
+   Program DSR             CMD4   NA        x
+   Select/deselect card    CMD7   R1b       x
+   Select/deselect card    CMD7   R1    x
+   Send CSD                CMD9   R2    x   x
+   Send CID                CMD10  R2    x   x
+   Read data until stop    CMD11  R1    x   x
+   Stop transmission       CMD12  R1/b  x   x
+   Send status             CMD13  R1    x   x
+   Go inactive state       CMD15  NA    x   x
+   Set block length        CMD16  R1    x   x
+   Read single block       CMD17  R1    x   x
+   Read multiple blocks    CMD18  R1    x   x
+   Write data until stop   CMD20  R1        x
+   Setblock count          CMD23  R1        x
+   Write single block      CMD24  R1    x   x
+   Write multiple blocks   CMD25  R1    x   x
+   Program CID             CMD26  R1        x
+   Program CSD             CMD27  R1    x   x
+   Set write protection    CMD28  R1b   x   x
+   Clear write protection  CMD29  R1b   x   x
+   Send write protection   CMD30  R1    x   x
+   Erase block start       CMD32  R1    x
+   Erase block end         CMD33  R1    x
+   Erase block start       CMD35  R1        x
+   Erase block end         CMD36  R1        x
+   Erase blocks            CMD38  R1b       x
+   Fast IO                 CMD39  R4        x
+   Go IRQ state            CMD40  R5        x
+   Lock/unlock             CMD42  R1b       x
+   Application command     CMD55  R1        x
+   General command         CMD56  R1b       x
+
+ *** SD card application commands - these must be preceded with ***
+ *** MMC CMD55 application specific command first               ***
+   Set bus width           ACMD6  R1    x
+   Send SD status          ACMD13 R1    x
+   Send number WR blocks   ACMD22 R1    x
+   Set WR block erase cnt  ACMD23 R1    x
+   Send op condition       ACMD41 R3    x
+   Set clear card detect   ACMD42 R1    x
+   Send CSR                ACMD51 R1    x */
+
+/**
+ * @brief  Possible SDMMC card state types
+ */
+typedef enum {
+  SDMMC_IDLE_ST = 0,  /*!< Idle state */
+  SDMMC_READY_ST,     /*!< Ready state */
+  SDMMC_IDENT_ST,     /*!< Identification State */
+  SDMMC_STBY_ST,      /*!< standby state */
+  SDMMC_TRAN_ST,      /*!< transfer state */
+  SDMMC_DATA_ST,      /*!< Sending-data State */
+  SDMMC_RCV_ST,       /*!< Receive-data State */
+  SDMMC_PRG_ST,       /*!< Programming State */
+  SDMMC_DIS_ST        /*!< Disconnect State */
+} SDMMC_STATE_T;
+
+
+/**
+ * @brief SD/MMC commands, arguments and responses
+ * Standard SD/MMC commands (3.1)       type  argument     response
+ */
+/* class 1 */
+#define MMC_GO_IDLE_STATE         0    /* bc                          */
+#define MMC_SEND_OP_COND          1    /* bcr  [31:0]  OCR        R3  */
+#define MMC_ALL_SEND_CID          2    /* bcr                     R2  */
+#define MMC_SET_RELATIVE_ADDR     3    /* ac   [31:16] RCA        R1  */
+#define MMC_SET_DSR               4    /* bc   [31:16] RCA            */
+#define MMC_SELECT_CARD           7    /* ac   [31:16] RCA        R1  */
+#define MMC_SEND_EXT_CSD          8    /* bc                      R1  */
+#define MMC_SEND_CSD              9    /* ac   [31:16] RCA        R2  */
+#define MMC_SEND_CID             10    /* ac   [31:16] RCA        R2  */
+#define MMC_STOP_TRANSMISSION    12    /* ac                      R1b */
+#define MMC_SEND_STATUS          13    /* ac   [31:16] RCA        R1  */
+#define MMC_GO_INACTIVE_STATE    15    /* ac   [31:16] RCA            */
+
+/* class 2 */
+#define MMC_SET_BLOCKLEN         16    /* ac   [31:0]  block len  R1  */
+#define MMC_READ_SINGLE_BLOCK    17    /* adtc [31:0]  data addr  R1  */
+#define MMC_READ_MULTIPLE_BLOCK  18    /* adtc [31:0]  data addr  R1  */
+
+/* class 3 */
+#define MMC_WRITE_DAT_UNTIL_STOP 20    /* adtc [31:0]  data addr  R1  */
+
+/* class 4 */
+#define MMC_SET_BLOCK_COUNT      23    /* adtc [31:0]  data addr  R1  */
+#define MMC_WRITE_BLOCK          24    /* adtc [31:0]  data addr  R1  */
+#define MMC_WRITE_MULTIPLE_BLOCK 25    /* adtc                    R1  */
+#define MMC_PROGRAM_CID          26    /* adtc                    R1  */
+#define MMC_PROGRAM_CSD          27    /* adtc                    R1  */
+
+/* class 6 */
+#define MMC_SET_WRITE_PROT       28    /* ac   [31:0]  data addr  R1b */
+#define MMC_CLR_WRITE_PROT       29    /* ac   [31:0]  data addr  R1b */
+#define MMC_SEND_WRITE_PROT      30    /* adtc [31:0]  wpdata addr R1  */
+
+/* class 5 */
+#define MMC_ERASE_GROUP_START    35    /* ac   [31:0]  data addr  R1  */
+#define MMC_ERASE_GROUP_END      36    /* ac   [31:0]  data addr  R1  */
+#define MMC_ERASE                37    /* ac                      R1b */
+#define SD_ERASE_WR_BLK_START    32    /* ac   [31:0]  data addr  R1  */
+#define SD_ERASE_WR_BLK_END      33    /* ac   [31:0]  data addr  R1  */
+#define SD_ERASE                 38    /* ac                      R1b */
+
+/* class 9 */
+#define MMC_FAST_IO              39    /* ac   <Complex>          R4  */
+#define MMC_GO_IRQ_STATE         40    /* bcr                     R5  */
+
+/* class 7 */
+#define MMC_LOCK_UNLOCK          42    /* adtc                    R1b */
+
+/* class 8 */
+#define MMC_APP_CMD              55    /* ac   [31:16] RCA        R1  */
+#define MMC_GEN_CMD              56    /* adtc [0]     RD/WR      R1b */
+
+/* SD commands                           type  argument     response */
+/* class 8 */
+/* This is basically the same command as for MMC with some quirks. */
+#define SD_SEND_RELATIVE_ADDR     3    /* ac                      R6  */
+#define SD_CMD8                   8    /* bcr  [31:0]  OCR        R3  */
+
+/* Application commands */
+#define SD_APP_SET_BUS_WIDTH      6    /* ac   [1:0]   bus width  R1   */
+#define SD_APP_OP_COND           41    /* bcr  [31:0]  OCR        R1 (R4)  */
+#define SD_APP_SEND_SCR          51    /* adtc                    R1   */
+
+
+/**
+ * @brief MMC status in R1<br>
+ * Type<br>
+ *   e : error bit<br>
+ *   s : status bit<br>
+ *   r : detected and set for the actual command response<br>
+ *   x : detected and set during command execution. the host must poll
+ *       the card by sending status command in order to read these bits.
+ * Clear condition<br>
+ *   a : according to the card state<br>
+ *   b : always related to the previous command. Reception of
+ *       a valid command will clear it (with a delay of one command)<br>
+ *   c : clear by read<br>
+ */
+
+#define R1_OUT_OF_RANGE         (1UL << 31)  /* er, c */
+#define R1_ADDRESS_ERROR        (1 << 30)  /* erx, c */
+#define R1_BLOCK_LEN_ERROR      (1 << 29)  /* er, c */
+#define R1_ERASE_SEQ_ERROR      (1 << 28)  /* er, c */
+#define R1_ERASE_PARAM          (1 << 27)  /* ex, c */
+#define R1_WP_VIOLATION         (1 << 26)  /* erx, c */
+#define R1_CARD_IS_LOCKED       (1 << 25)  /* sx, a */
+#define R1_LOCK_UNLOCK_FAILED   (1 << 24)  /* erx, c */
+#define R1_COM_CRC_ERROR        (1 << 23)  /* er, b */
+#define R1_ILLEGAL_COMMAND      (1 << 22)  /* er, b */
+#define R1_CARD_ECC_FAILED      (1 << 21)  /* ex, c */
+#define R1_CC_ERROR             (1 << 20)  /* erx, c */
+#define R1_ERROR                (1 << 19)  /* erx, c */
+#define R1_UNDERRUN             (1 << 18)  /* ex, c */
+#define R1_OVERRUN              (1 << 17)  /* ex, c */
+#define R1_CID_CSD_OVERWRITE    (1 << 16)  /* erx, c, CID/CSD overwrite */
+#define R1_WP_ERASE_SKIP        (1 << 15)  /* sx, c */
+#define R1_CARD_ECC_DISABLED    (1 << 14)  /* sx, a */
+#define R1_ERASE_RESET          (1 << 13)  /* sr, c */
+#define R1_STATUS(x)            (x & 0xFFFFE000)
+#define R1_CURRENT_STATE(x)     ((x & 0x00001E00) >> 9)  /* sx, b (4 bits) */
+#define R1_READY_FOR_DATA       (1 << 8)  /* sx, a */
+#define R1_APP_CMD              (1 << 5)  /* sr, c */
+
+
+/**
+ * @brief SD/MMC card OCR register bits
+ */
+#define OCR_ALL_READY           (1UL << 31)  /* Card Power up status bit */
+#define OCR_HC_CCS              (1 << 30)  /* High capacity card */
+#define OCR_VOLTAGE_RANGE_MSK   (0x00FF8000)
+
+#define SD_SEND_IF_ARG          0x000001AA
+#define SD_SEND_IF_ECHO_MSK     0x000000FF
+#define SD_SEND_IF_RESP         0x000000AA
+
+/**
+ * @brief R3 response definitions
+ */
+#define CMDRESP_R3_OCR_VAL(n)           (((uint32_t) n) & 0xFFFFFF)
+#define CMDRESP_R3_S18A                 (((uint32_t) 1 ) << 24)
+#define CMDRESP_R3_HC_CCS               (((uint32_t) 1 ) << 30)
+#define CMDRESP_R3_INIT_COMPLETE        (((uint32_t) 1 ) << 31)
+
+/**
+ * @brief R6 response definitions
+ */
+#define CMDRESP_R6_RCA_VAL(n)           (((uint32_t) (n >> 16)) & 0xFFFF)
+#define CMDRESP_R6_CARD_STATUS(n)       (((uint32_t) (n & 0x1FFF)) | \
+                     ((n & (1 << 13)) ? (1 << 19) : 0) | \
+                     ((n & (1 << 14)) ? (1 << 22) : 0) | \
+                     ((n & (1 << 15)) ? (1 << 23) : 0))
+
+/**
+ * @brief R7 response definitions
+ */
+/** Echo-back of check-pattern */
+#define CMDRESP_R7_CHECK_PATTERN(n)     (((uint32_t) n ) & 0xFF)
+/** Voltage accepted */
+#define CMDRESP_R7_VOLTAGE_ACCEPTED     (((uint32_t) 1 ) << 8)
+
+/**
+ * @brief CMD3 command definitions
+ */
+/** Card Address */
+#define CMD3_RCA(n)         (((uint32_t) (n & 0xFFFF) ) << 16)
+
+/**
+ * @brief CMD7 command definitions
+ */
+/** Card Address */
+#define CMD7_RCA(n)         (((uint32_t) (n & 0xFFFF) ) << 16)
+
+/**
+ * @brief CMD8 command definitions
+ */
+/** Check pattern */
+#define CMD8_CHECKPATTERN(n)            (((uint32_t) (n & 0xFF) ) << 0)
+/** Recommended pattern */
+#define CMD8_DEF_PATTERN                    (0xAA)
+/** Voltage supplied.*/
+#define CMD8_VOLTAGESUPPLIED_27_36     (((uint32_t) 1 ) << 8)
+
+/**
+ * @brief CMD9 command definitions
+ */
+#define CMD9_RCA(n)         (((uint32_t) (n & 0xFFFF) ) << 16)
+
+/**
+ * @brief CMD13 command definitions
+ */
+#define CMD13_RCA(n)            (((uint32_t) (n & 0xFFFF) ) << 16)
+
+/**
+ * @brief APP_CMD command definitions
+ */
+#define CMD55_RCA(n)            (((uint32_t) (n & 0xFFFF) ) << 16)
+
+/**
+ * @brief ACMD41 command definitions
+ */
+#define ACMD41_OCR(n)                   (((uint32_t) n) & 0xFFFFFF)
+#define ACMD41_S18R                     (((uint32_t) 1 ) << 24)
+#define ACMD41_XPC                      (((uint32_t) 1 ) << 28)
+#define ACMD41_HCS                      (((uint32_t) 1 ) << 30)
+
+/**
+ * @brief ACMD6 command definitions
+ */
+#define ACMD6_BUS_WIDTH(n)              ((uint32_t) n & 0x03)
+#define ACMD6_BUS_WIDTH_1               (0)
+#define ACMD6_BUS_WIDTH_4               (2)
+
+/** @brief Card type defines
+ */
+#define CARD_TYPE_SD    (1 << 0)
+#define CARD_TYPE_4BIT  (1 << 1)
+#define CARD_TYPE_8BIT  (1 << 2)
+#define CARD_TYPE_HC    (OCR_HC_CCS)/*!< high capacity card > 2GB */
+
+/**
+ * @brief SD/MMC sector size in bytes
+ */
+#define MMC_SECTOR_SIZE     512
+
+/******************************************************************************
+ * External global variables
+ *****************************************************************************/
+
+/******************************************************************************
+ * Local variables
+ *****************************************************************************/
+
+static MCIFileSystem* pUglyForIRQ = NULL;
+
+/******************************************************************************
+ * Local Functions
+ *****************************************************************************/
+
+static void mymciirq()
+{
+  pUglyForIRQ->mci_MCIIRQHandler();
+}
+
+static void mydmairq()
+{
+  pUglyForIRQ->mci_DMAIRQHandler();
+}
+
+/******************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+MCIFileSystem::MCIFileSystem(const char* name, PinName cd) :
+    FATFileSystem(name)
+{
+    pUglyForIRQ = this;
+
+    _Stat = STA_NOINIT;
+    memset(&_sdCardInfo, 0, sizeof(SDMMC_CARD_T));
+    _eventReceived = false;
+    _eventSuccess = false;
+
+    initMCI();
+
+    if (cd != NC)
+    {
+      _cardDetect = new DigitalIn(cd);
+    }
+}
+
+MCIFileSystem::~MCIFileSystem()
+{
+  if (_cardDetect != NULL)
+  {
+    delete _cardDetect;
+  }
+}
+void MCIFileSystem::initMCI()
+{
+    // Pinsel for MCI
+    LPC_IOCON->P1_2  = 2;          /* SD_CLK @ P1.2 */
+    LPC_IOCON->P1_3  = 2;          /* SD_CMD @ P1.3 */
+    LPC_IOCON->P1_5  = 2 | (1<<7); /* SD_PWR @ P1.5 - digital mode */
+    LPC_IOCON->P1_6  = 2 | (1<<7); /* SD_DAT[0] @ P1.6 - digital mode */
+    LPC_IOCON->P1_7  = 2 | (1<<7); /* SD_DAT[1] @ P1.7 - digital mode */
+    LPC_IOCON->P1_11 = 2;          /* SD_DAT[2] @ P1.11 */
+    LPC_IOCON->P1_12 = 2;          /* SD_DAT[3] @ P1.12 */
+
+    LPC_SC->PCONP |= SYSCTL_CLOCK_SDC;
+    LPC_SC->RSTCON0 = (1<<28);
+    LPC_SC->RSTCON0 &= ~(1<<28);
+
+    /* Initialize GPDMA controller */
+    gpdma_init();
+
+    /* Initialize SDC peripheral */
+    LPC_SC->PCONP |= SYSCTL_CLOCK_SDC;
+
+    /* Disable SD_CLK */
+    mci_ClockControl(SDC_CLOCK_ENABLE, false);
+
+    /* Power-off */
+    mci_PowerControl(PowerOff, 0);
+    mci_WriteDelay();
+
+    /* Disable all interrupts */
+    LPC_MCI->MASK0 = 0;
+
+    /*Setting for timeout problem */
+    LPC_MCI->DATATMR = 0x1FFFFFFF;
+
+    LPC_MCI->COMMAND = 0;
+    mci_WriteDelay();
+
+    LPC_MCI->DATACTRL = 0;
+    mci_WriteDelay();
+
+    /* clear all pending interrupts */
+    LPC_MCI->CLEAR = SDC_CLEAR_ALL;
+
+    /* Power-up SDC Peripheral */
+    mci_PowerControl(PowerUp, 0);
+
+    /* delays for the supply output is stable*/
+    for (uint32_t i = 0; i < 0x80000; i++ ) {}
+
+    mci_SetClock(SDC_IDENT_CLOCK_RATE);
+    mci_ClockControl(SDC_CLOCK_ENABLE, true);
+
+    /* Power-on SDC Interface */
+    mci_PowerControl(PowerOn, 0);
+
+    NVIC_SetVector(MCI_IRQn, (uint32_t) mymciirq);
+    NVIC_EnableIRQ(MCI_IRQn);
+
+    NVIC_SetVector(DMA_IRQn, (uint32_t) mydmairq);
+    NVIC_EnableIRQ(DMA_IRQn);
+}
+
+int MCIFileSystem::disk_initialize() {
+
+    debug_if(MCI_DBG, "mcifs:disk_initialize(), _Stat = %#x\n", _Stat);
+
+    if (!cardInserted()) {
+      /* No card in the socket */
+      _Stat = STA_NODISK | STA_NOINIT;
+    }
+
+    if (_Stat != STA_NOINIT) {
+        return _Stat;          /* card is already enumerated */
+    }
+
+    //rtc_init();
+
+    /* Initialize the Card Data Strucutre */
+    memset(&_sdCardInfo, 0, sizeof(SDMMC_CARD_T));
+
+    /* Reset */
+    _Stat = STA_NOINIT;
+
+    /* Enumerate the card once detected. Note this function may block for a little while. */
+    int ret = mci_Acquire();
+    if (ret != 1) {
+      debug("Card Acquire failed... got %d, but expected 1\r\n", ret);
+      return 1;//Stat;
+    }
+
+    _Stat &= ~STA_NOINIT;
+    return _Stat;
+}
+
+int MCIFileSystem::disk_write(const uint8_t *buffer, uint64_t block_number) {
+    debug_if(MCI_DBG, "mcifs:disk_write(%#x, %llu), _Stat = %#x\n", (uint32_t)buffer, block_number, _Stat);
+    if (_Stat & STA_NOINIT) {
+        // not ready
+        return 1;
+    }
+    if (mci_WriteBlocks((void*)buffer, block_number, 1) == SDC_RET_OK) {
+        return 0;
+    }
+
+    return 1;
+}
+
+int MCIFileSystem::disk_read(uint8_t *buffer, uint64_t block_number) {
+    debug_if(MCI_DBG, "mcifs:disk_read(%#x, %llu), _Stat = %#x\n", (uint32_t)buffer, block_number, _Stat);
+    if (_Stat & STA_NOINIT) {
+        // not ready
+        return _Stat;
+    }
+    if (mci_ReadBlocks(buffer, block_number, 1) == SDC_RET_OK) {
+        return 0;
+    }
+
+    return 1;
+}
+
+int MCIFileSystem::disk_status()
+{
+  debug_if(MCI_DBG, "mcifs:disk_status(), _Stat = %#x\n", _Stat);
+  return _Stat;
+}
+
+int MCIFileSystem::disk_sync()
+{
+  debug_if(MCI_DBG, "mcifs:disk_sync(), _Stat = %#x\n", _Stat);
+  uint32_t end = us_ticker_read() + 50*1000; // 50ms
+  while (us_ticker_read() < end)
+  {
+    if (mci_GetCardStatus() & R1_READY_FOR_DATA)
+    {
+      // card is ready
+      return 0;
+    }
+  }
+  // timeout while waiting for card to get ready
+  return 1;
+}
+
+uint64_t MCIFileSystem::disk_sectors()
+{
+    debug_if(MCI_DBG, "mcifs:disk_sectors(), _Stat = %#x, returning %llu\n", _Stat, _sdCardInfo.blocknr);
+    return _sdCardInfo.blocknr;
+}
+
+void MCIFileSystem::mci_MCIIRQHandler()
+{
+  int32_t Ret;
+
+  Ret = mci_IRQHandler(NULL, 0, NULL, 0);
+  if(Ret < 0) {
+    _eventSuccess = false;
+    _eventReceived = true;
+  }
+}
+
+void MCIFileSystem::mci_DMAIRQHandler()
+{
+  _eventSuccess = gpdma_interrupt(_eventDmaChannel);
+  _eventReceived = true;
+  NVIC_DisableIRQ(DMA_IRQn);
+}
+
+/******************************************************************************
+ * Private Functions
+ *****************************************************************************/
+
+bool MCIFileSystem::cardInserted() const
+{
+    // If no card detect pin is given, then assume that a card is inserted.
+    // If a pin is specified then use that to determing the presence of a card.
+    return ((_cardDetect == NULL) || (_cardDetect->read() == 0));
+}
+
+
+
+int32_t MCIFileSystem::mci_Acquire()
+{
+  int32_t Ret;
+
+  /* Initialize card info */
+  _sdCardInfo.speed = SDC_TRAN_CLOCK_RATE;
+  _sdCardInfo.card_type = 0;
+
+  /* During identification phase, the clock should be less than
+     400Khz. Once we pass this phase, the normal clock can be set up
+     to 25Mhz on SD card and 20Mhz on MMC card. */
+  mci_SetClock(SDC_IDENT_CLOCK_RATE);
+
+  /* Clear Open Drain output control for SD */
+  mci_PowerControl(PowerOn, 0);
+  
+  /* Card Reset */
+  Ret = mci_ExecuteCmd(SD_GO_IDLE_STATE, 0, NULL);
+  if (Ret != 0) {
+    return Ret;
+  }
+
+  wait(ACQUIRE_DELAY);
+
+  /* Send interface operation condiftion */
+  Ret = mci_SendIfCond();
+  if (Ret == SDC_RET_BAD_PARAMETERS) {
+    return Ret;    /* Non-compatible voltage range or check pattern is not correct */
+
+  }
+  /* Get Card Type */
+  if (Ret == SDC_RET_OK) {/* Ver2.00 or later SD Memory Card*/
+    bool CCS;
+    uint32_t OCR = SDC_OCR_27_36;
+    _sdCardInfo.card_type |= CARD_TYPE_SD;
+    Ret = mci_SendAppOpCond(0, true, &OCR, &CCS);
+    if (CCS) {  /* High Capacity or Extended Capacity SD Memory Card */
+      _sdCardInfo.card_type |= CARD_TYPE_HC;
+    }
+  }
+  else {  /*Ver2.00 or later SD Memory Card(voltage mismatch) or Ver1.X SD Memory Card
+         or not SD Memory Card*/
+    bool CCS;
+    uint32_t OCR = SDC_OCR_27_36;
+    Ret = mci_SendAppOpCond(0, false, &OCR, &CCS);
+    if (Ret == SDC_RET_OK) {
+      _sdCardInfo.card_type |= CARD_TYPE_SD;
+    }
+    else if (Ret == SDC_RET_BAD_PARAMETERS) {
+      return Ret;
+    }
+    else {  /* MMC Card setup */
+      uint32_t OCR;
+      /* Enter to Open Drain mode */
+      mci_PowerControl(PowerOn, SDC_PWR_OPENDRAIN);
+      wait(ACQUIRE_DELAY);
+      Ret = mci_SendOpCond(&OCR);
+      if (Ret != SDC_RET_OK) {
+        return Ret;
+      }
+
+    }
+  }
+
+  /* Read CID */
+  mci_GetCID(_sdCardInfo.cid);
+
+  /* RCA send, for SD get RCA */
+  if (_sdCardInfo.card_type & CARD_TYPE_SD) {
+    mci_GetAddr(&_sdCardInfo.rca);
+  }
+  else {
+    _sdCardInfo.rca = 1;
+    mci_SetAddr(_sdCardInfo.rca);
+    mci_PowerControl(PowerOn, 0);  /* enter to push-pull mode */
+  }
+
+  /* Get CSD */
+  mci_GetCSD(_sdCardInfo.rca, _sdCardInfo.csd);
+
+  /* Compute card size, block size and no. of blocks  based on CSD response recived. */
+  if (_sdCardInfo.cid[0]) {
+    mci_ProcessCSD();
+
+    if (mci_SetTranState(_sdCardInfo.rca) != SDC_RET_OK) {
+      return 0;
+    }
+
+    if (mci_GetCardState() != SDMMC_TRAN_ST) {
+      return 0;
+    }
+
+    if (mci_SetCardParams() != 0) {
+      return 0;
+    }
+  }
+
+  return (_sdCardInfo.cid[0]) ? 1 : 0;
+}
+
+uint32_t MCIFileSystem::mci_GetCardStatus() const
+{
+  uint32_t Status;
+  mci_GetStatus(_sdCardInfo.rca, &Status);
+  return Status;
+}
+
+MCIFileSystem::CardState MCIFileSystem::mci_GetCardState() const
+{
+  uint32_t Status;
+  volatile int32_t Ret;
+
+  /* get current state of the card */
+  Ret = mci_GetStatus(_sdCardInfo.rca, &Status);
+
+  /* check card state in response */
+  return (CardState) R1_CURRENT_STATE(Status);
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_StopTransmission(uint32_t rca) const
+{
+  uint32_t Status;
+  ReturnCode Ret = SDC_RET_FAILED;
+  response_t Response;
+  uint32_t RetryCnt =  20;
+
+  Ret = mci_GetStatus(rca, &Status);
+  if (Ret != SDC_RET_OK) {
+    return SDC_RET_ERR_STATE;
+  }
+
+  if (R1_CURRENT_STATE(Status) == SDMMC_TRAN_ST) {
+    return SDC_RET_OK;
+  }
+
+  if ((R1_CURRENT_STATE(Status) != SDMMC_DATA_ST) &&
+    (R1_CURRENT_STATE(Status) != SDMMC_RCV_ST)) {
+    return SDC_RET_ERR_STATE;
+  }
+
+  while (RetryCnt > 0) {
+    Ret = mci_ExecuteCmd(SD_CMD12_STOP_TRANSMISSION, 0, &Response);
+    if (Ret == SDC_RET_OK) {
+      if (mci_CheckR1Response(Response.Data[0], &Ret)) {
+        if (Ret != SDC_RET_OK) {
+          return Ret;
+        }
+        Ret = mci_GetStatus(rca, &Status);
+        if ((R1_CURRENT_STATE(Status) == SDMMC_TRAN_ST) || (R1_CURRENT_STATE(Status) == SDMMC_PRG_ST)) {
+          return SDC_RET_OK;
+        }
+        return SDC_RET_ERR_STATE;
+      }
+    }
+    RetryCnt--;
+  }
+  return Ret;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_ReadBlocks(void *buffer, int32_t startBlock, int32_t blockNum)
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+  uint8_t dmaChannel;
+  int32_t ByteNum = blockNum *  MMC_SECTOR_SIZE;
+
+  do
+  {
+    /* if card is not acquired return immediately */
+    if (( startBlock < 0) || ( (startBlock + blockNum) > _sdCardInfo.blocknr) ) {
+      Ret = SDC_RET_NOT_READY;
+      break;
+    }
+
+    /* Put to tran state */
+    Ret = mci_SetTranState(_sdCardInfo.rca);
+    if (Ret != SDC_RET_OK) {
+      break;
+    }
+
+    LPC_MCI->MASK0 = SDC_MASK0_DATA | SDC_MASK0_RXDATAERR;
+
+    /* DMA Setup */
+    gpdma_getFreeChannel(&dmaChannel);
+    gpdma_transfer_from_mci(dmaChannel, (uint32_t)buffer, ByteNum);
+    mci_SetupEventWakeup(dmaChannel);
+
+    /* set transfer information */
+    mci_SetDataTransfer(blockNum, true, DATA_TIMER_VALUE_R);
+
+    Ret = _readBlocks(_sdCardInfo.card_type, startBlock, blockNum);
+    if (Ret == SDC_RET_OK) {
+      /* Wait for transfer Finish */
+      if (mci_WaitForEvent() != 0) {
+        Ret = SDC_RET_FAILED;
+      }
+    } else {
+      Ret = SDC_RET_FAILED;
+    }
+
+    gpdma_stop(dmaChannel);
+
+    if ((blockNum > 1) || (mci_GetCardState() == SDMMC_DATA_ST)) {
+      /* Send Stop transmission command */
+      mci_StopTransmission(_sdCardInfo.rca);
+    }
+
+    /* Wait for card to enter tran state */
+    while (mci_GetCardState() != SDMMC_TRAN_ST) {}
+      
+  } while(false);
+
+  return Ret;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_WriteBlocks(void *buffer, int32_t startBlock, int32_t blockNum)
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+  uint8_t dmaChannel;
+  
+  do
+  {
+    /* if card is not acquired return immediately */
+    if (( startBlock < 0) || ( (startBlock + blockNum) > _sdCardInfo.blocknr) ) {
+      Ret = SDC_RET_NOT_READY;
+      break;
+    }
+
+    /* Put to tran state */
+    Ret = mci_SetTranState(_sdCardInfo.rca);
+    if (Ret != SDC_RET_OK) {
+      break;
+    }
+
+    Ret = _writeBlocks(_sdCardInfo.card_type, startBlock, blockNum);
+    if (Ret != SDC_RET_OK) {
+      break;
+    }
+
+    /*Wait for card enter to rcv state*/
+    while (mci_GetCardState() != SDMMC_RCV_ST) {}
+
+    LPC_MCI->MASK0 = SDC_MASK0_DATA | SDC_MASK0_TXDATAERR;
+
+    /* DMA Setup */
+    gpdma_getFreeChannel(&dmaChannel);
+    gpdma_transfer_to_mci(dmaChannel, (uint32_t)buffer, blockNum*MMC_SECTOR_SIZE);
+    mci_SetupEventWakeup(dmaChannel);
+
+    /* set transfer information */
+    mci_SetDataTransfer(blockNum, false, DATA_TIMER_VALUE_W);
+
+    /* Wait for transfer done */
+    if (mci_WaitForEvent() != 0) {
+      Ret = SDC_RET_FAILED;
+    }
+    gpdma_stop(dmaChannel);
+
+    if ((blockNum > 1) || (mci_GetCardState() == SDMMC_RCV_ST)) {
+      /* Send Stop transmission command */
+      mci_StopTransmission(_sdCardInfo.rca);
+    }
+
+    /* Wait for card to enter tran state */
+    while (mci_GetCardState() != SDMMC_TRAN_ST) {}
+      
+  } while (false);
+
+  return Ret;
+}
+
+void MCIFileSystem::mci_SetClock(uint32_t freq) const
+{
+  uint32_t PClk;
+  uint32_t ClkValue = 0;
+
+  PClk = PeripheralClock;
+
+  ClkValue = (PClk + 2 * freq - 1) / (2 * freq);
+  if (ClkValue > 0) {
+    ClkValue -= 1;
+  }
+  uint32_t temp;
+  temp = (LPC_MCI->CLOCK & (~SDC_CLOCK_CLKDIV_BITMASK));
+  LPC_MCI->CLOCK = temp | (SDC_CLOCK_CLKDIV(ClkValue));
+  mci_WriteDelay();
+}
+
+void MCIFileSystem::mci_ClockControl(ClockControl ctrlType, bool enable) const
+{
+  if (enable) {
+    LPC_MCI->CLOCK |= (1 << ctrlType);
+  }
+  else {
+    LPC_MCI->CLOCK &= (~(1 << ctrlType));
+  }
+  mci_WriteDelay();
+}
+
+void MCIFileSystem::mci_PowerControl(power_ctrl_t powerMode, uint32_t flag) const
+{
+  LPC_MCI->POWER = (powerMode & 0x3) | flag;
+  mci_WriteDelay();
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_ExecuteCmd(uint32_t Command, uint32_t Arg, response_t* pResp) const
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+
+  /* Send Command to card */
+  Ret = mci_SendCmd(Command, Arg, CMD_TIMEOUT);
+  if (Ret != SDC_RET_OK) {
+    return Ret;
+  }
+
+  /* Get response (if any) */
+  if ((Command & SDC_COMMAND_RSP_BITMASK) != SDC_COMMAND_NO_RSP) {
+
+    mci_GetResp(pResp);
+
+    /* If the response is not R1, in the response field, the Expected Cmd data
+            won't be the same as the CMD data in SendCmd(). Below four cmds have
+            R2 or R3 response. We don't need to check if MCI_RESP_CMD is the same
+            as the Expected or not. */
+    if ((SDC_COMMAND_INDEX(Command) != MMC_SEND_OP_COND) &&
+      (SDC_COMMAND_INDEX(Command) != SD_APP_OP_COND) &&
+      (SDC_COMMAND_INDEX(Command) != MMC_ALL_SEND_CID) &&
+      (SDC_COMMAND_INDEX(Command) != MMC_SEND_CSD) &&
+      (pResp->CmdIndex != SDC_COMMAND_INDEX(Command))) {
+      return SDC_RET_CMD_FAILED;
+    }
+  }
+
+  return SDC_RET_OK;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_SendIfCond() const
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+  response_t Response;
+  uint32_t RetryCnt =  20;
+
+  while (RetryCnt > 0) {
+    Ret = mci_ExecuteCmd(SD_CMD8_SEND_IF_COND, (CMD8_VOLTAGESUPPLIED_27_36 | CMD8_CHECKPATTERN(
+                              CMD8_DEF_PATTERN)), &Response);
+    if (Ret == SDC_RET_OK) {
+      if ((Response.Data[0] & CMDRESP_R7_VOLTAGE_ACCEPTED) &&
+        (CMDRESP_R7_CHECK_PATTERN(Response.Data[0]) == CMD8_DEF_PATTERN)) {
+        return SDC_RET_OK;
+      }
+      return SDC_RET_BAD_PARAMETERS;
+    }
+    RetryCnt--;
+  }
+  return Ret;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_SendOpCond(uint32_t *pOCR) const
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+  response_t Response;
+  uint32_t RetryCnt =  0x200;
+
+  while (RetryCnt > 0) {
+    Ret = mci_ExecuteCmd(SD_CMD1_SEND_OP_COND, SDC_OCR_27_36, &Response);
+    if (Ret == SDC_RET_OK) {
+      *pOCR = Response.Data[0];
+      if (*pOCR & SDC_OCR_IDLE) {
+        if ((Response.Data[0] & SDC_OCR_27_36) != SDC_OCR_27_36) {
+          return SDC_RET_BAD_PARAMETERS;
+        }
+        return SDC_RET_OK;
+      }
+    }
+    RetryCnt--;
+  }
+  return SDC_RET_FAILED;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_SendAppOpCond(uint16_t rca, bool hcs, uint32_t *pOcr, bool *pCCS) const
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+  response_t Response;
+  uint32_t Argument;
+  uint32_t RetryCnt =  0x2000;  /* The host repeatedly issues ACMD41 for at least 1 second or
+                         until the busy bit are set to 1 */
+
+  Argument = ACMD41_OCR(*pOcr);
+  if (hcs) {
+    Argument |= ACMD41_HCS;
+  }
+
+  while (RetryCnt > 0) {
+    Ret = mci_SendAppCmd(rca);
+    if (Ret == SDC_RET_OK) {
+      Ret = mci_ExecuteCmd(SD_ACMD41_SD_SEND_OP_COND, Argument, &Response);
+      if (Ret == SDC_RET_OK) {
+        if (Response.Data[0] & CMDRESP_R3_INIT_COMPLETE) {
+          if (*pOcr == 0) {
+            *pOcr = CMDRESP_R3_OCR_VAL(Response.Data[0]);
+            return SDC_RET_OK;
+          }
+          if ((CMDRESP_R3_OCR_VAL(Response.Data[0]) & *pOcr) != *pOcr) {
+            return SDC_RET_BAD_PARAMETERS;
+          }
+          *pCCS = (Response.Data[0] & CMDRESP_R3_HC_CCS) ? true : false;
+          return SDC_RET_OK;
+        }
+      }
+    }
+    else {
+      //If we abort here then some cards will go undetected, better to keep retrying
+      //return Ret;
+    }
+    RetryCnt--;
+  }
+  return SDC_RET_FAILED;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_GetCID(uint32_t *pCID) const
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+  response_t Response;
+  uint32_t RetryCnt =  20;
+
+  while (RetryCnt > 0) {
+    Ret = mci_ExecuteCmd(SD_CMD2_ALL_SEND_CID, 0, &Response);
+    if (Ret == SDC_RET_OK) {
+      pCID[3] = Response.Data[0];
+      pCID[2] = Response.Data[1];
+      pCID[1] = Response.Data[2];
+      pCID[0] = Response.Data[3];
+      return SDC_RET_OK;
+    }
+    RetryCnt--;
+  }
+  return Ret;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_SetAddr(uint16_t addr) const
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+  response_t Response;
+  uint32_t RetryCnt =  20;
+
+  while (RetryCnt > 0) {
+    Ret = mci_ExecuteCmd(SD_CMD3_SET_RELATIVE_ADDR, CMD3_RCA(addr), &Response);
+    if (Ret == SDC_RET_OK) {
+      if (mci_CheckR1Response(Response.Data[0], &Ret)) {
+        return Ret;
+      }
+    }
+    RetryCnt--;
+  }
+  return Ret;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_GetAddr(uint16_t *pRCA) const
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+  response_t Response;
+  uint32_t RetryCnt =  20;
+
+  *pRCA = 0;
+  while (RetryCnt > 0) {
+    Ret = mci_ExecuteCmd(SD_CMD3_SEND_RELATIVE_ADDR, 0, &Response);
+    if (Ret == SDC_RET_OK) {
+      if (!(CMDRESP_R6_CARD_STATUS(Response.Data[0]) & R1_READY_FOR_DATA)) {
+        Ret = SDC_RET_NOT_READY;
+      }
+      else if (R1_CURRENT_STATE(CMDRESP_R6_CARD_STATUS(Response.Data[0])) != SDMMC_STBY_ST) {
+        Ret = SDC_RET_ERR_STATE;
+      }
+      else {
+        *pRCA = CMDRESP_R6_RCA_VAL(Response.Data[0]);
+        return SDC_RET_OK;
+      }
+    }
+    RetryCnt--;
+  }
+  return Ret;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_GetCSD(uint16_t rca, uint32_t *pCSD) const
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+  response_t Response;
+  uint32_t RetryCnt =  20;
+
+  while (RetryCnt > 0) {
+    Ret = mci_ExecuteCmd(SD_CMD9_SEND_CSD, CMD9_RCA(rca), &Response);
+    if (Ret == SDC_RET_OK) {
+      pCSD[3] = Response.Data[0];
+      pCSD[2] = Response.Data[1];
+      pCSD[1] = Response.Data[2];
+      pCSD[0] = Response.Data[3];
+      return Ret;
+    }
+    RetryCnt--;
+  }
+  return Ret;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_SelectCard(uint16_t addr) const
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+  response_t Response;
+  uint32_t RetryCnt =  20;
+
+  while (RetryCnt > 0) {
+    Ret = mci_ExecuteCmd(SD_CMD7_SELECT_CARD, CMD7_RCA(addr), &Response);
+    if (Ret == SDC_RET_OK) {
+      if (mci_CheckR1Response(Response.Data[0], &Ret)) {
+        return Ret;
+      }
+    }
+    RetryCnt--;
+  }
+  return Ret;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_GetStatus(uint16_t rca, uint32_t *pStatus) const
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+  response_t Response;
+  uint32_t RetryCnt =  20;
+
+  *pStatus = (uint32_t) -1;
+  while (RetryCnt > 0) {
+    Ret = mci_ExecuteCmd(SD_CMD13_SEND_STATUS, CMD13_RCA(rca), &Response);
+    if (Ret == SDC_RET_OK) {
+      mci_CheckR1Response(Response.Data[0], &Ret);
+      *pStatus = Response.Data[0];
+      return Ret;
+    }
+    RetryCnt--;
+  }
+  return Ret;
+}
+
+void MCIFileSystem::mci_ProcessCSD()
+{
+  int32_t CSize = 0;
+  int32_t CSizeMult = 0;
+  int32_t Mult = 0;
+
+  /* compute block length based on CSD response */
+  _sdCardInfo.block_len = 1 << mci_GetBits(80, 83, _sdCardInfo.csd);
+
+  if ((_sdCardInfo.card_type & CARD_TYPE_HC) && (_sdCardInfo.card_type & CARD_TYPE_SD)) {
+    /* See section 5.3.3 CSD Register (CSD Version 2.0) of SD2.0 spec  an explanation for the calculation of these values */
+    CSize = mci_GetBits(48, 63, (uint32_t *) _sdCardInfo.csd) + 1;
+    _sdCardInfo.blocknr = CSize << 10;  /* 512 byte blocks */
+  }
+  else {
+    /* See section 5.3 of the 4.1 revision of the MMC specs for  an explanation for the calculation of these values */
+    CSize = mci_GetBits(62, 73, (uint32_t *) _sdCardInfo.csd);
+    CSizeMult = mci_GetBits(47, 49, (uint32_t *) _sdCardInfo.csd);
+    Mult = 1 << (CSizeMult + 2);
+    _sdCardInfo.blocknr = (CSize + 1) * Mult;
+
+    /* adjust blocknr to 512/block */
+    if (_sdCardInfo.block_len > MMC_SECTOR_SIZE) {
+      _sdCardInfo.blocknr = _sdCardInfo.blocknr * (_sdCardInfo.block_len >> 9);
+    }
+  }
+
+  _sdCardInfo.device_size = _sdCardInfo.blocknr << 9;  /* blocknr * 512 */
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_SetBusWidth(uint16_t rca, uint8_t width) const
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+  response_t Response;
+  uint8_t RetryCnt =  0x20;
+
+  while (RetryCnt > 0) {
+    Ret = mci_SendAppCmd(rca);
+    if (Ret == SDC_RET_OK) {
+      Ret = mci_ExecuteCmd(SD_ACMD6_SET_BUS_WIDTH, ACMD6_BUS_WIDTH(width), &Response);
+      if (Ret == SDC_RET_OK) {
+        if (mci_CheckR1Response(Response.Data[0], &Ret)) {
+          return Ret;
+        }
+      }
+    }
+    RetryCnt--;
+  }
+  return SDC_RET_FAILED;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_SetTranState(uint16_t rca) const
+{
+  ReturnCode Ret = SDC_RET_OK;
+  uint32_t status = 0;
+  SDMMC_STATE_T state;
+
+  /* get current state of the card */
+  Ret = mci_GetStatus(rca, &status);
+  if (Ret != SDC_RET_OK) {
+    /* unable to get the card state. So return immediatly. */
+    return Ret;
+  }
+
+  /* check card state in response */
+  state = (SDMMC_STATE_T) R1_CURRENT_STATE(status);
+  switch (state) {
+  case SDMMC_STBY_ST:
+    /* put card in 'Trans' state */
+    Ret = mci_SelectCard(rca);
+    if (Ret != SDC_RET_OK) {
+      /* unable to put the card in Trans state. So return immediatly. */
+      return Ret;
+    }
+    mci_GetStatus(rca, &status);
+    if (((SDMMC_STATE_T) R1_CURRENT_STATE(status)) != SDMMC_TRAN_ST) {
+      return SDC_RET_ERR_STATE;
+    }
+    break;
+
+  case SDMMC_TRAN_ST:
+    /*do nothing */
+    break;
+
+  default:
+    /* card shouldn't be in other states so return */
+    return SDC_RET_ERR_STATE;
+  }
+
+  return SDC_RET_OK;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_SetBlockLength(uint32_t rca, uint32_t block_len) const
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+  response_t Response;
+  uint8_t RetryCnt =  0x20;
+
+  while (RetryCnt > 0) {
+    Ret = mci_ExecuteCmd(SD_CMD16_SET_BLOCKLEN, block_len, &Response);
+    if (Ret == SDC_RET_OK) {
+      if (mci_CheckR1Response(Response.Data[0], &Ret)) {
+        return Ret;
+      }
+    }
+    RetryCnt--;
+  }
+  return SDC_RET_FAILED;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_SetCardParams() const
+{
+  ReturnCode Ret;
+
+  mci_SetClock(SDC_TRAN_CLOCK_RATE);
+  if (_sdCardInfo.card_type & CARD_TYPE_SD) {
+    mci_ClockControl(SDC_CLOCK_WIDEBUS_MODE, true);
+    Ret = mci_SetBusWidth(_sdCardInfo.rca, ACMD6_BUS_WIDTH_4);
+    if (Ret != SDC_RET_OK) {
+      return Ret;
+    }
+  }
+  else {
+    mci_ClockControl(SDC_CLOCK_WIDEBUS_MODE, false);
+  }
+
+  /* set block length */
+  Ret = mci_SetBlockLength(_sdCardInfo.rca, MMC_SECTOR_SIZE);
+  return Ret;
+}
+
+bool MCIFileSystem::mci_CheckR1Response(uint32_t resp, ReturnCode* pCheckResult) const
+{
+  bool Ret = true;
+
+  if (!(resp & R1_READY_FOR_DATA)) {
+    *pCheckResult = SDC_RET_NOT_READY;
+    Ret = false;
+  }
+  else if (R1_STATUS(resp)) {
+    *pCheckResult =  SDC_RET_FAILED;
+  }
+  else {
+    *pCheckResult =  SDC_RET_OK;
+  }
+  return Ret;
+}
+
+void MCIFileSystem::mci_WriteDelay() const
+{
+//  volatile uint8_t i;
+//  for ( i = 0; i < 0x10; i++ ) {  /* delay 3MCLK + 2PCLK  */
+//  }
+  wait(0.00001f); /* delay 10 us */
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_SendCmd(uint32_t Command, uint32_t Arg, uint32_t timeout) const
+{
+  ReturnCode ret = SDC_RET_TIMEOUT;
+  uint32_t Status;
+
+  /* Set Command Info */
+  mci_SetCommand(Command, Arg);
+
+  while (timeout) {
+
+    Status = LPC_MCI->STATUS;
+
+    /* check if command was sent */
+    if (((Command & SDC_COMMAND_RSP_BITMASK) == SDC_COMMAND_NO_RSP) && (Status & SDC_STATUS_CMDSENT)) {
+      ret =  SDC_RET_OK;
+      break;
+    }
+    /* check if response was received */
+    if (Status & SDC_STATUS_CMDRESPEND) {
+      ret = SDC_RET_OK;
+      break;
+    }
+
+    /* check command sending status */
+    if (Status & SDC_STATUS_CMDERR) {
+      if (Status & SDC_STATUS_CMDCRCFAIL) {
+        if ((SDC_COMMAND_INDEX(Command) == MMC_SEND_OP_COND) ||
+            (SDC_COMMAND_INDEX(Command) == SD_APP_OP_COND) ||
+            (SDC_COMMAND_INDEX(Command) == MMC_STOP_TRANSMISSION)) {
+          ret = SDC_RET_OK;  /* ignore CRC error if it's a resp for SEND_OP_COND  or STOP_TRANSMISSION. */
+          break;
+        }
+      }
+      ret = SDC_RET_CMD_FAILED;
+      break;
+    }
+
+    timeout--;
+  }
+
+  mci_ResetCommand();
+
+  return ret;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::mci_SendAppCmd(uint16_t rca) const
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+  response_t Response;
+  uint32_t RetryCnt =  20;
+
+  while (RetryCnt > 0) {
+    Ret = mci_ExecuteCmd(SD_CMD55_APP_CMD, CMD55_RCA(rca), &Response);
+    if (Ret == SDC_RET_OK) {
+      if (mci_CheckR1Response(Response.Data[0], &Ret)) {
+        if (Ret != SDC_RET_OK) {
+          return Ret;
+        }
+        if (Response.Data[0] & R1_APP_CMD) {
+          return SDC_RET_OK;
+        }
+        else {
+          Ret = SDC_RET_FAILED;
+        }
+      }
+    }
+    RetryCnt--;
+  }
+  return SDC_RET_FAILED;
+}
+
+void MCIFileSystem::mci_SetDataTransfer(uint16_t BlockNum, bool DirFromCard, uint32_t Timeout) const
+{
+  uint32_t DataCtrl = 0;
+  LPC_MCI->DATATMR = Timeout;
+  LPC_MCI->DATALEN = BlockNum * 512;
+
+  DataCtrl = SDC_DATACTRL_ENABLE;
+  // DataCtrl mode=block, block size=512byte
+  DataCtrl |= (0x9 << 4);
+  if (DirFromCard) {
+    DataCtrl |= (0x1 << 1);
+  }
+  DataCtrl |= SDC_DATACTRL_DMA_ENABLE;
+  LPC_MCI->DATACTRL = DataCtrl;
+  mci_WriteDelay();
+}
+
+void MCIFileSystem::mci_GetResp(response_t* pResp) const
+{
+  pResp->CmdIndex = SDC_RESPCOMMAND_VAL(LPC_MCI->RESP_CMD);
+  pResp->Data[0] = LPC_MCI->RESP0;
+  if (CardStatusNumBytes == 4) {
+    pResp->Data[1] = LPC_MCI->RESP1;
+    pResp->Data[2] = LPC_MCI->RESP2;
+    pResp->Data[3] = LPC_MCI->RESP3;
+  }
+}
+
+uint32_t MCIFileSystem::mci_GetBits(int32_t start, int32_t end, uint32_t *data) const
+{
+  uint32_t v;
+  uint32_t i = end >> 5;
+  uint32_t j = start & 0x1f;
+
+  if (i == (start >> 5)) {
+    v = (data[i] >> j);
+  }
+  else {
+    v = ((data[i] << (32 - j)) | (data[start >> 5] >> j));
+  }
+
+  return v & ((1 << (end - start + 1)) - 1);
+}
+
+void MCIFileSystem::mci_SetCommand(uint32_t Cmd, uint32_t Arg) const
+{
+  /* Clear status register */
+  LPC_MCI->CLEAR = SDC_CLEAR_ALL;
+
+  /* Set the argument first, finally command */
+  LPC_MCI->ARGUMENT = Arg;
+
+  /* Write command value, enable the command */
+  LPC_MCI->COMMAND = Cmd | SDC_COMMAND_ENABLE;
+
+  mci_WriteDelay();
+}
+
+void MCIFileSystem::mci_ResetCommand() const
+{
+  LPC_MCI->CLEAR = SDC_CLEAR_ALL;
+
+  LPC_MCI->ARGUMENT = 0xFFFFFFFF;
+
+  LPC_MCI->COMMAND = 0;
+
+  mci_WriteDelay();
+}
+
+int32_t MCIFileSystem::mci_IRQHandler(uint8_t *txBuf, uint32_t *txCnt, uint8_t *rxBuf, uint32_t *rxCnt)
+{
+  uint32_t Status;
+
+  Status = LPC_MCI->STATUS;
+
+  if ( Status & SDC_STATUS_DATAERR) {
+    LPC_MCI->CLEAR = SDC_STATUS_DATAERR;
+    return -1;  /* Data transfer error */
+  }
+
+  if ( Status & SDC_STATUS_DATAEND) {
+    LPC_MCI->CLEAR = SDC_STATUS_DATAEND;
+    LPC_MCI->MASK0 = 0;
+    return 0;
+  }
+
+  if ( Status & SDC_STATUS_DATABLOCKEND) {
+    LPC_MCI->CLEAR = SDC_STATUS_DATABLOCKEND;
+    return 1;
+  }
+
+  if (Status & SDC_STATUS_FIFO) {
+    return mci_FIFOIRQHandler(txBuf, txCnt, rxBuf, rxCnt);
+  }
+
+  return 1;
+}
+
+int32_t MCIFileSystem::mci_FIFOIRQHandler(uint8_t *txBuf, uint32_t *txCnt, uint8_t *rxBuf, uint32_t *rxCnt)
+{
+  uint32_t Status;
+  Status = LPC_MCI->STATUS;
+
+  if (txBuf) {
+    if (Status & SDC_STATUS_TXFIFOHALFEMPTY) {
+      if (*txCnt % 64) {
+        mci_WriteFIFO((uint32_t *) &txBuf[*txCnt], false);
+      }
+      else {
+        mci_WriteFIFO((uint32_t *) &txBuf[*txCnt], true);
+      }
+      *txCnt += 32;
+    }
+  }
+
+  if (rxBuf) {
+    if (Status & SDC_STATUS_RXFIFOHALFFULL) {
+      if (*rxCnt % 64) {
+        mci_ReadFIFO((uint32_t *) &rxBuf[*rxCnt], false);
+      }
+      else {
+        mci_ReadFIFO((uint32_t *) &rxBuf[*rxCnt], true);
+      }
+      *rxCnt += 32;
+    }
+  }
+
+  LPC_MCI->CLEAR = SDC_STATUS_FIFO;
+
+  return 1;
+}
+
+void MCIFileSystem::mci_ReadFIFO(uint32_t *pDst, bool bFirstHalf) const
+{
+  uint8_t start = 0, end = 7;
+
+  if (!bFirstHalf) {
+    start += 8;
+    end += 8;
+  }
+  for (; start <= end; start++) {
+    *pDst = LPC_MCI->FIFO[start];
+    pDst++;
+  }
+}
+
+void MCIFileSystem::mci_WriteFIFO(uint32_t *pSrc, bool bFirstHalf) const
+{
+  uint8_t start = 0, end = 7;
+  if (!bFirstHalf) {
+    start += 8;
+    end += 8;
+  }
+  for (; start <= end; start++) {
+    LPC_MCI->FIFO[start] = *pSrc;
+    pSrc++;
+  }
+}
+
+void MCIFileSystem::mci_SetupEventWakeup(uint8_t dmaChannel)
+{
+  /* Wait for IRQ - for an RTOS, you would pend on an event here with a IRQ based wakeup. */
+  NVIC_ClearPendingIRQ(DMA_IRQn);
+
+  _eventDmaChannel = dmaChannel;
+  _eventReceived = false;
+  _eventSuccess = false;
+
+  NVIC_EnableIRQ(DMA_IRQn);
+}
+
+uint32_t MCIFileSystem::mci_WaitForEvent() const
+{
+  /* Wait for the event (DMA or MCI interrupt) for a maximum of 2 seconds */
+  uint32_t end = us_ticker_read() + 2*1000*1000;
+  while ((us_ticker_read() < end) && (!_eventReceived))
+  {
+    wait(0.01);
+  }
+  
+  if (_eventReceived && _eventSuccess) {
+    return 0;
+  }
+
+  return 1;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::_readBlocks(uint32_t card_type, uint32_t startBlock, uint32_t blockNum) const
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+  response_t Response;
+  uint32_t Command, Argument;
+  uint8_t RetryCnt =  0x20;
+
+  if (blockNum == 1) {
+    Command = SD_CMD17_READ_SINGLE_BLOCK;
+  }
+  else {
+    Command = SD_CMD18_READ_MULTIPLE_BLOCK;
+  }
+
+  /* Select single or multiple read based on number of blocks */
+  /* if high capacity card use block indexing */
+  if (card_type & CARD_TYPE_HC) {
+    Argument = startBlock;
+  }
+  else {  /*fix at 512 bytes*/
+    Argument = startBlock << 9;
+  }
+
+  while (RetryCnt > 0) {
+    Ret = mci_ExecuteCmd(Command, Argument, &Response);
+    if (Ret == SDC_RET_OK) {
+      if (mci_CheckR1Response(Response.Data[0], &Ret)) {
+        return Ret;
+      }
+    }
+    RetryCnt--;
+  }
+  return Ret;
+}
+
+MCIFileSystem::ReturnCode MCIFileSystem::_writeBlocks(uint32_t card_type, uint32_t startBlock, uint32_t blockNum) const
+{
+  ReturnCode Ret = SDC_RET_FAILED;
+  response_t Response;
+  uint32_t Command, Argument;
+  uint8_t RetryCnt =  0x20;
+
+  if (blockNum == 1) {
+    Command = SD_CMD24_WRITE_BLOCK;
+  }
+  else {
+    Command = SD_CMD25_WRITE_MULTIPLE_BLOCK;
+  }
+
+  /* if high capacity card use block indexing */
+  if (card_type & CARD_TYPE_HC) {
+    Argument = startBlock;
+  }
+  else {  /*fix at 512 bytes*/
+    Argument = startBlock << 9;
+
+  }
+
+  while (RetryCnt > 0) {
+    Ret = mci_ExecuteCmd(Command, Argument, &Response);
+    if (Ret == SDC_RET_OK) {
+      if (mci_CheckR1Response(Response.Data[0], &Ret)) {
+        return Ret;
+      }
+    }
+    RetryCnt--;
+  }
+  return Ret;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MCIFileSystem.h	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,185 @@
+#ifndef MCIFILESYSTEM_H
+#define MCIFILESYSTEM_H
+
+#include "mbed.h"
+#include "FATFileSystem.h"
+
+/** Access the filesystem on an SD Card using MCI
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "MCIFileSystem.h"
+ *
+ * MCIFileSystem mcifs("mci");
+ *
+ * int main() {
+ *     printf("Please insert a SD/MMC card\n");
+ *     while(!mcifs.cardInserted()) {
+ *         wait(0.5);
+ *     }
+ *     
+ *     FILE *fp = fopen("/mci/myfile.txt", "w");
+ *     if (fp != NULL) {
+ *         fprintf(fp, "Hello World!\n");
+ *         fclose(fp);
+ *     }
+ * }
+ * @endcode
+ */
+class MCIFileSystem : public FATFileSystem {
+public:
+
+    /** Create the File System for accessing an SD/MMC Card using MCI
+     *
+     * @param name The name used to access the virtual filesystem
+     * @param cd   The pin connected to the CardDetect line
+     */
+    MCIFileSystem(const char* name, PinName cd = p38);
+
+    virtual ~MCIFileSystem();
+
+    virtual int disk_initialize();
+    virtual int disk_status();
+    virtual int disk_read(uint8_t * buffer, uint64_t block_number);
+    virtual int disk_write(const uint8_t * buffer, uint64_t block_number);
+    virtual int disk_sync();
+    virtual uint64_t disk_sectors();
+
+    void mci_MCIIRQHandler();
+    void mci_DMAIRQHandler();
+
+    /** Tests if a SD/MMC card is inserted or not.
+     *
+     * @returns
+     *   True if a card has been inserted,
+     *   False if no card is inserted or if the card detect pin is unavailable
+     */
+    bool cardInserted() const;
+
+private:
+
+    typedef enum {
+      CardStatusNumBytes = 4,
+    } Constants;
+
+    typedef enum {
+      PowerOff = 0,
+      PowerUp = 2,
+      PowerOn = 3,
+    } power_ctrl_t;
+
+    typedef enum {
+      SDMMC_IDLE_ST = 0, /*!< Idle state */
+      SDMMC_READY_ST,    /*!< Ready state */
+      SDMMC_IDENT_ST,    /*!< Identification State */
+      SDMMC_STBY_ST,     /*!< standby state */
+      SDMMC_TRAN_ST,     /*!< transfer state */
+      SDMMC_DATA_ST,     /*!< Sending-data State */
+      SDMMC_RCV_ST,      /*!< Receive-data State */
+      SDMMC_PRG_ST,      /*!< Programming State */
+      SDMMC_DIS_ST       /*!< Disconnect State */
+    } CardState;
+
+
+    typedef struct {
+      uint8_t CmdIndex;
+      uint32_t Data[CardStatusNumBytes];
+    } response_t;
+
+    /**
+     * @brief SDC Clock Control Options
+     */
+    typedef enum {
+      SDC_CLOCK_ENABLE         =  8, /*!< Enable SD Card Bus Clock */
+      SDC_CLOCK_POWER_SAVE     =  9, /*!< Disable SD_CLK output when bus is idle */
+      SDC_CLOCK_DIVIDER_BYPASS = 10, /*!< Enable bypass of clock divide logic */
+      SDC_CLOCK_WIDEBUS_MODE   = 11, /*!< Enable wide bus mode (SD_DAT[3:0] is used instead of SD_DAT[0]) */
+    } ClockControl;
+
+    /**
+     * @brief SD/MMC Card specific setup data structure
+     */
+    typedef struct {
+      uint32_t response[4];        /*!< Most recent response */
+      uint32_t cid[4];             /*!< CID of acquired card  */
+      uint32_t csd[4];             /*!< CSD of acquired card */
+      uint32_t ext_csd[512 / 4];   /*!< Ext CSD */
+      uint32_t card_type;          /*!< Card Type */
+      uint16_t rca;                /*!< Relative address assigned to card */
+      uint32_t speed;              /*!< Speed */
+      uint32_t block_len;          /*!< Card sector size */
+      uint32_t device_size;        /*!< Device Size */
+      uint32_t blocknr;            /*!< Block Number */
+      uint32_t clk_rate;           /*!< Clock rate */
+    } SDMMC_CARD_T;
+
+    typedef enum {
+      SDC_RET_OK             =  0,
+      SDC_RET_CMD_FAILED     = -1,
+      SDC_RET_BAD_PARAMETERS = -2,
+      SDC_RET_BUS_NOT_IDLE   = -3,
+      SDC_RET_TIMEOUT        = -4,
+      SDC_RET_ERR_STATE      = -5,
+      SDC_RET_NOT_READY      = -6,
+      SDC_RET_FAILED         = -7,
+    } ReturnCode;
+
+    void initMCI();
+
+    int32_t     mci_Acquire();
+    uint32_t    mci_GetCardStatus() const;
+    CardState   mci_GetCardState() const;
+    ReturnCode  mci_ReadBlocks(void *buffer, int32_t startBlock, int32_t blockNum);
+    ReturnCode  mci_WriteBlocks(void *buffer, int32_t startBlock, int32_t blockNum);
+    void        mci_SetClock(uint32_t freq) const;
+    void        mci_ClockControl(ClockControl ctrlType, bool enable) const;
+    void        mci_PowerControl(power_ctrl_t powerMode, uint32_t flag) const;
+    ReturnCode  mci_ExecuteCmd(uint32_t Command, uint32_t Arg, response_t* pResp) const;
+    ReturnCode  mci_SendIfCond() const;
+    ReturnCode  mci_SendOpCond(uint32_t *pOCR) const;
+    ReturnCode  mci_SendAppOpCond(uint16_t rca, bool hcs, uint32_t *pOcr, bool *pCCS) const;
+    ReturnCode  mci_GetCID(uint32_t *pCID) const;
+    ReturnCode  mci_SetAddr(uint16_t addr) const;
+    ReturnCode  mci_GetAddr(uint16_t *pRCA) const;
+    ReturnCode  mci_GetCSD(uint16_t rca, uint32_t *pCSD) const;
+    ReturnCode  mci_SelectCard(uint16_t addr) const;
+    ReturnCode  mci_GetStatus(uint16_t rca, uint32_t *pStatus) const;
+    void        mci_ProcessCSD();
+    ReturnCode  mci_SetBusWidth(uint16_t rca, uint8_t width) const;
+    ReturnCode  mci_SetTranState(uint16_t rca) const;
+    ReturnCode  mci_SetBlockLength(uint32_t rca, uint32_t block_len) const;
+    ReturnCode  mci_SetCardParams() const;
+    ReturnCode  mci_StopTransmission(uint32_t rca) const;
+    bool        mci_CheckR1Response(uint32_t resp, ReturnCode* pCheckResult) const;
+    void        mci_WriteDelay() const;
+    ReturnCode  mci_SendCmd(uint32_t Command, uint32_t Arg, uint32_t timeout) const;
+    ReturnCode  mci_SendAppCmd(uint16_t rca) const;
+    void        mci_SetDataTransfer(uint16_t BlockNum, bool DirFromCard, uint32_t Timeout) const;
+    void        mci_GetResp(response_t* pResp) const;
+    uint32_t    mci_GetBits(int32_t start, int32_t end, uint32_t *data) const;
+    void        mci_SetCommand(uint32_t Cmd, uint32_t Arg) const;
+    void        mci_ResetCommand() const;
+    int32_t     mci_IRQHandler(uint8_t *txBuf, uint32_t *txCnt, uint8_t *rxBuf, uint32_t *rxCnt);
+    int32_t     mci_FIFOIRQHandler(uint8_t *txBuf, uint32_t *txCnt, uint8_t *rxBuf, uint32_t *rxCnt);
+    void        mci_ReadFIFO(uint32_t *pDst, bool bFirstHalf) const;
+    void        mci_WriteFIFO(uint32_t *pSrc, bool bFirstHalf) const;
+                
+    void        mci_SetupEventWakeup(uint8_t dmaChannel);
+    uint32_t    mci_WaitForEvent() const;
+
+    ReturnCode _readBlocks(uint32_t card_type, uint32_t startBlock, uint32_t blockNum) const;
+    ReturnCode _writeBlocks(uint32_t card_type, uint32_t startBlock, uint32_t blockNum) const;
+
+
+    uint32_t _Stat;
+    SDMMC_CARD_T _sdCardInfo;
+
+    DigitalIn* _cardDetect;
+
+    uint8_t _eventDmaChannel;    /*!< DMA Channel used for transfer data */
+    volatile bool _eventReceived;
+    volatile bool _eventSuccess;
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QSPIFileSystem.cpp	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,1499 @@
+#include "QSPIFileSystem.h"
+#include "mbed_debug.h"
+
+#include "spifi_rom_api.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+#define QSPI_DBG             0
+
+/* 
+ * The SPIFI_ROM_PTR (0x1FFF1FF8) points to an area where the pointers to
+ * different drivers in ROM are stored.
+ */
+typedef struct {
+   /*const*/ unsigned p_usbd;     // USBROMD 
+   /*const*/ unsigned p_clib;
+   /*const*/ unsigned p_cand;
+   /*const*/ unsigned p_pwrd;     // PWRROMD
+   /*const*/ unsigned p_promd;    // DIVROMD
+   /*const*/ SPIFI_RTNS *pSPIFID; // SPIFIROMD
+   /*const*/ unsigned p_dev3;
+   /*const*/ unsigned p_dev4; 
+} ROM;
+
+#define ROM_DRIVERS_PTR ((ROM *)(*((unsigned int *)SPIFI_ROM_PTR)))
+#define IS_ADDR_IN_SPIFI(__addr)  ( (((uint32_t)(__addr)) & 0xff000000) == SPIFI_MEM_BASE )
+
+#define MEM_SIZE    (memInfo.memSize)          //(8*1024*1024)
+#define ERASE_SIZE  (memInfo.eraseBlockSize)   //(64*1024)
+#define NUM_BLOCKS  (memInfo.numEraseBlocks)   //(MEM_SIZE/ERASE_SIZE)
+
+typedef uint32_t toc_entry_t;
+
+#define TOC_BLOCK_ADDR   (memInfo.tocBlockAddr)   //(SPIFI_MEM_BASE + (NUM_BLOCKS - 1)*ERASE_SIZE)
+#define TOC_SIZE         (memInfo.tocSizeInBytes) //(sizeof(toc_entry_t) * NUM_BLOCKS)
+#define NUM_TOCS         (memInfo.numTocs)        //((int)(ERASE_SIZE/TOC_SIZE))
+#define NUM_TOC_BLOCKS   ((NUM_TOCS * TOC_SIZE) / ERASE_SIZE)
+#define NUM_TOC_ENTRIES  ((int)(TOC_SIZE/sizeof(toc_entry_t)))
+
+#define TOC_UNUSED          (0xffffffff)
+#define TOC_MAX             (NUM_BLOCKS - 1)
+#define TOC_VALID_MASK      (1UL<<31)
+#define TOC_RESERVED_MASK   (1UL<<30)
+#define TOC_USED_MASK       (1UL<<29)
+#define TOC_FILE_MASK       (1UL<<28)
+#define TOC_FSIZE_MASK      (0x3ffff)
+#define TOC_MANDAT_SET_MASK (0x0ffc0000)
+
+#define MANDATORY_BITS_SET(__v)  (((__v)&TOC_MANDAT_SET_MASK) == TOC_MANDAT_SET_MASK)
+
+#define VALID_TOC_ENTRY(__v)  (((__v)&TOC_VALID_MASK) == 0)
+#define USED_TOC_ENTRY(__v)   (VALID_TOC_ENTRY(__v) && (((__v)&TOC_USED_MASK) == 0))
+#define TOC_IS_FILE(__v)      (USED_TOC_ENTRY(__v) && (((__v)&TOC_FILE_MASK) == 0))
+#define TOC_IS_RESERVED(__v)  (VALID_TOC_ENTRY(__v) && (((__v)&TOC_RESERVED_MASK) == 0))
+#define FILESIZE(__v)         ((__v) & 0x3ffff)
+
+#define FS_MIN(__a, __b)  (((__a) < (__b)) ? (__a) : (__b))
+
+// Mask to compare the different access modes. In LPCXpresso this was defined
+// but not in uVision
+#ifndef O_ACCMODE
+#define O_ACCMODE  (O_RDONLY | O_WRONLY | O_RDWR)
+#endif
+
+
+/*
+ * The file header currently only consists of the filename (including path)
+ * and the string terminating character, but by separating the file name
+ * length from the size of the header in the code it allows future additions
+ * to the header without too much code modification.
+ */
+#define HEADER_DNAME_MAXLEN  (250)
+#define HEADER_FNAME_STRLEN  (HEADER_DNAME_MAXLEN + 5)
+#define HEADER_FNAME_LEN     (HEADER_FNAME_STRLEN + 1)
+#define HEADER_LEN           (HEADER_FNAME_LEN) // only filename in header for now
+
+typedef enum
+{
+  FS_OK,
+  FS_ERR_NOT_FORMATTED,
+  FS_ERR_NO_FILE,
+  FS_ERR_FILE_EXIST,
+  FS_ERR_INVALID_PARAM,
+  FS_ERR_DISK_FULL,
+  FS_ERR_SPIFI,
+  FS_ERR_MALLOC, 
+
+  // FS_ERR_SPIFI_* return codes are listed in the User's Manual
+  // as possible return values from spifi_init(), spifi_program()
+  // and spifi_erase() calls.
+  FS_ERR_SPIFI_INTERNAL_ERROR  = 0x20002,  // 0x20002, Internal error in API code
+  FS_ERR_SPIFI_TIMEOUT         = 0x20003,  // 0x20003, Time-out waiting for program or erase to begin: protection could not be removed.
+  FS_ERR_SPIFI_OPERAND         = 0x20004,  // 0x20004, Operand error (i.e. invalid params)
+  FS_ERR_SPIFI_STATUS          = 0x20005,  // 0x20005, Device status error
+  FS_ERR_SPIFI_EXT_DEVICE_ID   = 0x20006,  // 0x20006, Unknown extended device ID value
+  FS_ERR_SPIFI_DEVICE_ID       = 0x20007,  // 0x20007, Unknown device ID code
+  FS_ERR_SPIFI_DEVICE_TYPE     = 0x20008,  // 0x20008, Unknown device type code
+  FS_ERR_SPIFI_MANUFACTURER    = 0x20009,  // 0x20009, Unknown manufacturer code
+  FS_ERR_SPIFI_INVALID_JDEC_ID = 0x2000A,  // 0x2000A, No operative serial flash (JEDEC ID all zeroes or all ones)
+  FS_ERR_SPIFI_ERASE_CONFLICT  = 0x2000B,  // 0x2000B, S_CALLER_ERASE is included in options, and erasure is required.
+  FS_ERR_SPIFI_VERIFICATION,               // other,   Other non-zero values can occur if options selects verification.
+                                           //          They will be the address in the SPIFI memory area at which the first discrepancy was found.
+} fresult;
+
+// The number of times to re-attempt a spifi_program() or spifi_erase()
+// if the last one reported a verification error.
+#define NUM_VERIFICATION_ATTEMPTS  (1)
+
+typedef struct
+{
+  uint32_t memSize;
+  uint32_t eraseBlockSize;
+  uint32_t numEraseBlocks;
+  uint32_t tocBlockAddr;
+  uint32_t numTocs;
+  uint32_t tocSizeInBytes;
+  char memName[30];
+} meminfo_t;
+
+typedef struct
+{
+  int      tocIdx;
+  uint32_t size;
+  uint16_t lastBlock;
+} fileHandle_t;
+
+/******************************************************************************
+ * Local variables
+ *****************************************************************************/
+
+static toc_entry_t* TOC = NULL;//[NUM_BLOCKS];
+static int activeTOC = -1;
+
+static const SPIFI_RTNS *spifi = NULL;
+static SPIFIobj obj;
+static SPIFIopers opers;
+
+static char addr_conflict_buff[PROG_SIZE];
+
+static meminfo_t memInfo = {0,0,0,0,0,0,{0}};
+
+/******************************************************************************
+ * Forward Declarations of Local Functions
+ *****************************************************************************/
+static fresult qspifs_init();
+static fresult qspifs_translateSpifiError(int rc);
+static fresult qspifs_readTOC(void);
+static fresult qspifs_saveTOC(void);
+static fresult qspifs_findFile(const char* filename, fileHandle_t* fh);
+static fresult qspifs_fileSize(int tocIdx, uint32_t* pSize);
+static fresult qspifs_eraseBlock(int block);
+static fresult qspifs_allocateFile(const char* filename, int neededBlocks, int* pTocIdx);
+static void qspifs_deleteFile(fileHandle_t* fh);
+static fresult qspifs_allocateSpace(fileHandle_t* fh, uint32_t size);
+static fresult qspifs_format(unsigned int minReservedBytes);
+static fresult qspifs_write(fileHandle_t* fh, const uint8_t * const pData, uint32_t size);
+static bool qspifs_startsWith(const char* prefix, const char* str);
+
+/******************************************************************************
+ * Local Functions
+ *****************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *    Initializes spifi, identifies the chip and reads the file system's
+ *    table of content.
+ *
+ * Params:
+ *    None
+ *
+ * Returns:
+ *    FS_OK or one of the FS_ERR_* error codes
+ *
+ *****************************************************************************/
+static fresult qspifs_init()
+{
+  if (spifi == NULL) {
+    
+    // Turn on SPIFI block as it is disabled on reset
+    LPC_SC->PCONP |= 0x00010000;
+
+    // pinsel for SPIFI
+    LPC_IOCON->P2_7 = 5; /* SPIFI_CSN @ P2.7 */
+    LPC_IOCON->P0_22 = 5; /* SPIFI_CLK @ P0.22 */
+    LPC_IOCON->P0_15 = 5; /* SPIFI_IO2 @ P0.15 */
+    LPC_IOCON->P0_16 = 5; /* SPIFI_IO3 @ P0.16 */
+    LPC_IOCON->P0_17 = 5; /* SPIFI_IO1 @ P0.17 */
+    LPC_IOCON->P0_18 = 5; /* SPIFI_IO0 @ P0.18 */
+    
+    uint32_t spifi_clk_div = (*((volatile uint32_t*)0x400FC1B4)) & 0x1f;
+    uint32_t spifi_clk_mhz = (SystemCoreClock / spifi_clk_div) / 1000000;
+
+    spifi = ROM_DRIVERS_PTR->pSPIFID;
+    
+    /* Typical time tCS is 20 ns min, we give 200 ns to be on safer side */
+    int rc = spifi->spifi_init (&obj, spifi_clk_mhz/5, S_FULLCLK+S_RCVCLK, spifi_clk_mhz);
+    if (rc) {
+      spifi = NULL;
+      return qspifs_translateSpifiError(rc);
+    }
+
+    /* Make sure it is a tested flash module */
+    if ((obj.mfger == 1) && (obj.devType == 0x2) && (obj.devID == 0x15) && (obj.memSize > 0x100000)) 
+    {
+      /* For the Spansion memory the TOC occupies 256bytes and the TOC block will
+         hold 256 TOCs. */
+      strcpy(memInfo.memName, "Spansion S25FL032");
+      memInfo.memSize        = obj.memSize;
+      memInfo.eraseBlockSize = 64*1024;
+      memInfo.numEraseBlocks = memInfo.memSize / memInfo.eraseBlockSize;
+      memInfo.tocSizeInBytes = sizeof(toc_entry_t) * memInfo.numEraseBlocks;
+      memInfo.numTocs        = memInfo.eraseBlockSize / memInfo.tocSizeInBytes;
+      memInfo.tocBlockAddr   = SPIFI_MEM_BASE + (NUM_BLOCKS * ERASE_SIZE) - (memInfo.numTocs * memInfo.tocSizeInBytes);      
+    } 
+    else if ((obj.mfger == 0xef) && (obj.devType == 0x40) && (obj.devID == 0x17) && (obj.memSize > 0x100000))
+    {
+      /* For the Winbond memory the TOC occupies 8192 bytes and that is bigger than 
+         one erase block (which is 4096 bytes). It is possible to either keep only
+         one TOC or to create a couple to reduce wear on the memory. In this case 
+         the multiple TOCs option is used. */
+      strcpy(memInfo.memName, "Winbond W25Q64FV");
+      memInfo.memSize        = obj.memSize;
+      memInfo.eraseBlockSize = 4*1024;
+      memInfo.numEraseBlocks = memInfo.memSize / memInfo.eraseBlockSize;
+      memInfo.tocSizeInBytes = sizeof(toc_entry_t) * memInfo.numEraseBlocks;
+      memInfo.numTocs        = 8;
+      memInfo.tocBlockAddr   = SPIFI_MEM_BASE + (NUM_BLOCKS * ERASE_SIZE) - (memInfo.numTocs * memInfo.tocSizeInBytes);      
+    } 
+    else 
+    {
+      debug("INIT: Memory is unknown and may not work as expected\n");
+      
+      // Asuming it has 64Kb erase blocks (i.e. same setup as the Spansion S25FL032
+      strcpy(memInfo.memName, "Unknown - check ID");
+      memInfo.memSize        = obj.memSize;
+      memInfo.eraseBlockSize = 64*1024;
+      memInfo.numEraseBlocks = memInfo.memSize / memInfo.eraseBlockSize;      
+      memInfo.tocSizeInBytes = sizeof(toc_entry_t) * memInfo.numEraseBlocks;
+      memInfo.numTocs        = memInfo.eraseBlockSize / memInfo.tocSizeInBytes;
+      memInfo.tocBlockAddr   = SPIFI_MEM_BASE + (NUM_BLOCKS * ERASE_SIZE) - (memInfo.numTocs * memInfo.tocSizeInBytes);      
+
+      /*
+       * If this happens, check the manufacturer and device information
+       * and compare with the data sheet for your chip. Also make sure
+       * that the sector sizes are the same (i.e. 64KB) for your chip.
+       * If everything is the same then add an exception for your chip.
+       */
+    }
+    debug_if(QSPI_DBG, "INIT: Found %dMB %s\n", memInfo.memSize/0x100000, memInfo.memName);
+    
+    if (TOC != NULL) {
+      delete TOC;
+    }
+    TOC = (toc_entry_t*)malloc(TOC_SIZE);
+    if (TOC == NULL) {
+      debug_if(QSPI_DBG, "INIT: Failed to allocate memory for TOC\n");
+      spifi = NULL;
+      return FS_ERR_MALLOC;
+    }
+  }
+  if (activeTOC == -1)
+  {
+    return qspifs_readTOC();
+  }
+  return FS_OK;
+}
+
+/******************************************************************************
+ *
+ * Description:
+ *    Converts the return value from one of the spifi_init(), spifi_program()
+ *    or spifi_erase() calls into a FS_* error code to simplify it for the
+ *    fs_qspi API user.
+ *    This function also attempts to detect the verification failure error.
+ *    When a verification error occurs the spifi_* functions returns the
+ *    conflicting address and not an error code. As this can be any address
+ *    it is difficult to test but this function converts it into the
+ *    FS_ERR_SPIFI_VERIFICATION error code which can be tested against.
+ *
+ * Params:
+ *    [in] rc - The return code from any of the spifi_* functions
+ *
+ * Returns:
+ *    FS_OK or one of the FS_ERR_* error codes
+ *
+ *****************************************************************************/
+static fresult qspifs_translateSpifiError(int rc)
+{
+  fresult res;
+  if (rc == 0)
+  {
+    res = FS_OK;
+  }
+  else if ((rc >= FS_ERR_SPIFI_INTERNAL_ERROR) && (rc <= FS_ERR_SPIFI_ERASE_CONFLICT))
+  {
+    // This is a known error code
+    res = (fresult)rc;
+  }
+  else if (opers.options & (S_VERIFY_PROG | S_VERIFY_ERASE))
+  {
+    // As verification was selected and rc is not in the list of known
+    // codes this falls into this category in the User's Manual:
+    //
+    // "Other non-zero values can occur if options selects verification.
+    //  They will be the address in the SPIFI memory area at which the
+    //  first discrepancy was found."
+    res = FS_ERR_SPIFI_VERIFICATION;
+  }
+  else
+  {
+    // Should never happen :-) as all listed error codes are covered but
+    // to be on the safe side and not interpret this as a success, a generic
+    // error is set.
+    res = FS_ERR_SPIFI;
+  }
+  return res;
+}
+
+/******************************************************************************
+ *
+ * Description:
+ *    Reads the table of contents (TOC). The TOC is stored in the last erase
+ *    block on the QSPI flash. As the QSPI flash is not exactly RW (might
+ *    require erasing before writing) the TOC is relocated inside the erase
+ *    block everytime it is saved (see saveTOC()). The currently valid TOC 
+ *    is allways the last one stored.
+ *
+ * Params:
+ *    None
+ *
+ * Returns:
+ *    FS_OK or one of the FS_ERR_* error codes
+ *
+ *****************************************************************************/
+static fresult qspifs_readTOC(void)
+{
+  int i, j;
+  toc_entry_t* p;
+  uint8_t invalid = 0;
+  int lastValid = -1;
+
+  // Search for the first unused TOC, keeping track of the valid
+  // ones as we go.
+  for (i = 0; (i < NUM_TOCS) && !invalid; i++)
+  {
+    p = (toc_entry_t*)(TOC_BLOCK_ADDR + i*TOC_SIZE);
+    for (j = 0; j < NUM_BLOCKS; j++)
+    {
+      if (!VALID_TOC_ENTRY(*p) || !MANDATORY_BITS_SET(*p))
+      {
+        // invalid TOC entry, stop looking
+        invalid = 1;
+        break;
+      }
+      p++;
+    }
+
+    if (!invalid)
+    {
+      // this TOC was ok, but perhaps there is a newer one?
+      lastValid = i;
+    }
+  }
+
+  if (lastValid == -1)
+  {
+    // no valid TOCs on the flash
+    return FS_ERR_NOT_FORMATTED;
+  }
+  else
+  {
+    // previous entry was ok so use that
+    activeTOC = lastValid;
+    p = (toc_entry_t*)(TOC_BLOCK_ADDR + activeTOC*TOC_SIZE);
+    memcpy(TOC, p, TOC_SIZE);
+    return FS_OK;
+  }
+}
+
+/******************************************************************************
+ *
+ * Description:
+ *    Saves the table of contents (TOC). The TOC is stored in the last erase
+ *    block on the QSPI flash. As the QSPI flash is not exactly RW (might
+ *    require erasing before writing) the TOC is first compared with what is
+ *    stored in the QSPI flash and if there are no changes or all changes
+ *    only require bit changes 1->0 then the current TOC can be overwritten.
+ *    If bit value changes 0->1 are required then the current stored TOC
+ *    cannot be overwritten and the new TOC is instead stored in the next
+ *    available space. If the entire last block is filled then it is erased
+ *    and the new TOC is placed at the start of it.
+ *
+ * Params:
+ *    None
+ *
+ * Returns:
+ *    FS_OK or one of the FS_ERR_* error codes
+ *
+ *****************************************************************************/
+static fresult qspifs_saveTOC(void)
+{
+  int i, rc = 0;
+  uint32_t* pSrc;
+  uint32_t* pDest;
+  uint32_t tmp;
+  uint8_t identical = 1;
+
+  // active TOC same as the one we want to save?
+  pSrc = (uint32_t*)TOC;
+  pDest = (uint32_t*)(TOC_BLOCK_ADDR + activeTOC*TOC_SIZE);
+  for (i = 0; i < NUM_TOC_ENTRIES; i++)
+  {
+    if (*pSrc != *pDest)
+    {
+      identical = 0;
+      tmp = ((*pDest) ^ (*pSrc)) & (*pSrc);
+      if (tmp > 0)
+      {
+        // found a change that contains 0->1 bit modification which
+        // requires erasing or a new location
+        activeTOC = (activeTOC + 1)%NUM_TOCS;
+        if (activeTOC == 0)
+        {
+          // no more free TOCs so an erase is needed          
+#if 0          
+          opers.options &= ~S_CALLER_ERASE;
+          opers.options |= S_FORCE_ERASE;
+#else
+          opers.dest = (char *) TOC_BLOCK_ADDR;
+          opers.length = TOC_SIZE * NUM_TOCS;
+          opers.scratch = NULL;
+          opers.protect = 0;
+          opers.options = S_NO_VERIFY;
+          rc = spifi->spifi_erase(&obj, &opers);
+          if (rc) {
+            return qspifs_translateSpifiError(rc);
+          }
+#endif          
+        }
+        break;
+      }
+    }
+    pSrc++;
+    pDest++;
+  }
+
+  if (!identical)
+  {
+    opers.length = FS_MIN(TOC_SIZE, PROG_SIZE);
+    opers.scratch = NULL;
+    opers.protect = 0;
+    opers.options = S_VERIFY_PROG | S_CALLER_ERASE;
+    for (int i = 0; i < (TOC_SIZE / PROG_SIZE); i++) 
+    {
+      opers.dest = (char *)(TOC_BLOCK_ADDR + activeTOC*TOC_SIZE + i*PROG_SIZE);
+      rc = spifi->spifi_program(&obj, ((char*)TOC)+i*PROG_SIZE, &opers);
+      if (rc) 
+      {
+        break;
+      }
+    }
+    return qspifs_translateSpifiError(rc);
+  }
+  return FS_OK;
+}
+
+/******************************************************************************
+ *
+ * Description:
+ *    Searches the file system for a file with the specified name and
+ *    (if found) returns the file's position in the TOC.
+ *
+ *    Note that the content of fh is only valid if FS_OK is returned.
+ *
+ * Params:
+ *    [in] filename - The name of the file to find
+ *    [out] fh      - The handle with the file information
+ *
+ * Returns:
+ *    FS_OK or one of the FS_ERR_* error codes
+ *
+ *****************************************************************************/
+static fresult qspifs_findFile(const char* filename, fileHandle_t* fh)
+{
+  int i;
+
+  if (activeTOC == -1)
+  {
+    return FS_ERR_NOT_FORMATTED;
+  }
+
+  // Look at all blocks except for the reserved ones
+  for (i = 0; i < NUM_BLOCKS; i++)
+  {
+    if (TOC_IS_FILE(TOC[i]) && !TOC_IS_RESERVED(TOC[i]))
+    {
+      // found a file, see if name matches
+      char* p = (char*)(SPIFI_MEM_BASE + i*ERASE_SIZE);
+      if (strncmp(filename, p, HEADER_FNAME_LEN) == 0)
+      {
+        // found a matching name
+        fh->tocIdx = i;
+        fresult res = qspifs_fileSize(fh->tocIdx, &fh->size);
+        if (res == FS_OK) {
+            fh->lastBlock = fh->tocIdx + ((fh->size + HEADER_LEN)/ ERASE_SIZE);
+        }
+        return FS_OK;
+      }
+    }
+  }
+  return FS_ERR_NO_FILE;
+}
+
+/******************************************************************************
+ *
+ * Description:
+ *    Calculates and returns the file's size.
+ *
+ *    Note that the content of pSize is only valid if FS_OK is returned.
+ *
+ * Params:
+ *    [in] tocIdx - The file's position in the TOC
+ *    [out] pSize - The file's size
+ *
+ * Returns:
+ *    FS_OK or one of the FS_ERR_* error codes
+ *
+ *****************************************************************************/
+static fresult qspifs_fileSize(int tocIdx, uint32_t* pSize)
+{
+  int i;
+
+  if (tocIdx < 0 || tocIdx > NUM_BLOCKS || !TOC_IS_FILE(TOC[tocIdx]))
+  {
+    return FS_ERR_NO_FILE;
+  }
+
+  *pSize = 0;
+
+  // A file is always stored in sequential blocks so start with the files
+  // first block and as long as it is full continue sum up the occupied
+  // block sizes. As soon as a non-full block is found that must be the
+  // file's last block.
+  for (i = tocIdx; i < NUM_BLOCKS; i++)
+  {
+    *pSize += FILESIZE(TOC[i]);
+    if (FILESIZE(TOC[i]) < ERASE_SIZE)
+    {
+      // last block in chain
+      break;
+    }
+  }
+
+  // Remove the filename header from the file's size
+  *pSize -= HEADER_LEN;
+
+  return FS_OK;
+}
+
+/******************************************************************************
+ *
+ * Description:
+ *    Erases everything in one block on the QSPI flash.
+ *
+ * Params:
+ *    [in] block - The block's number
+ *
+ * Returns:
+ *    FS_OK or one of the FS_ERR_* error codes
+ *
+ *****************************************************************************/
+static fresult qspifs_eraseBlock(int block)
+{
+  opers.dest = (char *)(block * ERASE_SIZE);
+  opers.length = ERASE_SIZE;
+  opers.scratch = NULL;
+  opers.protect = 0;
+  opers.options = S_NO_VERIFY;
+  return qspifs_translateSpifiError(spifi->spifi_erase (&obj, &opers));
+}
+
+/******************************************************************************
+ *
+ * Description:
+ *    Creates a new file if there is enough space for it on the file system.
+ *    The TOC is searched for a unused sequence of blocks of at least the
+ *    needed size. That block is marked as used and the file's name is stored
+ *    in the first bytes of the file's first block.
+ *
+ *    Note: The filename will not be tested for uniqueness.
+ *    Note: The value of pTocIdx will only be valid if FS_OK is returned.
+ *
+ * Params:
+ *    [in] filename - The name of the new file
+ *    [in] neededBlocks - The number of blocks (in sequence) to allocate
+ *    [out] pTocIdx - The new file's position in the TOC
+ *
+ * Returns:
+ *    FS_OK or one of the FS_ERR_* error codes
+ *
+ *****************************************************************************/
+static fresult qspifs_allocateFile(const char* filename, int neededBlocks, int* pTocIdx)
+{
+  int i, rc;
+
+  if (activeTOC == -1)
+  {
+    return FS_ERR_NOT_FORMATTED;
+  }
+
+  // Look at all blocks except for the reserved ones
+  for (i = 0; i < NUM_BLOCKS; i++)
+  {
+    //TODO: Improve search to use gaps to avoid having to move files
+    //      that are written to
+    if (!USED_TOC_ENTRY(TOC[i]) && !TOC_IS_RESERVED(TOC[i]))
+    {
+      int j;
+      for (j = 1; j < neededBlocks; j++)
+      {
+        if (USED_TOC_ENTRY(TOC[i+j]) || TOC_IS_RESERVED(TOC[i+j]))
+        {
+          // not enough free blocks in sequence, skip past these
+          // tested entries and continue searching
+          i += j;
+          break;
+        }
+      }
+
+      if (j == neededBlocks)
+      {
+        const char* pSrc = filename;
+        if (IS_ADDR_IN_SPIFI(filename))
+        {
+          // The SPIFI ROM driver cannot write data from SPIFI into
+          // SPIFI (i.e. cannot read and write at the same time).
+          // The workaround is to copy the source data into a buffer
+          // in local memory and use that as source for the write
+          // instead.
+          memcpy(addr_conflict_buff, filename, strlen(filename)+1);
+          pSrc = addr_conflict_buff;
+        }
+
+        // Erase the new file's first block and store the filename at the
+        // start of it
+        opers.length = strlen(pSrc)+1;
+        opers.scratch = NULL;
+        opers.protect = 0;
+        opers.options = S_VERIFY_PROG | S_FORCE_ERASE;// S_CALLER_ERASE;
+        opers.dest = (char *)(i*ERASE_SIZE);
+        rc = spifi->spifi_program(&obj, (char*)pSrc, &opers);
+        if (rc) {
+          return qspifs_translateSpifiError(rc);
+        }
+
+        TOC[i] &= ~(TOC_VALID_MASK | TOC_USED_MASK | TOC_FILE_MASK | TOC_FSIZE_MASK);
+        TOC[i] |= HEADER_LEN;
+
+        *pTocIdx = i;
+        return FS_OK;
+      }
+    }
+  }
+  return FS_ERR_DISK_FULL;
+}
+
+/******************************************************************************
+ *
+ * Description:
+ *    Deletes the specified file by marking all its blocks as unused in
+ *    the TOC.
+ *
+ *    Note: The deleted blocks are not erased here - that is done when they
+ *          are allocated the next time.
+ *
+ * Params:
+ *    [in] fh - The file handle with information about what to delete
+ *
+ * Returns:
+ *    None
+ *
+ *****************************************************************************/
+static void qspifs_deleteFile(fileHandle_t* fh)
+{
+  int i;
+
+  for (i = fh->lastBlock; i >= fh->tocIdx; i--)
+  {
+    TOC[i] = ~TOC_VALID_MASK;
+  }
+}
+
+/******************************************************************************
+ *
+ * Description:
+ *    Ensures that the specified file can grow to the wanted size.
+ *    If the file size will increase enough to need one or more new blocks
+ *    and there isn't enough space then an attempt is made to move the
+ *    current file to a large enough space somewhere else.
+ *
+ *    If there are more free block(s) at the end of the file then it is not
+ *    moved and instead those blocks are marked as used.
+ *
+ *    Note: The filename will not be tested for uniqueness.
+ *    Note: The value of pTocIdx will only be valid if FS_OK is returned.
+ *
+ * Params:
+ *    [in/out] fh - The current file handle, might be updated after a move
+ *    [in] size   - The wanted new size
+ *
+ * Returns:
+ *    FS_OK or one of the FS_ERR_* error codes
+ *
+ *****************************************************************************/
+static fresult qspifs_allocateSpace(fileHandle_t* fh, uint32_t size)
+{
+  uint16_t oldNumBlocks = (fh->size + HEADER_LEN) / ERASE_SIZE;
+  uint16_t newNumBlocks = (fh->size + HEADER_LEN + size) / ERASE_SIZE;
+  uint16_t numNeeded = newNumBlocks - oldNumBlocks;
+  fresult res = FS_OK;
+
+  if (numNeeded > 0)
+  {
+    uint16_t i;
+    for (i = 0; i < numNeeded; i++)
+    {
+      if (USED_TOC_ENTRY(TOC[fh->tocIdx + oldNumBlocks + 1 + i]) || 
+          TOC_IS_RESERVED(TOC[fh->tocIdx + oldNumBlocks + 1 + i]))
+      {
+        fileHandle_t fhNew;
+
+        // have to move the chain
+        char* filename = (char*)(SPIFI_MEM_BASE + fh->tocIdx * ERASE_SIZE);
+        res = qspifs_allocateFile(filename, newNumBlocks, &(fhNew.tocIdx));
+        if (res == FS_OK)
+        {
+          // copy data
+          fhNew.lastBlock = fhNew.tocIdx;
+          fhNew.size = 0;
+          res = qspifs_write(&fhNew, (uint8_t*)(SPIFI_MEM_BASE + fh->tocIdx * ERASE_SIZE + HEADER_LEN), fh->size);
+        }
+        if (res == FS_OK)
+        {
+          // remove old entries
+            qspifs_deleteFile(fh);
+
+          // modify old handle to point to new information
+          fh->lastBlock = fhNew.lastBlock;
+          fh->size = fhNew.size;
+          fh->tocIdx = fhNew.tocIdx;
+        }
+        if (res != FS_OK)
+        {
+          // not possible to relocate the file => abort
+          return res;
+        }
+        break;
+      }
+    }
+
+    // have space that is unused, so mark as used
+    for (i = 0; i < numNeeded; i++)
+    {
+      int tocIdx = fh->tocIdx + oldNumBlocks + 1 + i;
+      TOC[tocIdx] &= ~TOC_USED_MASK;
+      qspifs_eraseBlock(tocIdx);
+    }
+  }
+
+  return res;
+}
+
+/******************************************************************************
+ *
+ * Description:
+ *    Adds a file system to the QSPI flash. The entire flash will be erase 
+ *    except for the minReservedBytes first bytes. That reserved area (rounded
+ *    up to the closest even multiple of the erase block size) can be used 
+ *    for anything and will never be touched by the file system. That area is
+ *    typically used for executing programs from when the internal flash is
+ *    full.
+ *
+ *    The file system will have a table of content (TOC) placed at the start
+ *    of the last erase block on the flash.
+ *
+ * Params:
+ *    [in] minReservedBytes  - The number of bytes to ignore at the start of
+ *                             the flash.
+ *
+ * Returns:
+ *    FS_OK on success or one of the FS_ERR_* on failure
+ *
+ *****************************************************************************/
+static fresult qspifs_format(unsigned int minReservedBytes)
+{
+  int i, rc;
+  int numReserved = 0;
+  
+  if (minReservedBytes > 0) {
+    numReserved = (minReservedBytes + ERASE_SIZE - 1) / ERASE_SIZE;
+    if (numReserved >= (NUM_BLOCKS - 2)) {
+      // Too many of the erase blocks are reserved - not even room for one file
+      return FS_ERR_INVALID_PARAM;
+    }
+  }
+
+#if 0   // works but is really slow  
+  // Erase all non-reserved blocks
+  for (i = numReserved; i < NUM_BLOCKS; i++) {
+    opers.dest = (char *) (i * ERASE_SIZE);
+    opers.length = ERASE_SIZE;
+    opers.scratch = NULL;
+    opers.protect = 0;
+    opers.options = S_NO_VERIFY;
+    rc = spifi->spifi_erase(&obj, &opers);
+    if (rc) {
+      return qspifs_translateSpifiError(rc);
+    }
+  }
+#else
+  // Erase all non-reserved blocks
+  opers.dest = (char *) (numReserved * ERASE_SIZE);
+  opers.length = MEM_SIZE - (numReserved * ERASE_SIZE);
+  opers.scratch = NULL;
+  opers.protect = 0;
+  opers.options = S_NO_VERIFY;
+  rc = spifi->spifi_erase(&obj, &opers);
+  if (rc) {
+    return qspifs_translateSpifiError(rc);
+  }
+#endif  
+
+  // Create the TOC, mark requested blocks as reserved and mark the TOC's
+  // block(s) as reserved as well.
+  for (i = 0; i < numReserved; i++) {
+    TOC[i] = ~(TOC_VALID_MASK | TOC_RESERVED_MASK);
+  }
+  for (; i < (NUM_BLOCKS - NUM_TOC_BLOCKS); i++) {
+    TOC[i] = ~TOC_VALID_MASK;
+  }
+  for (; i < NUM_BLOCKS; i++) {
+    TOC[i] = ~(TOC_VALID_MASK | TOC_RESERVED_MASK);
+  }
+  
+  // Save the TOC in the last block
+  activeTOC = 0;
+  fresult res = qspifs_saveTOC();
+  if (res != FS_OK) {
+    activeTOC = -1;
+    return res;
+  }
+//   opers.dest = (char *) TOC_BLOCK_ADDR;
+//   opers.length = TOC_SIZE;
+//   opers.scratch = NULL;
+//   opers.protect = 0;
+//   opers.options = S_VERIFY_PROG | S_CALLER_ERASE;
+//   rc = spifi->spifi_program(&obj, (char*) TOC, &opers);
+//   if (rc) {
+//     return qspifs_translateSpifiError(rc);
+//   }
+
+  // Read back TOC to be sure it worked
+  return qspifs_readTOC();
+}
+
+/******************************************************************************
+ *
+ * Description:
+ *    Deletes all files on the file system. This is a "quick format" that
+ *    leaves all blocks untouched and only modifies the TOC. Any reserved
+ *    blocks are kept reserved.
+ *
+ *    The purpose of this function is to make it easy to clear the file system
+ *    without going through a time consuming complete erase every time.
+ *
+ * Params:
+ *    None
+ *
+ * Returns:
+ *    FS_OK on success or one of the FS_ERR_* on failure
+ *
+ *****************************************************************************/
+// static fresult qspifs_deleteAllFiles(void)
+// {
+//   for (int i = 0; i < NUM_BLOCKS; i++)
+//   {
+//     if (!TOC_IS_RESERVED(TOC[i])) {
+//       TOC[i] = ~TOC_VALID_MASK;
+//     }
+//   }
+//   
+//   return qspifs_saveTOC();
+// }
+
+/******************************************************************************
+ *
+ * Description:
+ *    Appends the data to the end of the file.
+ *
+ * Params:
+ *    [in] fh     - The handle to the file as returned from fs_open_append()
+ *    [in] pData  - The data to save
+ *    [in] size   - Number of bytes to save
+ *
+ * Returns:
+ *    FS_OK on success or one of the FS_ERR_* on failure
+ *
+ *****************************************************************************/
+static fresult qspifs_write(fileHandle_t* fh, const uint8_t * const pData, uint32_t size)
+{
+    uint32_t left = size;
+    const uint8_t* pSrc = pData;
+    int rc, i;
+    fresult res;
+    int failed_attempts = 0;
+
+    do {
+        res = qspifs_allocateSpace(fh, size);
+        if (res != FS_OK) {
+            break;
+        }
+
+        opers.dest = (char *) (SPIFI_MEM_BASE + fh->tocIdx * ERASE_SIZE
+                + HEADER_LEN + fh->size);
+        opers.scratch = NULL;
+        opers.protect = 0;
+        opers.options = S_VERIFY_PROG; // | S_FORCE_ERASE;
+
+        while ((res == FS_OK) && (left > 0)) {
+            if (left >= PROG_SIZE) {
+                opers.length = PROG_SIZE;
+            } else {
+                opers.length = left;
+            }
+            if (IS_ADDR_IN_SPIFI(pData)) {
+                memcpy(addr_conflict_buff, pSrc, opers.length);
+                rc = spifi->spifi_program(&obj, addr_conflict_buff, &opers);
+            } else {
+                rc = spifi->spifi_program(&obj, (char*) pSrc, &opers);
+            }
+            res = qspifs_translateSpifiError(rc);
+            if ((res == FS_ERR_SPIFI_VERIFICATION)
+                    && (++failed_attempts <= NUM_VERIFICATION_ATTEMPTS)) {
+                // The verification process failed.
+                // In all the observed occasions re-running the exact same
+                // spifi_program command again yielded a 0 as a return value
+                // the second time.
+                // The quick'N'dirty fix is to re-run that program instruction
+                // NUM_VERIFICATION_ATTEMPTS more time(s) when this happens.
+                res = FS_OK;
+                continue;
+            }
+            if (res != FS_OK) {
+                // Got an error but cannot exit this function here as parts of the data
+                // (previous loops?) may have been written so the TOC must be updated.
+                break;
+            }
+            pSrc += opers.length;
+            opers.dest += opers.length;
+            left -= opers.length;
+            failed_attempts = 0;
+        }
+
+        // update file information
+        fh->size = fh->size + size - left;
+        fh->lastBlock = fh->tocIdx + ((fh->size + HEADER_LEN)/ ERASE_SIZE);
+        left = fh->size + HEADER_LEN;
+        for (i = 0; i <= (fh->lastBlock - fh->tocIdx); i++) {
+            TOC[fh->tocIdx + i] &= ~TOC_FSIZE_MASK;
+            TOC[fh->tocIdx + i] |= FS_MIN(ERASE_SIZE, left);
+            left -= FILESIZE(TOC[fh->tocIdx + i]);
+        }
+
+        if (res == FS_OK) {
+            res = qspifs_saveTOC();
+        } else {
+            // Want to save the TOC but not overwrite the previous error with
+            // a possibly successful TOC saving thus making it seem like there
+            // was no error
+            qspifs_saveTOC();
+        }
+    } while (0);
+
+    return res;
+}
+
+/******************************************************************************
+ *
+ * Description:
+ *    Tests if str starts with prefix. A prefix of NULL or an empty string
+ *    results in a positive result regardless of the content of str.
+ *
+ * Params:
+ *    [in] prefix - The prefix to look for
+ *    [in] str    - The string to search for prefix
+ *
+ * Returns:
+ *    True if the specified string starts with prefix
+ *
+ *****************************************************************************/
+static bool qspifs_startsWith(const char* prefix, const char* str)
+{
+    const char* pA = prefix;
+    const char* pB = str;
+
+    if (pA == NULL)
+    {
+      return true;
+    }
+    for (; *pA != '\0'; pA++, pB++)
+    {
+      if (*pB != *pA)
+      {
+        return false;
+      }
+    }
+
+    return true;
+}
+
+/******************************************************************************
+ * Class Declarations
+ *****************************************************************************/
+
+class QSPIFileHandle : public FileHandle {
+
+public:
+    QSPIFileHandle(fileHandle_t* handle, int flags);
+
+    virtual int close();
+
+    virtual ssize_t write(const void *buffer, size_t length);
+
+    virtual ssize_t read(void *buffer, size_t length);
+
+    virtual int isatty();
+
+    virtual off_t lseek(off_t position, int whence);
+
+    virtual int fsync();
+
+    virtual off_t flen();
+
+protected:
+
+    fileHandle_t fh;
+    bool allowReading;
+    bool allowWriting;
+    uint32_t pos;
+};
+
+class QSPIDirHandle : public DirHandle {
+
+public:
+    static QSPIDirHandle* openDir(const char* dirname);
+
+    virtual ~QSPIDirHandle();
+
+    virtual int closedir();
+    virtual struct dirent *readdir();
+    virtual void rewinddir();
+
+private:
+    QSPIDirHandle(const char* dirname);    
+
+    int findFileWithPrefix(const char* prefix, int startTOCIdx, int maxTOCIdx) const;
+
+protected:
+  
+    char* dirname;
+    int nextTocIdx;
+
+    bool isRoot;
+
+    struct dirent cur_entry;
+};
+
+/******************************************************************************
+ * Class Implementations
+ *****************************************************************************/
+
+QSPIFileHandle::QSPIFileHandle(fileHandle_t* handle, int flags)
+{
+    fh = *handle;
+    int accmode = (flags & O_ACCMODE);
+    allowReading = (accmode == O_RDONLY) || (accmode == O_RDWR);
+    allowWriting = (accmode == O_WRONLY) || (accmode == O_RDWR) || (flags & O_APPEND);
+    pos = 0;
+}
+
+int QSPIFileHandle::close()
+{
+    delete this;
+    return 0;
+}
+
+ssize_t QSPIFileHandle::write(const void *buffer, size_t length)
+{
+    if (!allowWriting) {
+        return -1;
+    }
+    fresult res = qspifs_write(&fh, (const uint8_t*)buffer, length);
+    if (res == FS_OK) {
+        // A write is always 'append' in this file system so the file
+        // position is always end of file after a write
+        pos = fh.size;
+        return length;
+    }
+    return -1;
+}
+
+ssize_t QSPIFileHandle::read(void *buffer, size_t length)
+{
+    if (!allowReading) {
+        return -1;
+    }
+    if (pos >= fh.size) {
+        return 0;
+    }
+    uint32_t len = FS_MIN(length, fh.size - pos);
+    const char* pData = (const char*)(SPIFI_MEM_BASE + fh.tocIdx*ERASE_SIZE + HEADER_LEN + pos);
+    memcpy(buffer, pData, len);
+    pos += len;
+    return len;
+}
+
+int QSPIFileHandle::isatty()
+{
+    return 0;
+}
+
+off_t QSPIFileHandle::lseek(off_t position, int whence)
+{
+    switch (whence) {
+    case SEEK_SET:
+        pos = position;
+        break;
+
+    case SEEK_CUR:
+        pos += position;
+        break;
+
+    case SEEK_END:
+        pos = fh.size + position;
+        break;
+
+    default:
+        return -1;
+    }
+    return pos;
+}
+
+int QSPIFileHandle::fsync()
+{
+    return 0; // always synced
+}
+
+off_t QSPIFileHandle::flen()
+{
+    return fh.size;
+}
+
+QSPIDirHandle::QSPIDirHandle(const char* dirname) {
+    size_t len = strlen(dirname);
+    this->dirname = (char*)malloc(len + 2); // null termination and possible ending '/'
+    if (this->dirname != NULL) {
+        if (len == 0 || ((len == 1) && (dirname[0] == '/'))) {
+            isRoot = true;
+            this->dirname[0] = '\0';
+        } else {
+            isRoot = false;
+            memcpy(this->dirname, dirname, len+1);
+            if (dirname[len - 1] != '/') {
+                this->dirname[len] = '/';
+                this->dirname[len+1] = '\0';
+            }
+        }
+        cur_entry.d_name[HEADER_FNAME_STRLEN] = '\0';
+        rewinddir();
+      }
+}
+
+QSPIDirHandle::~QSPIDirHandle()
+{
+  if (dirname != NULL) {
+    delete dirname;
+    dirname = NULL;
+  }
+}
+
+QSPIDirHandle* QSPIDirHandle::openDir(const char* dirname)
+{
+  QSPIDirHandle* d = new QSPIDirHandle(dirname);
+  if (d->dirname == NULL) {
+    // failed to allocate memory for the folder name
+    delete d;
+    d = NULL;
+  } else if (!d->isRoot) {
+    if (d->findFileWithPrefix(d->dirname, 0, NUM_BLOCKS) == NUM_BLOCKS) {
+      // There are no files in this directory, i.e. it does not exist
+      delete d;
+      d = NULL;
+    }
+  }
+  return d;
+}
+
+int QSPIDirHandle::closedir() {
+    delete this;
+    return 0;
+}
+
+int QSPIDirHandle::findFileWithPrefix(const char* prefix, int startTOCIdx, int maxTOCIdx) const
+{
+  for (int i = startTOCIdx; i < maxTOCIdx; i++) {
+    if (TOC_IS_FILE(TOC[i])) {
+      const char* filename = (const char*) (SPIFI_MEM_BASE + i * ERASE_SIZE);
+      if (qspifs_startsWith(prefix, filename)) {
+        return i;
+      }
+    }
+  }
+  return NUM_BLOCKS; // no match
+}
+
+
+struct dirent *QSPIDirHandle::readdir() {
+  if (nextTocIdx < NUM_BLOCKS) {
+    for (int i = nextTocIdx; i < NUM_BLOCKS; i++) {
+      int possible = findFileWithPrefix(dirname, i, NUM_BLOCKS);
+      if (possible < NUM_BLOCKS) {
+        const char* fullfilename = (const char*) (SPIFI_MEM_BASE + possible * ERASE_SIZE);
+        const char* filename = fullfilename + strlen(dirname);
+        
+        if (strchr(filename, '/') == NULL) {
+          // file is not in any sub folder so it is truly in the wanted dir
+          nextTocIdx = possible + 1;
+          strcpy(cur_entry.d_name, filename);
+          return &cur_entry;
+        }
+        
+        // this is a file in a subfolder and should not be reported,
+        // but the folder name itself should
+        strcpy(cur_entry.d_name, fullfilename);
+        char* pSlash = strchr(cur_entry.d_name + strlen(dirname), '/');
+        pSlash++;
+        *pSlash = '\0';
+        
+        // now that cur_entry.d_name contains the folder's complete 
+        // path with a trailing '/', see if it has occurred earlier
+        int older = findFileWithPrefix(cur_entry.d_name, 0, i);
+        if (older < possible) {
+          // already reported, move past this entry
+          i = possible;
+        } else {
+          // found a new subfolder 
+          nextTocIdx = possible + 1;
+          strcpy(cur_entry.d_name, filename);
+          char* pSlash = strchr(cur_entry.d_name, '/');
+//          pSlash++; //with ++ the returned dir name is "mydir/" without ++ "mydir" is returned
+          *pSlash = '\0';
+          return &cur_entry;
+        }
+      }
+    }
+  }
+  return NULL;
+}
+
+void QSPIDirHandle::rewinddir() {
+  nextTocIdx = 0;
+}
+
+
+QSPIFileSystem::QSPIFileSystem(const char* name) :
+    FileSystemLike(name) {
+
+    // Turn on SPIFI block as it is disabled on reset
+    LPC_SC->PCONP |= 0x00010000;
+
+    // pinsel for SPIFI
+    LPC_IOCON->P2_7 &= ~0x07;
+    LPC_IOCON->P2_7 |= 0x05; /* SPIFI_CSN @ P2.7 */
+    LPC_IOCON->P0_22 &= ~0x07;
+    LPC_IOCON->P0_22 |= 0x05; /* SPIFI_CLK @ P0.22 */
+    LPC_IOCON->P0_15 &= ~0x07;
+    LPC_IOCON->P0_15 |= 0x5; /* SPIFI_IO2 @ P0.15 */
+    LPC_IOCON->P0_16 &= ~0x07;
+    LPC_IOCON->P0_16 |= 0x5; /* SPIFI_IO3 @ P0.16 */
+    LPC_IOCON->P0_17 &= ~0x07;
+    LPC_IOCON->P0_17 |= 0x5; /* SPIFI_IO1 @ P0.17 */
+    LPC_IOCON->P0_18 &= ~0x07;
+    LPC_IOCON->P0_18 |= 0x5; /* SPIFI_IO0 @ P0.18 */
+
+    activeTOC = -1;
+    spifi = NULL;
+}
+
+// All modes are supported but:
+//
+//    1) All writes are treated as appends
+//    2) Truncation is only to size 0, i.e. effectively a delete
+//    3) File position operations work like this:
+//       ReadOnly - dictates where to read from
+//       WriteOnly - ignored, writes are always at the end
+//       ReadWrite - dictates where to read from, writes ignore it but
+//                   sets the position to the end afterwards
+//
+FileHandle *QSPIFileSystem::open(const char *filename, int flags)
+{
+    fresult res = qspifs_init();
+//     if (res == FS_OK) {
+//         if ((flags & O_ACCMODE) == O_RDONLY) {
+//             // ok
+//         } else if (flags & O_APPEND) {
+//             // ok
+//         } else {
+//             // not supported yet, this includes all combination of flags
+//             // allowing writing at specific positions in the file. This file system
+//             // only allows appending
+//             res = FS_ERR_INVALID_PARAM;
+//         }
+//     }
+    if (res == FS_OK) {
+        if (strlen(filename) > HEADER_FNAME_STRLEN) {
+            // Filename is too long
+            res = FS_ERR_INVALID_PARAM;
+        }
+    }
+    if (res == FS_OK) {
+      // Handle truncation by silently deleting the file before
+      // attempting to open it
+      if (flags & O_TRUNC) {
+        remove(filename);
+      }
+    }
+    if (res == FS_OK) {
+        fileHandle_t fh = {0,0,0};
+        res = qspifs_findFile(filename, &fh);
+        if ((res == FS_ERR_NO_FILE) && (flags & O_CREAT)) {
+            res = qspifs_allocateFile(filename, 1, &fh.tocIdx);
+        }
+        if (res == FS_OK) {
+            res = qspifs_saveTOC();
+        }
+        if (res == FS_OK) {
+            return new QSPIFileHandle(&fh, flags);
+        }
+    }
+    debug_if(QSPI_DBG, "QSPIFS: Failed to open: %d\n", res);
+    return NULL;
+}
+
+int QSPIFileSystem::remove(const char *filename)
+{
+    fileHandle_t fh = {0,0,0};
+    fresult res = qspifs_init();
+    if (res == FS_OK) {
+        res = qspifs_findFile(filename, &fh);
+    }
+    if (res == FS_OK) {
+        qspifs_deleteFile(&fh);
+        res = qspifs_saveTOC();
+    }
+    else if (res == FS_ERR_NO_FILE) {
+        // file does not exist so treat it as a successful deletion
+        res = FS_OK;
+    }
+    if (res != FS_OK) {
+        debug_if(QSPI_DBG, "QSPIFS: Failed to delete %s: %d\n", filename, res);
+        return -1;
+    }
+    return 0;
+}
+
+int QSPIFileSystem::rename(const char *oldname, const char *newname)
+{
+    fileHandle_t fhOld = {0,0,0};
+    fileHandle_t fhNew = {0,0,0};
+
+    fresult res = qspifs_init();
+    if (res == FS_OK) {
+        res = qspifs_findFile(oldname, &fhOld);
+    }
+    if (res == FS_OK) {
+        // Make sure the destination file doesn't exist
+        res = qspifs_findFile(newname, &fhNew);
+        if (res == FS_OK) {
+            res = FS_ERR_FILE_EXIST;
+        } else if (res == FS_ERR_NO_FILE) {
+            res = FS_OK;
+        }
+    }
+    if (res == FS_OK) {
+        int numNeededBlocks = 1 + ((fhOld.size + HEADER_LEN) / ERASE_SIZE);
+        res = qspifs_allocateFile(newname, numNeededBlocks, &fhNew.tocIdx);
+        if (res == FS_OK) {
+            const uint8_t* pData = (const uint8_t*)(SPIFI_MEM_BASE + fhOld.tocIdx*ERASE_SIZE + HEADER_LEN);
+            res = qspifs_write(&fhNew, pData, fhOld.size);
+            if (res == FS_OK) {
+                qspifs_deleteFile(&fhOld);
+            } else {
+                qspifs_deleteFile(&fhNew);
+            }
+        }
+        qspifs_saveTOC();
+    }
+    if (res != FS_OK) {
+        debug_if(QSPI_DBG, "QSPIFS: Failed to rename '%s' to '%s': %d\n", oldname, newname, res);
+        return -1;
+    }
+    return 0;
+}
+
+DirHandle *QSPIFileSystem::opendir(const char *name)
+{
+  FileHandle* fh = open(name, O_RDONLY);
+  if (fh != NULL) {
+    // Attempting to open a file as a dir
+    delete fh;
+    return NULL;
+  }
+  
+//     printf("opendir: name '%s'\n", name);
+  if (strlen(name) <= HEADER_DNAME_MAXLEN) {
+    return QSPIDirHandle::openDir(name);
+  }
+  return NULL;
+}
+
+int QSPIFileSystem::mkdir(const char *name, mode_t mode)
+{
+    // Creating folders is always successful as there are no folders in this filesystem
+    return 0;
+}
+
+int QSPIFileSystem::format(unsigned int fsSizeInMB)
+{
+    fresult res = qspifs_init();
+    if (res == FS_OK || res == FS_ERR_NOT_FORMATTED) {
+        if (((fsSizeInMB<<20) > memInfo.memSize) || (fsSizeInMB < 1)) {
+            debug_if(QSPI_DBG, "QSPIFS: Failed to format to size %d MByte: error %d\n", fsSizeInMB, res);
+            return -1;
+        }
+        activeTOC = -1;
+        res = qspifs_format(memInfo.memSize - (fsSizeInMB<<20));
+    }
+
+    if (res != FS_OK) {
+        debug_if(QSPI_DBG, "QSPIFS: Failed to format: %d\n", res);
+        return -1;
+    }
+    return 0;
+}
+
+bool QSPIFileSystem::isformatted()
+{
+    fresult res = qspifs_init();
+    if (res == FS_OK) {
+        return true;
+    } else if (res == FS_ERR_NOT_FORMATTED) {
+        return false;
+    }
+    debug_if(QSPI_DBG, "QSPIFS: Failed to detect status: %d\n", res);
+    return false;
+}
+
+bool QSPIFileSystem::getMemoryBoundaries(uint32_t* pStartAddr, uint32_t* pEndAddr)
+{
+  if (isformatted())
+  {
+    *pEndAddr = 0x28000000 + memInfo.memSize;
+    
+    // Look at all blocks except for the reserved ones
+    for (int i = 0; i < NUM_BLOCKS; i++)
+    {
+      if (!TOC_IS_RESERVED(TOC[i]))
+      {
+        // Found first non-reserved erase block, indicating the start of
+        // the file system.
+        *pStartAddr = SPIFI_MEM_BASE + i*ERASE_SIZE;
+        return true;
+      }
+    }
+    
+    // The entire file system seems to be reserved which should never happen
+    // but just in case, report it as beeing 1MB in size.
+    *pStartAddr = *pEndAddr - 1024*1024;
+    return true;
+  }
+  return false;
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/QSPIFileSystem.h	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,81 @@
+#ifndef QSPIFILESYSTEM_H
+#define QSPIFILESYSTEM_H
+
+#include "mbed.h"
+#include "FileSystemLike.h"
+
+/** Access the filesystem on an QSPI flash using SPIFI
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "QSPIFileSystem.h"
+ *
+ * QSPIFileSystem qspi("qspi");
+ *  
+ * int main() {
+ *     if (!qspifs.isFormatted()) {
+ *         qspifs.format();
+ *     }
+ *
+ *     FILE *fp = fopen("/qspi/myfile.txt", "w");
+ *     if (fp != NULL) {
+ *         fprintf(fp, "Hello World!\n");
+ *         fclose(fp);
+ *     }
+ * }
+ * @endcode
+ */
+class QSPIFileSystem : public FileSystemLike {
+public:
+
+    /** Create the File System for accessing a QSPI Flash
+     *
+     * @param name The name used to access the virtual filesystem
+     */
+    QSPIFileSystem(const char* name);
+
+    virtual FileHandle *open(const char *filename, int flags);
+    virtual int remove(const char *filename);
+    virtual int rename(const char *oldname, const char *newname);
+    virtual DirHandle *opendir(const char *name);
+    virtual int mkdir(const char *name, mode_t mode);
+
+    /** Creates a new file system on the QSPI flash.
+     * The file system will have the specified size and will always
+     * be positioned at the end of the QSPI flash. If the fsSizeInMB is
+     * less than the size of the QSPI flash the lower end of the flash
+     * will be left untouched.
+     *
+     * @param fsSizeInMB The size of the file system
+     *
+     * @returns
+     *    0 on success,
+     *   -1 on failure.
+     */
+    int format(unsigned int fsSizeInMB = 8);
+
+    /** Tests if there is a file system present on the QSPI flash
+     *
+     * @returns
+     *   True if a valid file system could be found,
+     *   False on failure.
+     */
+    bool isformatted();
+
+    /** Retrieves the start and end addresses for the file system.
+     * The pStartAddr and pEndAddr will only be assigned values if the
+     * function returns true.
+     *
+     * @param pStartAddr Will return the start of the file system area
+     * @param pEndAddr   Will return the end of the file system area
+     *
+     * @returns
+     *   True if there is a file system,
+     *   False on failure.
+     */
+    bool getMemoryBoundaries(uint32_t* pStartAddr, uint32_t* pEndAddr);
+};
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TSC2046.cpp	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,617 @@
+
+#include "mbed.h"
+#include "TSC2046.h"
+
+#ifndef ABS
+#define ABS(x) (  ((int32_t)(x)) < 0 ? (-(x)) : (x))
+#endif
+
+#define ADS_START         (1 << 7)
+#define ADS_A2A1A0_d_y    (1 << 4)  /* differential */
+#define ADS_A2A1A0_d_z1   (3 << 4)  /* differential */
+#define ADS_A2A1A0_d_z2   (4 << 4)  /* differential */
+#define ADS_A2A1A0_d_x    (5 << 4)  /* differential */
+#define ADS_A2A1A0_temp0  (0 << 4)  /* non-differential */
+#define ADS_A2A1A0_vbatt  (2 << 4)  /* non-differential */
+#define ADS_A2A1A0_vaux   (6 << 4)  /* non-differential */
+#define ADS_A2A1A0_temp1  (7 << 4)  /* non-differential */
+#define ADS_8_BIT         (1 << 3)
+#define ADS_12_BIT        (0 << 3)
+#define ADS_SER           (1 << 2)  /* non-differential */
+#define ADS_DFR           (0 << 2)  /* differential */
+#define ADS_PD10_PDOWN    (0 << 0)  /* lowpower mode + penirq */
+#define ADS_PD10_ADC_ON   (1 << 0)  /* ADC on */
+#define ADS_PD10_REF_ON   (2 << 0)  /* vREF on + penirq */
+#define ADS_PD10_ALL_ON   (3 << 0)  /* ADC + vREF on */
+
+
+#define READ_12BIT_DFR(d, adc, vref) (ADS_START | d \
+  | ADS_12_BIT | ADS_DFR | \
+  (adc ? ADS_PD10_ADC_ON : 0) | (vref ? ADS_PD10_REF_ON : 0))
+
+#define READ_Y(vref)  (READ_12BIT_DFR(ADS_A2A1A0_d_y,  1, vref))
+#define READ_Z1(vref) (READ_12BIT_DFR(ADS_A2A1A0_d_z1, 1, vref))
+#define READ_Z2(vref) (READ_12BIT_DFR(ADS_A2A1A0_d_z2, 1, vref))
+#define READ_X(vref)  (READ_12BIT_DFR(ADS_A2A1A0_d_x,  1, vref))
+#define PWRDOWN       (READ_12BIT_DFR(ADS_A2A1A0_d_y,  0, 0))  /* LAST */
+
+/* single-ended samples need to first power up reference voltage;
+ * we leave both ADC and VREF powered
+ */
+#define READ_12BIT_SER(x) (ADS_START | x \
+  | ADS_12_BIT | ADS_SER)
+
+#define REF_ON  (READ_12BIT_DFR(ADS_A2A1A0_d_x, 1, 1))
+#define REF_OFF (READ_12BIT_DFR(ADS_A2A1A0_d_y, 0, 0))
+
+#define DEBOUNCE_MAX 10
+#define DEBOUNCE_TOL  3
+
+TSC2046::TSC2046(PinName mosi, PinName miso, PinName sck, PinName cs) :
+_spi(mosi, miso, sck), _cs(cs)
+{
+    _cs = 1; // active low
+
+    _spi.format(8, 3);
+    _spi.frequency(1500000);
+    _calibrated = false;
+    _initialized = false;
+}
+
+
+void TSC2046::read(touchCoordinate_t &coord) {
+
+    touchCoordinate_t tmpCoord;
+    calibPoint_t displayPoint;
+    calibPoint_t screenSample;
+
+    if (!_initialized) {
+        init();
+        _initialized = true;
+    }
+
+    readAndFilter(tmpCoord);
+
+    _cs = 0;
+    _spi.write(PWRDOWN);
+    _cs = 1;
+
+    coord.z = tmpCoord.z;
+
+    if (_calibrated) {
+        screenSample.x = tmpCoord.x;
+        screenSample.y = tmpCoord.y;
+
+        getDisplayPoint(&displayPoint, &screenSample, &_calibMatrix);
+
+        coord.x = displayPoint.x;
+        coord.y = displayPoint.y;
+    }
+    else {
+        coord.x = tmpCoord.x;
+        coord.y = tmpCoord.y;
+    }
+
+}
+
+void TSC2046::calibrate(touchCoordinate_t &ref1,
+        touchCoordinate_t &ref2,
+        touchCoordinate_t &ref3,
+        touchCoordinate_t &scr1,
+        touchCoordinate_t &scr2,
+        touchCoordinate_t &scr3) {
+
+    calibPoint_t disp[3];
+    calibPoint_t scr[3];
+
+    disp[0].x = ref1.x;
+    disp[0].y = ref1.y;
+    disp[1].x = ref2.x;
+    disp[1].y = ref2.y;
+    disp[2].x = ref3.x;
+    disp[2].y = ref3.y;
+
+    scr[0].x = scr1.x;
+    scr[0].y = scr1.y;
+    scr[1].x = scr2.x;
+    scr[1].y = scr2.y;
+    scr[2].x = scr3.x;
+    scr[2].y = scr3.y;
+
+    setCalibrationMatrix(disp, scr, &_calibMatrix);
+
+    _calibrated = true;
+
+}
+
+void TSC2046::uncalibrate() {
+    _calibrated = false;
+}
+
+
+void TSC2046::init() {
+
+    _cs = 0;
+
+    _spi.write(REF_ON);
+    _spi.write((READ_12BIT_SER(ADS_A2A1A0_vaux) | ADS_PD10_ALL_ON));
+    _spi.write(PWRDOWN);
+
+    _cs = 1;
+}
+
+void TSC2046::readAndFilter(touchCoordinate_t &coord)
+{
+    int32_t ix, iy, iz1, iz2 = 0;
+    int32_t lastx, lasty, lastz1, lastz2 = 0;
+    int i = 0;
+
+    coord.x = 0;
+    coord.y = 0;
+    coord.z = 0;
+
+    lasty = getFilteredValue(READ_Y(0));
+    lasty >>= 3;
+    if (lasty >= 4095) {
+        lasty = 0;
+    }
+
+    lastx = getFilteredValue(READ_X(0));
+    lastx >>= 3;
+    if (lastx >= 4095) {
+        lastx = 0;
+    }
+
+    lastz1 = getFilteredValue(READ_Z1(0));
+    lastz1 >>= 3;
+
+    lastz2 = getFilteredValue(READ_Z2(0));
+    lastz2 >>= 3;
+
+
+    if (lastx && lastz1) {
+        coord.z = (lastx * ABS(lastz2 - lastz1)) / lastz1;
+    }
+    else {
+        coord.z = 0;
+    }
+
+    if (coord.z > 20000) {
+        coord.z = 0;
+    }
+
+    if (coord.z == 0) {
+        return;
+    }
+
+    for (i = 0; i < DEBOUNCE_MAX; i++) {
+        iy = getFilteredValue(READ_Y(0));
+        iy >>= 3;
+
+        if (ABS (lasty - iy) <= DEBOUNCE_TOL) {
+            break;
+        }
+
+        lasty = iy;
+    }
+
+    for (i = 0; i < DEBOUNCE_MAX; i++) {
+        ix = getFilteredValue(READ_X(0));
+        ix >>= 3;
+        if (ix > 4095) {
+            ix = 0;
+        }
+
+        if (ABS (lastx - ix) <= DEBOUNCE_TOL) {
+            break;
+        }
+
+        lastx = ix;
+    }
+
+    for (i = 0; i < DEBOUNCE_MAX; i++) {
+        iz1 = getFilteredValue(READ_Z1(0));
+        iz1 >>= 3;
+
+        if (ABS (lastz1 - iz1) <= DEBOUNCE_TOL) {
+            break;
+        }
+
+        lastz1 = iz1;
+    }
+
+    for (i = 0; i < DEBOUNCE_MAX; i++) {
+        iz2 = getFilteredValue(READ_Z2(0));
+        iz2 >>= 3;
+
+        if (ABS (lastz2 - iz2) <= DEBOUNCE_TOL) {
+            break;
+        }
+
+        lastz2 = iz2;
+    }
+
+    coord.x = ix;
+    coord.y = iy;
+
+    if (ix && iz1) {
+        coord.z = (ix * ABS(iz2 - iz1)) / iz1;
+    }
+    else {
+        coord.z = 0;
+    }
+
+    if (coord.z > 20000) {
+        coord.z = 0;
+    }
+
+}
+
+int32_t TSC2046::getFilteredValue(int cmd)
+{
+    int32_t a[7];
+    int32_t tmp = 0;
+    int i = 0, j = 0;
+
+    /*
+     * Median and averaging filter
+     *
+     * 1. Get 7 values
+     * 2. Sort these values
+     * 3. Take average of the 3 values in the middle
+     */
+
+    for (i = 0; i < 7; i++) {
+        a[i] = spiTransfer(cmd);
+    }
+
+    // bubble sort
+    for (i = 0; i < 7; i++) {
+        for (j = 0; j < (7-(i+1)); j++) {
+            if (a[j] > a[j+1]) {
+                // swap
+                tmp = a[j];
+                a[j] = a[j+1];
+                a[j+1] = tmp;
+            }
+        }
+    }
+
+    // average of 3 values in the middle
+    return ((a[2]+a[3]+a[4])/3);
+}
+
+uint16_t TSC2046::spiTransfer(uint8_t cmd)
+{
+    uint8_t data[3];
+
+    _cs = 0;
+
+    /*data[0] = */_spi.write(cmd);
+    data[0] = _spi.write(0xff);
+    data[1] = _spi.write(0xff);
+
+    _cs = 1;
+
+    return ((data[0] << 8) | data[1]);
+}
+
+
+// ############################################################################
+// >>>>>>>> Calibrate code >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+// ############################################################################
+
+
+/*
+ *
+ *   Copyright (c) 2001, Carlos E. Vidales. All rights reserved.
+ *
+ *   This sample program was written and put in the public domain
+ *    by Carlos E. Vidales.  The program is provided "as is"
+ *    without warranty of any kind, either expressed or implied.
+ *   If you choose to use the program within your own products
+ *    you do so at your own risk, and assume the responsibility
+ *    for servicing, repairing or correcting the program should
+ *    it prove defective in any manner.
+ *   You may copy and distribute the program's source code in any
+ *    medium, provided that you also include in each copy an
+ *    appropriate copyright notice and disclaimer of warranty.
+ *   You may also modify this program and distribute copies of
+ *    it provided that you include prominent notices stating
+ *    that you changed the file(s) and the date of any change,
+ *    and that you do not charge any royalties or licenses for
+ *    its use.
+ *
+ *
+ *
+ *   File Name:  calibrate.c
+ *
+ *
+ *   This file contains functions that implement calculations
+ *    necessary to obtain calibration factors for a touch screen
+ *    that suffers from multiple distortion effects: namely,
+ *    translation, scaling and rotation.
+ *
+ *   The following set of equations represent a valid display
+ *    point given a corresponding set of touch screen points:
+ *
+ *
+ *                                              /-     -\
+ *              /-    -\     /-            -\   |       |
+ *              |      |     |              |   |   Xs  |
+ *              |  Xd  |     | A    B    C  |   |       |
+ *              |      |  =  |              | * |   Ys  |
+ *              |  Yd  |     | D    E    F  |   |       |
+ *              |      |     |              |   |   1   |
+ *              \-    -/     \-            -/   |       |
+ *                                              \-     -/
+ *
+ *
+ *    where:
+ *
+ *           (Xd,Yd) represents the desired display point
+ *                    coordinates,
+ *
+ *           (Xs,Ys) represents the available touch screen
+ *                    coordinates, and the matrix
+ *
+ *           /-   -\
+ *           |A,B,C|
+ *           |D,E,F| represents the factors used to translate
+ *           \-   -/  the available touch screen point values
+ *                    into the corresponding display
+ *                    coordinates.
+ *
+ *
+ *    Note that for practical considerations, the utilitities
+ *     within this file do not use the matrix coefficients as
+ *     defined above, but instead use the following
+ *     equivalents, since floating point math is not used:
+ *
+ *            A = An/Divider
+ *            B = Bn/Divider
+ *            C = Cn/Divider
+ *            D = Dn/Divider
+ *            E = En/Divider
+ *            F = Fn/Divider
+ *
+ *
+ *
+ *    The functions provided within this file are:
+ *
+ *          setCalibrationMatrix() - calculates the set of factors
+ *                                    in the above equation, given
+ *                                    three sets of test points.
+ *               getDisplayPoint() - returns the actual display
+ *                                    coordinates, given a set of
+ *                                    touch screen coordinates.
+ * translateRawScreenCoordinates() - helper function to transform
+ *                                    raw screen points into values
+ *                                    scaled to the desired display
+ *                                    resolution.
+ *
+ *
+ */
+
+
+/**********************************************************************
+ *
+ *     Function: setCalibrationMatrix()
+ *
+ *  Description: Calling this function with valid input data
+ *                in the display and screen input arguments
+ *                causes the calibration factors between the
+ *                screen and display points to be calculated,
+ *                and the output argument - matrixPtr - to be
+ *                populated.
+ *
+ *               This function needs to be called only when new
+ *                calibration factors are desired.
+ *
+ *
+ *  Argument(s): displayPtr (input) - Pointer to an array of three
+ *                                     sample, reference points.
+ *               screenPtr (input) - Pointer to the array of touch
+ *                                    screen points corresponding
+ *                                    to the reference display points.
+ *               matrixPtr (output) - Pointer to the calibration
+ *                                     matrix computed for the set
+ *                                     of points being provided.
+ *
+ *
+ *  From the article text, recall that the matrix coefficients are
+ *   resolved to be the following:
+ *
+ *
+ *      Divider =  (Xs0 - Xs2)*(Ys1 - Ys2) - (Xs1 - Xs2)*(Ys0 - Ys2)
+ *
+ *
+ *
+ *                 (Xd0 - Xd2)*(Ys1 - Ys2) - (Xd1 - Xd2)*(Ys0 - Ys2)
+ *            A = ---------------------------------------------------
+ *                                   Divider
+ *
+ *
+ *                 (Xs0 - Xs2)*(Xd1 - Xd2) - (Xd0 - Xd2)*(Xs1 - Xs2)
+ *            B = ---------------------------------------------------
+ *                                   Divider
+ *
+ *
+ *                 Ys0*(Xs2*Xd1 - Xs1*Xd2) +
+ *                             Ys1*(Xs0*Xd2 - Xs2*Xd0) +
+ *                                           Ys2*(Xs1*Xd0 - Xs0*Xd1)
+ *            C = ---------------------------------------------------
+ *                                   Divider
+ *
+ *
+ *                 (Yd0 - Yd2)*(Ys1 - Ys2) - (Yd1 - Yd2)*(Ys0 - Ys2)
+ *            D = ---------------------------------------------------
+ *                                   Divider
+ *
+ *
+ *                 (Xs0 - Xs2)*(Yd1 - Yd2) - (Yd0 - Yd2)*(Xs1 - Xs2)
+ *            E = ---------------------------------------------------
+ *                                   Divider
+ *
+ *
+ *                 Ys0*(Xs2*Yd1 - Xs1*Yd2) +
+ *                             Ys1*(Xs0*Yd2 - Xs2*Yd0) +
+ *                                           Ys2*(Xs1*Yd0 - Xs0*Yd1)
+ *            F = ---------------------------------------------------
+ *                                   Divider
+ *
+ *
+ *       Return: OK - the calibration matrix was correctly
+ *                     calculated and its value is in the
+ *                     output argument.
+ *               NOT_OK - an error was detected and the
+ *                         function failed to return a valid
+ *                         set of matrix values.
+ *                        The only time this sample code returns
+ *                        NOT_OK is when Divider == 0
+ *
+ *
+ *
+ *                 NOTE!    NOTE!    NOTE!
+ *
+ *  setCalibrationMatrix() and getDisplayPoint() will do fine
+ *  for you as they are, provided that your digitizer
+ *  resolution does not exceed 10 bits (1024 values).  Higher
+ *  resolutions may cause the integer operations to overflow
+ *  and return incorrect values.  If you wish to use these
+ *  functions with digitizer resolutions of 12 bits (4096
+ *  values) you will either have to a) use 64-bit signed
+ *  integer variables and math, or b) judiciously modify the
+ *  operations to scale results by a factor of 2 or even 4.
+ *
+ *
+ */
+int TSC2046::setCalibrationMatrix( calibPoint_t * displayPtr,
+        calibPoint_t * screenPtr,
+        calibMatrix_t * matrixPtr)
+{
+    int  retValue = 0 ;
+
+
+    matrixPtr->Divider = ((screenPtr[0].x - screenPtr[2].x) * (screenPtr[1].y - screenPtr[2].y)) -
+                         ((screenPtr[1].x - screenPtr[2].x) * (screenPtr[0].y - screenPtr[2].y)) ;
+    if( matrixPtr->Divider == 0 )
+    {
+        retValue = 1 ;
+    }
+    else
+    {
+        matrixPtr->An = ((displayPtr[0].x - displayPtr[2].x) * (screenPtr[1].y - screenPtr[2].y)) -
+                        ((displayPtr[1].x - displayPtr[2].x) * (screenPtr[0].y - screenPtr[2].y)) ;
+        matrixPtr->Bn = ((screenPtr[0].x - screenPtr[2].x) * (displayPtr[1].x - displayPtr[2].x)) -
+                        ((displayPtr[0].x - displayPtr[2].x) * (screenPtr[1].x - screenPtr[2].x)) ;
+        matrixPtr->Cn = (screenPtr[2].x * displayPtr[1].x - screenPtr[1].x * displayPtr[2].x) * screenPtr[0].y +
+                        (screenPtr[0].x * displayPtr[2].x - screenPtr[2].x * displayPtr[0].x) * screenPtr[1].y +
+                        (screenPtr[1].x * displayPtr[0].x - screenPtr[0].x * displayPtr[1].x) * screenPtr[2].y ;
+        matrixPtr->Dn = ((displayPtr[0].y - displayPtr[2].y) * (screenPtr[1].y - screenPtr[2].y)) -
+                        ((displayPtr[1].y - displayPtr[2].y) * (screenPtr[0].y - screenPtr[2].y)) ;
+
+        matrixPtr->En = ((screenPtr[0].x - screenPtr[2].x) * (displayPtr[1].y - displayPtr[2].y)) -
+                        ((displayPtr[0].y - displayPtr[2].y) * (screenPtr[1].x - screenPtr[2].x)) ;
+        matrixPtr->Fn = (screenPtr[2].x * displayPtr[1].y - screenPtr[1].x * displayPtr[2].y) * screenPtr[0].y +
+                        (screenPtr[0].x * displayPtr[2].y - screenPtr[2].x * displayPtr[0].y) * screenPtr[1].y +
+                        (screenPtr[1].x * displayPtr[0].y - screenPtr[0].x * displayPtr[1].y) * screenPtr[2].y ;
+    }
+
+    return( retValue ) ;
+}
+
+/**********************************************************************
+ *
+ *     Function: getDisplayPoint()
+ *
+ *  Description: Given a valid set of calibration factors and a point
+ *                value reported by the touch screen, this function
+ *                calculates and returns the true (or closest to true)
+ *                display point below the spot where the touch screen
+ *                was touched.
+ *
+ *
+ *
+ *  Argument(s): displayPtr (output) - Pointer to the calculated
+ *                                      (true) display point.
+ *               screenPtr (input) - Pointer to the reported touch
+ *                                    screen point.
+ *               matrixPtr (input) - Pointer to calibration factors
+ *                                    matrix previously calculated
+ *                                    from a call to
+ *                                    setCalibrationMatrix()
+ *
+ *
+ *  The function simply solves for Xd and Yd by implementing the
+ *   computations required by the translation matrix.
+ *
+ *                                              /-     -\
+ *              /-    -\     /-            -\   |       |
+ *              |      |     |              |   |   Xs  |
+ *              |  Xd  |     | A    B    C  |   |       |
+ *              |      |  =  |              | * |   Ys  |
+ *              |  Yd  |     | D    E    F  |   |       |
+ *              |      |     |              |   |   1   |
+ *              \-    -/     \-            -/   |       |
+ *                                              \-     -/
+ *
+ *  It must be kept brief to avoid consuming CPU cycles.
+ *
+ *
+ *       Return: OK - the display point was correctly calculated
+ *                     and its value is in the output argument.
+ *               NOT_OK - an error was detected and the function
+ *                         failed to return a valid point.
+ *
+ *
+ *
+ *                 NOTE!    NOTE!    NOTE!
+ *
+ *  setCalibrationMatrix() and getDisplayPoint() will do fine
+ *  for you as they are, provided that your digitizer
+ *  resolution does not exceed 10 bits (1024 values).  Higher
+ *  resolutions may cause the integer operations to overflow
+ *  and return incorrect values.  If you wish to use these
+ *  functions with digitizer resolutions of 12 bits (4096
+ *  values) you will either have to a) use 64-bit signed
+ *  integer variables and math, or b) judiciously modify the
+ *  operations to scale results by a factor of 2 or even 4.
+ *
+ *
+ */
+int TSC2046::getDisplayPoint( calibPoint_t * displayPtr,
+        calibPoint_t * screenPtr,
+        calibMatrix_t * matrixPtr )
+{
+    int  retValue = 0 ;
+
+    if( matrixPtr->Divider != 0 )
+    {
+        /* Operation order is important since we are doing integer */
+        /*  math. Make sure you add all terms together before      */
+        /*  dividing, so that the remainder is not rounded off     */
+        /*  prematurely.                                           */
+        displayPtr->x = ( (matrixPtr->An * screenPtr->x) +
+                (matrixPtr->Bn * screenPtr->y) +
+                matrixPtr->Cn
+        ) / matrixPtr->Divider ;
+        displayPtr->y = ( (matrixPtr->Dn * screenPtr->x) +
+                (matrixPtr->En * screenPtr->y) +
+                matrixPtr->Fn
+        ) / matrixPtr->Divider ;
+    }
+    else
+    {
+        retValue = 1 ;
+    }
+    return( retValue ) ;
+}
+
+
+// ############################################################################
+// <<<<<<<< Calibrate code <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+// ############################################################################
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TSC2046.h	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,99 @@
+
+#ifndef TSC2046_H
+#define TSC2046_H
+
+
+/**
+ * Texas Instruments Touch Screen Controller (TSC2046).
+ */
+class TSC2046 {
+public:
+
+    typedef struct {
+        int32_t x;
+        int32_t y;
+        int32_t z;
+    } touchCoordinate_t;
+
+    /**
+     * Constructor
+     *
+     * @param mosi SPI MOSI pin
+     * @param miso SPI MISO pin
+     * @param sck SPI SCK pin
+     * @param cs chip-select pin
+     */
+    TSC2046(PinName mosi, PinName miso, PinName sck, PinName cs);
+
+    /**
+     * Read coordinates from the touch panel.
+     *
+     * Before calibrate() is called this function will return uncalibrated
+     * values. If there is no touch active the coordinate values will be 0.
+     *
+     * @param coord pointer to coordinate object. The read coordinates will be
+     * written to this object.
+     */
+    void read(touchCoordinate_t &coord);
+
+    /**
+     * Calibrate touch screen based on three reference points and
+     * three actual readings. This means that the user must be presented
+     * with three points (one at a time) and asked to press on these points
+     * to get an actual reading.
+     */
+    void calibrate(touchCoordinate_t &ref1,
+            touchCoordinate_t &ref2,
+            touchCoordinate_t &ref3,
+            touchCoordinate_t &scr1,
+            touchCoordinate_t &scr2,
+            touchCoordinate_t &scr3);
+
+    /**
+     * Reset a previous calibration (in order to do a new calibration)
+     */
+    void uncalibrate();
+
+
+private:
+
+    typedef struct {
+        int64_t x;
+        int64_t y;
+    } calibPoint_t;
+
+    typedef struct {
+        int64_t An;
+        int64_t Bn;
+        int64_t Cn;
+        int64_t Dn;
+        int64_t En;
+        int64_t Fn;
+        int64_t Divider;
+    } calibMatrix_t;
+
+    SPI _spi;
+    DigitalOut _cs;
+    bool _calibrated;
+    bool _initialized;
+    calibMatrix_t _calibMatrix;
+
+    void init();
+    void readAndFilter(touchCoordinate_t &coord);
+    int32_t getFilteredValue(int cmd);
+    uint16_t spiTransfer(uint8_t cmd);
+
+
+
+    int setCalibrationMatrix( calibPoint_t * displayPtr,
+            calibPoint_t * screenPtr,
+            calibMatrix_t * matrixPtr);
+    int getDisplayPoint( calibPoint_t * displayPtr,
+            calibPoint_t * screenPtr,
+            calibMatrix_t * matrixPtr );
+
+};
+
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/glcdfont.c	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,272 @@
+#ifndef FONT5X7_H
+#define FONT5X7_H
+
+#ifdef __AVR__
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+#else
+#define PROGMEM
+#endif
+
+// Standard ASCII 5x7 font
+
+static const unsigned char font[] PROGMEM = {
+        0x00, 0x00, 0x00, 0x00, 0x00,
+        0x3E, 0x5B, 0x4F, 0x5B, 0x3E,
+        0x3E, 0x6B, 0x4F, 0x6B, 0x3E,
+        0x1C, 0x3E, 0x7C, 0x3E, 0x1C,
+        0x18, 0x3C, 0x7E, 0x3C, 0x18,
+        0x1C, 0x57, 0x7D, 0x57, 0x1C,
+        0x1C, 0x5E, 0x7F, 0x5E, 0x1C,
+        0x00, 0x18, 0x3C, 0x18, 0x00,
+        0xFF, 0xE7, 0xC3, 0xE7, 0xFF,
+        0x00, 0x18, 0x24, 0x18, 0x00,
+        0xFF, 0xE7, 0xDB, 0xE7, 0xFF,
+        0x30, 0x48, 0x3A, 0x06, 0x0E,
+        0x26, 0x29, 0x79, 0x29, 0x26,
+        0x40, 0x7F, 0x05, 0x05, 0x07,
+        0x40, 0x7F, 0x05, 0x25, 0x3F,
+        0x5A, 0x3C, 0xE7, 0x3C, 0x5A,
+        0x7F, 0x3E, 0x1C, 0x1C, 0x08,
+        0x08, 0x1C, 0x1C, 0x3E, 0x7F,
+        0x14, 0x22, 0x7F, 0x22, 0x14,
+        0x5F, 0x5F, 0x00, 0x5F, 0x5F,
+        0x06, 0x09, 0x7F, 0x01, 0x7F,
+        0x00, 0x66, 0x89, 0x95, 0x6A,
+        0x60, 0x60, 0x60, 0x60, 0x60,
+        0x94, 0xA2, 0xFF, 0xA2, 0x94,
+        0x08, 0x04, 0x7E, 0x04, 0x08,
+        0x10, 0x20, 0x7E, 0x20, 0x10,
+        0x08, 0x08, 0x2A, 0x1C, 0x08,
+        0x08, 0x1C, 0x2A, 0x08, 0x08,
+        0x1E, 0x10, 0x10, 0x10, 0x10,
+        0x0C, 0x1E, 0x0C, 0x1E, 0x0C,
+        0x30, 0x38, 0x3E, 0x38, 0x30,
+        0x06, 0x0E, 0x3E, 0x0E, 0x06,
+        0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x5F, 0x00, 0x00,
+        0x00, 0x07, 0x00, 0x07, 0x00,
+        0x14, 0x7F, 0x14, 0x7F, 0x14,
+        0x24, 0x2A, 0x7F, 0x2A, 0x12,
+        0x23, 0x13, 0x08, 0x64, 0x62,
+        0x36, 0x49, 0x56, 0x20, 0x50,
+        0x00, 0x08, 0x07, 0x03, 0x00,
+        0x00, 0x1C, 0x22, 0x41, 0x00,
+        0x00, 0x41, 0x22, 0x1C, 0x00,
+        0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
+        0x08, 0x08, 0x3E, 0x08, 0x08,
+        0x00, 0x80, 0x70, 0x30, 0x00,
+        0x08, 0x08, 0x08, 0x08, 0x08,
+        0x00, 0x00, 0x60, 0x60, 0x00,
+        0x20, 0x10, 0x08, 0x04, 0x02,
+        0x3E, 0x51, 0x49, 0x45, 0x3E,
+        0x00, 0x42, 0x7F, 0x40, 0x00,
+        0x72, 0x49, 0x49, 0x49, 0x46,
+        0x21, 0x41, 0x49, 0x4D, 0x33,
+        0x18, 0x14, 0x12, 0x7F, 0x10,
+        0x27, 0x45, 0x45, 0x45, 0x39,
+        0x3C, 0x4A, 0x49, 0x49, 0x31,
+        0x41, 0x21, 0x11, 0x09, 0x07,
+        0x36, 0x49, 0x49, 0x49, 0x36,
+        0x46, 0x49, 0x49, 0x29, 0x1E,
+        0x00, 0x00, 0x14, 0x00, 0x00,
+        0x00, 0x40, 0x34, 0x00, 0x00,
+        0x00, 0x08, 0x14, 0x22, 0x41,
+        0x14, 0x14, 0x14, 0x14, 0x14,
+        0x00, 0x41, 0x22, 0x14, 0x08,
+        0x02, 0x01, 0x59, 0x09, 0x06,
+        0x3E, 0x41, 0x5D, 0x59, 0x4E,
+        0x7C, 0x12, 0x11, 0x12, 0x7C,
+        0x7F, 0x49, 0x49, 0x49, 0x36,
+        0x3E, 0x41, 0x41, 0x41, 0x22,
+        0x7F, 0x41, 0x41, 0x41, 0x3E,
+        0x7F, 0x49, 0x49, 0x49, 0x41,
+        0x7F, 0x09, 0x09, 0x09, 0x01,
+        0x3E, 0x41, 0x41, 0x51, 0x73,
+        0x7F, 0x08, 0x08, 0x08, 0x7F,
+        0x00, 0x41, 0x7F, 0x41, 0x00,
+        0x20, 0x40, 0x41, 0x3F, 0x01,
+        0x7F, 0x08, 0x14, 0x22, 0x41,
+        0x7F, 0x40, 0x40, 0x40, 0x40,
+        0x7F, 0x02, 0x1C, 0x02, 0x7F,
+        0x7F, 0x04, 0x08, 0x10, 0x7F,
+        0x3E, 0x41, 0x41, 0x41, 0x3E,
+        0x7F, 0x09, 0x09, 0x09, 0x06,
+        0x3E, 0x41, 0x51, 0x21, 0x5E,
+        0x7F, 0x09, 0x19, 0x29, 0x46,
+        0x26, 0x49, 0x49, 0x49, 0x32,
+        0x03, 0x01, 0x7F, 0x01, 0x03,
+        0x3F, 0x40, 0x40, 0x40, 0x3F,
+        0x1F, 0x20, 0x40, 0x20, 0x1F,
+        0x3F, 0x40, 0x38, 0x40, 0x3F,
+        0x63, 0x14, 0x08, 0x14, 0x63,
+        0x03, 0x04, 0x78, 0x04, 0x03,
+        0x61, 0x59, 0x49, 0x4D, 0x43,
+        0x00, 0x7F, 0x41, 0x41, 0x41,
+        0x02, 0x04, 0x08, 0x10, 0x20,
+        0x00, 0x41, 0x41, 0x41, 0x7F,
+        0x04, 0x02, 0x01, 0x02, 0x04,
+        0x40, 0x40, 0x40, 0x40, 0x40,
+        0x00, 0x03, 0x07, 0x08, 0x00,
+        0x20, 0x54, 0x54, 0x78, 0x40,
+        0x7F, 0x28, 0x44, 0x44, 0x38,
+        0x38, 0x44, 0x44, 0x44, 0x28,
+        0x38, 0x44, 0x44, 0x28, 0x7F,
+        0x38, 0x54, 0x54, 0x54, 0x18,
+        0x00, 0x08, 0x7E, 0x09, 0x02,
+        0x18, 0xA4, 0xA4, 0x9C, 0x78,
+        0x7F, 0x08, 0x04, 0x04, 0x78,
+        0x00, 0x44, 0x7D, 0x40, 0x00,
+        0x20, 0x40, 0x40, 0x3D, 0x00,
+        0x7F, 0x10, 0x28, 0x44, 0x00,
+        0x00, 0x41, 0x7F, 0x40, 0x00,
+        0x7C, 0x04, 0x78, 0x04, 0x78,
+        0x7C, 0x08, 0x04, 0x04, 0x78,
+        0x38, 0x44, 0x44, 0x44, 0x38,
+        0xFC, 0x18, 0x24, 0x24, 0x18,
+        0x18, 0x24, 0x24, 0x18, 0xFC,
+        0x7C, 0x08, 0x04, 0x04, 0x08,
+        0x48, 0x54, 0x54, 0x54, 0x24,
+        0x04, 0x04, 0x3F, 0x44, 0x24,
+        0x3C, 0x40, 0x40, 0x20, 0x7C,
+        0x1C, 0x20, 0x40, 0x20, 0x1C,
+        0x3C, 0x40, 0x30, 0x40, 0x3C,
+        0x44, 0x28, 0x10, 0x28, 0x44,
+        0x4C, 0x90, 0x90, 0x90, 0x7C,
+        0x44, 0x64, 0x54, 0x4C, 0x44,
+        0x00, 0x08, 0x36, 0x41, 0x00,
+        0x00, 0x00, 0x77, 0x00, 0x00,
+        0x00, 0x41, 0x36, 0x08, 0x00,
+        0x02, 0x01, 0x02, 0x04, 0x02,
+        0x3C, 0x26, 0x23, 0x26, 0x3C,
+        0x1E, 0xA1, 0xA1, 0x61, 0x12,
+        0x3A, 0x40, 0x40, 0x20, 0x7A,
+        0x38, 0x54, 0x54, 0x55, 0x59,
+        0x21, 0x55, 0x55, 0x79, 0x41,
+        0x21, 0x54, 0x54, 0x78, 0x41,
+        0x21, 0x55, 0x54, 0x78, 0x40,
+        0x20, 0x54, 0x55, 0x79, 0x40,
+        0x0C, 0x1E, 0x52, 0x72, 0x12,
+        0x39, 0x55, 0x55, 0x55, 0x59,
+        0x39, 0x54, 0x54, 0x54, 0x59,
+        0x39, 0x55, 0x54, 0x54, 0x58,
+        0x00, 0x00, 0x45, 0x7C, 0x41,
+        0x00, 0x02, 0x45, 0x7D, 0x42,
+        0x00, 0x01, 0x45, 0x7C, 0x40,
+        0xF0, 0x29, 0x24, 0x29, 0xF0,
+        0xF0, 0x28, 0x25, 0x28, 0xF0,
+        0x7C, 0x54, 0x55, 0x45, 0x00,
+        0x20, 0x54, 0x54, 0x7C, 0x54,
+        0x7C, 0x0A, 0x09, 0x7F, 0x49,
+        0x32, 0x49, 0x49, 0x49, 0x32,
+        0x32, 0x48, 0x48, 0x48, 0x32,
+        0x32, 0x4A, 0x48, 0x48, 0x30,
+        0x3A, 0x41, 0x41, 0x21, 0x7A,
+        0x3A, 0x42, 0x40, 0x20, 0x78,
+        0x00, 0x9D, 0xA0, 0xA0, 0x7D,
+        0x39, 0x44, 0x44, 0x44, 0x39,
+        0x3D, 0x40, 0x40, 0x40, 0x3D,
+        0x3C, 0x24, 0xFF, 0x24, 0x24,
+        0x48, 0x7E, 0x49, 0x43, 0x66,
+        0x2B, 0x2F, 0xFC, 0x2F, 0x2B,
+        0xFF, 0x09, 0x29, 0xF6, 0x20,
+        0xC0, 0x88, 0x7E, 0x09, 0x03,
+        0x20, 0x54, 0x54, 0x79, 0x41,
+        0x00, 0x00, 0x44, 0x7D, 0x41,
+        0x30, 0x48, 0x48, 0x4A, 0x32,
+        0x38, 0x40, 0x40, 0x22, 0x7A,
+        0x00, 0x7A, 0x0A, 0x0A, 0x72,
+        0x7D, 0x0D, 0x19, 0x31, 0x7D,
+        0x26, 0x29, 0x29, 0x2F, 0x28,
+        0x26, 0x29, 0x29, 0x29, 0x26,
+        0x30, 0x48, 0x4D, 0x40, 0x20,
+        0x38, 0x08, 0x08, 0x08, 0x08,
+        0x08, 0x08, 0x08, 0x08, 0x38,
+        0x2F, 0x10, 0xC8, 0xAC, 0xBA,
+        0x2F, 0x10, 0x28, 0x34, 0xFA,
+        0x00, 0x00, 0x7B, 0x00, 0x00,
+        0x08, 0x14, 0x2A, 0x14, 0x22,
+        0x22, 0x14, 0x2A, 0x14, 0x08,
+        0xAA, 0x00, 0x55, 0x00, 0xAA,
+        0xAA, 0x55, 0xAA, 0x55, 0xAA,
+        0x00, 0x00, 0x00, 0xFF, 0x00,
+        0x10, 0x10, 0x10, 0xFF, 0x00,
+        0x14, 0x14, 0x14, 0xFF, 0x00,
+        0x10, 0x10, 0xFF, 0x00, 0xFF,
+        0x10, 0x10, 0xF0, 0x10, 0xF0,
+        0x14, 0x14, 0x14, 0xFC, 0x00,
+        0x14, 0x14, 0xF7, 0x00, 0xFF,
+        0x00, 0x00, 0xFF, 0x00, 0xFF,
+        0x14, 0x14, 0xF4, 0x04, 0xFC,
+        0x14, 0x14, 0x17, 0x10, 0x1F,
+        0x10, 0x10, 0x1F, 0x10, 0x1F,
+        0x14, 0x14, 0x14, 0x1F, 0x00,
+        0x10, 0x10, 0x10, 0xF0, 0x00,
+        0x00, 0x00, 0x00, 0x1F, 0x10,
+        0x10, 0x10, 0x10, 0x1F, 0x10,
+        0x10, 0x10, 0x10, 0xF0, 0x10,
+        0x00, 0x00, 0x00, 0xFF, 0x10,
+        0x10, 0x10, 0x10, 0x10, 0x10,
+        0x10, 0x10, 0x10, 0xFF, 0x10,
+        0x00, 0x00, 0x00, 0xFF, 0x14,
+        0x00, 0x00, 0xFF, 0x00, 0xFF,
+        0x00, 0x00, 0x1F, 0x10, 0x17,
+        0x00, 0x00, 0xFC, 0x04, 0xF4,
+        0x14, 0x14, 0x17, 0x10, 0x17,
+        0x14, 0x14, 0xF4, 0x04, 0xF4,
+        0x00, 0x00, 0xFF, 0x00, 0xF7,
+        0x14, 0x14, 0x14, 0x14, 0x14,
+        0x14, 0x14, 0xF7, 0x00, 0xF7,
+        0x14, 0x14, 0x14, 0x17, 0x14,
+        0x10, 0x10, 0x1F, 0x10, 0x1F,
+        0x14, 0x14, 0x14, 0xF4, 0x14,
+        0x10, 0x10, 0xF0, 0x10, 0xF0,
+        0x00, 0x00, 0x1F, 0x10, 0x1F,
+        0x00, 0x00, 0x00, 0x1F, 0x14,
+        0x00, 0x00, 0x00, 0xFC, 0x14,
+        0x00, 0x00, 0xF0, 0x10, 0xF0,
+        0x10, 0x10, 0xFF, 0x10, 0xFF,
+        0x14, 0x14, 0x14, 0xFF, 0x14,
+        0x10, 0x10, 0x10, 0x1F, 0x00,
+        0x00, 0x00, 0x00, 0xF0, 0x10,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+        0xFF, 0xFF, 0xFF, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0xFF, 0xFF,
+        0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+        0x38, 0x44, 0x44, 0x38, 0x44,
+        0x7C, 0x2A, 0x2A, 0x3E, 0x14,
+        0x7E, 0x02, 0x02, 0x06, 0x06,
+        0x02, 0x7E, 0x02, 0x7E, 0x02,
+        0x63, 0x55, 0x49, 0x41, 0x63,
+        0x38, 0x44, 0x44, 0x3C, 0x04,
+        0x40, 0x7E, 0x20, 0x1E, 0x20,
+        0x06, 0x02, 0x7E, 0x02, 0x02,
+        0x99, 0xA5, 0xE7, 0xA5, 0x99,
+        0x1C, 0x2A, 0x49, 0x2A, 0x1C,
+        0x4C, 0x72, 0x01, 0x72, 0x4C,
+        0x30, 0x4A, 0x4D, 0x4D, 0x30,
+        0x30, 0x48, 0x78, 0x48, 0x30,
+        0xBC, 0x62, 0x5A, 0x46, 0x3D,
+        0x3E, 0x49, 0x49, 0x49, 0x00,
+        0x7E, 0x01, 0x01, 0x01, 0x7E,
+        0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
+        0x44, 0x44, 0x5F, 0x44, 0x44,
+        0x40, 0x51, 0x4A, 0x44, 0x40,
+        0x40, 0x44, 0x4A, 0x51, 0x40,
+        0x00, 0x00, 0xFF, 0x01, 0x03,
+        0xE0, 0x80, 0xFF, 0x00, 0x00,
+        0x08, 0x08, 0x6B, 0x6B, 0x08,
+        0x36, 0x12, 0x36, 0x24, 0x36,
+        0x06, 0x0F, 0x09, 0x0F, 0x06,
+        0x00, 0x00, 0x18, 0x18, 0x00,
+        0x00, 0x00, 0x10, 0x10, 0x00,
+        0x30, 0x40, 0xFF, 0x01, 0x01,
+        0x00, 0x1F, 0x01, 0x01, 0x1E,
+        0x00, 0x19, 0x1D, 0x17, 0x12,
+        0x00, 0x3C, 0x3C, 0x3C, 0x3C,
+        0x00, 0x00, 0x00, 0x00, 0x00
+};
+#endif // FONT5X7_H
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gpdma.cpp	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,312 @@
+
+/******************************************************************************
+ * Includes
+ *****************************************************************************/
+
+#include "gpdma.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+#define NUM_GPDMA_CHANNELS  8
+
+#define GPDMACH(__x) ((LPC_GPDMACH_TypeDef*)(LPC_GPDMACH0_BASE + (0x20 * (__x))))
+
+#define CH_MASK(__ch)  (((1UL << (__ch)) & 0xFF))
+
+/**
+ * @brief GPDMA request connections
+ */
+#define GPDMA_CONN_MEMORY           ((0UL))
+#define GPDMA_CONN_SDC              ((1UL))      /*!< SD card */
+
+/**
+ * @brief Macro defines for DMA channel control registers
+ */
+#define GPDMA_DMACCxControl_TransferSize(n) (((n & 0xFFF) << 0))  /*!< Transfer size*/
+#define GPDMA_DMACCxControl_SBSize(n)       (((n & 0x07) << 12))  /*!< Source burst size*/
+#define GPDMA_DMACCxControl_DBSize(n)       (((n & 0x07) << 15))  /*!< Destination burst size*/
+#define GPDMA_DMACCxControl_SWidth(n)       (((n & 0x07) << 18))  /*!< Source transfer width*/
+#define GPDMA_DMACCxControl_DWidth(n)       (((n & 0x07) << 21))  /*!< Destination transfer width*/
+#define GPDMA_DMACCxControl_SI              ((1UL << 26))      /*!< Source increment*/
+#define GPDMA_DMACCxControl_DI              ((1UL << 27))      /*!< Destination increment*/
+#define GPDMA_DMACCxControl_SrcTransUseAHBMaster1   0
+#define GPDMA_DMACCxControl_DestTransUseAHBMaster1  0
+#define GPDMA_DMACCxControl_Prot1           ((1UL << 28))      /*!< Indicates that the access is in user mode or privileged mode*/
+#define GPDMA_DMACCxControl_Prot2           ((1UL << 29))      /*!< Indicates that the access is bufferable or not bufferable*/
+#define GPDMA_DMACCxControl_Prot3           ((1UL << 30))      /*!< Indicates that the access is cacheable or not cacheable*/
+#define GPDMA_DMACCxControl_I               ((1UL << 31))      /*!< Terminal count interrupt enable bit */
+
+/**
+ * @brief GPDMA Burst size in Source and Destination definitions
+ */
+#define GPDMA_BSIZE_1   ((0UL))  /*!< Burst size = 1 */
+#define GPDMA_BSIZE_4   ((1UL))  /*!< Burst size = 4 */
+#define GPDMA_BSIZE_8   ((2UL))  /*!< Burst size = 8 */
+#define GPDMA_BSIZE_16  ((3UL))  /*!< Burst size = 16 */
+#define GPDMA_BSIZE_32  ((4UL))  /*!< Burst size = 32 */
+#define GPDMA_BSIZE_64  ((5UL))  /*!< Burst size = 64 */
+#define GPDMA_BSIZE_128 ((6UL))  /*!< Burst size = 128 */
+#define GPDMA_BSIZE_256 ((7UL))  /*!< Burst size = 256 */
+
+/**
+ * @brief Width in Source transfer width and Destination transfer width definitions
+ */
+#define GPDMA_WIDTH_BYTE        ((0UL))  /*!< Width = 1 byte */
+#define GPDMA_WIDTH_HALFWORD    ((1UL))  /*!< Width = 2 bytes */
+#define GPDMA_WIDTH_WORD        ((2UL))  /*!< Width = 4 bytes */
+
+/**
+ * @brief Macro defines for DMA Configuration register
+ */
+#define GPDMA_DMACConfig_E              ((0x01))  /*!< DMA Controller enable*/
+#define GPDMA_DMACConfig_M              ((0x02))  /*!< AHB Master endianness configuration*/
+#define GPDMA_DMACConfig_BITMASK        ((0x03))
+
+/**
+ * @brief Macro defines for DMA Channel Configuration registers
+ */
+#define GPDMA_DMACCxConfig_E                    ((1UL << 0))      /*!< DMA control enable*/
+#define GPDMA_DMACCxConfig_SrcPeripheral(n)     (((n & 0x1F) << 1))    /*!< Source peripheral*/
+#define GPDMA_DMACCxConfig_DestPeripheral(n)    (((n & 0x1F) << 6))    /*!< Destination peripheral*/
+#define GPDMA_DMACCxConfig_TransferType(n)      (((n & 0x7) << 11))    /*!< This value indicates the type of transfer*/
+#define GPDMA_DMACCxConfig_IE                   ((1UL << 14))      /*!< Interrupt error mask*/
+#define GPDMA_DMACCxConfig_ITC                  ((1UL << 15))      /*!< Terminal count interrupt mask*/
+#define GPDMA_DMACCxConfig_L                    ((1UL << 16))      /*!< Lock*/
+#define GPDMA_DMACCxConfig_A                    ((1UL << 17))      /*!< Active*/
+#define GPDMA_DMACCxConfig_H                    ((1UL << 18))      /*!< Halt*/
+
+/**
+ * @brief GPDMA structure using for DMA configuration
+ */
+typedef struct {
+  uint32_t ChannelNum;  /*!< DMA channel number, should be in
+               *  range from 0 to 7.
+               *  Note: DMA channel 0 has the highest priority
+               *  and DMA channel 7 the lowest priority.
+               */
+  uint32_t TransferSize;  /*!< Length/Size of transfer */
+  uint32_t TransferWidth;  /*!< Transfer width - used for TransferType is GPDMA_TRANSFERTYPE_M2M only */
+  uint32_t SrcAddr;    /*!< Physical Source Address, used in case TransferType is chosen as
+               *   GPDMA_TRANSFERTYPE_M2M or GPDMA_TRANSFERTYPE_M2P */
+  uint32_t DstAddr;    /*!< Physical Destination Address, used in case TransferType is chosen as
+               *   GPDMA_TRANSFERTYPE_M2M or GPDMA_TRANSFERTYPE_P2M */
+  uint32_t TransferType;  /*!< Transfer Type, should be one of the following:
+               * - GPDMA_TRANSFERTYPE_M2M: Memory to memory - DMA control
+               * - GPDMA_TRANSFERTYPE_M2P: Memory to peripheral - DMA control
+               * - GPDMA_TRANSFERTYPE_P2M: Peripheral to memory - DMA control
+               * - GPDMA_TRANSFERTYPE_P2P: Source peripheral to destination peripheral - DMA control
+               */
+} GPDMA_Channel_CFG_T;
+
+/******************************************************************************
+ * External global variables
+ *****************************************************************************/
+
+/******************************************************************************
+ * Local variables
+ *****************************************************************************/
+
+static bool used_channels[NUM_GPDMA_CHANNELS];
+
+/******************************************************************************
+ * Local Functions
+ *****************************************************************************/
+
+static void gpdma_transfer(GPDMA_Channel_CFG_T* cfg,
+                           uint32_t CtrlWord,
+                           uint32_t LinkListItem,
+                           uint8_t SrcPeripheral,
+                           uint8_t DstPeripheral)
+{
+  /* Get Channel pointer */
+  LPC_GPDMACH_TypeDef* pCh = GPDMACH(cfg->ChannelNum);
+
+  /* Reset the Interrupt status */
+  LPC_GPDMA->IntTCClear = CH_MASK(cfg->ChannelNum);
+  LPC_GPDMA->IntErrClr = CH_MASK(cfg->ChannelNum);
+
+  /* Assign Linker List Item value */
+  pCh->CLLI = LinkListItem;
+
+  /* Enable DMA channels, little endian */
+  LPC_GPDMA->Config = GPDMA_DMACConfig_E;
+  while (!(LPC_GPDMA->Config & GPDMA_DMACConfig_E)) {}
+
+  pCh->CSrcAddr = cfg->SrcAddr;
+  pCh->CDestAddr = cfg->DstAddr;
+
+  /* Configure DMA Channel, enable Error Counter and Terminate counter */
+  pCh->CConfig = GPDMA_DMACCxConfig_IE
+           | GPDMA_DMACCxConfig_ITC
+           | GPDMA_DMACCxConfig_TransferType((uint32_t) cfg->TransferType)
+           | GPDMA_DMACCxConfig_SrcPeripheral(SrcPeripheral)
+           | GPDMA_DMACCxConfig_DestPeripheral(DstPeripheral);
+
+  pCh->CControl = CtrlWord;
+
+  /* Start the Channel */
+  pCh->CConfig |= GPDMA_DMACCxConfig_E;
+}
+
+/******************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+void gpdma_init()
+{
+  uint8_t i;
+
+  /* Enable GPDMA master clock */
+  LPC_SC->PCONP |= (1<<29);
+
+  /* Reset all channel configuration register */
+  for (i = 0; i < NUM_GPDMA_CHANNELS; i++) {
+    GPDMACH(i)->CConfig = 0;
+  }
+
+  /* Clear all DMA interrupt and error flag */
+  LPC_GPDMA->IntTCClear = 0xFF;
+  LPC_GPDMA->IntErrClr  = 0xFF;
+
+  /* Reset all channels are free */
+  for (int i = 0; i < NUM_GPDMA_CHANNELS; i++)
+  {
+    used_channels[i] = false;
+  }
+}
+
+void gpdma_deinit()
+{
+  /* Disable GPDMA master clock */
+  LPC_SC->PCONP &= ~(1<<29);
+}
+
+void gpdma_stop(uint8_t ChannelNum)
+{
+  if (ChannelNum >= NUM_GPDMA_CHANNELS) {
+    return;
+  }
+
+  /* Disable channel */
+  GPDMACH(ChannelNum)->CConfig &= ~GPDMA_DMACCxConfig_E;
+
+  /* check terminal count interrupt request status for DMA */
+  if (LPC_GPDMA->IntTCStat & CH_MASK(ChannelNum)) {
+    /* Clear terminate counter Interrupt pending */
+    LPC_GPDMA->IntTCClear = CH_MASK(ChannelNum);
+  }
+
+  /* check status of the error interrupt for DMA channels */
+  if (LPC_GPDMA->IntErrStat & CH_MASK(ChannelNum)) {
+    /* clear the error interrupt request */
+    LPC_GPDMA->IntErrClr = CH_MASK(ChannelNum);
+  }
+
+  used_channels[ChannelNum] = false;
+}
+
+bool gpdma_interrupt(uint8_t ChannelNum)
+{
+  /* check status of DMA channel interrupts */
+  if (LPC_GPDMA->IntStat & CH_MASK(ChannelNum)) {
+    /* Check counter terminal status */
+    if (LPC_GPDMA->IntTCStat & CH_MASK(ChannelNum)) {
+      /* Clear terminate counter Interrupt pending */
+      LPC_GPDMA->IntTCClear = CH_MASK(ChannelNum);
+      return true;
+    }
+    /* Check error terminal status */
+    if (LPC_GPDMA->IntErrStat & CH_MASK(ChannelNum)) {
+      /* Clear error counter Interrupt pending */
+      LPC_GPDMA->IntErrClr = CH_MASK(ChannelNum);
+      return false;
+    }
+  }
+  return false;
+}
+
+bool gpdma_getFreeChannel(uint8_t* pCh)
+{
+  for (int i = 0; i < NUM_GPDMA_CHANNELS; i++)
+  {
+    if ((!used_channels[i]) && ((LPC_GPDMA->EnbldChns & CH_MASK(i)) == 0))
+    {
+      used_channels[i] = true;
+      *pCh = i;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool gpdma_transfer_to_mci(uint8_t ChannelNum,
+                           uint32_t src,
+                           uint32_t Size)
+{
+  GPDMA_Channel_CFG_T cfg;
+  cfg.ChannelNum = ChannelNum;
+  cfg.TransferType = GPDMA_TRANSFERTYPE_M2P_CONTROLLER_PERIPHERAL;
+  cfg.TransferSize = Size;
+  cfg.TransferWidth = 0;
+  cfg.SrcAddr = src;
+  cfg.DstAddr = (uint32_t) (&LPC_MCI->FIFO);
+
+  uint32_t ctrl_word =
+      GPDMA_DMACCxControl_TransferSize((uint32_t) cfg.TransferSize)
+          | GPDMA_DMACCxControl_SBSize(GPDMA_BSIZE_8)
+          | GPDMA_DMACCxControl_DBSize(GPDMA_BSIZE_8)
+          | GPDMA_DMACCxControl_SWidth(GPDMA_WIDTH_WORD)
+          | GPDMA_DMACCxControl_DWidth(GPDMA_WIDTH_WORD)
+          | GPDMA_DMACCxControl_DestTransUseAHBMaster1
+          | GPDMA_DMACCxControl_SI
+          | GPDMA_DMACCxControl_I;
+
+  if (LPC_GPDMA->EnbldChns & CH_MASK(ChannelNum)) {
+    /* This channel is enabled, return ERROR, need to release this channel first */
+    return false;
+  }
+
+  /* Select SD card interface in the DMA MUX*/
+  LPC_SC->DMAREQSEL &= ~(1 << 1);
+
+  gpdma_transfer(&cfg, ctrl_word, 0, GPDMA_CONN_MEMORY, GPDMA_CONN_SDC);
+  return true;
+}
+
+bool gpdma_transfer_from_mci(uint8_t ChannelNum,
+                             uint32_t dst,
+                             uint32_t Size)
+{
+  GPDMA_Channel_CFG_T cfg;
+  cfg.ChannelNum = ChannelNum;
+  cfg.TransferType = GPDMA_TRANSFERTYPE_P2M_CONTROLLER_PERIPHERAL;
+  cfg.TransferSize = Size;
+  cfg.TransferWidth = 0;
+  cfg.SrcAddr = (uint32_t) (&LPC_MCI->FIFO);
+  cfg.DstAddr = dst;
+
+  uint32_t ctrl_word =
+      GPDMA_DMACCxControl_TransferSize((uint32_t) cfg.TransferSize)
+          | GPDMA_DMACCxControl_SBSize(GPDMA_BSIZE_8)
+          | GPDMA_DMACCxControl_DBSize(GPDMA_BSIZE_8)
+          | GPDMA_DMACCxControl_SWidth(GPDMA_WIDTH_WORD)
+          | GPDMA_DMACCxControl_DWidth(GPDMA_WIDTH_WORD)
+          | GPDMA_DMACCxControl_SrcTransUseAHBMaster1
+          | GPDMA_DMACCxControl_DI
+          | GPDMA_DMACCxControl_I;
+
+  if (LPC_GPDMA->EnbldChns & CH_MASK(ChannelNum)) {
+    /* This channel is enabled, return ERROR, need to release this channel first */
+    return false;
+  }
+
+  /* Select SD card interface in the DMA MUX*/
+  LPC_SC->DMAREQSEL &= ~(1 << 1);
+
+  gpdma_transfer(&cfg, ctrl_word, 0, GPDMA_CONN_SDC, GPDMA_CONN_MEMORY);
+  return true;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gpdma.h	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,91 @@
+
+#ifndef GPDMA_H
+#define GPDMA_H
+
+#include "platform.h"
+
+#define GPDMA_CONN_SDC              ((1UL))      /*!< SD card */
+
+typedef enum
+{
+  GPDMA_TRANSFERTYPE_M2M_CONTROLLER_DMA,             /* Memory to memory - DMA control */
+  GPDMA_TRANSFERTYPE_M2P_CONTROLLER_DMA,             /* Memory to peripheral - DMA control */
+  GPDMA_TRANSFERTYPE_P2M_CONTROLLER_DMA,             /* Peripheral to memory - DMA control */
+  GPDMA_TRANSFERTYPE_P2P_CONTROLLER_DMA,             /* Source peripheral to destination peripheral - DMA control */
+  GPDMA_TRANSFERTYPE_P2P_CONTROLLER_DestPERIPHERAL,  /* Source peripheral to destination peripheral - destination peripheral control */
+  GPDMA_TRANSFERTYPE_M2P_CONTROLLER_PERIPHERAL,      /* Memory to peripheral - peripheral control */
+  GPDMA_TRANSFERTYPE_P2M_CONTROLLER_PERIPHERAL,      /* Peripheral to memory - peripheral control */
+  GPDMA_TRANSFERTYPE_P2P_CONTROLLER_SrcPERIPHERAL,  /* Source peripheral to destination peripheral - source peripheral control */
+} gpdma_flowControl_t;
+
+/**
+ * @brief  Initialize the GPDMA
+ * @param  pGPDMA  : The base of GPDMA on the chip
+ * @return  Nothing
+ */
+void gpdma_init();
+
+/**
+ * @brief  Shutdown the GPDMA
+ * @param  pGPDMA  : The base of GPDMA on the chip
+ * @return  Nothing
+ */
+void gpdma_deinit();
+
+/**
+ * @brief  Stop a stream DMA transfer
+ * @param  ChannelNum  : Channel Number to be closed
+ * @return  Nothing
+ */
+void gpdma_stop(uint8_t ChannelNum);
+
+/**
+ * @brief  The GPDMA stream interrupt status checking
+ * @param  ChannelNum  : Channel Number to be checked on interruption
+ * @return  Status:
+ *              - true  : DMA transfer success
+ *              - false  : DMA transfer failed
+ */
+bool gpdma_interrupt(uint8_t ChannelNum);
+
+/**
+ * @brief  Get a free GPDMA channel for one DMA connection
+ * @param  pCh  : Assigned channel number (only valid if success)
+ * @return  Status:
+ *              - true  : Found a free DMA channel
+ *              - false  : No free DMA channels, pCh value is undefined
+ */
+bool gpdma_getFreeChannel(uint8_t* pCh);
+
+/**
+ * @brief  Do a DMA transfer M2M, M2P,P2M or P2P
+ * @param  ChannelNum  : Channel used for transfer
+ * @param  src      : Address of Memory or PeripheralConnection_ID which is the source
+ * @param  dst      : Address of Memory or PeripheralConnection_ID which is the destination
+ * @param  TransferType: Select the transfer controller and the type of transfer. Should be:
+ *                               - GPDMA_TRANSFERTYPE_M2M_CONTROLLER_DMA
+ *                               - GPDMA_TRANSFERTYPE_M2P_CONTROLLER_DMA
+ *                               - GPDMA_TRANSFERTYPE_P2M_CONTROLLER_DMA
+ *                               - GPDMA_TRANSFERTYPE_P2P_CONTROLLER_DMA
+ *                               - GPDMA_TRANSFERTYPE_P2P_CONTROLLER_DestPERIPHERAL
+ *                               - GPDMA_TRANSFERTYPE_M2P_CONTROLLER_PERIPHERAL
+ *                               - GPDMA_TRANSFERTYPE_P2M_CONTROLLER_PERIPHERAL
+ *                               - GPDMA_TRANSFERTYPE_P2P_CONTROLLER_SrcPERIPHERAL
+ * @param  Size    : The number of DMA transfers
+ * @return  False on error, true on success
+ */
+//bool gpdma_transfer(uint8_t ChannelNum,
+//                    uint32_t src,
+//                    uint32_t dst,
+//                    gpdma_flowControl_t TransferType,
+//                    uint32_t Size);
+
+bool gpdma_transfer_to_mci(uint8_t ChannelNum,
+                           uint32_t src,
+                           uint32_t Size);
+bool gpdma_transfer_from_mci(uint8_t ChannelNum,
+                             uint32_t dst,
+                             uint32_t Size);
+#endif
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sdram.cpp	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,587 @@
+/*****************************************************************************
+ *
+ *   Copyright(C) 2011, Embedded Artists AB
+ *   All rights reserved.
+ *
+ ******************************************************************************
+ * Software that is described herein is for illustrative purposes only
+ * which provides customers with programming information regarding the
+ * products. This software is supplied "AS IS" without any warranties.
+ * Embedded Artists AB assumes no responsibility or liability for the
+ * use of the software, conveys no license or title under any patent,
+ * copyright, or mask work right to the product. Embedded Artists AB
+ * reserves the right to make changes in the software without
+ * notification. Embedded Artists AB also make no representation or
+ * warranty that such application will be suitable for the specified
+ * use without further testing or modification.
+ *****************************************************************************/
+
+
+
+/******************************************************************************
+ * Includes
+ *****************************************************************************/
+
+#include "mbed.h"
+#include "sdram.h"
+
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+
+/******************************************************************************
+ * External global variables
+ *****************************************************************************/
+
+/******************************************************************************
+ * Local variables
+ *****************************************************************************/
+
+static volatile uint32_t ringosccount[2] = {0,0};
+
+static bool okToUseSdramForHeap = true;
+static bool initialized = false;
+
+/******************************************************************************
+ * Overridden Global Functions
+ *****************************************************************************/
+
+#if defined(TOOLCHAIN_ARM) /* KEIL uVision and mbed online compiler */
+  //http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0349c/Cihehbce.html
+  
+  extern "C" unsigned __rt_heap_extend(unsigned size, void **block) {
+    static uint32_t lastReturnedBlock = 0;
+    
+    if (okToUseSdramForHeap && !initialized) {
+      sdram_init();
+    }
+    
+    // Make sure that SDRAM is only returned once (as all of it is returned
+    // the first time) and only if the user has chosen to do it (via the
+    // okToUseSdramForHeap variable.
+    if (okToUseSdramForHeap && lastReturnedBlock==0) {
+      *block = (void*)SDRAM_BASE;
+      lastReturnedBlock = SDRAM_BASE;
+      return SDRAM_SIZE;
+    }
+    return 0;
+  }
+#elif defined(TOOLCHAIN_GCC_CR) /* CodeRed's RedSuite or LPCXpresso IDE */
+  
+  // NOTE: This way of overriding the implementation of malloc in NEWLIB
+  //       will prevent the internal RAM from being used by malloc as 
+  //       it only exposes the SDRAM. 
+  
+  // Dynamic memory allocation related syscall.
+  extern "C" caddr_t _sbrk(int incr) {
+    static unsigned char* heap = (unsigned char*)SDRAM_BASE;
+    unsigned char*        prev_heap = heap;
+    unsigned char*        new_heap = heap + incr;
+
+    if (okToUseSdramForHeap && !initialized) {
+      sdram_init();
+    }    
+    if (!okToUseSdramForHeap) {
+      //errno = ENOMEM;
+      return (caddr_t)-1;
+    }
+    if (new_heap >= (unsigned char*)(SDRAM_BASE + SDRAM_SIZE)) {
+      //errno = ENOMEM;
+      return (caddr_t)-1;
+    }
+
+    heap = new_heap;
+    return (caddr_t) prev_heap;
+  }  
+#endif
+ 
+/******************************************************************************
+ * Local Functions
+ *****************************************************************************/
+
+static void pinConfig(void)
+{
+  LPC_IOCON->P3_0 |= 1; /* D0 @ P3.0 */
+  LPC_IOCON->P3_1 |= 1; /* D1 @ P3.1 */
+  LPC_IOCON->P3_2 |= 1; /* D2 @ P3.2 */
+  LPC_IOCON->P3_3 |= 1; /* D3 @ P3.3 */
+
+  LPC_IOCON->P3_4 |= 1; /* D4 @ P3.4 */
+  LPC_IOCON->P3_5 |= 1; /* D5 @ P3.5 */
+  LPC_IOCON->P3_6 |= 1; /* D6 @ P3.6 */
+  LPC_IOCON->P3_7 |= 1; /* D7 @ P3.7 */
+
+  LPC_IOCON->P3_8 |= 1; /* D8 @ P3.8 */
+  LPC_IOCON->P3_9 |= 1; /* D9 @ P3.9 */
+  LPC_IOCON->P3_10 |= 1; /* D10 @ P3.10 */
+  LPC_IOCON->P3_11 |= 1; /* D11 @ P3.11 */
+
+  LPC_IOCON->P3_12 |= 1; /* D12 @ P3.12 */
+  LPC_IOCON->P3_13 |= 1; /* D13 @ P3.13 */
+  LPC_IOCON->P3_14 |= 1; /* D14 @ P3.14 */
+  LPC_IOCON->P3_15 |= 1; /* D15 @ P3.15 */
+
+  LPC_IOCON->P3_16 |= 1; /* D16 @ P3.16 */
+  LPC_IOCON->P3_17 |= 1; /* D17 @ P3.17 */
+  LPC_IOCON->P3_18 |= 1; /* D18 @ P3.18 */
+  LPC_IOCON->P3_19 |= 1; /* D19 @ P3.19 */
+
+  LPC_IOCON->P3_20 |= 1; /* D20 @ P3.20 */
+  LPC_IOCON->P3_21 |= 1; /* D21 @ P3.21 */
+  LPC_IOCON->P3_22 |= 1; /* D22 @ P3.22 */
+  LPC_IOCON->P3_23 |= 1; /* D23 @ P3.23 */
+
+  LPC_IOCON->P3_24 |= 1; /* D24 @ P3.24 */
+  LPC_IOCON->P3_25 |= 1; /* D25 @ P3.25 */
+  LPC_IOCON->P3_26 |= 1; /* D26 @ P3.26 */
+  LPC_IOCON->P3_27 |= 1; /* D27 @ P3.27 */
+
+  LPC_IOCON->P3_28 |= 1; /* D28 @ P3.28 */
+  LPC_IOCON->P3_29 |= 1; /* D29 @ P3.29 */
+  LPC_IOCON->P3_30 |= 1; /* D30 @ P3.30 */
+  LPC_IOCON->P3_31 |= 1; /* D31 @ P3.31 */
+
+  LPC_IOCON->P4_0 |= 1; /* A0 @ P4.0 */
+  LPC_IOCON->P4_1 |= 1; /* A1 @ P4.1 */
+  LPC_IOCON->P4_2 |= 1; /* A2 @ P4.2 */
+  LPC_IOCON->P4_3 |= 1; /* A3 @ P4.3 */
+
+  LPC_IOCON->P4_4 |= 1; /* A4 @ P4.4 */
+  LPC_IOCON->P4_5 |= 1; /* A5 @ P4.5 */
+  LPC_IOCON->P4_6 |= 1; /* A6 @ P4.6 */
+  LPC_IOCON->P4_7 |= 1; /* A7 @ P4.7 */
+
+  LPC_IOCON->P4_8 |= 1; /* A8 @ P4.8 */
+  LPC_IOCON->P4_9 |= 1; /* A9 @ P4.9 */
+  LPC_IOCON->P4_10 |= 1; /* A10 @ P4.10 */
+  LPC_IOCON->P4_11 |= 1; /* A11 @ P4.11 */
+
+  LPC_IOCON->P4_12 |= 1; /* A12 @ P4.12 */
+  LPC_IOCON->P4_13 |= 1; /* A13 @ P4.13 */
+  LPC_IOCON->P4_14 |= 1; /* A14 @ P4.14 */
+#if 0 // not used for SDRAM
+  LPC_IOCON->P4_15 |= 1; /* A15 @ P4.15 */
+
+  LPC_IOCON->P4_16 |= 1; /* A16 @ P4.16 */
+  LPC_IOCON->P4_17 |= 1; /* A17 @ P4.17 */
+  LPC_IOCON->P4_18 |= 1; /* A18 @ P4.18 */
+  LPC_IOCON->P4_19 |= 1; /* A19 @ P4.19 */
+
+  LPC_IOCON->P4_20 |= 1; /* A20 @ P4.20 */
+  LPC_IOCON->P4_21 |= 1; /* A21 @ P4.21 */
+  LPC_IOCON->P4_22 |= 1; /* A22 @ P4.22 */
+  LPC_IOCON->P4_23 |= 1; /* A23 @ P4.23 */
+#endif
+
+  LPC_IOCON->P4_24 |= 1; /* OEN @ P4.24 */
+  LPC_IOCON->P4_25 |= 1; /* WEN @ P4.25 */
+#if 0 // not used for SDRAM
+  LPC_IOCON->P4_26 |= 1; /* BLSN[0] @ P4.26 */
+  LPC_IOCON->P4_27 |= 1; /* BLSN[1] @ P4.27 */
+
+
+  LPC_IOCON->P4_28 |= 1; /* BLSN[2] @ P4.28 */
+  LPC_IOCON->P4_29 |= 1; /* BLSN[3] @ P4.29 */
+  LPC_IOCON->P4_30 |= 1; /* CSN[0] @ P4.30 */
+  LPC_IOCON->P4_31 |= 1; /* CSN[1] @ P4.31 */
+#endif
+
+  LPC_IOCON->P2_14 |= 1; /* CSN[2] @ P2.14 */
+  LPC_IOCON->P2_15 |= 1; /* CSN[3] @ P2.15 */
+
+  LPC_IOCON->P2_16 |= 1; /* CASN @ P2.16 */
+  LPC_IOCON->P2_17 |= 1; /* RASN @ P2.17 */
+  LPC_IOCON->P2_18 |= 1; /* CLK[0] @ P2.18 */
+#if 0 // not used for SDRAM
+  LPC_IOCON->P2_19 |= 1; /* CLK[1] @ P2.19 */
+#endif
+
+  LPC_IOCON->P2_20 |= 1; /* DYCSN[0] @ P2.20 */
+#if 0 // not used for SDRAM
+  LPC_IOCON->P2_21 |= 1; /* DYCSN[1] @ P2.21 */
+  LPC_IOCON->P2_22 |= 1; /* DYCSN[2] @ P2.22 */
+  LPC_IOCON->P2_23 |= 1; /* DYCSN[3] @ P2.23 */
+#endif
+
+  LPC_IOCON->P2_24 |= 1; /* CKE[0] @ P2.24 */
+#if 0 // not used for SDRAM
+  LPC_IOCON->P2_25 |= 1; /* CKE[1] @ P2.25 */
+  LPC_IOCON->P2_26 |= 1; /* CKE[2] @ P2.26 */
+  LPC_IOCON->P2_27 |= 1; /* CKE[3] @ P2.27 */
+#endif
+
+  LPC_IOCON->P2_28 |= 1; /* DQM[0] @ P2.28 */
+  LPC_IOCON->P2_29 |= 1; /* DQM[1] @ P2.29 */
+  LPC_IOCON->P2_30 |= 1; /* DQM[2] @ P2.30 */
+  LPC_IOCON->P2_31 |= 1; /* DQM[3] @ P2.31 */
+}
+
+
+static uint32_t sdram_test( void )
+{
+  volatile uint32_t *wr_ptr; 
+  volatile uint16_t *short_wr_ptr;
+  uint32_t data;
+  uint32_t i, j;
+
+  wr_ptr = (uint32_t *)SDRAM_BASE;
+  short_wr_ptr = (uint16_t *)wr_ptr;
+  /* Clear content before 16 bit access test */
+//  for (i = 0; i < SDRAM_SIZE/4; i++)
+//  {
+//	*wr_ptr++ = 0;
+//  }
+
+  /* 16 bit write */
+  for (i = 0; i < SDRAM_SIZE/0x40000; i++)
+  {
+    for (j = 0; j < 0x100; j++)
+    {
+      *short_wr_ptr++ = (i + j);
+      *short_wr_ptr++ = (i + j) + 1;
+    }
+  }
+
+  /* Verifying */
+  wr_ptr = (uint32_t *)SDRAM_BASE;
+  for (i = 0; i < SDRAM_SIZE/0x40000; i++)
+  {
+    for (j = 0; j < 0x100; j++)
+    {
+      data = *wr_ptr;          
+      if (data != (((((i + j) + 1) & 0xFFFF) << 16) | ((i + j) & 0xFFFF)))
+      {
+        return 0x0;
+      }
+      wr_ptr++;
+    }
+  }
+  return 0x1;
+}
+
+static uint32_t find_cmddly(void)
+{
+  uint32_t cmddly, cmddlystart, cmddlyend, dwtemp;
+  uint32_t ppass = 0x0, pass = 0x0;
+
+  cmddly = 0x0;
+  cmddlystart = cmddlyend = 0xFF;
+
+  while (cmddly < 32)
+  {
+    dwtemp = LPC_SC->EMCDLYCTL & ~0x1F;
+    LPC_SC->EMCDLYCTL = dwtemp | cmddly;
+
+    if (sdram_test() == 0x1)
+    {
+      /* Test passed */
+      if (cmddlystart == 0xFF)
+      {
+        cmddlystart = cmddly;
+      }
+      ppass = 0x1;
+    }
+    else
+    {
+      /* Test failed */
+      if (ppass == 1)
+      {
+        cmddlyend = cmddly;
+        pass = 0x1;
+        ppass = 0x0;
+      }
+    }
+
+    /* Try next value */
+    cmddly++;
+  }
+
+  /* If the test passed, the we can use the average of the min and max values to get an optimal DQSIN delay */
+  if (pass == 0x1)
+  {
+    cmddly = (cmddlystart + cmddlyend) / 2;
+  }
+  else if (ppass == 0x1)
+  {
+    cmddly = (cmddlystart + 0x1F) / 2;
+  }
+  else
+  {
+    /* A working value couldn't be found, just pick something safe so the system doesn't become unstable */
+    cmddly = 0x10;
+  }
+
+  dwtemp = LPC_SC->EMCDLYCTL & ~0x1F;
+  LPC_SC->EMCDLYCTL = dwtemp | cmddly;
+
+  return (pass | ppass);
+}
+
+static uint32_t find_fbclkdly(void)
+{
+  uint32_t fbclkdly, fbclkdlystart, fbclkdlyend, dwtemp;
+  uint32_t ppass = 0x0, pass = 0x0;
+
+  fbclkdly = 0x0;
+  fbclkdlystart = fbclkdlyend = 0xFF;
+
+  while (fbclkdly < 32)
+  {
+    dwtemp = LPC_SC->EMCDLYCTL & ~0x1F00;
+    LPC_SC->EMCDLYCTL = dwtemp | (fbclkdly << 8);
+
+    if (sdram_test() == 0x1)
+    {
+      /* Test passed */
+      if (fbclkdlystart == 0xFF)
+      {
+        fbclkdlystart = fbclkdly;
+      }
+      ppass = 0x1;
+    }
+    else
+    {
+      /* Test failed */
+      if (ppass == 1)
+      {
+        fbclkdlyend = fbclkdly;
+        pass = 0x1;
+        ppass = 0x0;
+      }
+    }
+
+    /* Try next value */
+    fbclkdly++;
+  }
+
+  /* If the test passed, the we can use the average of the min and max values to get an optimal DQSIN delay */
+  if (pass == 0x1)
+  {
+    fbclkdly = (fbclkdlystart + fbclkdlyend) / 2;
+  }
+  else if (ppass == 0x1)
+  {
+    fbclkdly = (fbclkdlystart + 0x1F) / 2;
+  }
+  else
+  {
+    /* A working value couldn't be found, just pick something safe so the system doesn't become unstable */
+    fbclkdly = 0x10;
+  }
+
+  dwtemp = LPC_SC->EMCDLYCTL & ~0x1F00;
+  LPC_SC->EMCDLYCTL = dwtemp | (fbclkdly << 8);
+
+  return (pass | ppass);
+}
+
+static uint32_t calibration( void )
+{
+  uint32_t dwtemp, i;
+  uint32_t cnt = 0;
+
+  for (i = 0; i < 10; i++)
+  {
+    dwtemp = LPC_SC->EMCCAL & ~0x4000;
+    LPC_SC->EMCCAL = dwtemp | 0x4000;
+    
+    dwtemp = LPC_SC->EMCCAL;
+    while ((dwtemp & 0x8000) == 0x0000)
+    {
+      dwtemp = LPC_SC->EMCCAL;
+    }
+    cnt += (dwtemp & 0xFF); 
+  }
+  return (cnt / 10);
+}
+
+/******************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+
+void adjust_timing( void )
+{
+  uint32_t dwtemp, cmddly, fbclkdly;
+
+  /* Current value */
+  ringosccount[1] = calibration();
+
+  dwtemp   = LPC_SC->EMCDLYCTL;
+  cmddly   = ((dwtemp & 0x1F) * ringosccount[0] / ringosccount[1]) & 0x1F;
+  fbclkdly = ((dwtemp & 0x1F00) * ringosccount[0] / ringosccount[1]) & 0x1F00;
+  LPC_SC->EMCDLYCTL = (dwtemp & ~0x1F1F) | fbclkdly | cmddly;
+}
+
+/******************************************************************************
+ *
+ * Description:
+ *    Initialize the SDRAM
+ *
+ *****************************************************************************/
+uint32_t sdram_init (void)
+{
+  uint32_t i;
+  uint32_t dwtemp = 0;
+  //uint16_t wtemp = 0;
+  
+  if (initialized) {
+    return 0;
+  }
+
+  LPC_SC->PCONP     |= 0x00000800;
+  LPC_SC->EMCDLYCTL  = 0x00001010;
+  LPC_EMC->Control   = 0x00000001;
+  LPC_EMC->Config    = 0x00000000;
+
+  pinConfig(); //Full 32-bit Data bus, 24-bit Address 
+
+  /* Configure memory layout, but MUST DISABLE BUFFERs during configuration */
+  /* 256MB, 8Mx32, 4 banks, row=12, column=9 */
+  LPC_EMC->DynamicConfig0    = 0x00004480; 
+
+  /*Configure timing for ISSI IS4x32800D SDRAM*/
+
+#if (SDRAM_SPEED==SDRAM_SPEED_48)
+//Timing for 48MHz Bus
+  LPC_EMC->DynamicRasCas0    = 0x00000201; /* 1 RAS, 2 CAS latency */
+  LPC_EMC->DynamicReadConfig = 0x00000001; /* Command delayed strategy, using EMCCLKDELAY */
+  LPC_EMC->DynamicRP         = 0x00000000; /* ( n + 1 ) -> 1 clock cycles */
+  LPC_EMC->DynamicRAS        = 0x00000002; /* ( n + 1 ) -> 3 clock cycles */
+  LPC_EMC->DynamicSREX       = 0x00000003; /* ( n + 1 ) -> 4 clock cycles */
+  LPC_EMC->DynamicAPR        = 0x00000001; /* ( n + 1 ) -> 2 clock cycles */
+  LPC_EMC->DynamicDAL        = 0x00000002; /* ( n ) -> 2 clock cycles */
+  LPC_EMC->DynamicWR         = 0x00000001; /* ( n + 1 ) -> 2 clock cycles */
+  LPC_EMC->DynamicRC         = 0x00000003; /* ( n + 1 ) -> 4 clock cycles */
+  LPC_EMC->DynamicRFC        = 0x00000003; /* ( n + 1 ) -> 4 clock cycles */
+  LPC_EMC->DynamicXSR        = 0x00000003; /* ( n + 1 ) -> 4 clock cycles */
+  LPC_EMC->DynamicRRD        = 0x00000000; /* ( n + 1 ) -> 1 clock cycles */
+  LPC_EMC->DynamicMRD        = 0x00000000; /* ( n + 1 ) -> 1 clock cycles */
+#elif (SDRAM_SPEED==SDRAM_SPEED_50)
+//Timing for 50MHz Bus (with 100MHz M3 Core)
+  LPC_EMC->DynamicRasCas0    = 0x00000201; /* 1 RAS, 2 CAS latency */
+  LPC_EMC->DynamicReadConfig = 0x00000001; /* Command delayed strategy, using EMCCLKDELAY */
+  LPC_EMC->DynamicRP         = 0x00000000; /* ( n + 1 ) -> 1 clock cycles */
+  LPC_EMC->DynamicRAS        = 0x00000002; /* ( n + 1 ) -> 3 clock cycles */
+  LPC_EMC->DynamicSREX       = 0x00000003; /* ( n + 1 ) -> 4 clock cycles */
+  LPC_EMC->DynamicAPR        = 0x00000001; /* ( n + 1 ) -> 2 clock cycles */
+  LPC_EMC->DynamicDAL        = 0x00000002; /* ( n ) -> 2 clock cycles */
+  LPC_EMC->DynamicWR         = 0x00000001; /* ( n + 1 ) -> 2 clock cycles */
+  LPC_EMC->DynamicRC         = 0x00000003; /* ( n + 1 ) -> 4 clock cycles */
+  LPC_EMC->DynamicRFC        = 0x00000003; /* ( n + 1 ) -> 4 clock cycles */
+  LPC_EMC->DynamicXSR        = 0x00000003; /* ( n + 1 ) -> 4 clock cycles */
+  LPC_EMC->DynamicRRD        = 0x00000000; /* ( n + 1 ) -> 1 clock cycles */
+  LPC_EMC->DynamicMRD        = 0x00000000; /* ( n + 1 ) -> 1 clock cycles */
+#elif (SDRAM_SPEED==SDRAM_SPEED_60) 
+  //Timing for 60 MHz Bus (same as 72MHz)
+  LPC_EMC->DynamicRasCas0    = 0x00000202; /* 2 RAS, 2 CAS latency */
+  LPC_EMC->DynamicReadConfig = 0x00000001; /* Command delayed strategy, using EMCCLKDELAY */
+  LPC_EMC->DynamicRP         = 0x00000001; /* ( n + 1 ) -> 2 clock cycles */
+  LPC_EMC->DynamicRAS        = 0x00000003; /* ( n + 1 ) -> 4 clock cycles */
+  LPC_EMC->DynamicSREX       = 0x00000005; /* ( n + 1 ) -> 6 clock cycles */
+  LPC_EMC->DynamicAPR        = 0x00000002; /* ( n + 1 ) -> 3 clock cycles */
+  LPC_EMC->DynamicDAL        = 0x00000003; /* ( n ) -> 3 clock cycles */
+  LPC_EMC->DynamicWR         = 0x00000001; /* ( n + 1 ) -> 2 clock cycles */
+  LPC_EMC->DynamicRC         = 0x00000004; /* ( n + 1 ) -> 5 clock cycles */
+  LPC_EMC->DynamicRFC        = 0x00000004; /* ( n + 1 ) -> 5 clock cycles */
+  LPC_EMC->DynamicXSR        = 0x00000005; /* ( n + 1 ) -> 6 clock cycles */
+  LPC_EMC->DynamicRRD        = 0x00000001; /* ( n + 1 ) -> 2 clock cycles */
+  LPC_EMC->DynamicMRD        = 0x00000001; /* ( n + 1 ) -> 2 clock cycles */
+#elif (SDRAM_SPEED==SDRAM_SPEED_72)
+  //Timing for 72 MHz Bus
+  LPC_EMC->DynamicRasCas0    = 0x00000202; /* 2 RAS, 2 CAS latency */
+  LPC_EMC->DynamicReadConfig = 0x00000001; /* Command delayed strategy, using EMCCLKDELAY */
+  LPC_EMC->DynamicRP         = 0x00000001; /* ( n + 1 ) -> 2 clock cycles */
+  LPC_EMC->DynamicRAS        = 0x00000003; /* ( n + 1 ) -> 4 clock cycles */
+  LPC_EMC->DynamicSREX       = 0x00000005; /* ( n + 1 ) -> 6 clock cycles */
+  LPC_EMC->DynamicAPR        = 0x00000002; /* ( n + 1 ) -> 3 clock cycles */
+  LPC_EMC->DynamicDAL        = 0x00000003; /* ( n ) -> 3 clock cycles */
+  LPC_EMC->DynamicWR         = 0x00000001; /* ( n + 1 ) -> 2 clock cycles */
+  LPC_EMC->DynamicRC         = 0x00000004; /* ( n + 1 ) -> 5 clock cycles */
+  LPC_EMC->DynamicRFC        = 0x00000004; /* ( n + 1 ) -> 5 clock cycles */
+  LPC_EMC->DynamicXSR        = 0x00000005; /* ( n + 1 ) -> 6 clock cycles */
+  LPC_EMC->DynamicRRD        = 0x00000001; /* ( n + 1 ) -> 2 clock cycles */
+  LPC_EMC->DynamicMRD        = 0x00000001; /* ( n + 1 ) -> 2 clock cycles */
+#elif (SDRAM_SPEED==SDRAM_SPEED_80)
+  //Timing for 80 MHz Bus (same as 72MHz) 
+  LPC_EMC->DynamicRasCas0    = 0x00000202; /* 2 RAS, 2 CAS latency */
+  LPC_EMC->DynamicReadConfig = 0x00000001; /* Command delayed strategy, using EMCCLKDELAY */
+  LPC_EMC->DynamicRP         = 0x00000001; /* ( n + 1 ) -> 2 clock cycles */
+  LPC_EMC->DynamicRAS        = 0x00000003; /* ( n + 1 ) -> 4 clock cycles */
+  LPC_EMC->DynamicSREX       = 0x00000005; /* ( n + 1 ) -> 6 clock cycles */
+  LPC_EMC->DynamicAPR        = 0x00000002; /* ( n + 1 ) -> 3 clock cycles */
+  LPC_EMC->DynamicDAL        = 0x00000003; /* ( n ) -> 3 clock cycles */
+  LPC_EMC->DynamicWR         = 0x00000001; /* ( n + 1 ) -> 2 clock cycles */
+  LPC_EMC->DynamicRC         = 0x00000004; /* ( n + 1 ) -> 5 clock cycles */
+  LPC_EMC->DynamicRFC        = 0x00000004; /* ( n + 1 ) -> 5 clock cycles */
+  LPC_EMC->DynamicXSR        = 0x00000005; /* ( n + 1 ) -> 6 clock cycles */
+  LPC_EMC->DynamicRRD        = 0x00000001; /* ( n + 1 ) -> 2 clock cycles */
+  LPC_EMC->DynamicMRD        = 0x00000001; /* ( n + 1 ) -> 2 clock cycles */
+#else
+	#error UNSUPPORTED SDRAM FREQ
+#endif
+
+  LPC_EMC->DynamicControl    = 0x00000183; /* Issue NOP command */
+  wait(0.2);                         /* wait 200ms */
+  LPC_EMC->DynamicControl    = 0x00000103; /* Issue PALL command */
+  LPC_EMC->DynamicRefresh    = 0x00000002; /* ( n * 16 ) -> 32 clock cycles */
+  for(i = 0; i < 0x80; i++);               /* wait 128 AHB clock cycles */
+
+
+#if (SDRAM_SPEED==SDRAM_SPEED_48)
+  //Timing for 48MHz Bus
+  LPC_EMC->DynamicRefresh    = 0x0000002E; /* ( n * 16 ) -> 736 clock cycles -> 15.330uS at 48MHz <= 15.625uS ( 64ms / 4096 row ) */
+#elif (SDRAM_SPEED==SDRAM_SPEED_50)
+  //Timing for 50MHz Bus
+  LPC_EMC->DynamicRefresh    = 0x0000003A; /* ( n * 16 ) -> 768 clock cycles -> 15.360uS at 50MHz <= 15.625uS ( 64ms / 4096 row ) */
+#elif (SDRAM_SPEED==SDRAM_SPEED_60)
+  //Timing for 60MHz Bus
+  LPC_EMC->DynamicRefresh    = 0x0000003A; /* ( n * 16 ) -> 928 clock cycles -> 15.466uS at 60MHz <= 15.625uS ( 64ms / 4096 row ) */
+#elif (SDRAM_SPEED==SDRAM_SPEED_72)
+  //Timing for 72MHz Bus
+  LPC_EMC->DynamicRefresh    = 0x00000046; /* ( n * 16 ) -> 1120 clock cycles -> 15.556uS at 72MHz <= 15.625uS ( 64ms / 4096 row ) */
+#elif (SDRAM_SPEED==SDRAM_SPEED_80)
+  //Timing for 80MHz Bus
+  LPC_EMC->DynamicRefresh    = 0x0000004E; /* ( n * 16 ) -> 1248 clock cycles -> 15.600uS at 80MHz <= 15.625uS ( 64ms / 4096 row ) */
+#else
+	#error UNSUPPORTED SDRAM FREQ
+#endif
+
+  LPC_EMC->DynamicControl    = 0x00000083; /* Issue MODE command */
+  //Timing for 48/60/72MHZ Bus
+  dwtemp = *((volatile uint32_t *)(SDRAM_BASE | (0x22<<(2+2+9)))); /* 4 burst, 2 CAS latency */
+  dwtemp = dwtemp;
+  LPC_EMC->DynamicControl    = 0x00000000; /* Issue NORMAL command */
+//[re]enable buffers
+  LPC_EMC->DynamicConfig0    = 0x00084480; /* 256MB, 8Mx32, 4 banks, row=12, column=9 */
+
+  /* Nominal value */
+  ringosccount[0] = calibration();
+
+  if (find_cmddly() == 0x0)
+  {
+    //while (1);  /* fatal error */
+    return 1;//FALSE;
+  }
+
+  if (find_fbclkdly() == 0x0)
+  {
+    //while (1);  /* fatal error */
+    return 1;//FALSE;
+  }
+
+  adjust_timing();
+  
+  initialized = true;
+
+  return 0;//TRUE;
+}
+
+void sdram_disableMallocSdram()
+{
+  okToUseSdramForHeap = false;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sdram.h	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,68 @@
+/*****************************************************************************
+ *
+ *   Copyright(C) 2011, Embedded Artists AB
+ *   All rights reserved.
+ *
+ ******************************************************************************
+ * Software that is described herein is for illustrative purposes only
+ * which provides customers with programming information regarding the
+ * products. This software is supplied "AS IS" without any warranties.
+ * Embedded Artists AB assumes no responsibility or liability for the
+ * use of the software, conveys no license or title under any patent,
+ * copyright, or mask work right to the product. Embedded Artists AB
+ * reserves the right to make changes in the software without
+ * notification. Embedded Artists AB also make no representation or
+ * warranty that such application will be suitable for the specified
+ * use without further testing or modification.
+ *****************************************************************************/
+#ifndef __SDRAM_H
+#define __SDRAM_H
+
+#include "stdint.h"
+
+/*
+ * These timing parameters are based on the EMC clock
+ * there is no way of ensuring what the EMC clock frequency is
+ * without severely bloating the code
+ * ENSURE THAT THE EMC clock is one of these values
+ */
+#define SDRAM_SPEED_48 0
+#define SDRAM_SPEED_50 1
+#define SDRAM_SPEED_60 2
+#define SDRAM_SPEED_72 3
+#define SDRAM_SPEED_80 4
+
+#define SDRAM_SPEED SDRAM_SPEED_60
+
+#define SDRAM_CONFIG_32BIT
+#define SDRAM_SIZE               0x2000000
+
+#define SDRAM_BASE               0xA0000000 /*CS0*/
+
+/* Initializes the SDRAM.
+ *
+ * The entire SDRAM will be made available to malloc per default.
+ *
+ * Note that this functions is called internally if malloc requests
+ * memory from SDRAM and that hasn't been disabled with a call to
+ * sdram_disableMallocSdram().
+ *
+ * @returns 0 on success, 1 on failure
+ */
+uint32_t sdram_init();
+
+/* Prevents malloc from using SDRAM.
+ *
+ * This function must be called before the first allocation that 
+ * would have been in SDRAM. If a big allocation has already been
+ * made then this call will do nothing as the SDRAM will have been
+ * initialized and all SDRAM given to malloc.
+ */
+void sdram_disableMallocSdram();
+
+#endif /* end __SDRAM_H */
+/****************************************************************************
+**                            End Of File
+*****************************************************************************/
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spifi_rom_api.h	Thu Sep 26 06:37:02 2013 +0000
@@ -0,0 +1,165 @@
+/* definitions for ROM API for SPIFI in NXP MCUs
+   copyright (c) 2010 NXP Semiconductors
+   written by CAM  start                                     4/16/10
+                   first testing                             5/12/10
+                   OK with first SST & Winbond devices       6/8/10
+				   OK with Gigadevice, Numonyx, Atmel, 
+				                              some Macronyx  7/13/10
+				   consensus with BK, performance optimized  8/24/10              
+   this file is largely platform-independent */
+
+#ifndef SPIFI_ROM_API_H
+#define SPIFI_ROM_API_H
+
+
+#define SPIFI_MEM_BASE 0x28000000
+/* allocated size of the SPIFI memory area on this device */
+#define MEM_AREA_SIZE  0x00001000 
+#define SPIFI_ROM_PTR  0x1FFF1FF8
+
+/* define the symbol TESTING in the environment	if test output desired */
+
+/* maintain LONGEST_PROT >= the length (in bytes) of the largest
+	protection block of any serial flash that this driver handles */
+#define LONGEST_PROT 68
+
+/* protection/sector descriptors */
+typedef struct {
+	unsigned base;
+	uint8_t flags;
+	signed char log2;
+	uint16_t rept;
+} protEnt;
+
+typedef union {
+	uint16_t hw;
+	uint8_t byte[2];
+}stat_t;
+
+/* the object that init returns, and other routines use as an operand */
+typedef struct {
+	unsigned base, regbase, devSize, memSize;
+	uint8_t mfger, devType, devID, busy;
+	stat_t stat;
+	uint16_t reserved;
+	uint16_t set_prot, write_prot;
+	unsigned mem_cmd, prog_cmd;
+	uint16_t sectors, protBytes;
+	unsigned opts, errCheck;
+	uint8_t erase_shifts[4], erase_ops[4];
+	protEnt *protEnts;
+	char prot[LONGEST_PROT];
+} SPIFIobj;
+
+/* operands of program and erase */
+typedef struct {
+    char *dest;			/* starting address for programming or erasing */
+    unsigned length;	/* number of bytes to be programmed or erased */
+    char *scratch;		/* address of work area or NULL */
+    int protect;		/* protection to apply after programming/erasing is done */
+    unsigned options;	/* see the table below */
+} SPIFIopers;
+
+
+/* bits in options operands (MODE3, RCVCLK, and FULLCLK 
+	have the same relationship as in the Control register) */
+#define S_MODE3 1
+#define S_MODE0 0
+#define S_MINIMAL 2
+#define S_MAXIMAL 0
+#define S_FORCE_ERASE 4
+#define S_ERASE_NOT_REQD 8
+#define S_CALLER_ERASE 8
+#define S_ERASE_AS_REQD 0
+#define S_VERIFY_PROG 0x10
+#define S_VERIFY_ERASE 0x20
+#define S_NO_VERIFY 0
+#define S_RCVCLK 0x80
+#define S_INTCLK 0
+#define S_FULLCLK 0x40
+#define S_HALFCLK 0
+#define S_DUAL 0x100
+#define S_CALLER_PROT 0x200
+#define S_DRIVER_PROT 0
+
+/* the length of a standard	program command is 256 on all devices */
+#define PROG_SIZE 256
+
+/* interface to ROM API */
+typedef struct {
+  int (*spifi_init)      (SPIFIobj *obj, unsigned csHigh, unsigned options, 
+                          unsigned mhz);
+  int (*spifi_program)   (SPIFIobj *obj, char *source, SPIFIopers *opers);
+  int (*spifi_erase)     (SPIFIobj *obj, SPIFIopers *opers);
+  /* mode switching */
+  void (*cancel_mem_mode)(SPIFIobj *obj);
+  void (*set_mem_mode)   (SPIFIobj *obj);
+
+  /* mid level functions */
+  int (*checkAd)         (SPIFIobj *obj, SPIFIopers *opers);
+  int (*setProt)         (SPIFIobj *obj, SPIFIopers *opers, char *change, 
+                          char *saveProt);
+  int (*check_block)     (SPIFIobj *obj, char *source, SPIFIopers *opers, 
+                          unsigned check_program);
+  int (*send_erase_cmd)  (SPIFIobj *obj, unsigned char op, unsigned addr);
+  unsigned (*ck_erase)   (SPIFIobj *obj, unsigned *addr, unsigned length);
+  int (*prog_block)      (SPIFIobj *obj, char *source, SPIFIopers *opers, 
+                          unsigned *left_in_page);
+  unsigned (*ck_prog)    (SPIFIobj *obj, char *source, char *dest, unsigned length);
+
+  /* low level functions */
+  void(*setSize)         (SPIFIobj *obj, int value);
+  int (*setDev)          (SPIFIobj *obj, unsigned opts, unsigned mem_cmd, 
+                          unsigned prog_cmd);
+  unsigned (*cmd)        (uint8_t op, uint8_t addrLen, uint8_t intLen, unsigned short len);
+  unsigned (*readAd)     (SPIFIobj *obj, unsigned cmd, unsigned addr);
+  void (*send04)         (SPIFIobj *obj, uint8_t op, uint8_t len, unsigned value);
+  void (*wren_sendAd)    (SPIFIobj *obj, unsigned cmd, unsigned addr, unsigned value);
+  int (*write_stat)      (SPIFIobj *obj, uint8_t len, uint16_t value);
+  int (*wait_busy)       (SPIFIobj *obj, uint8_t prog_or_erase);
+} SPIFI_RTNS;
+
+//#define define_spifi_romPtr(name) const SPIFI_RTNS *name=*((SPIFI_RTNS **)SPIFI_ROM_PTR)
+
+/* example of using this interface:
+#include "spifi_rom_api.h"
+#define CSHIGH 4
+#define SPIFI_MHZ 80
+#define source_data_ad (char *)1234
+
+	int rc;
+	SPIFIopers opers;
+
+	define_spifi_romPtr(spifi);
+	SPIFIobj *obj = malloc(sizeof(SPIFIobj));
+	if (!obj) { can't allocate memory }
+
+	rc = spifi->spifi_init (obj, CSHIGH, S_FULLCLK+S_RCVCLK, SPIFI_MHZ);
+	if (rc) { investigate init error rc }
+	printf ("the serial flash contains %d bytes\n", obj->devSize);
+
+	opers.dest = where_to_program;
+	opers.length = how_many_bytes;
+	opers.scratch = NULL;			// unprogrammed data is not saved/restored
+	opers.protect = -1;				// save & restore protection
+	opers.options = S_VERIFY_PROG;
+
+	rc = spifi->spifi_program (obj, source_data_ad, &opers);
+	if (rc) { investigate program error rc }
+*/
+
+/* these are for normal users, including boot code */
+int spifi_init (SPIFIobj *obj, unsigned csHigh, unsigned options, unsigned mhz);
+int spifi_program (SPIFIobj *obj, char *source, SPIFIopers *opers);
+int spifi_erase (SPIFIobj *obj, SPIFIopers *opers);
+
+/* these are used by the manufacturer-specific init functions */
+void setSize (SPIFIobj *obj, int value);
+int setDev (SPIFIobj *obj, unsigned opts, unsigned mem_cmd, unsigned prog_cmd);
+unsigned read04(SPIFIobj *obj, uint8_t op, uint8_t len);
+int write_stat (SPIFIobj *obj, uint8_t len, uint16_t value);
+void setProtEnts(SPIFIobj *obj, const protEnt *p, unsigned protTabLen);
+
+#endif
+
+