Production Test Program (PTP) for the LPC4088 Experiment Base Board

Dependencies:   EALib I2S LM75B SDFileSystem mbed

Revision:
2:2f4b7535ceb3
Child:
7:48375cb50f3a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TestDisplay.cpp	Thu Aug 28 09:36:13 2014 +0000
@@ -0,0 +1,264 @@
+/*
+ *  Copyright 2013 Embedded Artists AB
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+/******************************************************************************
+ * Includes
+ *****************************************************************************/
+
+#include "mbed.h"
+#include "TestDisplay.h"
+#include "sdram.h"
+
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+
+#define LCD_CONFIGURATION \
+        40,                         /* horizontalBackPorch */ \
+        5,                          /* horizontalFrontPorch */ \
+        2,                          /* hsync */ \
+        480,                        /* width */ \
+        8,                          /* verticalBackPorch */ \
+        8,                          /* verticalFrontPorch */ \
+        2,                          /* vsync */ \
+        272,                        /* height */ \
+        false,                      /* invertOutputEnable */ \
+        false,                      /* invertPanelClock */ \
+        true,                       /* invertHsync */ \
+        true,                       /* invertVsync */ \
+        1,                          /* acBias */ \
+        LcdController::Bpp_16_565,  /* bpp */ \
+        9000000,                    /* optimalClock */ \
+        LcdController::Tft,         /* panelType */ \
+        false                       /* dualPanel */
+
+#define LCD_INIT_STRING  (char*)"v1,cd0,c50,cc0,c30,d100,c31,d100,cd1,d10,o,c51,cc100"
+
+/******************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+/*
+   Prerequisites:
+ 
+   - A display must be connected to the LPC4088 Experiment Base Board
+     with the FPC connector
+
+   - The touch controller uses the I2C bus so for this test to work 
+     jumpers JP8 and JP9 on the LPC4088 Experiment Base Board must 
+     both be in positions 1-2
+
+*/
+
+/* 
+   Test Description:
+
+   - The SDRAM is initialized and a framebuffer is allocated
+   - Display is initialized and a color bar (red-green-blue) is shown
+   - The user have 10 seconds to test display contrast by turning the
+     right trimpot on the board
+   - The touch calibration is started and the user must press each of
+     the four crosshairs that appear.
+   - After calibration the display can be drawn upon for 5 seconds.
+   
+   Any failed part test will abort the sequence
+*/
+
+TestDisplay::TestDisplay() : 
+    _lcdCfg(LCD_CONFIGURATION),
+    _lcdBoard(P0_27, P0_28),
+    _touch(P0_27, P0_28, P2_25) {
+        
+    if (sdram_init() == 1) {
+        printf("Failed to initialize SDRAM\n");
+        _framebuffer = 0;
+    } else {
+        _framebuffer = (uint32_t) malloc(_lcdCfg.width * _lcdCfg.height * 2);
+    }
+    _displayWorking = false;
+}
+
+TestDisplay::~TestDisplay() {
+    if (_framebuffer != 0) {
+        free((void*)_framebuffer);
+        _framebuffer = 0;
+    }
+}
+
+void TestDisplay::showStatus(bool success) {
+    if (_displayWorking) {
+        if (success) {
+            // Green cannot be memsetted so it will have to be the
+            // more manual way
+            uint16_t* p = (uint16_t*)_framebuffer;
+            for (int x = _lcdCfg.width; x > 0; x--) {
+                for (int y = _lcdCfg.height; y > 0; y--) {
+                    *p++ = 0x07e0;
+                }
+            }
+        } else {
+            // Red is possible to set directly as 0xe0e0 in RGB565 have
+            // only significant RED bits set.
+            memset((uint8_t*)_framebuffer, 0xe0, _lcdCfg.width * _lcdCfg.height * 2); // RED
+        }
+    }    
+}
+
+bool TestDisplay::runTest() {
+    bool testPassed = false;
+    do {
+        if (_framebuffer == 0) {
+            printf("Failed to allocate memory for framebuffer\n");
+            break;
+        }
+        
+        // Prepare framebuffer
+        drawBars();
+
+        EaLcdBoard::Result result = _lcdBoard.open(&_lcdCfg, LCD_INIT_STRING);
+        if (result != EaLcdBoard::Ok) {
+            printf("Failed to open display, error %d\n", result);
+            break;
+        }
+
+        result = _lcdBoard.setFrameBuffer(_framebuffer);
+        if (result != EaLcdBoard::Ok) {
+            printf("Failed to set framebuffer, error %d\n", result);
+            break;
+        }
+            
+        printf("Initialized. Control contrast with right trimpot (8 seconds)\n");
+        AnalogIn trimpot(p15);
+        Timer t;
+        t.start();
+        int delays = 0;
+        float last = -0.999;
+        while (t.read() < 8) {
+            float f = trimpot.read();
+            if (f != last) {
+                last = f;
+                _lcdBoard.setBC(100*f); // contrast is in 0..100 and analog value is 0.000..1.000
+            }
+            wait(0.1);
+            
+            // Countdown
+            if (delays%10 == 0) {
+                printf("%ds\n", (80-delays)/10);
+            }
+            delays++;
+        }
+        
+        int vh,vl,r,ty;
+        if (_touch.info(&vh,&vl,&r,&ty)) {
+            printf("Touch info: v%d.%d, %d-bit resolution, type 0x%x\n", vh, vl, r, ty);
+        } else {
+            printf("Failed to read touch information\n");
+            break;
+        }
+
+        printf("Calibrate display\n");
+        testPassed = calibrate_display();
+    } while(0);
+    
+    _displayWorking = testPassed;
+    return testPassed;
+}
+
+void TestDisplay::drawBars() {
+    uint16_t* p = (uint16_t*)_framebuffer;
+    int third = _lcdCfg.width/3;
+    for (int y = 0; y < _lcdCfg.height; y++) {
+        int x;
+        for (x = 0; x < third; x++) {
+            *p = 0xf800;
+            p++;
+        }
+        for (; x < 2*third; x++) {
+            *p = 0x07e0;
+            p++;
+        }
+        for (; x < _lcdCfg.width; x++) {
+            *p = 0x001f;
+            p++;
+        }
+    }
+}
+
+void TestDisplay::calibrate_drawMarker(Graphics &g, uint16_t x, uint16_t y, bool erase) {
+    uint16_t color = (erase ? 0x0000 : 0xffff);
+    g.put_line(x-15, y, x+15, y, color);
+    g.put_line(x, y-15, x, y+15, color);
+    g.put_circle(x, y, color, 10, false);
+}
+
+bool TestDisplay::calibrate_display() {
+    bool morePoints = true;
+    uint16_t x, y;
+    int point = 0;
+    Graphics g((uint16_t*)_framebuffer, _lcdCfg.width, _lcdCfg.height);
+    
+    do {
+        if (!_touch.init(_lcdCfg.width, _lcdCfg.height)) {
+            printf("Failed to initialize touch controller\n");
+            break;
+        }
+        if (!_touch.calibrateStart()) {
+            printf("Failed to start calibration\n");
+            break;
+        }  
+        while (morePoints) {
+            if (point++ > 0) {
+                // erase old location
+                calibrate_drawMarker(g, x, y, true);
+            }
+            if (!_touch.getNextCalibratePoint(&x, &y)) {
+                printf("Failed to get calibration point\n");
+                break;
+            }
+            calibrate_drawMarker(g, x, y, false);
+            if (!_touch.waitForCalibratePoint(&morePoints, 0)) {
+                printf("Failed to get user click\n");
+                break;
+            }
+        }
+        if (morePoints) {
+            // aborted calibration due to error(s)
+            break;
+        }
+
+        // erase old location
+        calibrate_drawMarker(g, x, y, true);
+
+        // allow user to draw for 5 seconds
+        Timer t;
+        t.start();
+        TouchPanel::touchCoordinate_t tc;
+        while(t.read() < 6) {
+            if (_touch.read(tc)) {
+                //printf("TC: x,y,z = {%5d, %5d, %5d}\n", tc.x, tc.y, tc.z);
+                if (tc.z) {
+                    g.put_dot(tc.x, tc.y, 0xffff);
+                }
+            }
+        }
+    } while(0);
+    
+    return !morePoints;
+}
+
+
+