Small changes
Dependencies: FATFileSystem
Fork of EALib by
Diff: LcdController.cpp
- Revision:
- 0:0fdadbc3d852
- Child:
- 4:b32cf4ef45c5
diff -r 000000000000 -r 0fdadbc3d852 LcdController.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LcdController.cpp Thu Sep 26 06:37:02 2013 +0000 @@ -0,0 +1,437 @@ + +#include "mbed.h" +#include "LcdController.h" + +#undef _SBF +#define _SBF(p,v) (((uint32_t)(v)) << (p)) + +#undef _BITMASK +#define _BITMASK(field_width) (_BIT(field_width) - 1) + +#undef _BIT +#define _BIT(p) (((uint32_t)(1)) << (p)) + +/*********************************************************************** + * Color LCD controller horizontal axis plane control register definitions + **********************************************************************/ + +/* LCD controller horizontal axis plane control register pixels per line */ +#define CLCDC_LCDTIMING0_PPL_WIDTH 6 +#define CLCDC_LCDTIMING0_PPL(n) _SBF(2, (((n) / 16) - 1) & _BITMASK(CLCDC_LCDTIMING0_PPL_WIDTH)) +/* LCD controller horizontal axis plane control register HSYNC pulse width */ +#define CLCDC_LCDTIMING0_HSW_WIDTH 8 +#define CLCDC_LCDTIMING0_HSW(n) _SBF(8, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING0_HSW_WIDTH)) +/* LCD controller horizontal axis plane control register horizontal front porch */ +#define CLCDC_LCDTIMING0_HFP_WIDTH 8 +#define CLCDC_LCDTIMING0_HFP(n) _SBF(16, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING0_HFP_WIDTH)) +/* LCD controller horizontal axis plane control register horizontal back porch */ +#define CLCDC_LCDTIMING0_HBP_WIDTH 8 +#define CLCDC_LCDTIMING0_HBP(n) _SBF(24, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING0_HBP_WIDTH)) + +/*********************************************************************** + * Color LCD controller vertical axis plane control register definitions + **********************************************************************/ + +/* LCD controller vertical axis plane control register lines per panel */ +#define CLCDC_LCDTIMING1_LPP_WIDTH 10 +#define CLCDC_LCDTIMING1_LPP(n) _SBF(0, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING1_LPP_WIDTH)) +/* LCD controller vertical axis plane control register VSYNC pulse width */ +#define CLCDC_LCDTIMING1_VSW_WIDTH 6 +#define CLCDC_LCDTIMING1_VSW(n) _SBF(10, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING1_VSW_WIDTH)) +/* LCD controller vertical axis plane control register vertical front porch */ +#define CLCDC_LCDTIMING1_VFP_WIDTH 8 +#define CLCDC_LCDTIMING1_VFP(n) _SBF(16, (n) & _BITMASK(CLCDC_LCDTIMING1_VFP_WIDTH)) +/* LCD controller vertical axis plane control register vertical back porch */ +#define CLCDC_LCDTIMING1_VBP_WIDTH 8 +#define CLCDC_LCDTIMING1_VBP(n) _SBF(24, (n) & _BITMASK(CLCDC_LCDTIMING1_VBP_WIDTH)) + +/*********************************************************************** + * Color LCD controller clock and signal polarity control register definitions + **********************************************************************/ + +/* LCD controller clock and signal polarity control register panel clock divisor low*/ +#define CLCDC_LCDTIMING2_PCD_LO_WIDTH 5 +#define CLCDC_LCDTIMING2_PCD_LO(n) _SBF(0, ((n) - 2) & _BITMASK(CLCDC_LCDTIMING2_PCD_LO_WIDTH)) +/* LCD controller clock and signal polarity control register clock select */ +#define CLCDC_LCDTIMING2_CLKSEL _BIT(5) +/* LCD controller clock and signal polarity control register AC bias pin frequency */ +#define CLCDC_LCDTIMING2_ACB_WIDTH 5 +#define CLCDC_LCDTIMING2_ACB(n) _SBF(6, ((n) - 1) & _BITMASK(CLCDC_LCDTIMING2_ACB_WIDTH)) +/* LCD controller clock and signal polarity control register invert VSYNC */ +#define CLCDC_LCDTIMING2_IVS _BIT(11) +/* LCD controller clock and signal polarity control register invert HSYNC */ +#define CLCDC_LCDTIMING2_IHS _BIT(12) +/* LCD controller clock and signal polarity control register invert plane clock */ +#define CLCDC_LCDTIMING2_IPC _BIT(13) +/* LCD controller clock and signal polarity control register invert output enable */ +#define CLCDC_LCDTIMING2_IOE _BIT(14) +/* LCD controller clock and signal polarity control register clocks per line */ +#define CLCDC_LCDTIMING2_CPL_WIDTH 10 +#define CLCDC_LCDTIMING2_CPL(n) _SBF(16, (n) & _BITMASK(CLCDC_LCDTIMING2_CPL_WIDTH)) +/* LCD controller clock and signal polarity control register bypass pixel clock divider */ +#define CLCDC_LCDTIMING2_BCD _BIT(26) +/* LCD controller clock and signal polarity control register panel clock divisor high*/ +#define CLCDC_LCDTIMING2_PCD_HI_WIDTH 5 +#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))) + + +/*********************************************************************** + * Color LCD controller control register definitions + **********************************************************************/ + +/* LCD control enable bit */ +#define CLCDC_LCDCTRL_ENABLE (1<<0) +/* LCD control 1 bit per pixel bit field */ +#define CLCDC_LCDCTRL_BPP1 (0 << 1) +/* LCD control 2 bits per pixel bit field */ +#define CLCDC_LCDCTRL_BPP2 (1 << 1) +/* LCD control 4 bits per pixel bit field */ +#define CLCDC_LCDCTRL_BPP4 (2 << 1) +/* LCD control 8 bits per pixel bit field */ +#define CLCDC_LCDCTRL_BPP8 (3 << 1) +/* LCD control 16 bits per pixel bit field */ +#define CLCDC_LCDCTRL_BPP16 (4 << 1) +/* LCD control 24 bits per pixel bit field */ +#define CLCDC_LCDCTRL_BPP24 (5 << 1) +/* LCD control 16 bits (5:6:5 mode) per pixel bit field */ +#define CLCDC_LCDCTRL_BPP16_565_MODE (6 << 1) +/* LCD control 12 bits (4:4:4 mode) per pixel bit field */ +#define CLCDC_LCDCTRL_BPP12_444_MODE (7 << 1) +/* LCD control mono select bit */ +#define CLCDC_LCDCTRL_BW_COLOR (0 << 4) +#define CLCDC_LCDCTRL_BW_MONO (1 << 4) +/* LCD controler TFT select bit */ +#define CLCDC_LCDCTRL_TFT (1 << 5) +/* LCD control monochrome LCD has 4-bit/8-bit select bit */ +#define CLCDC_LCDCTRL_MON8 (1 << 6) +/* LCD control dual panel select bit */ +#define CLCDC_LCDCTRL_DUAL (1 << 7) +/* LCD control RGB or BGR format select bit */ +#define CLCDC_LCDCTRL_RGB (0 << 8) +#define CLCDC_LCDCTRL_BGR (1 << 8) +/* LCD control big-endian byte order select bit */ +#define CLCDC_LCDCTRL_BEBO (1 << 9) +/* LCD control big-endian pixel order within a byte select bit */ +#define CLCDC_LCDCTRL_BEPO (1 << 10) +/* LCD control power enable bit */ +#define CLCDC_LCDCTRL_PWR (1 << 11) +/* LCD control VCOMP interrupt is start of VSYNC */ +#define CLCDC_LCDCTRL_VCOMP_VS (0 << 12) +/* LCD control VCOMP interrupt is start of back porch */ +#define CLCDC_LCDCTRL_VCOMP_BP (1 << 12) +/* LCD control VCOMP interrupt is start of active video */ +#define CLCDC_LCDCTRL_VCOMP_AV (2 << 12) +/* LCD control VCOMP interrupt is start of front porch */ +#define CLCDC_LCDCTRL_VCOMP_FP (3 << 12) +/* LCD control watermark level is 8 or more words free bit */ +#define CLCDC_LCDCTRL_WATERMARK (1 << 16) + + + +bool LcdController::_lcdControllerUsed = false; + +LcdController::LcdController() { + _opened = false; +} + +int LcdController::open(LcdController::Config* cfg) { + if (_lcdControllerUsed) return 1; + if (cfg == NULL) return 1; + + // enable power for LCD controller + LPC_SC->PCONP |= 0x00000001; + + pinConfig(); + init(cfg); + + // only one instance at a time is allowed to be used + _lcdControllerUsed = true; + _opened = true; + + return 0; +} + +int LcdController::close() { + + if (!_opened) return 1; + + if (_lcdControllerUsed) { + + // disable power for LCD controller + LPC_SC->PCONP &= ~(0x00000001); + + _lcdControllerUsed = false; + _opened = false; + } + + + return 0; +} + +int LcdController::setFrameBuffer(uint32_t address) { + if (!_opened) return 1; + + LPC_LCD->UPBASE = address; + + return 0; +} + +int LcdController::setPower(bool on) { + if (!_opened) return 1; + + if (on) { + LPC_LCD->CTRL |= CLCDC_LCDCTRL_ENABLE; + LPC_LCD->CTRL |= CLCDC_LCDCTRL_PWR; + } + else { + LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_PWR; + LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_ENABLE; + } + + return 0; +} + +void LcdController::init(LcdController::Config* cfg) { + uint32_t tmp, i; + + // Disable the display in case it is on + LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_ENABLE; + + // Generate the horizontal axis plane control word + tmp = (CLCDC_LCDTIMING0_PPL(cfg->width) | + CLCDC_LCDTIMING0_HSW(cfg->hsync) | + CLCDC_LCDTIMING0_HFP(cfg->horizontalFrontPorch) | + CLCDC_LCDTIMING0_HBP(cfg->horizontalBackPorch)); + LPC_LCD->TIMH = tmp; + + // Generate the vertical axis plane control word + tmp = (CLCDC_LCDTIMING1_LPP(cfg->height) | + CLCDC_LCDTIMING1_VSW(cfg->vsync) | + CLCDC_LCDTIMING1_VFP(cfg->verticalFrontPorch) | + CLCDC_LCDTIMING1_VBP(cfg->verticalBackPorch)); + LPC_LCD->TIMV = tmp; + + // Generate the clock and signal polarity control word + if(cfg->acBias != 0) + { + /* STN panel has AC bias value */ + tmp = CLCDC_LCDTIMING2_ACB(cfg->acBias); + } + else + { + tmp = 0; + } + + if (cfg->invertOutputEnable) + { + tmp |= CLCDC_LCDTIMING2_IOE; + } + + if (cfg->invertPanelClock) + { + tmp |= CLCDC_LCDTIMING2_IPC; + } + + if (cfg->invertHsync) + { + tmp |= CLCDC_LCDTIMING2_IHS; + } + + if (cfg->invertVsync) + { + tmp |= CLCDC_LCDTIMING2_IVS; + } + + // Compute clocks per line based on panel type + switch (cfg->panelType) + { + case Mono_4Bit: + // Clocks per line is a quarter of pixels per line + tmp = tmp | CLCDC_LCDTIMING2_CPL((cfg->width / 4) - 1); + break; + + case Mono_8Bit: + // Clocks per line is an eighth of pixels per line + tmp = tmp | CLCDC_LCDTIMING2_CPL((cfg->width / 8) - 1); + break; + + case ColorStn: + // CSTN Clocks per line (* 3 / 8) + tmp = tmp | CLCDC_LCDTIMING2_CPL(((cfg->width * 3) / 8) - 1); + break; + + case Tft: + case AdTft: + case HrTft: + default: + // Clocks per line and pixels per line are the same + tmp = tmp | CLCDC_LCDTIMING2_CPL(cfg->width - 1); + break; + } + + // clock + tmp = tmp | getClockDivisor(cfg->optimalClock); + + LPC_LCD->POL = tmp; + + // Skip line end control word - just set to 0x0 + LPC_LCD->LE = 0x00000000; + + // Default with all interrupts of + LPC_LCD->INTMSK = 0x00000000; + + + switch(cfg->bpp) { + case Bpp_1: + tmp = CLCDC_LCDCTRL_BPP1; + break; + case Bpp_2: + tmp = CLCDC_LCDCTRL_BPP2; + break; + case Bpp_4: + tmp = CLCDC_LCDCTRL_BPP4; + break; + case Bpp_8: + tmp = CLCDC_LCDCTRL_BPP8; + break; + case Bpp_16: + tmp = CLCDC_LCDCTRL_BPP16; + break; + case Bpp_24: + tmp = CLCDC_LCDCTRL_BPP24; + break; + case Bpp_16_565: + tmp = CLCDC_LCDCTRL_BPP16_565_MODE; + break; + case Bpp_12_444: + tmp = CLCDC_LCDCTRL_BPP12_444_MODE; + break; + default: + tmp = CLCDC_LCDCTRL_BPP16_565_MODE; + break; + } + + // red and blue swapped + tmp |= CLCDC_LCDCTRL_BGR; + + switch (cfg->panelType) + { + case AdTft: + case HrTft: + case Tft: + tmp |= CLCDC_LCDCTRL_TFT; + break; + + case Mono_4Bit: + tmp |= CLCDC_LCDCTRL_BW_MONO; + break; + + case Mono_8Bit: + tmp |= (CLCDC_LCDCTRL_MON8 | CLCDC_LCDCTRL_BW_MONO); + break; + + case ColorStn: + ; + break; + + default: + // Unsupported panel type + break; + } + + // Dual panel operation + if (cfg->dualPanel) + { + tmp |= CLCDC_LCDCTRL_DUAL; + } + + LPC_LCD->CTRL = tmp; + + // clear the palette (color is black ) + for (i = 0; i < sizeof(LPC_LCD->PAL)/sizeof(LPC_LCD->PAL[0]); i++) + { + LPC_LCD->PAL[i] = 0; + } + + LPC_SC->LCD_CFG = 0x0; + +} + +void LcdController::pinConfig() { + + LPC_IOCON->P0_4 |= 7; /* LCD_VD_0 @ P0.4 */ + LPC_IOCON->P0_5 |= 7; /* LCD_VD_1 @ P0.5 */ + LPC_IOCON->P0_6 |= 7; /* LCD_VD_8 @ P0.6 */ + LPC_IOCON->P0_7 |= 7; /* LCD_VD_9 @ P0.7 */ + LPC_IOCON->P0_8 |= 7; /* LCD_VD_16 @ P0.8 */ + LPC_IOCON->P0_9 |= 7; /* LCD_VD_17 @ P0.9 */ + LPC_IOCON->P0_10 |= 7; /* LCD_VD_5 @ P0.10 */ /* LPC4088 */ + +#ifdef LPC4088_OEM + LPC_IOCON->P1_20 |= 7; /* LCD_VD_10 @ P1.20 */ + LPC_IOCON->P1_23 |= 7; /* LCD_VD_13 @ P1.23 */ + LPC_IOCON->P1_24 |= 7; /* LCD_VD_14 @ P1.24 */ +#else + LPC_IOCON->P0_11 |= 7; /* LCD_VD_10 @ P0.11 */ + LPC_IOCON->P0_19 |= 7; /* LCD_VD_13 @ P0.19 */ + LPC_IOCON->P0_20 |= 7; /* LCD_VD_14 @ P0.20 */ +#endif + + LPC_IOCON->P1_21 |= 7; /* LCD_VD_11 @ P1.21 */ + LPC_IOCON->P1_22 |= 7; /* LCD_VD_12 @ P1.22 */ + + LPC_IOCON->P1_25 |= 7; /* LCD_VD_15 @ P1.25 */ + LPC_IOCON->P1_26 |= 7; /* LCD_VD_20 @ P1.26 */ + LPC_IOCON->P1_27 |= 7; /* LCD_VD_21 @ P1.27 */ + LPC_IOCON->P1_28 |= 7; /* LCD_VD_22 @ P1.28 */ + LPC_IOCON->P1_29 |= 7; /* LCD_VD_23 @ P1.29 */ + + LPC_IOCON->P2_0 |= 7; /* LCD_PWR @ P2.0 */ + LPC_IOCON->P2_1 |= 7; /* LCD_LE @ P2.1 */ + LPC_IOCON->P2_2 |= 7; /* LCD_DCLK @ P2.2 */ + LPC_IOCON->P2_3 |= 7; /* LCD_FP @ P2.3 */ + LPC_IOCON->P2_4 |= 7; /* LCD_ENAB_M @ P2.4 */ + LPC_IOCON->P2_5 |= 7; /* LCD_LP @ P2.5 */ + LPC_IOCON->P2_6 |= 7; /* LCD_VD_4 @ P2.6 */ + //LPC_IOCON->P2_7 |= 7; /* LCD_VD_5 @ P2.7 */ /* LPC4088 */ + LPC_IOCON->P2_8 |= 7; /* LCD_VD_6 @ P2.8 */ + LPC_IOCON->P2_9 |= 7; /* LCD_VD_7 @ P2.9 */ + + LPC_IOCON->P2_11 |= 7; /* LCD_CLKIN @ P2.11 */ + 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 */ + LPC_IOCON->P2_13 |= 7; /* LCD_VD_19 @ P2.13 */ +} + +uint32_t LcdController::getClockDivisor(int clock) { + uint32_t pixel_div, tmp = 0; + uint32_t clk; + + clk = SystemCoreClock; + + // Find closest clock divider to get clock rate + pixel_div = 1; + while (((clk / pixel_div) > clock) && (pixel_div <= 0x3F)) + { + pixel_div++; + } + + if (pixel_div <= 1) + { + // Pixel clock divider is 1, skip divider logic + tmp = CLCDC_LCDTIMING2_BCD; + } + else + { + // Add in new divider + pixel_div -= 2; + + tmp |= (((pixel_div >> 0) & 0x1F) + | (((pixel_div >> 5) & 0x1F) << 27)); + } + + return tmp; +} + + + +