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:
Sun Nov 09 18:52:46 2014 +0000
Parent:
72:ecffe56af969
Child:
74:686faa218914
Commit message:
Improved PrintScreen function automatically senses some of the modes of operation.

Changed in this revision

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.h	Sat Oct 11 17:24:29 2014 +0000
+++ b/GraphicsDisplay.h	Sun Nov 09 18:52:46 2014 +0000
@@ -207,11 +207,11 @@
     /// @note This method probably has very little value outside of
     ///         the internal methods for reading BMP files.
     ///
-    /// @param colorPalette is the handle to the color palette to use.
-    /// @param i is the index into the color palette.
+    /// @param colorPaletteArray is the handle to the color palette array to use.
+    /// @param index is the index into the color palette.
     /// @returns the color in color_t format.
     ///
-    color_t RGBQuadToRGB16(RGBQUAD * colorPalette, uint16_t i);
+    color_t RGBQuadToRGB16(RGBQUAD * colorPaletteArray, uint16_t index);
     
     /// This method converts a 16-bit color value into a 24-bit RGB Quad.
     ///
--- a/RA8875.cpp	Sat Oct 11 17:24:29 2014 +0000
+++ b/RA8875.cpp	Sun Nov 09 18:52:46 2014 +0000
@@ -1,7 +1,7 @@
 /// RA8875 Display Controller Library.
-/// 
+///
 /// This is being created for a Raio RA8875-based display from buydisplay.com,
-/// which is 480 x 272 using a 4-wire SPI interface. 
+/// which is 480 x 272 using a 4-wire SPI interface.
 /// This display controller is used in other display resolutions, up to 800x600.
 /// While this driver has not been tested with these variants, nothing was done
 /// to prevent easily supporting them.
@@ -16,10 +16,31 @@
 #define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
 #define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
 #define ERR(x, ...)  std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
+static void HexDump(char * title, uint8_t * p, int count)
+{
+    int i;
+    char buf[100] = "0000: ";
+
+    if (*title)
+        INFO("%s", title);
+    for (i=0; i<count; ) {
+        sprintf(buf + strlen(buf), "%02X ", *(p+i));
+        if ((++i & 0x0F) == 0x00) {
+            INFO("%s", buf);
+            if (i < count)
+                sprintf(buf, "%04X: ", i);
+            else
+                buf[0] = '\0';
+        }
+    }
+    if (strlen(buf))
+        INFO("%s", buf);
+}
 #else
 #define INFO(x, ...)
 #define WARN(x, ...)
 #define ERR(x, ...)
+#define HexDump(a, b, c)
 #endif
 
 
@@ -31,12 +52,11 @@
 #define PERFORMANCE_RESET performance.reset()
 #define REGISTERPERFORMANCE(a) RegisterPerformance(a)
 #define COUNTIDLETIME(a) CountIdleTime(a)
-static const char *metricsName[] = 
-{
-    "Cls", "Pixel", "Pixel Stream", 
+static const char *metricsName[] = {
+    "Cls", "Pixel", "Pixel Stream",
     "Read Pixel", "Read Pixel Stream",
-    "Line", 
-    "Rectangle", "Rounded Rectangle", 
+    "Line",
+    "Rectangle", "Rounded Rectangle",
     "Triangle", "Circle", "Ellipse"
 };
 #else
@@ -45,7 +65,7 @@
 #define COUNTIDLETIME(a)
 #endif
 
-// When it is going to poll a register for completion, how many 
+// When it is going to poll a register for completion, how many
 // uSec should it wait between each polling activity.
 #define POLLWAITuSec 10
 
@@ -123,14 +143,23 @@
     return noerror;
 }
 
+color_t RA8875::GetBackgroundTransparencyColor(void)
+{
+    RGBQUAD q;
+    q.rgbRed = ReadCommand(0x67);
+    q.rgbGreen = ReadCommand(0x68);
+    q.rgbBlue = ReadCommand(0x69);
+    return RGBQuadToRGB16(&q, 0);
+}
+
 // ### Touch Panel support code additions begin here
 
 RetCode_t RA8875::TouchPanelInit(void)
-{        
+{
     //TPCR0: Set enable bit, default sample time, wakeup, and ADC clock
     WriteCommand(TPCR0, TP_ENABLE | TP_ADC_SAMPLE_DEFAULT_CLKS | TP_ADC_CLKDIV_DEFAULT);
     // TPCR1: Set auto/manual, Ref voltage, debounce, manual mode params
-    WriteCommand(TPCR1, TP_MODE_DEFAULT | TP_DEBOUNCE_DEFAULT);   
+    WriteCommand(TPCR1, TP_MODE_DEFAULT | TP_DEBOUNCE_DEFAULT);
     WriteCommand(INTC1, ReadCommand(INTC1) | RA8875_INT_TP);        // reg INTC1: Enable Touch Panel Interrupts (D2 = 1)
     WriteCommand(INTC2, RA8875_INT_TP);                            // reg INTC2: Clear any TP interrupt flag
     return noerror;
@@ -140,13 +169,13 @@
 {
     // Parameter bounds check
     if( \
-        !(bTpEnable == TP_ENABLE || bTpEnable == TP_ENABLE) || \
-        !(bTpAutoManual == TP_MODE_AUTO || bTpAutoManual == TP_MODE_MANUAL) || \
-        !(bTpDebounce == TP_DEBOUNCE_OFF || bTpDebounce == TP_DEBOUNCE_ON) || \
-        !(bTpManualMode <= TP_MANUAL_LATCH_Y) || \
-        !(bTpAdcClkDiv <= TP_ADC_CLKDIV_128) || \
-        !(bTpAdcSampleTime <= TP_ADC_SAMPLE_65536_CLKS) \
-        ) return bad_parameter;
+            !(bTpEnable == TP_ENABLE || bTpEnable == TP_ENABLE) || \
+            !(bTpAutoManual == TP_MODE_AUTO || bTpAutoManual == TP_MODE_MANUAL) || \
+            !(bTpDebounce == TP_DEBOUNCE_OFF || bTpDebounce == TP_DEBOUNCE_ON) || \
+            !(bTpManualMode <= TP_MANUAL_LATCH_Y) || \
+            !(bTpAdcClkDiv <= TP_ADC_CLKDIV_128) || \
+            !(bTpAdcSampleTime <= TP_ADC_SAMPLE_65536_CLKS) \
+      ) return bad_parameter;
     // Construct the config byte for TPCR0 and write them
     WriteCommand(TPCR0, bTpEnable | bTpAdcClkDiv | bTpAdcSampleTime);    // Note: Wakeup is never enabled
     // Construct the config byte for TPCR1 and write them
@@ -154,7 +183,7 @@
     // Set up the interrupt flag and enable bits
     WriteCommand(INTC1, ReadCommand(INTC1) | RA8875_INT_TP);        // reg INTC1: Enable Touch Panel Interrupts (D2 = 1)
     WriteCommand(INTC2, RA8875_INT_TP);                            // reg INTC2: Clear any TP interrupt flag
-    return noerror;    
+    return noerror;
 }
 
 unsigned char RA8875::TouchPanelRead(loc_t *x, loc_t *y)
@@ -163,26 +192,26 @@
     static int xbuf[TPBUFSIZE], ybuf[TPBUFSIZE], sample = 0;
     int i, j, temp;
 
-    if( (ReadCommand(INTC2) & RA8875_INT_TP) ) {        // Test for TP Interrupt pending in register INTC2    
+    if( (ReadCommand(INTC2) & RA8875_INT_TP) ) {        // Test for TP Interrupt pending in register INTC2
         // Get the next data samples
         ybuf[sample] =  ReadCommand(TPYH) << 2 | ( (ReadCommand(TPXYL) & 0xC) >> 2 );   // D[9:2] from reg TPYH, D[1:0] from reg TPXYL[3:2]
         xbuf[sample] =  ReadCommand(TPXH) << 2 | ( (ReadCommand(TPXYL) & 0x3)      );   // D[9:2] from reg TPXH, D[1:0] from reg TPXYL[1:0]
         // Check for a complete set
         if(++sample == TPBUFSIZE) {
-           // Buffers are full, so process them using Finn's method described in Analog Dialogue No. 44, Feb 2010
-           // This requires sorting the samples in order of size, then discarding the top 25% and
-           //   bottom 25% as noise spikes. Finally, the middle 50% of the values are averaged to
-           //   reduce Gaussian noise.
-           
-           // Sort the Y buffer using an Insertion Sort
+            // Buffers are full, so process them using Finn's method described in Analog Dialogue No. 44, Feb 2010
+            // This requires sorting the samples in order of size, then discarding the top 25% and
+            //   bottom 25% as noise spikes. Finally, the middle 50% of the values are averaged to
+            //   reduce Gaussian noise.
+
+            // Sort the Y buffer using an Insertion Sort
             for(i = 1; i <= TPBUFSIZE; i++) {
                 temp = ybuf[i];
                 j = i;
                 while( j && (ybuf[j-1] > temp) ) {
                     ybuf[j] = ybuf[j-1];
-                    j = j-1;    
+                    j = j-1;
                 }
-                ybuf[j] = temp;             
+                ybuf[j] = temp;
             } // End of Y sort
             // Sort the X buffer the same way
             for(i = 1; i <= TPBUFSIZE; i++) {
@@ -190,31 +219,30 @@
                 j = i;
                 while( j && (xbuf[j-1] > temp) ) {
                     xbuf[j] = xbuf[j-1];
-                    j = j-1;    
+                    j = j-1;
                 }
-                xbuf[j] = temp;             
+                xbuf[j] = temp;
             } // End of X sort
             // Average the middle half of the  Y values and report them
             j = 0;
             for(i = (TPBUFSIZE/4) - 1; i < TPBUFSIZE - TPBUFSIZE/4; i++ ) {
-                j += ybuf[i];    
+                j += ybuf[i];
             }
             *y = j * (float)2/TPBUFSIZE;    // This is the average
             // Average the middle half of the  X values and report them
             j = 0;
             for(i = (TPBUFSIZE/4) - 1; i < TPBUFSIZE - TPBUFSIZE/4; i++ ) {
-                j += xbuf[i];    
+                j += xbuf[i];
             }
-            *x = j * (float)2/TPBUFSIZE;    // This is the average           
-            // Tidy up and return 
+            *x = j * (float)2/TPBUFSIZE;    // This is the average
+            // Tidy up and return
             touchready = 1;
             sample = 0;             // Ready to start on the next set of data samples
-        }
-        else {
+        } else {
             // Buffer not yet full, so do not return any results yet
             touchready = 0;
         }
-        WriteCommand(INTC2, RA8875_INT_TP);            // reg INTC2: Clear that TP interrupt flag                       
+        WriteCommand(INTC2, RA8875_INT_TP);            // reg INTC2: Clear that TP interrupt flag
     } // End of initial if -- data has been read and processed
     else
         touchready = 0;         // Touch Panel "Int" was not set
@@ -225,24 +253,23 @@
 {
     unsigned char touchready;
 
-    if( (ReadCommand(INTC2) & RA8875_INT_TP) ) {        // Test for TP Interrupt pending in register INTC2    
+    if( (ReadCommand(INTC2) & RA8875_INT_TP) ) {        // Test for TP Interrupt pending in register INTC2
         *y =  ReadCommand(TPYH) << 2 | ( (ReadCommand(TPXYL) & 0xC) >> 2 );   // D[9:2] from reg TPYH, D[1:0] from reg TPXYL[3:2]
         *x =  ReadCommand(TPXH) << 2 | ( (ReadCommand(TPXYL) & 0x3)      );   // D[9:2] from reg TPXH, D[1:0] from reg TPXYL[1:0]
-        WriteCommand(INTC2, RA8875_INT_TP);            // reg INTC2: Clear that TP interrupt flag   
+        WriteCommand(INTC2, RA8875_INT_TP);            // reg INTC2: Clear that TP interrupt flag
         touchready = 1;
-    }
-    else
-        touchready = 0;  
+    } else
+        touchready = 0;
     return touchready;
 }
 // #### end of touch panel code additions
 
 
-RetCode_t RA8875::KeypadInit(bool scanEnable, bool longDetect, uint8_t sampleTime, uint8_t scanFrequency, 
-    uint8_t longTimeAdjustment, bool interruptEnable, bool wakeupEnable)
+RetCode_t RA8875::KeypadInit(bool scanEnable, bool longDetect, uint8_t sampleTime, uint8_t scanFrequency,
+                             uint8_t longTimeAdjustment, bool interruptEnable, bool wakeupEnable)
 {
     uint8_t value = 0;
-    
+
     if (sampleTime > 3 || scanFrequency > 7 || longTimeAdjustment  > 3)
         return bad_parameter;
     value |= (scanEnable) ? 0x80 : 0x00;
@@ -250,12 +277,12 @@
     value |= (sampleTime & 0x03) << 4;
     value |= (scanFrequency & 0x07);
     WriteCommand(0xC0, value);   // Enable Key Scan (and ignore possibility of an error)
-    
+
     value = 0;
     value |= (wakeupEnable) ? 0x80 : 0x00;
     value |= (longTimeAdjustment & 0x03) << 2;
     WriteCommand(0xC1, value);  // (and ignore possibility of an error)
-    
+
     value = ReadCommand(0xF0);  // (and ignore possibility of an error)
     value &= ~0x10;
     value |= (interruptEnable) ? 0x10 : 0x00;
@@ -294,7 +321,7 @@
 void RA8875::RegisterPerformance(method_e method)
 {
     unsigned long elapsed = performance.read_us();
-    
+
     if (method < METRICCOUNT && elapsed > metrics[method])
         metrics[method] = elapsed;
 }
@@ -317,10 +344,10 @@
 
 RetCode_t RA8875::WriteCommandW(uint8_t command, uint16_t data)
 {
-    #if 1
+#if 1
     WriteCommand(command, data & 0xFF);
     WriteCommand(command+1, data >> 8);
-    #else
+#else
     // This should be a little faster, but doesn't work...
     INFO("WriteCommandW(%02X, %04X)", command, data);
     select(true);
@@ -330,7 +357,7 @@
     spiwrite(data & 0xFF);
     spiwrite(data >> 8);
     select(false);
-    #endif
+#endif
     return noerror;
 }
 
@@ -380,7 +407,7 @@
 unsigned char RA8875::ReadData(void)
 {
     unsigned char data;
-    
+
     select(true);
     spiwrite(0x40);
     data = spiread();
@@ -392,7 +419,7 @@
 uint16_t RA8875::ReadDataW(void)
 {
     uint16_t data;
-    
+
     select(true);
     spiwrite(0x40);
     data  = spiread();
@@ -405,7 +432,7 @@
 unsigned char RA8875::ReadStatus(void)
 {
     unsigned char data;
-    
+
     select(true);
     spiwrite(0xC0);         // These two bits are for the special "Status Read" [STSR]
     data = spiread();
@@ -506,7 +533,8 @@
 
 RetCode_t RA8875::SetTextCursor(loc_t x, loc_t y)
 {
-    cursor_x = x; cursor_y = y;     // for non-internal fonts
+    cursor_x = x;
+    cursor_y = y;     // for non-internal fonts
     WriteCommandW(0x2A, x);
     WriteCommandW(0x2C, y);
     return noerror;
@@ -537,7 +565,7 @@
     unsigned char mwcr1 = ReadCommand(0x41) & 0x01; // retain currently selected layer
     unsigned char horz = 0;
     unsigned char vert = 0;
-    
+
     mwcr0 |= 0x80;                  // text mode
     if (cursor != NOCURSOR)
         mwcr0 |= 0x40;              // visible
@@ -581,15 +609,15 @@
 
 
 RetCode_t RA8875::SetTextFontControl(fill_t fillit,
-    RA8875::font_angle_t angle, 
-    RA8875::HorizontalScale hScale, 
-    RA8875::VerticalScale vScale, 
-    RA8875::alignment_t alignment)
+                                     RA8875::font_angle_t angle,
+                                     RA8875::HorizontalScale hScale,
+                                     RA8875::VerticalScale vScale,
+                                     RA8875::alignment_t alignment)
 {
-    if (hScale >= 1 && hScale <= 4 && 
-    vScale >= 1 && vScale <= 4) {
+    if (hScale >= 1 && hScale <= 4 &&
+            vScale >= 1 && vScale <= 4) {
         unsigned char x = 0;
-        
+
         if (alignment == align_full)
             x |= 0x80;
         if (fillit == NOFILL)
@@ -609,7 +637,7 @@
 RetCode_t RA8875::SetTextFontSize(RA8875::HorizontalScale hScale, RA8875::VerticalScale vScale)
 {
     unsigned char reg = ReadCommand(0x22);
-    
+
     if (vScale == -1)
         vScale = hScale;
     if (hScale >= 1 && hScale <= 4 && vScale >= 1 && vScale <= 4) {
@@ -664,7 +692,7 @@
 {
     if (c) {
         unsigned char mwcr0;
-        
+
         mwcr0 = ReadCommand(0x40);
         if ((mwcr0 & 0x80) == 0x00) {
             WriteCommand(0x40, 0x80 | mwcr0);    // Put in Text mode if not already
@@ -709,7 +737,7 @@
 RetCode_t RA8875::_putp(color_t pixel)
 {
     WriteDataW((pixel>>8) | (pixel<<8));
-    return noerror;   
+    return noerror;
 }
 
 
@@ -723,7 +751,7 @@
 void RA8875::puts(const char * string)
 {
     unsigned char mwcr0 = ReadCommand(0x40);
-    
+
     if (font == NULL) {
         if ((mwcr0 & 0x80) == 0x00)
             WriteCommand(0x40,0x80);    // Put in Text mode if not already
@@ -731,11 +759,11 @@
         _StartGraphicsStream();
     }
     if (*string != '\0') {
-        #if 1
+#if 1
         while (*string) {           // @TODO calling individual _putc is slower... optimizations?
             _putc(*string++);
         }
-        #else
+#else
         WriteCommand(0x02);
         select(true);
         while (*string != '\0') {
@@ -744,7 +772,7 @@
             _WaitWhileBusy(0x80);
         }
         select(false);
-        #endif
+#endif
     }
     if (font)
         _EndGraphicsStream();
@@ -784,7 +812,7 @@
 RetCode_t RA8875::cls(uint16_t layers)
 {
     RetCode_t ret;
-    
+
     PERFORMANCE_RESET;
     if (layers == 0) {
         ret = clsw(FULLWINDOW);
@@ -821,14 +849,14 @@
 RetCode_t RA8875::pixel(loc_t x, loc_t y, color_t color)
 {
     RetCode_t ret;
-    
+
     PERFORMANCE_RESET;
-    #if 1
+#if 1
     ret = pixelStream(&color, 1, x,y);
-    #else
+#else
     foreground(color);
     ret = pixel(x,y);
-    #endif
+#endif
     REGISTERPERFORMANCE(PRF_DRAWPIXEL);
     return ret;
 }
@@ -837,18 +865,18 @@
 RetCode_t RA8875::pixel(loc_t x, loc_t y)
 {
     RetCode_t ret;
-    
+
     PERFORMANCE_RESET;
     color_t color = GetForeColor();
-    #if 1
+#if 1
     ret = pixelStream(&color, 1, x, y);
-    #else
+#else
     WriteCommand(0x40,0x00);    // Graphics write mode
     SetGraphicsCursor(x, y);
     WriteCommand(0x02);
     WriteDataW(color);
     ret = noerror;
-    #endif
+#endif
     REGISTERPERFORMANCE(PRF_DRAWPIXEL);
     return ret;
 }
@@ -876,7 +904,7 @@
 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
@@ -896,7 +924,7 @@
 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
@@ -943,23 +971,23 @@
 }
 
 
-RetCode_t RA8875::fillrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
-    color_t color, fill_t fillit)
+RetCode_t RA8875::fillrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
+                           color_t color, fill_t fillit)
 {
     return rect(x1,y1,x2,y2,color,fillit);
 }
 
 
-RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
-    color_t color, fill_t fillit)
+RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
+                       color_t color, fill_t fillit)
 {
     foreground(color);
     return rect(x1,y1,x2,y2,fillit);
 }
 
 
-RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
-    fill_t fillit)
+RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
+                       fill_t fillit)
 {
     PERFORMANCE_RESET;
     if (x1 == x2 && y1 == y2) {
@@ -985,27 +1013,27 @@
 }
 
 
-RetCode_t RA8875::fillroundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
-    dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
+RetCode_t RA8875::fillroundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
+                                dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
 {
     foreground(color);
     return roundrect(x1,y1,x2,y2,radius1,radius2,fillit);
 }
 
 
-RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
-    dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
+RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
+                            dim_t radius1, dim_t radius2, color_t color, fill_t fillit)
 {
     foreground(color);
     return roundrect(x1,y1,x2,y2,radius1,radius2,fillit);
 }
 
 
-RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
-    dim_t radius1, dim_t radius2, fill_t fillit)
+RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
+                            dim_t radius1, dim_t radius2, fill_t fillit)
 {
     RetCode_t ret = noerror;
-    
+
     PERFORMANCE_RESET;
     if (x1 > x2 || y1 > y2 || (radius1 > (x2-x1)/2) || (radius2 > (y2-y1)/2) ) {
         ret = bad_parameter;
@@ -1037,19 +1065,8 @@
 }
 
 
-RetCode_t RA8875::triangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
-    loc_t x3, loc_t y3, color_t color, fill_t fillit)
-{
-    RetCode_t ret;
-    
-    foreground(color);
-    ret = triangle(x1,y1,x2,y2,x3,y3,fillit);
-    return ret;
-}
-
-
-RetCode_t RA8875::filltriangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 
-    loc_t x3, loc_t y3, color_t color, fill_t fillit)
+RetCode_t RA8875::triangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
+                           loc_t x3, loc_t y3, color_t color, fill_t fillit)
 {
     RetCode_t ret;
 
@@ -1059,11 +1076,22 @@
 }
 
 
-RetCode_t RA8875::triangle(loc_t x1, loc_t y1 ,loc_t x2, loc_t y2, 
-    loc_t x3, loc_t y3, fill_t fillit)
+RetCode_t RA8875::filltriangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2,
+                               loc_t x3, loc_t y3, color_t color, fill_t fillit)
+{
+    RetCode_t ret;
+
+    foreground(color);
+    ret = triangle(x1,y1,x2,y2,x3,y3,fillit);
+    return ret;
+}
+
+
+RetCode_t RA8875::triangle(loc_t x1, loc_t y1 ,loc_t x2, loc_t y2,
+                           loc_t x3, loc_t y3, fill_t fillit)
 {
     RetCode_t ret = noerror;
-    
+
     PERFORMANCE_RESET;
     if (x1 == x2 && y1 == y2 && x1 == x3 && y1 == y3) {
         pixel(x1, y1);
@@ -1085,16 +1113,16 @@
     return ret;
 }
 
-RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius, 
-    color_t color, fill_t fillit)
+RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius,
+                         color_t color, fill_t fillit)
 {
     foreground(color);
     return circle(x,y,radius,fillit);
 }
 
 
-RetCode_t RA8875::fillcircle(loc_t x, loc_t y, dim_t radius, 
-    color_t color, fill_t fillit)
+RetCode_t RA8875::fillcircle(loc_t x, loc_t y, dim_t radius,
+                             color_t color, fill_t fillit)
 {
     foreground(color);
     return circle(x,y,radius,fillit);
@@ -1104,7 +1132,7 @@
 RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius, fill_t fillit)
 {
     RetCode_t ret = noerror;
-    
+
     PERFORMANCE_RESET;
     if (radius <= 0) {
         ret = bad_parameter;
@@ -1139,11 +1167,11 @@
     return ellipse(x,y,radius1,radius2,fillit);
 }
 
-        
+
 RetCode_t RA8875::ellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, fill_t fillit)
 {
     RetCode_t ret = noerror;
-    
+
     PERFORMANCE_RESET;
     if (radius1 <= 0 || radius2 <= 0) {
         ;   // do nothing
@@ -1205,7 +1233,7 @@
     WriteCommand(0x01, 0x01);   // Apply Display Off, Reset
     wait_ms(2);                     // no idea if I need to wait, or how long
     WriteCommand(0x01, 0x00);   // Display off, Remove reset
-    wait_ms(2);                     // no idea if I need to wait, or how long    
+    wait_ms(2);                     // no idea if I need to wait, or how long
     init(RA8875_DISPLAY_WIDTH, RA8875_DISPLAY_HEIGHT, RA8875_COLORDEPTH_BPP);
     return noerror;
 }
@@ -1233,7 +1261,7 @@
 RetCode_t RA8875::Backlight(float brightness)
 {
     unsigned char b;
-    
+
     if (brightness >= 1.0)
         b = 255;
     else if (brightness <= 0.0)
@@ -1298,7 +1326,7 @@
 color_t RA8875::GetForeColor(void)
 {
     color_t color;
-    
+
     color  = (ReadCommand(0x63) & 0x1F) << 11;
     color |= (ReadCommand(0x64) & 0x3F) << 5;
     color |= (ReadCommand(0x65) & 0x1F);
@@ -1307,35 +1335,33 @@
 
 
 color_t RA8875::DOSColor(int i)
-    {
-    const color_t colors[16] = 
-        {
+{
+    const color_t colors[16] = {
         Black,    Blue,       Green,       Cyan,
         Red,      Magenta,    Brown,       Gray,
         Charcoal, BrightBlue, BrightGreen, BrightCyan,
         Orange,   Pink,       Yellow,      White
-        };
+    };
     if (i < 16)
         return colors[i];
     else
         return 0;
-    }
+}
 
 
-const char * RA8875::DOSColorNames(int i) 
-    {
-    const char * names[16] = 
-        {
+const char * RA8875::DOSColorNames(int i)
+{
+    const char * names[16] = {
         "Black",    "Blue",       "Green",       "Cyan",
         "Red",      "Magenta",    "Brown",       "Gray",
         "Charcoal", "BrightBlue", "BrightGreen", "BrightCyan",
         "Orange",   "Pink",       "Yellow",      "White"
-        };
+    };
     if (i < 16)
         return names[i];
     else
         return NULL;
-    }
+}
 
 
 ///////////////////////////////////////////////////////////////
@@ -1344,7 +1370,7 @@
 unsigned char RA8875::spiwrite(unsigned char data)
 {
     unsigned char retval;
-    
+
     if (!spiWriteSpeed)
         _setWriteSpeed(true);
     retval = spi.write(data);
@@ -1356,7 +1382,7 @@
 {
     unsigned char retval;
     unsigned char data = 0;
-    
+
     if (spiWriteSpeed)
         _setWriteSpeed(false);
     retval = spi.write(data);
@@ -1378,7 +1404,7 @@
     wait_ms(1);
     WriteCommand(0x89, 0x02);
     wait_ms(1);
-    
+
     // System Config Register (SYSR)
     if (color_bpp == 16) {
         WriteCommand(0x10, 0x0C);               // 16-bpp (65K colors) color depth, 8-bit interface
@@ -1410,7 +1436,7 @@
     } else {
         WriteCommand(0x20, 0x80);               // DPCR - 2-layer mode
     }
-    
+
     // Set display image to Blue on Black as default
     window(0,0, width, height);             // Initialize to full screen
     SetTextCursorControl();
@@ -1438,19 +1464,19 @@
 {
     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()) {
+            && 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;
@@ -1474,11 +1500,11 @@
         //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) {
@@ -1487,38 +1513,86 @@
             return(not_enough_ram);
         }
         color_t * pixelBuffer = (color_t *)malloc(w * sizeof(color_t));
-        if (pixelBuffer == NULL) {
+        color_t * pixelBuffer2 = (color_t *)malloc(w * sizeof(color_t));
+        color_t transparency = GetBackgroundTransparencyColor();
+        unsigned char ltpr0 = ReadCommand(0x52) & 0x7;
+
+        if (pixelBuffer == NULL || pixelBuffer2 == NULL) {
             fclose(Image);
             free(lineBuffer);
             ERR("Not enough RAM for pixelBuffer");
+            if (pixelBuffer)
+                free(pixelBuffer);
             return(not_enough_ram);
         }
-        
+
+        uint16_t prevLayer = GetDrawingLayer();
+        // If only one of the layers is visible, select that layer
+        switch(ltpr0) {
+            case 0:
+                SelectDrawingLayer(0);
+                break;
+            case 1:
+                SelectDrawingLayer(1);
+                break;
+            default:
+                break;
+        }
+
         // 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--) {
+            if (ltpr0 >= 2)             // Need to combine the layers...
+                SelectDrawingLayer(0);  // so read layer 0 first
             // Read one line of pixels to a local buffer
             if (getPixelStream(pixelBuffer, w, x,y+j) != noerror) {
                 ERR("getPixelStream error, and no recovery handler...");
             }
+            if (ltpr0 >= 2) {           // Need to combine the layers...
+                SelectDrawingLayer(1);  // so read layer 0 first
+                if (getPixelStream(pixelBuffer2, 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;
+                RGBQUAD q0 = RGB16ToRGBQuad(pixelBuffer[x+i]);      // Scale to 24-bits
+                RGBQUAD q1 = RGB16ToRGBQuad(pixelBuffer2[x+i]);     // Scale to 24-bits
+                switch (ltpr0) {
+                    case 0:
+                    case 1:
+                    case 2: // lighten-overlay  (@TODO Not supported yet)
+                    case 6: // Floating Windows     (@TODO not sure how to support)
+                    default: // Reserved...
+                        lineBuffer[lb++] = q0.rgbBlue;
+                        lineBuffer[lb++] = q0.rgbGreen;
+                        lineBuffer[lb++] = q0.rgbRed;
+                        break;
+                    case 3: // transparent mode (@TODO Read the background color register for transparent)
+                    case 4: // boolean or
+                        lineBuffer[lb++] = q0.rgbBlue | q1.rgbBlue;
+                        lineBuffer[lb++] = q0.rgbGreen | q1.rgbGreen;
+                        lineBuffer[lb++] = q0.rgbRed | q1.rgbRed;
+                        break;
+                    case 5: // boolean AND
+                        lineBuffer[lb++] = q0.rgbBlue & q1.rgbBlue;
+                        lineBuffer[lb++] = q0.rgbGreen & q1.rgbGreen;
+                        lineBuffer[lb++] = q0.rgbRed & q1.rgbRed;
+                        break;
+                }
             }
+            if (j == h - 1)
+                HexDump("Line", lineBuffer, lineBufSize);
             // Write to disk
-            //HexDump("Line", lineBuffer, lineBufSize);
             fwrite(lineBuffer, sizeof(char), lb, Image);
         }
+        SelectDrawingLayer(prevLayer);
         fclose(Image);
-        free(pixelBuffer);  // don't leak memory.
+        free(pixelBuffer2);  // don't leak memory.
+        free(pixelBuffer);
         free(lineBuffer);
-        INFO("Image closed"); 
+        INFO("Image closed");
         return noerror;
     } else {
         return bad_parameter;
@@ -1574,17 +1648,17 @@
     const char * bbCursor = "The Blinking Block cursor should be visible for this text.\r\n";
     const char * p;
     int delay = 100;
-    
+
     if (!SuppressSlowStuff)
         pc.printf("Text Cursor Test\r\n");
-    else 
+    else
         delay = 0;
     display.background(Black);
     display.foreground(Blue);
     display.cls();
     display.Backlight_u8(255);
     display.puts(0,0, "Text Cursor Test.");
-    
+
     // visible, non-blinking
     display.SetTextCursor(0,20);
     display.SetTextCursorControl(RA8875::IBEAM, false);
@@ -1600,7 +1674,7 @@
         display._putc(*p++);
         wait_ms(delay);
     }
-    
+
     display.SetTextCursorControl(RA8875::BLOCK, false);
     p = bCursor;
     while (*p) {
@@ -1678,12 +1752,12 @@
     display.puts(0,0, "External Font Test.");
 
     display.set_font(Small_6);
-    display.puts(0,30, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n");    
+    display.puts(0,30, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n");
 
     display.set_font(Arial12x12);
     display.puts("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n");
     display.set_font();     // restore to internal
-    
+
     display.puts("Normal font again.");
     //display.window(0,0, display.width(), display.height());
 }
@@ -1798,7 +1872,7 @@
     display.line(20,52, 20,52, BrightRed);
     display.line(22,52, 22,52, BrightGreen);
     display.line(24,52, 24,52, BrightBlue);
-    
+
     // point
     display.line(50,50, 50,50, Red);
     display.line(52,52, 52,52, Green);
@@ -1893,7 +1967,7 @@
         if (!SuppressSlowStuff)
             wait_ms(200);
     }
-    
+
     // Restore before we exit
     display.SetLayerTransparency(0, 0);
     display.SetLayerMode(RA8875::ShowLayer0);        // Restore to layer 0
@@ -1910,7 +1984,7 @@
     display.foreground(Blue);
     display.cls();
     display.puts(0,0, "Rounded Rectangle Test");
-    
+
     for (i=0; i<16; i++) {
         x1 = rand() % 240;
         y1 = 50 + rand() % 200;
@@ -2049,7 +2123,7 @@
 {
     LocalFileSystem local("local");
     if (!SuppressSlowStuff)
-        pc.printf("Bitmap File Load\r\n");    
+        pc.printf("Bitmap File Load\r\n");
     display.background(Black);
     display.foreground(Blue);
     display.cls();
@@ -2086,9 +2160,9 @@
     LayerTest(display, pc);
     //TestGraphicsBitmap(display, pc);
     pc.printf("SpeedTest completed in %d msec\r\n", t.read_ms());
-    #ifdef PERF_METRICS
+#ifdef PERF_METRICS
     display.ReportPerformance(pc);
-    #endif
+#endif
     SuppressSlowStuff = false;
 }
 
@@ -2097,7 +2171,7 @@
 {
     LocalFileSystem local("local");
     if (!SuppressSlowStuff)
-        pc.printf("PrintScreen\r\n");    
+        pc.printf("PrintScreen\r\n");
     display.PrintScreen( 0,0, 480,272, "/local/Capture.bmp");
 }
 
@@ -2120,9 +2194,9 @@
                   "A - Auto Test mode    S - Speed Test\r\n"
                   "p - print screen      r - reset  \r\n"
                   "l - layer test        w - wrapping text \r\n"
-                  #ifdef PERF_METRICS
+#ifdef PERF_METRICS
                   "0 - clear performance 1 - report performance\r\n"
-                  #endif
+#endif
                   "> ");
         if (automode == -1 || pc.readable()) {
             automode = -1;
@@ -2133,14 +2207,14 @@
             q = modelist[automode];
         }
         switch(q) {
-            #ifdef PERF_METRICS
+#ifdef PERF_METRICS
             case '0':
                 lcd.ClearPerformance();
                 break;
             case '1':
                 lcd.ReportPerformance(pc);
                 break;
-            #endif
+#endif
             case 'A':
                 automode = 0;
                 break;
--- a/RA8875.h	Sat Oct 11 17:24:29 2014 +0000
+++ b/RA8875.h	Sun Nov 09 18:52:46 2014 +0000
@@ -293,6 +293,16 @@
     ///
     RetCode_t SetBackgroundTransparencyColor(color_t color = RGB(0,0,0));
  
+ 
+    /// Get the background color value used for transparency.
+    ///
+    /// This command reads the background color registers that define
+    /// the transparency color for operations involving layers.
+    ///
+    /// @returns the color.
+    ///
+    color_t GetBackgroundTransparencyColor(void);
+ 
     /// Initialize theTouch Panel controller with default values 
     ///
     /// @returns success/failure code. @see RetCode_t.
@@ -1286,6 +1296,11 @@
     /// Even though this is a 16-bit display, the stored image is in
     /// 24-bit format.
     ///
+    /// This method will interrogate the current display setting and
+    /// create a bitmap based on those settings. For instance, if 
+    /// only layer 1 is visible, then the bitmap is only layer 1. However,
+    /// if there is some other operation in effect (transparent mode).
+    ///
     /// @param[in] x is the left edge of the region to capture
     /// @param[in] y is the top edge of the region to capture
     /// @param[in] w is the width of the region to capture