text: /**********************************************************************
  * $Id$		lpc18xx_lcd.c		2011-06-02
  *//**
  * @file		lpc18xx_lcd.c
  * @brief	Contains all function support for LCD Driver
  * @version	1.0
  * @date		02. June. 2011
  * @author	NXP MCU SW Application Team
  *
  * Copyright(C) 2011, NXP Semiconductor
  * All rights reserved.
  *
  ***********************************************************************
  * Software that is described herein is for illustrative purposes only
  * which provides customers with programming information regarding the
  * products. This software is supplied "AS IS" without any warranties.
  * NXP Semiconductors assumes no responsibility or liability for the
  * use of the software, conveys no license or title under any patent,
  * copyright, or mask work right to the product. NXP Semiconductors
  * reserves the right to make changes in the software without
  * notification. NXP Semiconductors also make no representation or
  * warranty that such application will be suitable for the specified
  * use without further testing or modification.
  * Permission to use, copy, modify, and distribute this software and its
  * documentation is hereby granted, under NXP Semiconductors'
  * relevant copyright in the software, without fee, provided that it
  * is used in conjunction with NXP Semiconductors microcontrollers.  This
  * copyright, permission, and disclaimer notice must appear in all copies of
  * this code.
  **********************************************************************/
  
  /* Peripheral group ----------------------------------------------------------- */
  /** @addtogroup LCD
   * @{
   */
  
  /* Includes ------------------------------------------------------------------- */
  #include "LPC18xx.h"
  #include "lpc18xx_lcd.h"
  
  /* If this source file built with example, the LPC18xx FW library configuration
   * file in each example directory ("lpc18xx_libcfg.h") must be included,
   * otherwise the default FW library configuration file must be included instead
   */
  #ifdef __BUILD_WITH_EXAMPLE__
  #include "lpc18xx_libcfg.h"
  #else
  #include "lpc18xx_libcfg_default.h"
  #endif /* __BUILD_WITH_EXAMPLE__ */
  
  #ifdef _LCD
  
  LCD_CURSOR_SIZE_OPT LCD_Cursor_Size = LCD_CURSOR_64x64;
  
  /* Private Functions ---------------------------------------------------------- */
  
  /*********************************************************************//**
   * @brief 		Init the LPC18xx LCD Controller
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @param[in]	LCD_ConfigStruct point to LCD_CFG_Type that describe the LCD Panel
   * @return 		None
   **********************************************************************/
  void LCD_Init(LPC_LCD_Type *LCDx, LCD_CFG_Type *LCD_ConfigStruct){
  	uint32_t i, regValue, *pPal;
  	uint32_t pcd;
  	/* disable the display */
  	LCDx->CTRL &= ~CLCDC_LCDCTRL_ENABLE;
  
  	/* Setting LCD_TIMH register */
  	regValue= ( ((((LCD_ConfigStruct->screen_width/16)-1)&0x3F) << 2)
  	|         (( (LCD_ConfigStruct->HSync_pulse_width-1)    &0xFF) << 8)
  	|         (( (LCD_ConfigStruct->horizontal_porch.front-1)    &0xFF) << 16)
  	|         (( (LCD_ConfigStruct->horizontal_porch.back-1)    &0xFF) << 24) );
  
  	LCDx->TIMH = regValue;
  
  	/* Setting LCD_TIMV register */
  	regValue =((((LCD_ConfigStruct->screen_height-1) &0x3FF) << 0)
  	|        (((LCD_ConfigStruct->VSync_pulse_width-1) &0x03F) << 10)
  	|        (((LCD_ConfigStruct->vertical_porch.front-1) &0x0FF) << 16)
  	|        (((LCD_ConfigStruct->vertical_porch.back-1) &0x0FF) << 24) );
  
  	LCDx->TIMV = regValue;
  
  	/* Generate the clock and signal polarity control word */
  	regValue = 0;
  	regValue = (((LCD_ConfigStruct->ac_bias_frequency-1) & 0x1F) << 6);
  
  	regValue |= (LCD_ConfigStruct->OE_pol & 1)<< 14;
  
  	regValue |= (LCD_ConfigStruct->panel_clk_edge & 1)<< 13;
  
  	regValue |= (LCD_ConfigStruct->HSync_pol & 1)<< 12;
  
  	regValue |= (LCD_ConfigStruct->VSync_pol & 1)<< 11;
  
  	/* Compute clocks per line based on panel type */
  
  	switch(LCD_ConfigStruct->lcd_panel_type)
  	{
  	  case LCD_MONO_4:
  		regValue |= ((((LCD_ConfigStruct->screen_width / 4)-1) & 0x3FF) << 16);
  		break;
  	  case LCD_MONO_8:
  		regValue |= ((((LCD_ConfigStruct->screen_width / 8)-1) & 0x3FF) << 16);
  		break;
  	  case LCD_CSTN:
  		regValue |= (((((LCD_ConfigStruct->screen_width * 3)/8)-1) & 0x3FF) << 16);
  		break;
  	  case LCD_TFT:
  	  default:
  		regValue |= /* 1<<26 | */ (((LCD_ConfigStruct->screen_width-1) & 0x3FF) << 16);
  	}
  
  	/* panel clock divisor */
  	pcd = 5; //LCD_ConfigStruct->pcd;   // TODO: should be calculated from LCDDCLK
  	pcd &= 0x3FF;
  	regValue |=  ((pcd>>5)<<27) | ((pcd)&0x1F);
  
  	LCDx->POL = regValue;
  
  	/* configure line end control */
  	CHECK_PARAM(LCD_ConfigStruct->line_end_delay<=(1<<7));
  	if(LCD_ConfigStruct->line_end_delay)
  		LCDx->LE  = (LCD_ConfigStruct->line_end_delay-1) | 1<<16;
  	else
  		LCDx->LE = 0;
  
  	/* disable interrupts */
  	LCDx->INTMSK = 0;
  
  	/* set bits per pixel */
  	regValue = LCD_ConfigStruct->bits_per_pixel << 1;
  
  	/* set color format BGR or RGB */
  	regValue |= LCD_ConfigStruct->color_format << 8;
  
  	regValue |= LCD_ConfigStruct->lcd_panel_type << 4;
  
  	if(LCD_ConfigStruct->dual_panel == 1)
  	{
  		regValue |= 1 << 7;
  	}
  	LCDx->CTRL = regValue;
  	/* clear palette */
  	pPal = (uint32_t*) (&(LCDx->PAL));
  
  	for(i = 0; i < 128; i++)
  	{
  		*pPal = 0;
  		pPal++;
  	}
  }
  
  
  /*********************************************************************//**
   * @brief 		Deinit LCD controller
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @return 		None
   **********************************************************************/
  void LCD_DeInit(LPC_LCD_Type *LCDx);
  
  
  /*********************************************************************//**
   * @brief 		Power the LCD Panel
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @param[in]	OnOff	Turn on/off LCD
   * 					- TRUE	:Turn on
   * 					- FALSE :Turn off
   * @return 		None
   **********************************************************************/
  void LCD_Power(LPC_LCD_Type *LCDx, FunctionalState OnOff){
  volatile int i;
  	if(OnOff){
  		LPC_LCD->CTRL |= CLCDC_LCDCTRL_PWR;
  		for(i=0;i<1000000;i++);
  		LPC_LCD->CTRL |= CLCDC_LCDCTRL_ENABLE;
  	}else{
  		LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_PWR;
  		for(i=0;i<1000000;i++);
  		LPC_LCD->CTRL &= ~CLCDC_LCDCTRL_ENABLE;
  	}
  }
  
  
  /*********************************************************************//**
   * @brief 		Enable/Disable the LCD Controller
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @param[in]	EnDis	Enable/disable status
   * 					- TRUE	:Enable
   * 					- FALSE :Disable
   * @return 		None
   **********************************************************************/
  void LCD_Enable(LPC_LCD_Type *LCDx, FunctionalState EnDis){
  	if (EnDis)
  	{
  	  LCDx->CTRL |= CLCDC_LCDCTRL_ENABLE;
  	}
  	else
  	{
  	  LCDx->CTRL &= ~CLCDC_LCDCTRL_ENABLE;
  	}
  }
  
  
  /*********************************************************************//**
   * @brief 		Set LCD Frame Buffer for Single Panel or Upper Panel Frame
   * 				Buffer for Dual Panel
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @param[in]	buffer address of buffer
   * @return 		None
   **********************************************************************/
  void LCD_SetFrameBuffer(LPC_LCD_Type *LCDx, void* buffer){
  	LCDx->UPBASE = (uint32_t)buffer;
  }
  
  
  /*********************************************************************//**
   * @brief 		Set LCD Lower Panel Frame Buffer for Dual Panel
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @param[in]	buffer address of buffer
   * @return 		None
   **********************************************************************/
  void LCD_SetLPFrameBuffer(LPC_LCD_Type *LCDx, void* buffer){
  	LCDx->LPBASE = (uint32_t)buffer;
  }
  
  
  /*********************************************************************//**
   * @brief 		Configure Cursor
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @param[in]	cursor_size specify size of cursor
   * 					- LCD_CURSOR_32x32	:cursor size is 32x32 pixels
   * 					- LCD_CURSOR_64x64	:cursor size is 64x64 pixels
   * @param[in]	sync cursor sync mode
   * 					- TRUE	:cursor sync to the frame sync pulse
   * 					- FALSE	:cursor async mode
   * @return 		None
   **********************************************************************/
  void LCD_Cursor_Config(LPC_LCD_Type *LCDx, LCD_CURSOR_SIZE_OPT cursor_size, Bool sync){
  	LCD_Cursor_Size = cursor_size;
  	LCDx->CRSR_CFG = ((sync?1:0)<<1) | cursor_size;
  }
  
  
  /*********************************************************************//**
   * @brief 		Write Cursor Image into Internal Cursor Image Buffer
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @param[in]	cursor_num specify number of cursor is going to be written
   * 				this param must < 4
   * @param[in]	Image point to Cursor Image Buffer
   * @return 		None
   **********************************************************************/
  void LCD_Cursor_WriteImage(LPC_LCD_Type *LCDx, uint8_t cursor_num, void* Image){
  	int i,j;
  	uint32_t *fifoptr, *crsr_ptr = (uint32_t *)Image;
  
  	CHECK_PARAM(cursor_num<4);
  	/* Check if Cursor Size was configured as 32x32 or 64x64*/
  	if(LCD_Cursor_Size == LCD_CURSOR_32x32){
  		i = cursor_num * 64;
  		j = i + 64;
  	}else{
  		i = 0;
  		j = 256;
  	}
  	fifoptr = (uint32_t*)&(LCDx->CRSR_IMG[0]);
  	/* Copy Cursor Image content to FIFO */
  	for(; i < j; i++)
  	{
  
  		*fifoptr = *crsr_ptr;
  		crsr_ptr++;
  		fifoptr++;
  	}
  }
  
  
  /*********************************************************************//**
   * @brief 		Get Internal Cursor Image Buffer Address
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @param[in]	cursor_num specify number of cursor is going to be written
   * 				this param must < 4
   * @return 		Cursor Image Buffer Address
   **********************************************************************/
  void* LCD_Cursor_GetImageBufferAddress(LPC_LCD_Type *LCDx, uint8_t cursor_num){
  	CHECK_PARAM(cursor_num<4);
  	return (void*)&(LCDx->CRSR_IMG[cursor_num*64]);
  }
  
  
  /*********************************************************************//**
   * @brief 		Enable Cursor
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @param[in]	cursor_num specify number of cursor is going to be written
   * 				this param must < 4
   * @param[in]	OnOff Turn on/off LCD
   * 					- TRUE	:Enable
   * 					- FALSE :Disable
   * @return 		None
   **********************************************************************/
  void LCD_Cursor_Enable(LPC_LCD_Type *LCDx, uint8_t cursor_num, FunctionalState OnOff){
  	CHECK_PARAM(cursor_num<4);
  	if (OnOff)
  	{
  	  LCDx->CRSR_CTRL = (cursor_num<<4) | 1;
  	}
  	else
  	{
  	  LCDx->CRSR_CTRL = (cursor_num<<4);
  	}
  }
  
  
  /*********************************************************************//**
   * @brief 		Load LCD Palette
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @param[in]	palette point to palette address
   * @return 		None
   **********************************************************************/
  void LCD_LoadPalette(LPC_LCD_Type *LCDx, void* palette){
  	LCD_PALETTE_ENTRY_Type pal_entry, *ptr_pal_entry;
  	uint8_t i, *pal_ptr;
  	/* This function supports loading of the color palette from
  	the C file generated by the bmp2c utility. It expects the
  	palette to be passed as an array of 32-bit BGR entries having
  	the following format:
  	2:0 - Not used
  	7:3 - Blue
  	10:8 - Not used
  	15:11 - Green
  	18:16 - Not used
  	23:19 - Red
  	31:24 - Not used
  	arg = pointer to input palette table address */
  	ptr_pal_entry = &pal_entry;
  	pal_ptr = (uint8_t *) palette;
  
  	/* 256 entry in the palette table */
  	for(i = 0; i < 256/2; i++)
  	{
  	pal_entry.Bl = (*pal_ptr++) >> 3;  /* blue first */
  	pal_entry.Gl = (*pal_ptr++) >> 3;  /* get green */
  	pal_entry.Rl = (*pal_ptr++) >> 3;  /* get red */
  	pal_ptr++;      /* skip over the unused byte */
  	/* do the most significant halfword of the palette */
  	pal_entry.Bu = (*pal_ptr++) >> 3;  /* blue first */
  	pal_entry.Gu = (*pal_ptr++) >> 3;  /* get green */
  	pal_entry.Ru = (*pal_ptr++) >> 3;  /* get red */
  	pal_ptr++;      /* skip over the unused byte */
  
  	LCDx->PAL[i] = *(uint32_t *)ptr_pal_entry;
  	}
  }
  
  
  /*********************************************************************//**
   * @brief 		Load Cursor Palette
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @param[in]	palette_color cursor palette 0 value
   * @return 		None
   **********************************************************************/
  void LCD_Cursor_LoadPalette0(LPC_LCD_Type *LCDx, uint32_t palette_color){
  	/* 7:0 - Red
  	15:8 - Green
  	23:16 - Blue
  	31:24 - Not used*/
  	LCDx->CRSR_PAL0 = (uint32_t)palette_color;
  }
  
  
  /*********************************************************************//**
   * @brief 		Load Cursor Palette
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @param[in]	palette_color cursor palette 1 value
   * @return 		None
   **********************************************************************/
  void LCD_Cursor_LoadPalette1(LPC_LCD_Type *LCDx, uint32_t palette_color){
  	/* 7:0 - Red
  	15:8 - Green
  	23:16 - Blue
  	31:24 - Not used*/
  	LCDx->CRSR_PAL1 = (uint32_t)palette_color;
  }
  
  
  /*********************************************************************//**
   * @brief 		Set Interrupt
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @param[in]	Int LCD Interrupt Source, should be:
   * 					- LCD_INT_FUF	:FIFO underflow
   * 					- LCD_INT_LNBU	:LCD next base address update bit
   * 					- LCD_INT_VCOMP	:Vertical compare bit
   * 					- LCD_INT_BER	:AHB master error interrupt bit
   * @return 		None
   **********************************************************************/
  void LCD_SetInterrupt(LPC_LCD_Type *LCDx, LCD_INT_SRC Int){
  	LCDx->INTMSK |= Int;
  }
  
  
  /*********************************************************************//**
   * @brief 		Clear Interrupt
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @param[in]	Int LCD Interrupt Source, should be:
   * 					- LCD_INT_FUF	:FIFO underflow
   * 					- LCD_INT_LNBU	:LCD next base address update bit
   * 					- LCD_INT_VCOMP	:Vertical compare bit
   * 					- LCD_INT_BER	:AHB master error interrupt bit
   * @return 		None
   **********************************************************************/
  void LCD_ClrInterrupt(LPC_LCD_Type *LCDx, LCD_INT_SRC Int){
  	LCDx->INTCLR |= Int;
  }
  
  
  /*********************************************************************//**
   * @brief 		Get LCD Interrupt Status
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @return 		None
   **********************************************************************/
  LCD_INT_SRC LCD_GetInterrupt(LPC_LCD_Type *LCDx){
  	return (LCD_INT_SRC)LCDx->INTRAW;
  }
  
  
  /*********************************************************************//**
   * @brief 		Enable Cursor Interrupt
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @return 		None
   **********************************************************************/
  void LCD_Cursor_SetInterrupt(LPC_LCD_Type *LCDx){
  	LCDx->CRSR_INTMSK |= 1;
  }
  
  
  /*********************************************************************//**
   * @brief 		Clear Cursor Interrupt
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @return 		None
   **********************************************************************/
  void LCD_Cursor_ClrInterrupt(LPC_LCD_Type *LCDx){
  	LCDx->CRSR_INTCLR |= 1;
  }
  
  
  /*********************************************************************//**
   * @brief 		Set Cursor Position
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @param[in]	x horizontal position
   * @param[in]	y vertical position
   * @return 		None
   **********************************************************************/
  void LCD_Cursor_SetPos(LPC_LCD_Type *LCDx, uint16_t x, uint16_t y){
  	LCDx->CRSR_XY = (x & 0x3FF) | ((y & 0x3FF) << 16);
  }
  
  
  /*********************************************************************//**
   * @brief 		Set Cursor Clipping Position
   * @param[in]	LCDx pointer to LCD Controller Reg Struct, should be: LPC_LCD
   * @param[in]	x horizontal position, should be in range: 0..63
   * @param[in]	y vertical position, should be in range: 0..63
   * @return 		None
   **********************************************************************/
  void LCD_Cursor_SetClip(LPC_LCD_Type *LCDx, uint16_t x, uint16_t y){
  	LCDx->CRSR_CLIP = (x & 0x3F) | ((y & 0x3F) << 8);
  }
  #endif /* _LCD */
  
  /**
   * @}
   */
  
  /* --------------------------------- End Of File ------------------------------ */
  