Library to control a Graphics TFT connected to 4-wire SPI - revised for the Raio RA8875 Display Controller.

Dependents:   FRDM_RA8875_mPaint RA8875_Demo RA8875_KeyPadDemo SignalGenerator ... more

Fork of SPI_TFT by Peter Drescher

See Components - RA8875 Based Display

Enhanced touch-screen support - where it previous supported both the Resistive Touch and Capacitive Touch based on the FT5206 Touch Controller, now it also has support for the GSL1680 Touch Controller.

Offline Help Manual (Windows chm)

/media/uploads/WiredHome/ra8875.zip.bin (download, rename to .zip and unzip)

Files at this revision

API Documentation at this revision

Comitter:
WiredHome
Date:
Sat Feb 08 17:35:45 2014 +0000
Parent:
40:04aa280dfa39
Child:
42:7cbdfd2bbfc5
Commit message:
Added PrintScreen method, to capture the current image to a file system.; Improved performance of pixel streaming (rendering a bitmap and capturing a bitmap).; Ran performance checks, then disabled debug and the performance information.

Changed in this revision

GraphicsDisplay.cpp Show annotated file Show diff for this revision Revisions of this file
GraphicsDisplay.h Show annotated file Show diff for this revision Revisions of this file
RA8875.cpp Show annotated file Show diff for this revision Revisions of this file
RA8875.h Show annotated file Show diff for this revision Revisions of this file
--- a/GraphicsDisplay.cpp	Tue Feb 04 02:58:06 2014 +0000
+++ b/GraphicsDisplay.cpp	Sat Feb 08 17:35:45 2014 +0000
@@ -8,10 +8,6 @@
 #include "GraphicsDisplay.h"
 #include "Bitmap.h"
 
-// Defining USE_HW causes compilation of code that uses hardware drawing
-// provided by the super-class.
-#define USE_HW
-
 #define DEBUG "GD"
 // ...
 // INFO("Stuff to show %d", var); // new-line is automatically appended
@@ -219,17 +215,7 @@
 
 void GraphicsDisplay::fill(int x, int y, int w, int h, color_t color)
 {
-    #ifdef USE_HW
     fillrect(x,y, x+w, y+h, color);
-    #else
-    window(x, y, w, h);
-    _StartGraphicsStream();
-    for(int i=0; i<w*h; i++) {
-        putp(color);
-    }
-    _EndGraphicsStream();
-    WindowMax();
-    #endif
 }
 
 RetCode_t GraphicsDisplay::cls()
@@ -323,6 +309,109 @@
     return c;
 }
 
+/// RRRR RGGG GGGB BBBB
+RGBQUAD GraphicsDisplay::RGB16ToRGBQuad(color_t c)
+{
+    RGBQUAD q;
+    
+    memset(&q, 0, sizeof(q));
+    q.rgbBlue  = (c & 0x001F) << 3;      /* Blue value */
+    q.rgbGreen = (c & 0x07E0) >> 3;      /* Green value */
+    q.rgbRed   = (c & 0xF800) >> 8;      /* Red value */
+    q.rgbReserved = 0;
+    return q;
+}
+
+
+RetCode_t GraphicsDisplay::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP)
+{
+    BITMAPFILEHEADER BMP_Header;
+    BITMAPINFOHEADER BMP_Info;
+    
+    INFO("(%d,%d) - (%d,%d) %s", x,y,w,h,Name_BMP);
+    if (x >= 0 && x < width()
+    && y >= 0 && y < height()
+    && w > 0 && x + w <= width()
+    && h > 0 && y + h <= height()) {
+
+        BMP_Header.bfType = BF_TYPE;
+        BMP_Header.bfSize = (w * h * sizeof(RGBQUAD)) + sizeof(BMP_Header) + sizeof(BMP_Header);
+        BMP_Header.bfReserved1 = 0;
+        BMP_Header.bfReserved2 = 0;
+        BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Header);
+        
+        BMP_Info.biSize = sizeof(BMP_Info);
+        BMP_Info.biWidth = w;
+        BMP_Info.biHeight = h;
+        BMP_Info.biPlanes = 1;
+        BMP_Info.biBitCount = 24;
+        BMP_Info.biCompression = BI_RGB;
+        BMP_Info.biSizeImage = 0;
+        BMP_Info.biXPelsPerMeter = 0;
+        BMP_Info.biYPelsPerMeter = 0;
+        BMP_Info.biClrUsed = 0;
+        BMP_Info.biClrImportant = 0;
+
+        INFO("Writing {%s}", Name_BMP);
+        FILE *Image = fopen(Name_BMP, "wb");
+        if (!Image) {
+            ERR("File not found");
+            return(file_not_found);
+        }
+
+        // Be optimistic - don't check for errors.
+        //HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header));
+        fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image);
+        //INFO("fwrite returned %d", r);
+        
+        //HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
+        fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image);
+        //INFO("fwrite returned %d", r);
+        
+        int lineBufSize = ((24 * w + 7)/8);
+        uint8_t * lineBuffer = (uint8_t *)malloc(lineBufSize);
+        if (lineBuffer == NULL) {
+            fclose(Image);
+            ERR("Not enough RAM for lineBuffer");
+            return(not_enough_ram);
+        }
+        color_t * pixelBuffer = (color_t *)malloc(w * sizeof(color_t));
+        if (pixelBuffer == NULL) {
+            fclose(Image);
+            free(lineBuffer);
+            ERR("Not enough RAM for pixelBuffer");
+            return(not_enough_ram);
+        }
+        
+        // Read the display from the last line toward the top
+        // so we can write the file in one pass.
+        for (int j = h - 1; j >= 0; j--) {
+            // Read one line of pixels to a local buffer
+            if (getPixelStream(pixelBuffer, w, x,y+j) != noerror) {
+                ERR("getPixelStream error, and no recovery handler...");
+            }
+            // Convert the local buffer to RGBQUAD format
+            int lb = 0;
+            for (int i=0; i<w; i++) {
+                color_t pixel = pixelBuffer[x+i];
+                // Scale to 24-bits
+                RGBQUAD q = RGB16ToRGBQuad(pixel);
+                lineBuffer[lb++] = q.rgbBlue;
+                lineBuffer[lb++] = q.rgbGreen;
+                lineBuffer[lb++] = q.rgbRed;
+            }
+            // Write to disk
+            //HexDump("Line", lineBuffer, lineBufSize);
+            fwrite(lineBuffer, sizeof(char), lb, Image);
+        }
+        fclose(Image);       
+        INFO("Image closed"); 
+        return noerror;
+    } else {
+        return bad_parameter;
+    }
+}
+
 
 RetCode_t GraphicsDisplay::RenderBitmapFile(loc_t x, loc_t y, const char *Name_BMP)
 {
@@ -395,6 +484,13 @@
         fclose(Image);
         return(not_enough_ram);
     }
+    color_t * pixelBuffer = (color_t *)malloc(PixelWidth * sizeof(color_t));
+    if (pixelBuffer == NULL) {
+        free(colorPalette);
+        free(lineBuffer);
+        fclose(Image);
+        return(not_enough_ram);
+    }
 
     // the Raw Data records are padded to a multiple of 4 bytes
     int recordSize = 2;
@@ -431,17 +527,22 @@
                 if ((i & 1) == 0)
                     dPix >>= 4;
                 dPix &= 0x0F;
-                putp(RGBQuadToRGB16(colorPalette, dPix));
+                pixelBuffer[i] = RGBQuadToRGB16(colorPalette, dPix);
+                //putp(RGBQuadToRGB16(colorPalette, dPix));
             } else if (BPP_t == 8) {
-                putp(RGBQuadToRGB16(colorPalette, lineBuffer[i]));
+                pixelBuffer[i] = RGBQuadToRGB16(colorPalette, lineBuffer[i]);
+                //putp(RGBQuadToRGB16(colorPalette, lineBuffer[i]));
             } else if (BPP_t == 16) {
-                putp(lineBuffer[i]);
+                pixelBuffer[i] = lineBuffer[i];
+                //putp(lineBuffer[i]);
             } else if (BPP_t == 24) {
                 color_t color;
                 color = RGB(lineBuffer[i*3+2], lineBuffer[i*3+1], lineBuffer[i*3+0]);
-                putp(color);
+                pixelBuffer[i] = color;
+                //putp(color);
             }
         }
+        pixelStream(pixelBuffer, PixelWidth, x, y++);
     }
     free(lineBuffer);
     free(colorPalette);
--- a/GraphicsDisplay.h	Tue Feb 04 02:58:06 2014 +0000
+++ b/GraphicsDisplay.h	Sat Feb 08 17:35:45 2014 +0000
@@ -48,6 +48,40 @@
     ///
     virtual RetCode_t pixel(loc_t x, loc_t y, color_t color) = 0;
     
+    /// Write a stream of pixels to the display.
+    ///
+    /// @note this method must be supported in the derived class.
+    ///
+    /// @param p is a pointer to a color_t array to write.
+    /// @param count is the number of pixels to write.
+    /// @param x is the horizontal position on the display.
+    /// @param y is the vertical position on the display.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t pixelStream(color_t * p, uint32_t count, loc_t x, loc_t y) = 0;
+
+    /// Get a pixel from the display.
+    ///
+    /// @note this method must be supported in the derived class.
+    ///
+    /// @param x is the horizontal offset to this pixel.
+    /// @param y is the vertical offset to this pixel.
+    /// @returns the pixel. see @color_t
+    ///
+    virtual color_t getPixel(loc_t x, loc_t y) = 0;
+
+    /// Get a stream of pixels from the display.
+    ///
+    /// @note this method must be supported in the derived class.
+    ///
+    /// @param p is a pointer to a color_t array to accept the stream.
+    /// @param count is the number of pixels to read.
+    /// @param x is the horizontal offset to this pixel.
+    /// @param y is the vertical offset to this pixel.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t getPixelStream(color_t * p, uint32_t count, loc_t x, loc_t y) = 0;
+    
     /// get the screen width in pixels
     ///
     /// @note this method must be supported in the derived class.
@@ -75,6 +109,15 @@
     ///
     virtual RetCode_t SetGraphicsCursor(loc_t x, loc_t y) = 0;
     
+    /// Prepare the controller to read binary data from the screen by positioning
+    /// the memory read cursor.
+    ///
+    /// @param x is the horizontal position in pixels (from the left edge)
+    /// @param y is the vertical position in pixels (from the top edge)
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t SetGraphicsCursorRead(loc_t x, loc_t y) = 0;
+    
     /// Draw a filled rectangle in the specified color
     ///
     /// @note As a side effect, this changes the current
@@ -168,6 +211,13 @@
     ///
     color_t RGBQuadToRGB16(RGBQUAD * colorPalette, uint16_t i);
     
+    /// This method converts a 16-bit color value into a 24-bit RGB Quad.
+    ///
+    /// @param c is the 16-bit color. @see color_t
+    /// @returns an RGBQUAD value. @see RGBQUAD
+    ///
+    RGBQUAD RGB16ToRGBQuad(color_t c);
+
     /// This method reads a disk file that is in bitmap format and 
     /// puts it on the screen.
     ///
@@ -207,6 +257,19 @@
     ///
     RetCode_t RenderBitmapFile(loc_t x, loc_t y, const char *Name_BMP);
     
+    /// This method captures the specified area as a 24-bit bitmap file.
+    ///
+    /// Even though this is a 16-bit display, the stored image is in
+    /// 24-bit format.
+    ///
+    /// @param x is the left edge of the region to capture
+    /// @param y is the top edge of the region to capture
+    /// @param w is the width of the region to capture
+    /// @param h is the height of the region to capture.
+    /// @return success or error code.
+    ///
+    RetCode_t PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP);
+    
     /// prints one character at the specified coordinates.
     ///
     /// This will print the character at the specified pixel coordinates.
--- a/RA8875.cpp	Tue Feb 04 02:58:06 2014 +0000
+++ b/RA8875.cpp	Sat Feb 08 17:35:45 2014 +0000
@@ -7,12 +7,7 @@
 ///
 #include "RA8875.h"
 
-DigitalOut zz1(LED1);
-DigitalOut zz2(LED2);
-DigitalOut zz3(LED3);
-DigitalOut zz4(LED4);
-
-#define DEBUG "RAIO"
+//#define DEBUG "RAIO"
 // ...
 // INFO("Stuff to show %d", var); // new-line is automatically appended
 //
@@ -30,13 +25,15 @@
 #define RA8875_DISPLAY_WIDTH  480
 #define RA8875_DISPLAY_HEIGHT 272
 
-
 #ifdef PERF_METRICS
 #define PERFORMANCE_RESET performance.reset()
 #define REGISTERPERFORMANCE(a) RegisterPerformance(a)
 static const char *metricsName[] = 
 {
-    "Point", "Line", "Rectangle", "Rounded Rectangle", "Triangle", "Circle", "Ellipse"
+    "Cls", "Pixel", "Pixel Stream", 
+    "Read Pixel", "Read Pixel Stream",
+    "Line", 
+    "Rectangle", "Rounded Rectangle", "Triangle", "Circle", "Ellipse"
 };
 #else
 #define PERFORMANCE_RESET
@@ -85,10 +82,11 @@
         metrics[method] = elapsed;
 }
 
-void RA8875::ReportPerformance()
+void RA8875::ReportPerformance(Serial & pc)
 {
+    pc.printf("\r\nPerformance Metrics\r\n");
     for (int i=0; i<METRICCOUNT; i++) {
-        printf("%10d uS %s\r\n", metrics[i], metricsName[i]);
+        pc.printf("%10d uS %s\r\n", metrics[i], metricsName[i]);
     }    
 }
 #endif
@@ -99,11 +97,12 @@
     WriteCommand(command, data & 0xFF);
     WriteCommand(command+1, data >> 8);
     #else
+    // This should be a little faster, but doesn't work...
     INFO("WriteCommandW(%02X, %04X)", command, data);
     select(true);
     spiwrite(0x80);
     spiwrite(command);
-//    spiwrite(0x00);
+    //spiwrite(0x00);     // dummy
     spiwrite(data & 0xFF);
     spiwrite(data >> 8);
     select(false);
@@ -114,7 +113,7 @@
 RetCode_t RA8875::WriteCommand(unsigned char command, unsigned int data)
 {
     select(true);
-    spiwrite(0x80);
+    spiwrite(0x80);         // cmd: write command
     spiwrite(command);
     if (data <= 0xFF) {   // only if in the valid range
         spiwrite(0x00);
@@ -127,7 +126,7 @@
 RetCode_t RA8875::WriteDataW(uint16_t data)
 {
     select(true);
-    spiwrite(0x00);
+    spiwrite(0x00);         // cmd: write data
     spiwrite(data & 0xFF);
     spiwrite(data >> 8);
     select(false);
@@ -160,6 +159,18 @@
     return data;
 }
 
+uint16_t RA8875::ReadDataW(void)
+{
+    uint16_t data;
+    
+    select(true);
+    spiwrite(0x40);
+    data  = spiread();
+    data |= (spiread() << 8);
+    select(false);
+    return data;
+}
+
 unsigned char RA8875::ReadStatus(void)
 {
     unsigned char data;
@@ -452,6 +463,15 @@
     return noerror;
 }
 
+RetCode_t RA8875::SetGraphicsCursorRead(loc_t x, loc_t y)
+{
+    //WriteCommand(0x40, 0);  // Graphics mode
+    //WriteCommand(0x45, 0);  // left->right, top->bottom
+    WriteCommandW(0x4A, x);
+    WriteCommandW(0x4C, y);
+    return noerror;
+}
+
 RetCode_t RA8875::window(loc_t x, loc_t y, dim_t width, dim_t height)
 {
     GraphicsDisplay::window(x,y, width,height);
@@ -484,9 +504,12 @@
 
 RetCode_t RA8875::pixel(loc_t x, loc_t y, color_t color)
 {
-    //INFO("pixel(%d,%d, %04X)", x,y, color);
+    #if 1
+    return pixelStream(&color, 1, x,y);
+    #else
     foreground(color);
     return pixel(x,y);
+    #endif
 }
 
 RetCode_t RA8875::pixel(loc_t x, loc_t y)
@@ -500,10 +523,69 @@
     WriteCommand(0x02);
     WriteDataW(color);
     ret = noerror;
-    REGISTERPERFORMANCE(PRF_DRAWPOINT);
+    REGISTERPERFORMANCE(PRF_DRAWPIXEL);
     return ret;
 }
 
+RetCode_t RA8875::pixelStream(color_t * p, uint32_t count, loc_t x, loc_t y)
+{
+    PERFORMANCE_RESET;
+    WriteCommand(0x40,0x00);    // Graphics write mode
+    SetGraphicsCursor(x, y);
+    WriteCommand(0x02);
+    select(true);
+    spiwrite(0x00);         // Cmd: write data
+    while (count--) {
+        spiwrite(*p >> 8);
+        spiwrite(*p & 0xFF);
+        p++;
+    }
+    select(false);
+    REGISTERPERFORMANCE(PRF_PIXELSTREAM);
+    return(noerror);
+}
+
+color_t RA8875::getPixel(loc_t x, loc_t y)
+{
+    color_t pixel;
+    
+    PERFORMANCE_RESET;
+    //WriteCommand(0x45,0x00);    // read left->right, top->bottom
+    WriteCommand(0x40,0x00);    // Graphics write mode
+    SetGraphicsCursorRead(x, y);
+    WriteCommand(0x02);
+    select(true);
+    spiwrite(0x40);         // Cmd: read data
+    spiwrite(0x00);         // dummy read
+    pixel  = spiread();
+    pixel |= (spiread() << 8);
+    select(false);
+    REGISTERPERFORMANCE(PRF_READPIXEL);
+    return pixel;
+}
+
+RetCode_t RA8875::getPixelStream(color_t * p, uint32_t count, loc_t x, loc_t y)
+{
+    color_t pixel;
+    
+    PERFORMANCE_RESET;
+    //WriteCommand(0x45,0x00);    // read left->right, top->bottom
+    WriteCommand(0x40,0x00);    // Graphics write mode
+    SetGraphicsCursorRead(x, y);
+    WriteCommand(0x02);
+    select(true);
+    spiwrite(0x40);         // Cmd: read data
+    spiwrite(0x00);         // dummy read
+    while (count--) {
+        pixel  = spiread();
+        pixel |= (spiread() << 8);
+        *p++ = pixel;
+    }
+    select(false);
+    REGISTERPERFORMANCE(PRF_READPIXELSTREAM);
+    return noerror;
+}
+
 RetCode_t RA8875::line(loc_t x1, loc_t y1, loc_t x2, loc_t y2, color_t color)
 {
     foreground(color);
@@ -968,6 +1050,7 @@
 //     /__/      /_____________/ /_____________/       /__/
 //
 //    Everything from here down is test code.
+bool SuppressSlowStuff = false;
 
 void TextCursorTest(RA8875 & display, Serial & pc)
 {
@@ -976,8 +1059,12 @@
     const char * bCursor = "The Block cursor should be visible for this text.\r\n";
     const char * bbCursor = "The Blinking Block cursor should be visible for this text.\r\n";
     const char * p;
+    int delay = 100;
     
-    pc.printf("Text Cursor Test\r\n");
+    if (!SuppressSlowStuff)
+        pc.printf("Text Cursor Test\r\n");
+    else 
+        delay = 0;
     display.background(Black);
     display.foreground(Blue);
     display.cls();
@@ -990,46 +1077,52 @@
     p = iCursor;
     while (*p) {
         display._putc(*p++);
-        wait_ms(100);
+        wait_ms(delay);
     }
 
     display.SetTextCursorControl(UNDER, false);
     p = uCursor;
     while (*p) {
         display._putc(*p++);
-        wait_ms(100);
+        wait_ms(delay);
     }
     
     display.SetTextCursorControl(BLOCK, false);
     p = bCursor;
     while (*p) {
         display._putc(*p++);
-        wait_ms(100);
+        wait_ms(delay);
     }
 
     display.SetTextCursorControl(BLOCK, true);
     p = bbCursor;
     while (*p) {
         display._putc(*p++);
-        wait_ms(100);
+        wait_ms(delay);
     }
-    wait_ms(2000);
+    wait_ms(delay * 20);
     display.SetTextCursorControl(NOCURSOR, false);
 }
 
 void BacklightTest(RA8875 & display, Serial & pc, float ramptime)
 {
     char buf[60];
-    
-    pc.printf("Backlight Test - ramp over %f sec.\r\n", ramptime);
+    unsigned int w = (ramptime * 1000)/ 256;
+    int delay = 200;
+
+    if (!SuppressSlowStuff)
+        pc.printf("Backlight Test - ramp over %f sec.\r\n", ramptime);
+    else {
+        delay = 0;
+        w = 0;
+    }
     display.Backlight_u8(0);
     display.background(White);
     display.foreground(Blue);
     display.cls();
-    wait_ms(200);
+    wait_ms(delay);
     display.puts(0,0, "RA8875 Backlight Test - Ramp up.");
     for (int i=0; i <= 255; i++) {
-        unsigned int w = (ramptime * 1000)/ 256;
         sprintf(buf, "%3d, %4d", i, w);
         display.puts(100,100,buf);
         display.Backlight_u8(i);
@@ -1039,21 +1132,28 @@
 
 void BacklightTest2(RA8875 & display, Serial & pc)
 {
-    pc.printf("Backlight Test 2\r\n");
+    int delay = 20;
+
+    if (!SuppressSlowStuff)
+        pc.printf("Backlight Test 2\r\n");
+    else
+        delay = 0;
+
     // Dim it out at the end of the tests.
     display.foreground(Blue);
     display.puts(0,0, "Ramp Backlight down.");
     // Ramp it off
     for (int i=255; i != 0; i--) {
         display.Backlight_u8(i);
-        wait_ms(20);
+        wait_ms(delay);
     }
     display.Backlight_u8(0);
 }
 
 void ExternalFontTest(RA8875 & display, Serial & pc)
 {
-    pc.printf("External Font Test\r\n");
+    if (!SuppressSlowStuff)
+        pc.printf("External Font Test\r\n");
     display.background(Black);
     display.foreground(Blue);
     display.cls();
@@ -1073,7 +1173,8 @@
 
 void DOSColorTest(RA8875 & display, Serial & pc)
 {
-    pc.printf("DOS Color Test\r\n");
+    if (!SuppressSlowStuff)
+        pc.printf("DOS Color Test\r\n");
     display.background(Black);
     display.foreground(Blue);
     display.cls();
@@ -1095,7 +1196,8 @@
 
 void WebColorTest(RA8875 & display, Serial & pc)
 {
-    pc.printf("Web Color Test\r\n");
+    if (!SuppressSlowStuff)
+        pc.printf("Web Color Test\r\n");
     display.background(Black);
     display.foreground(Blue);
     display.window(0,0, display.width(), display.height());
@@ -1115,7 +1217,8 @@
 {
     int i, c, x, y;
 
-    pc.printf("Pixel Test\r\n");
+    if (!SuppressSlowStuff)
+        pc.printf("Pixel Test\r\n");
     display.background(Black);
     display.foreground(Blue);
     display.cls();
@@ -1133,7 +1236,8 @@
 {
     int i, x, y, x2, y2;
 
-    pc.printf("Line Test\r\n");
+    if (!SuppressSlowStuff)
+        pc.printf("Line Test\r\n");
     display.background(Black);
     display.foreground(Blue);
     display.cls();
@@ -1152,7 +1256,8 @@
 {
     int i, x1,y1, x2,y2;
 
-    pc.printf("Rectangle Test\r\n");
+    if (!SuppressSlowStuff)
+        pc.printf("Rectangle Test\r\n");
     display.background(Black);
     display.foreground(Blue);
     display.cls();
@@ -1176,7 +1281,8 @@
 {
     loc_t i, x1,y1, x2,y2, r1,r2;
 
-    pc.printf("Round Rectangle Test\r\n");
+    if (!SuppressSlowStuff)
+        pc.printf("Round Rectangle Test\r\n");
     display.background(Black);
     display.foreground(Blue);
     display.cls();
@@ -1205,7 +1311,8 @@
 {
     int i, x1, y1, x2, y2, x3, y3;
 
-    pc.printf("Triangle Test\r\n");
+    if (!SuppressSlowStuff)
+        pc.printf("Triangle Test\r\n");
     display.background(Black);
     display.foreground(Blue);
     display.cls();
@@ -1265,7 +1372,8 @@
 {
     int i, x, y, r1;
 
-    pc.printf("Circle Test\r\n");
+    if (!SuppressSlowStuff)
+        pc.printf("Circle Test\r\n");
     display.background(Black);
     display.foreground(Blue);
     display.cls();
@@ -1289,7 +1397,8 @@
 {
     int i,x,y,r1,r2;
 
-    pc.printf("Ellipse Test\r\n");
+    if (!SuppressSlowStuff)
+        pc.printf("Ellipse Test\r\n");
     display.background(Black);
     display.foreground(Blue);
     display.cls();
@@ -1312,6 +1421,8 @@
 void TestGraphicsBitmap(RA8875 & display, Serial & pc)
 {
     LocalFileSystem local("local");
+    if (!SuppressSlowStuff)
+        pc.printf("Bitmap File Load\r\n");    
     display.background(Black);
     display.foreground(Blue);
     display.cls();
@@ -1321,6 +1432,42 @@
     int r = display.RenderBitmapFile(0,0, "/local/TestPat.bmp");
 }
 
+void SpeedTest(RA8875 & display, Serial & pc)
+{
+    Timer t;
+    SuppressSlowStuff = true;
+    pc.printf("\r\nSpeedTest disables delays, runs tests, reports overall time.\r\n");
+    t.start();
+    // do stuff fast
+    TextCursorTest(display, pc);
+    BacklightTest(display, pc, 0);
+    BacklightTest2(display, pc);
+    ExternalFontTest(display, pc);
+    DOSColorTest(display, pc);
+    WebColorTest(display, pc);
+    PixelTest(display, pc);
+    LineTest(display, pc);
+    RectangleTest(display, pc);
+    RoundRectTest(display, pc);
+    TriangleTest(display, pc);
+    CircleTest(display, pc);
+    EllipseTest(display, pc);
+    //TestGraphicsBitmap(display, pc);
+    pc.printf("SpeedTest completed in %d msec\r\n", t.read_ms());
+    #ifdef DEBUG
+    display.ReportPerformance(pc);
+    #endif
+    SuppressSlowStuff = false;
+}
+
+void PrintScreen(RA8875 & display, Serial & pc)
+{
+    LocalFileSystem local("local");
+    if (!SuppressSlowStuff)
+        pc.printf("PrintScreen\r\n");    
+    display.PrintScreen( 0,0, 480,272, "/local/Capture.bmp");
+}
+
 void RunTestSet(RA8875 & lcd, Serial & pc)
 {
     int q = 0;
@@ -1329,14 +1476,18 @@
 
     while(1) {
         pc.printf("\r\n"
-                  "B - Backlight up    b - backlight dim\r\n"
-                  "D - DOS Colors      W - Web Colors\r\n"
-                  "t - text cursor     G - Graphics Bitmap\r\n"
-                  "L - Lines           F - external Font\r\n"
-                  "R - Rectangles      O - rOund rectangles\r\n"
-                  "T - Triangles       P - Pixels  \r\n"
-                  "C - Circles         E - Ellipses\r\n"
-                  "A - Auto Test mode  r - reset  \r\n"
+                  "B - Backlight up      b - backlight dim\r\n"
+                  "D - DOS Colors        W - Web Colors\r\n"
+                  "t - text cursor       G - Graphics Bitmap\r\n"
+                  "L - Lines             F - external Font\r\n"
+                  "R - Rectangles        O - rOund rectangles\r\n"
+                  "T - Triangles         P - Pixels  \r\n"
+                  "C - Circles           E - Ellipses\r\n"
+                  "A - Auto Test mode    S - Speed Test\r\n"
+                  "p - print screen      r - reset  \r\n"
+                  #ifdef DEBUG
+                  "0 - clear performance 1 - report performance\r\n"
+                  #endif
                   "> ");
         if (automode == -1 || pc.readable()) {
             automode = -1;
@@ -1347,11 +1498,19 @@
             q = modelist[automode];
         }
         switch(q) {
+            #ifdef DEBUG
+            case '0':
+                lcd.ClearPerformance();
+                break;
+            case '1':
+                lcd.ReportPerformance(pc);
+                break;
+            #endif
             case 'A':
                 automode = 0;
                 break;
             case 'B':
-                BacklightTest(lcd, pc, 4);
+                BacklightTest(lcd, pc, 2);
                 break;
             case 'b':
                 BacklightTest2(lcd, pc);
@@ -1377,6 +1536,12 @@
             case 'O':
                 RoundRectTest(lcd, pc);
                 break;
+            case 'p':
+                PrintScreen(lcd, pc);
+                break;
+            case 'S':
+                SpeedTest(lcd, pc);
+                break;
             case 'T':
                 TriangleTest(lcd, pc);
                 break;
--- a/RA8875.h	Tue Feb 04 02:58:06 2014 +0000
+++ b/RA8875.h	Sat Feb 08 17:35:45 2014 +0000
@@ -4,7 +4,7 @@
 
 #include "GraphicsDisplay.h"
 
-#define RA8875_DEFAULT_SPI_FREQ 2000000
+#define RA8875_DEFAULT_SPI_FREQ 5000000
 
 // Define this to enable code that monitors the performance of various
 // graphics commands.
@@ -181,7 +181,7 @@
     ///
     unsigned char ReadCommand(unsigned char command);
     
-    /// Read a data byte to the display
+    /// Read a data byte from the display
     ///
     /// This is a high level command, and may invoke several primitives.
     ///
@@ -189,6 +189,14 @@
     ///
     unsigned char ReadData(void);
     
+    /// Read a word from the display
+    ///
+    /// This is a high level command, and may invoke several primitives.
+    ///
+    /// @returns data that was read.
+    ///
+    uint16_t ReadDataW(void);
+
     /// Read the display status
     ///
     /// This is a high level command, and may invoke several primitives.
@@ -379,6 +387,15 @@
     ///
     virtual RetCode_t SetGraphicsCursor(loc_t x, loc_t y);
     
+    /// Prepare the controller to read binary data from the screen by positioning
+    /// the memory read cursor.
+    ///
+    /// @param x is the horizontal position in pixels (from the left edge)
+    /// @param y is the vertical position in pixels (from the top edge)
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t SetGraphicsCursorRead(loc_t x, loc_t y);
+    
     /// Set the window, which controls where items are written to the screen.
     ///
     /// When something hits the window width, it wraps back to the left side
@@ -453,8 +470,8 @@
         
     /// Draw a pixel in the specified color.
     ///
-    /// @note As a side effect, this also sets the foreground  
-    ///     color affecting all subsequent operations.
+    /// @note Unlike many other operations, this does not
+    ///         set the forecolor!
     ///
     /// @param x is the horizontal offset to this pixel.
     /// @param y is the vertical offset to this pixel.
@@ -471,6 +488,34 @@
     ///
     virtual RetCode_t pixel(loc_t x, loc_t y);
     
+    /// Get a pixel from the display.
+    ///
+    /// @param x is the horizontal offset to this pixel.
+    /// @param y is the vertical offset to this pixel.
+    /// @returns the pixel. see @color_t
+    ///
+    virtual color_t getPixel(loc_t x, loc_t y);
+    
+    /// Write a stream of pixels to the display.
+    ///
+    /// @param p is a pointer to a color_t array to write.
+    /// @param count is the number of pixels to write.
+    /// @param x is the horizontal position on the display.
+    /// @param y is the vertical position on the display.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t pixelStream(color_t * p, uint32_t count, loc_t x, loc_t y);
+    
+    /// Get a stream of pixels from the display.
+    ///
+    /// @param p is a pointer to a color_t array to accept the stream.
+    /// @param count is the number of pixels to read.
+    /// @param x is the horizontal offset to this pixel.
+    /// @param y is the vertical offset to this pixel.
+    /// @returns success/failure code. @see RetCode_t.
+    ///
+    virtual RetCode_t getPixelStream(color_t * p, uint32_t count, loc_t x, loc_t y);
+    
     /// Draw a line in the specified color
     ///
     /// @note As a side effect, this changes the current
@@ -827,8 +872,11 @@
     void ClearPerformance();
     
     /// Report the performance metrics for drawing functions using
-    /// printf()
-    void ReportPerformance();
+    /// the available serial channel.
+    ///
+    /// @param pc is the serial channel to write to.
+    ///
+    void ReportPerformance(Serial & pc);
 #endif
 
 private:
@@ -947,7 +995,10 @@
     typedef enum
     {
         PRF_CLS,
-        PRF_DRAWPOINT,
+        PRF_DRAWPIXEL,
+        PRF_PIXELSTREAM,
+        PRF_READPIXEL,
+        PRF_READPIXELSTREAM,
         PRF_DRAWLINE,
         PRF_DRAWRECTANGLE,
         PRF_DRAWROUNDEDRECTANGLE,