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

Dependencies:   EALib I2S LM75B SDFileSystem mbed

TestDisplay.cpp

Committer:
embeddedartists
Date:
2014-10-01
Revision:
9:eb6086159020
Parent:
7:48375cb50f3a

File content as of revision 9:eb6086159020:

/*
 *  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,att;
        for (att = 1; att <= 5;att++) {
            if (_touch.info(&vh,&vl,&r,&ty)) {
                printf("Touch info: v%d.%d, %d-bit resolution, type 0x%x\n", vh, vl, r, ty);
                break;
            } else {
                printf("Attempt %d to get touch controller info failed...\n", att);
                wait(1);
            }
        }
        if (att > 5) {
            printf("Failed to read touch controller info even after %d attempts\n", att);
            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;
}