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)

Revision:
164:76edd7d9cb68
Parent:
163:17526689a3ed
Child:
165:695c24cc5197
--- a/RA8875.cpp	Wed Feb 13 04:20:12 2019 +0000
+++ b/RA8875.cpp	Thu Feb 14 12:34:52 2019 +0000
@@ -108,6 +108,11 @@
     uint8_t a;
 } rgbTrio_t;
 
+/// This is defined as a "Web-Safe" color palette of 216 colors. 
+///
+/// It is defined so it can be emitted into a BMP file as the color palette, and it is then used
+/// for downscaling from higher resolution color depth to an 8-bit format.
+///
 static const rgbTrio_t WebColorPalette[] = {
     {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x33,0xFF}, {0x00,0x00,0x66,0xFF}, {0x00,0x00,0x99,0xFF}, {0x00,0x00,0xCC,0xFF}, {0x00,0x00,0xFF,0xFF},
     {0x00,0x33,0x00,0xFF}, {0x00,0x33,0x33,0xFF}, {0x00,0x33,0x66,0xFF}, {0x00,0x33,0x99,0xFF}, {0x00,0x33,0xCC,0xFF}, {0x00,0x33,0xFF,0xFF},
@@ -155,13 +160,21 @@
     {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, 
 };
 
-#define sqr(a) (double)((a) * (a))
-
+#define sqr(a) ((a) * (a))
+
+/// Find the nearest color match in the lookup table.
+///
+/// The typical process is to find the difference between a given color and each entry in
+/// the table. The difference is defined as:
+///     diff = sqrt(sqr(r - table[i].r) + sqr(g - table[i].g) + sqr(b - table[i].b))
+/// The square root function is very CPU intensive, especially w/o a floating point unit,
+/// so that step is omitted to speed it up a bit.
+///
 static int FindNearestWebColor(uint8_t r, uint8_t g, uint8_t b) {
     int bestNdx = 0;
-    float bestDiff = sqrt(sqr(r - WebColorPalette[0].r) + sqr(g - WebColorPalette[0].g) + sqr(b - WebColorPalette[0].b));
+    float bestDiff = (sqr(r - WebColorPalette[0].r) + sqr(g - WebColorPalette[0].g) + sqr(b - WebColorPalette[0].b));
     for (int i=1; i<216; i++) {
-        float thisDiff = sqrt(sqr(r - WebColorPalette[i].r) + sqr(g - WebColorPalette[i].g) + sqr(b - WebColorPalette[i].b));
+        float thisDiff = (sqr(r - WebColorPalette[i].r) + sqr(g - WebColorPalette[i].g) + sqr(b - WebColorPalette[i].b));
         if (thisDiff < bestDiff) {
             bestDiff = thisDiff;
             bestNdx = i;
@@ -2137,7 +2150,7 @@
     return ((value + roundTo - 1) / roundTo) * roundTo;
 }
 
-RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h)
+RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, uint8_t bitsPerPixel)
 {
     BITMAPFILEHEADER BMP_Header;
     BITMAPINFOHEADER BMP_Info;
@@ -2145,33 +2158,49 @@
     color_t * pixelBuffer = NULL;
     color_t * pixelBuffer2 = NULL;
     
-    INFO("(%d,%d) - (%d,%d)", x,y,w,h);
+    INFO("(%d,%d)-(%d,%d)x%d", x,y,w,h,bitsPerPixel);
     if (x >= 0 && x < screenwidth
             && y >= 0 && y < screenheight
             && w > 0 && x + w <= screenwidth
             && h > 0 && y + h <= screenheight) {
-
         BMP_Header.bfType = BF_TYPE;
-        BMP_Header.bfSize = (w * h * sizeof(RGBQUAD)) + sizeof(BMP_Header) + sizeof(BMP_Info);
         BMP_Header.bfReserved1 = 0;
         BMP_Header.bfReserved2 = 0;
-        BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Info);
+        switch (bitsPerPixel) {
+            case 24:
+                BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Info);
+                BMP_Header.bfSize = (h * RoundUp(w * sizeof(RGBQUAD),4)) + BMP_Header.bfOffBits;
+                break;
+            case 8:
+            default:
+                BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Info) + sizeof(WebColorPalette);
+                INFO("Initial Offset to Bitstream %X", BMP_Header.bfOffBits);
+                //if (BMP_Header.bfOffBits & 0x03) {
+                //    BMP_Header.bfOffBits += (4 - (BMP_Header.bfOffBits & 0x03));
+                //}
+                BMP_Header.bfSize = (h * RoundUp(w * 1,4)) + BMP_Header.bfOffBits;
+                break;
+        }
+        INFO("Offset to Bitstream %X", BMP_Header.bfOffBits);
 
         // Bytes in the line buffer
-        int lineBufSize = RoundUp(3 * w, 4);    // ((24 * w + 7)/8);
+        int lineBufSize = RoundUp(((bitsPerPixel == 24) ? 3 : 1) * w, 4);
         INFO("LineBufSize: %d", lineBufSize);
 
         BMP_Info.biSize = sizeof(BMP_Info);
         BMP_Info.biWidth = w;
         BMP_Info.biHeight = h;
         BMP_Info.biPlanes = 1;
-        BMP_Info.biBitCount = 24;
+        BMP_Info.biBitCount = bitsPerPixel;
         BMP_Info.biCompression = BI_RGB;
         BMP_Info.biSizeImage = lineBufSize * h;
         BMP_Info.biXPelsPerMeter = 0;
         BMP_Info.biYPelsPerMeter = 0;
-        BMP_Info.biClrUsed = 0;
-        BMP_Info.biClrImportant = 0;
+        // for 24-bit, there is no palette, so these are zero
+        // for 8-bit, there can be up to 256 RGB values in the palette
+        
+        BMP_Info.biClrUsed = (bitsPerPixel == 24) ? 0 : sizeof(WebColorPalette)/sizeof(WebColorPalette[0]);    // for 8b/pixel
+        BMP_Info.biClrImportant = BMP_Info.biClrUsed;
 
         // Allocate the memory we need to proceed
         lineBuffer = (uint8_t *)swMalloc(lineBufSize);
@@ -2207,6 +2236,7 @@
         }
 
         // Get the file primed...
+        /// @todo check return value for possibility of a fatal error
         privateCallback(OPEN, (uint8_t *)&BMP_Header.bfSize, 4);
 
         // Be optimistic - don't check for errors.
@@ -2217,7 +2247,16 @@
         HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
         //fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image);
         privateCallback(WRITE, (uint8_t *)&BMP_Info, sizeof(BMP_Info));
-
+        if (bitsPerPixel != 24) {
+            HexDump("Palette", (uint8_t *)&WebColorPalette, sizeof(WebColorPalette));
+            //fwrite(&WebColorPalette, sizeof(char), sizeof(WebColorPalette), Image);
+            privateCallback(WRITE, (uint8_t *)&WebColorPalette, sizeof(WebColorPalette));
+            if (0 && sizeof(WebColorPalette) % 4) {
+                const uint8_t padd[] = { 0, 0, 0 };
+                //fwrite(&padd, sizeof(char), (sizeof(BMP_Header) + sizeof(BMP_Info) + sizeof(WebColorPalette)) % 4, Image);
+                privateCallback(WRITE, (uint8_t *)&padd, (sizeof(BMP_Header) + sizeof(BMP_Info) + sizeof(WebColorPalette)) % 4);
+            }
+        }
         //color_t transparency = GetBackgroundTransparencyColor();
         LayerMode_T ltpr0 = GetLayerMode();
 
@@ -2253,8 +2292,8 @@
                     ERR("getPixelStream error, and no recovery handler...");
                 }
             }
-            INFO("1st Color: %04X", pixelBuffer[0]);
-            HexDump("Raster", (uint8_t *)pixelBuffer, w * 3);
+            INFO("Line: %3d", j);
+            //HexDump("Raster", (uint8_t *)pixelBuffer, w * sizeof(color_t));
             // Convert the local buffer to RGBQUAD format
             int lb = 0;
             for (int i=0; i<w; i++) {
@@ -2270,32 +2309,42 @@
                     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
+                        q0.rgbBlue = q0.rgbBlue | q1.rgbBlue;
+                        q0.rgbGreen = q0.rgbGreen | q1.rgbGreen;
+                        q0.rgbRed = q0.rgbRed | q1.rgbRed;
+                        break;
+                    case 5: // boolean AND
+                        q0.rgbBlue = q0.rgbBlue & q1.rgbBlue;
+                        q0.rgbGreen = q0.rgbGreen & q1.rgbGreen;
+                        q0.rgbRed = q0.rgbRed & q1.rgbRed;
+                        break;
+                }
+                switch (bitsPerPixel) {
+                    case 24:
                         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;
+                    case 8:
+                    default:
+                        lineBuffer[lb++] = FindNearestWebColor(q0.rgbRed,q0.rgbGreen,q0.rgbBlue);
                         break;
                 }
             }
-            if (j == h - 1) {
-                HexDump("LineBuffer", lineBuffer, lineBufSize);
-            }
+            //if (j == h - 1) {
+            //    HexDump("Line", lineBuffer, lineBufSize);
+            //}
             // Write to disk
             privateCallback(WRITE, (uint8_t *)lineBuffer, lineBufSize);
         }
         SelectDrawingLayer(prevLayer);
         privateCallback(CLOSE, NULL, 0);
-        
         #ifndef DOUBLEBUF
         if (pixelBuffer2)
             swFree(pixelBuffer2);
@@ -2311,6 +2360,7 @@
 }
 
 
+
 RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP, uint8_t bitsPerPixel)
 {
     BITMAPFILEHEADER BMP_Header;