A library with drivers for different peripherals on the LPC4088 QuickStart Board or related add-on boards.

Dependencies:   FATFileSystem

Dependents:   LPC4088test LPC4088test_ledonly LPC4088test_deleteall LPC4088_RAMtest ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers LcdController.cpp Source File

LcdController.cpp

00001 /*
00002  *  Copyright 2013 Embedded Artists AB
00003  *
00004  *  Licensed under the Apache License, Version 2.0 (the "License");
00005  *  you may not use this file except in compliance with the License.
00006  *  You may obtain a copy of the License at
00007  *
00008  *    http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  *  Unless required by applicable law or agreed to in writing, software
00011  *  distributed under the License is distributed on an "AS IS" BASIS,
00012  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *  See the License for the specific language governing permissions and
00014  *  limitations under the License.
00015  */
00016 
00017 /******************************************************************************
00018  * Includes
00019  *****************************************************************************/
00020 
00021 #include "mbed.h"
00022 #include "LcdController.h"
00023 
00024 /******************************************************************************
00025  * Defines and typedefs
00026  *****************************************************************************/
00027 
00028 #undef _SBF
00029 #define _SBF(p,v) (((uint32_t)(v)) << (p))
00030 
00031 #undef _BITMASK
00032 #define _BITMASK(field_width) (_BIT(field_width) - 1)
00033 
00034 #undef _BIT
00035 #define _BIT(p) (((uint32_t)(1)) << (p))
00036 
00037 /***********************************************************************
00038  * Color LCD controller horizontal axis plane control register definitions
00039  **********************************************************************/
00040 
00041 /* LCD controller horizontal axis plane control register pixels per line */
00042 #define CLCDC_LCDTIMING0_PPL_WIDTH 6
00043 #define CLCDC_LCDTIMING0_PPL(n) _SBF(2, (((n) / 16) - 1) & _BITMASK(CLCDC_LCDTIMING0_PPL_WIDTH))
00044 /* LCD controller horizontal axis plane control register HSYNC pulse width */
00045 #define CLCDC_LCDTIMING0_HSW_WIDTH 8
00046 #define CLCDC_LCDTIMING0_HSW(n) _SBF(8, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING0_HSW_WIDTH))
00047 /* LCD controller horizontal axis plane control register horizontal front porch */
00048 #define CLCDC_LCDTIMING0_HFP_WIDTH 8
00049 #define CLCDC_LCDTIMING0_HFP(n) _SBF(16, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING0_HFP_WIDTH))
00050 /* LCD controller horizontal axis plane control register horizontal back porch */
00051 #define CLCDC_LCDTIMING0_HBP_WIDTH 8
00052 #define CLCDC_LCDTIMING0_HBP(n) _SBF(24, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING0_HBP_WIDTH))
00053 
00054 /***********************************************************************
00055  * Color LCD controller vertical axis plane control register definitions
00056  **********************************************************************/
00057 
00058 /* LCD controller vertical axis plane control register lines per panel */
00059 #define CLCDC_LCDTIMING1_LPP_WIDTH 10
00060 #define CLCDC_LCDTIMING1_LPP(n) _SBF(0, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING1_LPP_WIDTH))
00061 /* LCD controller vertical axis plane control register VSYNC pulse width */
00062 #define CLCDC_LCDTIMING1_VSW_WIDTH 6
00063 #define CLCDC_LCDTIMING1_VSW(n) _SBF(10, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING1_VSW_WIDTH))
00064 /* LCD controller vertical axis plane control register vertical front porch */
00065 #define CLCDC_LCDTIMING1_VFP_WIDTH 8
00066 #define CLCDC_LCDTIMING1_VFP(n) _SBF(16, (n) & _BITMASK(CLCDC_LCDTIMING1_VFP_WIDTH))
00067 /* LCD controller vertical axis plane control register vertical back porch */
00068 #define CLCDC_LCDTIMING1_VBP_WIDTH 8
00069 #define CLCDC_LCDTIMING1_VBP(n) _SBF(24, (n) & _BITMASK(CLCDC_LCDTIMING1_VBP_WIDTH))
00070 
00071 /***********************************************************************
00072  * Color LCD controller clock and signal polarity control register definitions
00073  **********************************************************************/
00074 
00075 /* LCD controller clock and signal polarity control register panel clock divisor low*/
00076 #define CLCDC_LCDTIMING2_PCD_LO_WIDTH 5
00077 #define CLCDC_LCDTIMING2_PCD_LO(n) _SBF(0, ((n) - 2) & _BITMASK(CLCDC_LCDTIMING2_PCD_LO_WIDTH))
00078 /* LCD controller clock and signal polarity control register clock select */
00079 #define CLCDC_LCDTIMING2_CLKSEL _BIT(5)
00080 /* LCD controller clock and signal polarity control register AC bias pin frequency */
00081 #define CLCDC_LCDTIMING2_ACB_WIDTH 5
00082 #define CLCDC_LCDTIMING2_ACB(n) _SBF(6, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING2_ACB_WIDTH))
00083 /* LCD controller clock and signal polarity control register invert VSYNC */
00084 #define CLCDC_LCDTIMING2_IVS    _BIT(11)
00085 /* LCD controller clock and signal polarity control register invert HSYNC */
00086 #define CLCDC_LCDTIMING2_IHS    _BIT(12)
00087 /* LCD controller clock and signal polarity control register invert plane clock */
00088 #define CLCDC_LCDTIMING2_IPC    _BIT(13)
00089 /* LCD controller clock and signal polarity control register invert output enable */
00090 #define CLCDC_LCDTIMING2_IOE    _BIT(14)
00091 /* LCD controller clock and signal polarity control register clocks per line */
00092 #define CLCDC_LCDTIMING2_CPL_WIDTH 10
00093 #define CLCDC_LCDTIMING2_CPL(n) _SBF(16, (n) & _BITMASK(CLCDC_LCDTIMING2_CPL_WIDTH))
00094 /* LCD controller clock and signal polarity control register bypass pixel clock divider */
00095 #define CLCDC_LCDTIMING2_BCD    _BIT(26)
00096 /* LCD controller clock and signal polarity control register panel clock divisor high*/
00097 #define CLCDC_LCDTIMING2_PCD_HI_WIDTH 5
00098 #define CLCDC_LCDTIMING2_PCD_HI(n) _SBF((27 - CLCDC_LCDTIMING2_PCD_LO_WIDTH), ((n) - 2) & _SBF(CLCDC_LCDTIMING2_PCD_LO_WIDTH, _BITMASK(CLCDC_LCDTIMING2_PCD_HI_WIDTH)))
00099 
00100 
00101 /***********************************************************************
00102  * Color LCD controller control register definitions
00103  **********************************************************************/
00104 
00105 /* LCD control enable bit */
00106 #define CLCDC_LCDCTRL_ENABLE    (1<<0)
00107 /* LCD control 1 bit per pixel bit field */
00108 #define CLCDC_LCDCTRL_BPP1      (0 << 1)
00109 /* LCD control 2 bits per pixel bit field */
00110 #define CLCDC_LCDCTRL_BPP2      (1 << 1)
00111 /* LCD control 4 bits per pixel bit field */
00112 #define CLCDC_LCDCTRL_BPP4      (2 << 1)
00113 /* LCD control 8 bits per pixel bit field */
00114 #define CLCDC_LCDCTRL_BPP8      (3 << 1)
00115 /* LCD control 16 bits per pixel bit field */
00116 #define CLCDC_LCDCTRL_BPP16     (4 << 1)
00117 /* LCD control 24 bits per pixel bit field */
00118 #define CLCDC_LCDCTRL_BPP24     (5 << 1)
00119 /* LCD control 16 bits (5:6:5 mode) per pixel bit field */
00120 #define CLCDC_LCDCTRL_BPP16_565_MODE (6 << 1)
00121 /* LCD control 12 bits (4:4:4 mode) per pixel bit field */
00122 #define CLCDC_LCDCTRL_BPP12_444_MODE (7 << 1)
00123 /* LCD control mono select bit */
00124 #define CLCDC_LCDCTRL_BW_COLOR  (0 << 4)
00125 #define CLCDC_LCDCTRL_BW_MONO   (1 << 4)
00126 /* LCD controler TFT select bit */
00127 #define CLCDC_LCDCTRL_TFT       (1 << 5)
00128 /* LCD control monochrome LCD has 4-bit/8-bit select bit */
00129 #define CLCDC_LCDCTRL_MON8      (1 << 6)
00130 /* LCD control dual panel select bit */
00131 #define CLCDC_LCDCTRL_DUAL      (1 << 7)
00132 /* LCD control RGB or BGR format select bit */
00133 #define CLCDC_LCDCTRL_RGB       (0 << 8)
00134 #define CLCDC_LCDCTRL_BGR       (1 << 8)
00135 /* LCD control big-endian byte order select bit */
00136 #define CLCDC_LCDCTRL_BEBO      (1 << 9)
00137 /* LCD control big-endian pixel order within a byte select bit */
00138 #define CLCDC_LCDCTRL_BEPO      (1 << 10)
00139 /* LCD control power enable bit */
00140 #define CLCDC_LCDCTRL_PWR       (1 << 11)
00141 /* LCD control VCOMP interrupt is start of VSYNC */
00142 #define CLCDC_LCDCTRL_VCOMP_VS  (0 << 12)
00143 /* LCD control VCOMP interrupt is start of back porch */
00144 #define CLCDC_LCDCTRL_VCOMP_BP  (1 << 12)
00145 /* LCD control VCOMP interrupt is start of active video */
00146 #define CLCDC_LCDCTRL_VCOMP_AV  (2 << 12)
00147 /* LCD control VCOMP interrupt is start of front porch */
00148 #define CLCDC_LCDCTRL_VCOMP_FP  (3 << 12)
00149 /* LCD control watermark level is 8 or more words free bit */
00150 #define CLCDC_LCDCTRL_WATERMARK (1 << 16)
00151 
00152 
00153 
00154 bool LcdController::_lcdControllerUsed = false;
00155 
00156 LcdController::LcdController() {
00157   _opened = false;
00158 }
00159 
00160 int LcdController::open(LcdController::Config* cfg) {
00161     if (_lcdControllerUsed) return 1;
00162     if (cfg == NULL) return 1;
00163 
00164     // enable power for LCD controller
00165     LPC_SC->PCONP |= 0x00000001;
00166 
00167     pinConfig();
00168     init(cfg);
00169 
00170     // only one instance at a time is allowed to be used
00171     _lcdControllerUsed = true;
00172     _opened = true;
00173 
00174     return 0;
00175 }
00176 
00177 int LcdController::close() {
00178 
00179     if (!_opened) return 1;
00180 
00181     if (_lcdControllerUsed) {
00182 
00183         // disable power for LCD controller
00184         LPC_SC->PCONP &= ~(0x00000001);
00185 
00186         _lcdControllerUsed = false;
00187         _opened = false;
00188     }
00189 
00190 
00191     return 0;
00192 }
00193 
00194 int LcdController::setFrameBuffer(uint32_t address) {
00195     if (!_opened) return 1;
00196 
00197     LPC_LCD->UPBASE = address;
00198 
00199     return 0;
00200 }
00201 
00202 int LcdController::setPower(bool on) {
00203     if (!_opened) return 1;
00204 
00205     if (on) {
00206         LPC_LCD->CTRL |= CLCDC_LCDCTRL_ENABLE;
00207         LPC_LCD->CTRL |= CLCDC_LCDCTRL_PWR;
00208     }
00209     else {
00210         LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_PWR;
00211         LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_ENABLE;
00212     }
00213 
00214     return 0;
00215 }
00216 
00217 void LcdController::init(LcdController::Config* cfg) {
00218     uint32_t tmp, i;
00219 
00220     // Disable the display in case it is on
00221     LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_ENABLE;
00222 
00223     // Generate the horizontal axis plane control word
00224     tmp = (CLCDC_LCDTIMING0_PPL(cfg->width) |
00225             CLCDC_LCDTIMING0_HSW(cfg->hsync) |
00226             CLCDC_LCDTIMING0_HFP(cfg->horizontalFrontPorch) |
00227             CLCDC_LCDTIMING0_HBP(cfg->horizontalBackPorch));
00228     LPC_LCD->TIMH = tmp;
00229 
00230     // Generate the vertical axis plane control word
00231     tmp = (CLCDC_LCDTIMING1_LPP(cfg->height) |
00232             CLCDC_LCDTIMING1_VSW(cfg->vsync) |
00233             CLCDC_LCDTIMING1_VFP(cfg->verticalFrontPorch) |
00234             CLCDC_LCDTIMING1_VBP(cfg->verticalBackPorch));
00235     LPC_LCD->TIMV = tmp;
00236 
00237     // Generate the clock and signal polarity control word
00238     if(cfg->acBias != 0)
00239     {
00240         /* STN panel has AC bias value */
00241         tmp = CLCDC_LCDTIMING2_ACB(cfg->acBias);
00242     }
00243     else
00244     {
00245         tmp = 0;
00246     }
00247 
00248     if (cfg->invertOutputEnable)
00249     {
00250         tmp |= CLCDC_LCDTIMING2_IOE;
00251     }
00252 
00253     if (cfg->invertPanelClock)
00254     {
00255         tmp |= CLCDC_LCDTIMING2_IPC;
00256     }
00257 
00258     if (cfg->invertHsync)
00259     {
00260         tmp |= CLCDC_LCDTIMING2_IHS;
00261     }
00262 
00263     if (cfg->invertVsync)
00264     {
00265         tmp |= CLCDC_LCDTIMING2_IVS;
00266     }
00267 
00268     // Compute clocks per line based on panel type
00269     switch (cfg->panelType)
00270     {
00271     case Mono_4Bit:
00272         // Clocks per line is a quarter of pixels per line
00273         tmp = tmp | CLCDC_LCDTIMING2_CPL((cfg->width / 4) - 1);
00274         break;
00275 
00276     case Mono_8Bit:
00277         // Clocks per line is an eighth of pixels per line
00278         tmp = tmp | CLCDC_LCDTIMING2_CPL((cfg->width / 8) - 1);
00279         break;
00280 
00281     case ColorStn:
00282         // CSTN Clocks per line (* 3 / 8)
00283         tmp = tmp | CLCDC_LCDTIMING2_CPL(((cfg->width * 3) / 8) - 1);
00284         break;
00285 
00286     case Tft:
00287     case AdTft:
00288     case HrTft:
00289     default:
00290         // Clocks per line and pixels per line are the same
00291         tmp = tmp | CLCDC_LCDTIMING2_CPL(cfg->width - 1);
00292         break;
00293     }
00294 
00295     // clock
00296     tmp = tmp | getClockDivisor(cfg->optimalClock);
00297 
00298     LPC_LCD->POL = tmp;
00299 
00300     // Skip line end control word - just set to 0x0
00301     LPC_LCD->LE = 0x00000000;
00302 
00303     // Default with all interrupts of
00304     LPC_LCD->INTMSK = 0x00000000;
00305 
00306 
00307     switch(cfg->bpp) {
00308     case Bpp_1:
00309         tmp = CLCDC_LCDCTRL_BPP1;
00310         break;
00311     case Bpp_2:
00312         tmp = CLCDC_LCDCTRL_BPP2;
00313         break;
00314     case Bpp_4:
00315         tmp = CLCDC_LCDCTRL_BPP4;
00316         break;
00317     case Bpp_8:
00318         tmp = CLCDC_LCDCTRL_BPP8;
00319         break;
00320     case Bpp_16:
00321         tmp = CLCDC_LCDCTRL_BPP16;
00322         break;
00323     case Bpp_24:
00324         tmp = CLCDC_LCDCTRL_BPP24;
00325         break;
00326     case Bpp_16_565:
00327         tmp = CLCDC_LCDCTRL_BPP16_565_MODE;
00328         break;
00329     case Bpp_12_444:
00330         tmp = CLCDC_LCDCTRL_BPP12_444_MODE;
00331         break;
00332     default:
00333         tmp = CLCDC_LCDCTRL_BPP16_565_MODE;
00334         break;
00335     }
00336 
00337     // red and blue swapped
00338     tmp |= CLCDC_LCDCTRL_BGR;
00339 
00340     switch (cfg->panelType)
00341     {
00342     case AdTft:
00343     case HrTft:
00344     case Tft:
00345         tmp |= CLCDC_LCDCTRL_TFT;
00346         break;
00347 
00348     case Mono_4Bit:
00349         tmp |= CLCDC_LCDCTRL_BW_MONO;
00350         break;
00351 
00352     case Mono_8Bit:
00353         tmp |= (CLCDC_LCDCTRL_MON8 | CLCDC_LCDCTRL_BW_MONO);
00354         break;
00355 
00356     case ColorStn:
00357         ;
00358         break;
00359 
00360     default:
00361         // Unsupported panel type
00362         break;
00363     }
00364 
00365     // Dual panel operation
00366     if (cfg->dualPanel)
00367     {
00368         tmp |= CLCDC_LCDCTRL_DUAL;
00369     }
00370 
00371     LPC_LCD->CTRL = tmp;
00372 
00373     // clear the palette (color is black )
00374     for (i = 0; i < sizeof(LPC_LCD->PAL)/sizeof(LPC_LCD->PAL[0]); i++)
00375     {
00376         LPC_LCD->PAL[i] = 0;
00377     }
00378 
00379     LPC_SC->LCD_CFG = 0x0;
00380 
00381 }
00382 
00383 void LcdController::pinConfig() {
00384 
00385     LPC_IOCON->P0_4 |= 7; /* LCD_VD_0 @ P0.4 */
00386     LPC_IOCON->P0_5 |= 7; /* LCD_VD_1 @ P0.5 */
00387     LPC_IOCON->P0_6 |= 7; /* LCD_VD_8 @ P0.6 */
00388     LPC_IOCON->P0_7 |= 7; /* LCD_VD_9 @ P0.7 */
00389     LPC_IOCON->P0_8 |= 7; /* LCD_VD_16 @ P0.8 */
00390     LPC_IOCON->P0_9 |= 7; /* LCD_VD_17 @ P0.9 */
00391     LPC_IOCON->P0_10 |= 7; /* LCD_VD_5 @ P0.10 */  /* LPC4088 */
00392 
00393 #ifdef LPC4088_OEM
00394     LPC_IOCON->P1_20 |= 7; /* LCD_VD_10 @ P1.20 */
00395     LPC_IOCON->P1_23 |= 7; /* LCD_VD_13 @ P1.23 */
00396     LPC_IOCON->P1_24 |= 7; /* LCD_VD_14 @ P1.24 */
00397 #else
00398     LPC_IOCON->P0_11 |= 7; /* LCD_VD_10 @ P0.11 */
00399     LPC_IOCON->P0_19 |= 7; /* LCD_VD_13 @ P0.19 */
00400     LPC_IOCON->P0_20 |= 7; /* LCD_VD_14 @ P0.20 */
00401 #endif
00402 
00403     LPC_IOCON->P1_21 |= 7; /* LCD_VD_11 @ P1.21 */
00404     LPC_IOCON->P1_22 |= 7; /* LCD_VD_12 @ P1.22 */
00405 
00406     LPC_IOCON->P1_25 |= 7; /* LCD_VD_15 @ P1.25 */
00407     LPC_IOCON->P1_26 |= 7; /* LCD_VD_20 @ P1.26 */
00408     LPC_IOCON->P1_27 |= 7; /* LCD_VD_21 @ P1.27 */
00409     LPC_IOCON->P1_28 |= 7; /* LCD_VD_22 @ P1.28 */
00410     LPC_IOCON->P1_29 |= 7; /* LCD_VD_23 @ P1.29 */
00411 
00412     // pwr always controlled by gpio
00413 //    LPC_IOCON->P2_0 |= 7; /* LCD_PWR @ P2.0 */
00414 //    LPC_IOCON->P2_1 |= 7; /* LCD_LE  @ P2.1 */  /* Never Used */
00415     LPC_IOCON->P2_2 |= 7; /* LCD_DCLK @ P2.2 */
00416     LPC_IOCON->P2_3 |= 7; /* LCD_FP @ P2.3 */
00417     LPC_IOCON->P2_4 |= 7; /* LCD_ENAB_M @ P2.4 */
00418     LPC_IOCON->P2_5 |= 7; /* LCD_LP @ P2.5 */
00419     LPC_IOCON->P2_6 |= 7; /* LCD_VD_4 @ P2.6 */
00420     //LPC_IOCON->P2_7 |= 7; /* LCD_VD_5 @ P2.7 */  /* LPC4088 */
00421     LPC_IOCON->P2_8 |= 7; /* LCD_VD_6 @ P2.8 */
00422     LPC_IOCON->P2_9 |= 7; /* LCD_VD_7 @ P2.9 */
00423 
00424     LPC_IOCON->P2_11 |= 7; /* LCD_CLKIN @ P2.11 */
00425     LPC_IOCON->P2_12 |= 5; /* LCD_VD_3 @ P2.12 Signal marked as LCD_VD_18 on base board, but shall carry the LCD_VD_3 signal */
00426     LPC_IOCON->P2_13 |= 7; /* LCD_VD_19 @ P2.13 */
00427 }
00428 
00429 uint32_t LcdController::getClockDivisor(int clock) {
00430     uint32_t pixel_div, tmp = 0;
00431     uint32_t clk;
00432 
00433     clk = SystemCoreClock;
00434 
00435     // Find closest clock divider to get clock rate
00436     pixel_div = 1;
00437     while (((clk / pixel_div) > clock) && (pixel_div <= 0x3F))
00438     {
00439       pixel_div++;
00440     }
00441 
00442     if (pixel_div <= 1)
00443     {
00444       // Pixel clock divider is 1, skip divider logic
00445       tmp = CLCDC_LCDTIMING2_BCD;
00446     }
00447     else
00448     {
00449       // Add in new divider
00450       pixel_div -= 2;
00451 
00452       tmp |= (((pixel_div >> 0) & 0x1F)
00453              | (((pixel_div >> 5) & 0x1F) << 27));
00454     }
00455 
00456     return tmp;
00457 }
00458 
00459