

/**
 ******************************************************************************
 *
 * @file        BSP_LCD.c
 * @brief       The code is Using SPI of MG32x02z to control ILI9341 
 *
 * @par         Project
 *              MG32x02z
 * @version     V1.02
 * @date        2022/12/22
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2017 MegaWin Technology Co., Ltd.
 *              All rights reserved.
 * 
 ******************************************************************************* 
 * @par Disclaimer
 * The Demo software is provided "AS IS" without any warranty, either
 * expressed or implied, including, but not limited to, the implied warranties
 * of merchantability and fitness for a particular purpose. The author will
 * not be liable for any special, incidental, consequential or indirect
 * damages due to loss of data or any other reason.
 * These statements agree with the world wide and local dictated laws about
 * authorship and violence against these laws.
 *******************************************************************************
 *******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "BSP_SPILCD.h"
#include "BSP_SPILCDFont.h"

/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define LCD_DMA_ENABLE()     URT0->CR2.MBIT.TX_EN = 0;   \
                             URT0->CR0.MBIT.DMA_TXEN = 1;\
                             URT0->CR2.MBIT.TX_EN = 1
#define FLASH_DMA_ENABLE()   SPI0->CR0.MBIT.DMA_TXEN = 1; SPI0->CR0.MBIT.DMA_RXEN = 1


#define LCD_SPI              URT0


/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/

Display_HandleTypeDef LCD_CTR;

static uint8_t LCD_DMA_Dummy = 0xFF;                    /*!< For Flash Read  */

uint32_t const LCD_BackGroundFlashTable[6] = 
{
    0x00000000,      // LCD FrontPage     
    0x00025620,
    0x0004AC40,
    0x00070260,
    0x00095880,
    0x000BAEA0,    
};

// Frame format in fornt page. 
uint16_t const BSP_LCDFrameFormat[7*BSP_LCDFormatSize] = 
{
   54, 53,239,103,
   54,107,239,157, 
   54,161,239,211,
   54,215,239,265,
   54,269,239,319,
    0,107, 50,319, 
    0, 53, 50,103,
};
// String format in fornt page. 
uint16_t const BSP_LCDStringFormat[7*BSP_LCDFormatSize] = 
{ 
   62, 65,232, 24,
   62,119,232, 24,
   62,173,232, 24,
   62,227,232, 24,
   62,281,232, 24,
   10,203,232, 24,
    8, 65,232, 24,    
};

/* Private function prototypes -----------------------------------------------*/
void BSP_LCD_IRQHandler(void);

static void BSP_LCD_Reset(uint32_t LCDRst_Time);
static void BSP_LCD_SelectRegister(uint16_t Register);
static void BSP_LCD_WriteData(uint16_t Data);
static void BSP_LCD_WriteData8(uint8_t Data);
static uint16_t BSP_LCD_ReadData(void);
static void BSP_LCD_WriteRegister(uint16_t Register, uint16_t Value);
static void BSP_LCDPowerOn_Init(Display_HandleTypeDef *LCD_PW);
static void BSP_LCD_BackLight(uint16_t Duty);
static void BSP_LCD_Scan_Dir(Display_HandleTypeDef *DispX, uint8_t dir);
static void BSP_LCD_Display_Dir(Display_HandleTypeDef *DispX, uint8_t dir);
static void BSP_LCD_SetCursor(Display_HandleTypeDef *DispX, uint16_t Xpos, uint16_t Ypos);
static void BSP_LCD_Clear(Display_HandleTypeDef *DispX, uint16_t color);
static void BSP_LCD_DrawPoint(Display_HandleTypeDef *DispX, uint16_t x, uint16_t y, uint16_t color);
static void BSP_LCD_DrawLine(Display_HandleTypeDef *DispX, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t Color);
    
/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/


/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
void BSP_LCD_ShowChar(Display_HandleTypeDef *DispX, uint16_t x, uint16_t y, uint8_t num, uint8_t mode, uint16_t Color)
{
    uint8_t temp,t1,t;
    uint16_t y0 = y;
    uint8_t csize = (LCD_STRING_SIZE / 8 ) * (LCD_STRING_SIZE / 2); 
    //
    num = num - ' ' ;
    for(t = 0; t < csize; t++)
    {   
        temp = asc2_1608[num][t];         
        
        for(t1=0;t1<8;t1++)
        {
            if(temp & 0x80) BSP_LCD_DrawPoint(DispX, x, y, Color);
            else if(mode == 0) BSP_LCD_DrawPoint(DispX, x, y, DispX->BackColor);
            temp <<= 1;
            y++;
            if(x >= DispX->Width)return;                
            if((y - y0) == LCD_STRING_SIZE)
            {
                y = y0;
                x++;
                if(x >= DispX->Width)return;            
                break;
            }
        }
    }
}

/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
void BSP_LCD_ShowString(Display_HandleTypeDef *DispX, uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t Color, uint8_t *p)
{
    uint16_t x0 = x;
    
    width  += x;
    height += y;
    
    while((*p <= '~')&&(*p >= ' '))
    {
        if(x >= width){x = x0; y += LCD_STRING_SIZE;}
        if(y >= height)break;
        BSP_LCD_ShowChar(DispX, x, y, *p, 1, Color);
        x += LCD_STRING_SIZE / 2;
        p++;
    }
}
/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
void BSP_LCD_FillMonochrome(Display_HandleTypeDef *DispX, uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey, uint16_t color)
{
    uint32_t LCD_FSC_XAxis;
    uint32_t LCD_FSC_YAxis;
    uint32_t LCD_FSC_Len;
    
    LCD_FSC_Len = ex - sx + 1;
    
    for( LCD_FSC_YAxis = sy; LCD_FSC_YAxis < (ey + 1); LCD_FSC_YAxis++)
    {
        BSP_LCD_SetCursor(DispX, sx, (uint16_t)LCD_FSC_YAxis);                
        DispX->SelectReg(DispX->GRAMcmd);           
        for(LCD_FSC_XAxis= 0; LCD_FSC_XAxis < LCD_FSC_Len; LCD_FSC_XAxis++)
            DispX->WriteData(color);                
    }
}
/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
void BSP_LCD_Draw_Circle(Display_HandleTypeDef *DispX, uint16_t x0, uint16_t y0, uint8_t r, uint16_t Color)
{
    int a, b;
    int di;
    a = 0; b = r;
    di = 3 - (r << 1);             //??????????
    while(a <= b)
    {
        BSP_LCD_DrawPoint(DispX, (uint16_t)(x0-b), (uint16_t)(y0-a), Color);             //3
        BSP_LCD_DrawPoint(DispX, (uint16_t)(x0+b), (uint16_t)(y0-a), Color);             //0
        BSP_LCD_DrawPoint(DispX, (uint16_t)(x0-a), (uint16_t)(y0+b), Color);             //1
        BSP_LCD_DrawPoint(DispX, (uint16_t)(x0-b), (uint16_t)(y0-a), Color);             //7
        BSP_LCD_DrawPoint(DispX, (uint16_t)(x0-a), (uint16_t)(y0-b), Color);             //2
        BSP_LCD_DrawPoint(DispX, (uint16_t)(x0+b), (uint16_t)(y0+a), Color);             //4
        BSP_LCD_DrawPoint(DispX, (uint16_t)(x0+a), (uint16_t)(y0-b), Color);             //5
        BSP_LCD_DrawPoint(DispX, (uint16_t)(x0+a), (uint16_t)(y0+b), Color);             //6 
        BSP_LCD_DrawPoint(DispX, (uint16_t)(x0-b), (uint16_t)(y0+a), Color);
        a++;
        if(di<0)di +=4*a+6;	  
        else
        {
            di += 10 + 4 * (a - b);
            b--;
        } 
        BSP_LCD_DrawPoint(DispX, (uint16_t)(x0 + a), (uint16_t)(y0 + b), Color);
    }
}

/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
void BSP_LCD_DrawRectangle(Display_HandleTypeDef *DispX, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t Color)
{
    BSP_LCD_DrawLine(DispX, x1, y1, x2, y1, Color);
    BSP_LCD_DrawLine(DispX, x1, y1, x1, y2, Color);
    BSP_LCD_DrawLine(DispX, x1, y2, x2, y2, Color);
    BSP_LCD_DrawLine(DispX, x2, y1, x2, y2, Color);
}
/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
void BSP_LCD_ButtonUp(Display_HandleTypeDef *DispX, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t Color)
{
    BSP_LCD_DrawRectangle(DispX, (x1 + 3), (y1 + 0), (x2 - 3), (y2 - 0), Color);
    BSP_LCD_DrawRectangle(DispX, (x1 + 2), (y1 + 1), (x2 - 2), (y2 - 1), Color);
    BSP_LCD_DrawRectangle(DispX, (x1 + 1), (y1 + 2), (x2 - 1), (y2 - 2), Color);
    BSP_LCD_DrawRectangle(DispX, (x1 + 0), (y1 + 3), (x2 - 0), (y2 - 3), Color);
}
/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
void BSP_LCD_ButtonDone(Display_HandleTypeDef *DispX, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t Color)
{
    BSP_LCD_DrawRectangle(DispX, (x1 + 3), (y1 + 0), (x2 - 3), (y2 - 0), Color);
    BSP_LCD_DrawRectangle(DispX, (x1 + 2), (y1 + 1), (x2 - 2), (y2 - 1), Color);
    BSP_LCD_DrawRectangle(DispX, (x1 + 1), (y1 + 2), (x2 - 1), (y2 - 2), Color);
    BSP_LCD_DrawRectangle(DispX, (x1 + 0), (y1 + 3), (x2 - 0), (y2 - 3), Color);
}
/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note      The IRQHandler is URT0_IRQHandler  
 *******************************************************************************
 */
void BSP_LCD_UpdateFromFlash(uint32_t FlashData_Address, uint32_t DataSize)
{
//    ctype BSP_LCD_UpdateFromFlashTmp;
    
    
    BSP_LCD_UpdateFromFlashCallback();

    /*LCD Write Ready*/
    BSP_LCD_SetCursor(&LCD_CTR, 0, 0);
    LCD_CTR.SelectReg(LCD_CTR.GRAMcmd);
    

    /*Flash Read Ready*/
    Flash0.Total_Length = DataSize;                                /*!< A backgroud fig. date size.*/
    
    Flash0.Address.W    = FlashData_Address;
    
    FLASH_CEN = FLASH_CEN_ACTIVE;
    
    
    BPS_Flash_InputData( 1 , FLASH_FAST_READ);                     /*!< Flash Read Commond*/
    BPS_Flash_InputData(1, Flash0.Address.B[2]);                   /*!< Flash Address*/
    BPS_Flash_InputData(1, Flash0.Address.B[1]);
    BPS_Flash_InputData(1, Flash0.Address.B[0]);
    BPS_Flash_InputData(1, FLASH_DUMMY_DATA);
    
    
    if( Flash0.Total_Length > Flash0.DMA_MaxSize)
    {
        Flash0.BLen = Flash0.DMA_MaxSize;
    }
    else
    {
        Flash0.BLen = Flash0.Total_Length;
    }
    Flash0.Total_Length = Flash0.Total_Length - Flash0.BLen;
    
    
    /*DMA Start*/
    DMA_SetTransferDataNumber(DMA_LCD_INChannel,Flash0.BLen);
    DMA_SetTransferDataNumber(DMA_Flash_INChannel,Flash0.BLen);
    
    FLASH_DMA_ENABLE();                                            /* Flash(SPI) DMA enable*/
    LCD_DMA_ENABLE();                                              /* LCD(SPI) DMA enable*/
                              
    
    URT_IT_Config(LCD_SPI, URT_IT_TC, ENABLE);
    URT_ITEA_Cmd( LCD_SPI, ENABLE);
    NVIC_EnableIRQ( URT0_IRQn);    
    
    
    DMA_ClearFlag(DMA, (DMA_LCD_INFlag | DMA_Flash_INFlag));
    URT_ClearITFlag( LCD_SPI, URT_IT_TC);
    
    __LCD_RS_SET();
    __LCD_CS_CLR();
    
    
    DMA_StartRequest(DMA_LCD_INChannel);
    DMA_StartRequest(DMA_Flash_INChannel);

}
/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
void BSP_LCD_DefineFormatUpdate( uint32_t FrameNumber, uint32_t FrameColor, uint32_t StringColor, unsigned char *String)
{
    uint32_t BSP_LCD_DefineFormatUpdateTmp;
    
    BSP_LCD_DefineFormatUpdateTmp = FrameNumber * BSP_LCDFormatSize;
    
    
    BSP_LCD_ButtonUp(&LCD_CTR, BSP_LCDFrameFormat[BSP_LCD_DefineFormatUpdateTmp + 0],
                               BSP_LCDFrameFormat[BSP_LCD_DefineFormatUpdateTmp + 1], 
                               BSP_LCDFrameFormat[BSP_LCD_DefineFormatUpdateTmp + 2],
                               BSP_LCDFrameFormat[BSP_LCD_DefineFormatUpdateTmp + 3],
                               (uint16_t)FrameColor);
    
    BSP_LCD_ShowString(&LCD_CTR, BSP_LCDStringFormat[BSP_LCD_DefineFormatUpdateTmp + 0],
                                 BSP_LCDStringFormat[BSP_LCD_DefineFormatUpdateTmp + 1], 
                                 BSP_LCDStringFormat[BSP_LCD_DefineFormatUpdateTmp + 2],
                                 BSP_LCDStringFormat[BSP_LCD_DefineFormatUpdateTmp + 3],
                                (uint16_t)StringColor,String);
    
}
/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
void BSP_LCD_DefineFormatStringUpdate( uint32_t FrameNumber, uint32_t StringColor, unsigned char *String)
{
    uint32_t BSP_LCD_DefineFormatStringUpdateTmp;
    
    BSP_LCD_DefineFormatStringUpdateTmp = FrameNumber * BSP_LCDFormatSize;

    BSP_LCD_ShowString(&LCD_CTR, BSP_LCDStringFormat[BSP_LCD_DefineFormatStringUpdateTmp + 0],
                                 BSP_LCDStringFormat[BSP_LCD_DefineFormatStringUpdateTmp + 1], 
                                 BSP_LCDStringFormat[BSP_LCD_DefineFormatStringUpdateTmp + 2],
                                 BSP_LCDStringFormat[BSP_LCD_DefineFormatStringUpdateTmp + 3],
                                (uint16_t)StringColor,String);
    
}

/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note      The IRQHandler is URT0_IRQHandler  
 *******************************************************************************
 */
void BSP_LCD_IRQHandler(void)
{
    URT_ClearITFlag( LCD_SPI, (URT_IT_TC));
    
    /*LCD Background update complete*/
    if( Flash0.Total_Length == 0)
    {
        /*Flash Read End*/
        SPI0->CR1.B[0] |= 0x03; 
        SPI_ClearFlag(SPI0, SPI_ALLF);
     
        FLASH_CEN = FLASH_CEN_NOACTIVE;
        Flash0.Status = Flash_Idle;
        
        /*LCD update End*/
        URT_ClearRXData( LCD_SPI);
        URT_ClearTXData( LCD_SPI);
        URT_IT_Config(LCD_SPI, (URT_IT_TC | URT_IT_RX), DISABLE);
        __LCD_CS_SET();
        
        /*LCD background update callback */
        BSP_LCD_UpdateFromFlashCpltCallback();
        return;
    }

    /*Because LCD Background update not over yet, calculating next DMA data size. */
    if( Flash0.Total_Length > Flash0.DMA_MaxSize)
    {
        Flash0.BLen = Flash0.DMA_MaxSize;
    }
    else
    {
        Flash0.BLen = Flash0.Total_Length;
    }
    Flash0.Total_Length = Flash0.Total_Length - Flash0.BLen;
    
    
    /*Restart DMA to continue updating */
    DMA_ClearFlag(DMA, (DMA_LCD_INFlag | DMA_Flash_INFlag));
    FLASH_DMA_ENABLE();                                             /* Flash(SPI) DMA enable*/                               
    LCD_DMA_ENABLE();                                               /* LCD(SPI) DMA enable*/
    
    DMA_SetTransferDataNumber(DMA_LCD_INChannel,Flash0.BLen);
    DMA_SetTransferDataNumber(DMA_Flash_INChannel,Flash0.BLen);
    
    DMA_StartRequest(DMA_LCD_INChannel);
    DMA_StartRequest(DMA_Flash_INChannel);
    
}
/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
void BSP_LCD_Init(void)
{
    URT_BRG_TypeDef     LCD_BRG;
    DMA_BaseInitTypeDef LCD_DMA_Init;
    
    /*GPIO Initial*/
    BSP_GPIO_PinConfig( LCD_RSTN_IOM , Data_DIR_OUT_PP, 0);
    BSP_GPIO_PinConfig( LCD_RS_IOM   , Data_DIR_OUT_PP, 0);
    BSP_GPIO_PinConfig( LCD_CS_IOM   , Data_DIR_OUT_PP, 0);
    BSP_GPIO_PinConfig( LCD_SCK_IOM  , Data_DIR_OUT_PP, LCD_SCK_AFS);
    BSP_GPIO_PinConfig( LCD_SDI_IOM  , Data_DIR_OUT_PP, LCD_SDI_AFS);
    BSP_GPIO_PinConfig( LCD_SDO_IOM  , Data_DIR_IN_RU , LCD_SDO_AFS);
    BSP_GPIO_PinConfig( LCD_BL_IOM   , Data_DIR_OUT_PP, 0);
    
    
    /*SPI Initial ( URT Module )*/
    //Baud-Rate
    LCD_BRG.URT_InternalClockSource = URT_BDClock_PROC;
    LCD_BRG.URT_BaudRateMode = URT_BDMode_Combined;
    LCD_BRG.URT_PrescalerCounterReload = 0;	                  //Set PSR
    LCD_BRG.URT_BaudRateCounterReload  = 0;	                  //Set RLR
    URT_BaudRateGenerator_Config(LCD_SPI, &LCD_BRG);		  //BR115200 = f(CK_URTx)/(PSR+1)/(RLR+1)/(OS_NUM+1)
    URT_BaudRateGenerator_Cmd(LCD_SPI, ENABLE);	              //Enable BaudRateGenerator
    
    URT_TXClockSource_Select(LCD_SPI, URT_TXClock_Internal);  //URT_TX use BaudRateGenerator
    URT_RXClockSource_Select(LCD_SPI, URT_RXClock_Internal);  //URT_RX use BaudRateGenerator
    URT_TXOverSamplingSampleNumber_Select(LCD_SPI, 2);	      //Set TX OS_NUM
    URT_RXOverSamplingSampleNumber_Select(LCD_SPI, 2);	      //Set RX OS_NUM
    URT_RXOverSamplingMode_Select(LCD_SPI, URT_RXSMP_3TIME);
    URT_TX_Cmd(LCD_SPI, ENABLE);	                          //Enable TX
    URT_RX_Cmd(LCD_SPI, ENABLE);	                          //Enable RX
    

    //Character format
    // - Data bit     : 8 bit
    // - Dart order   : MSB
    // - Parity bit   : No
    // - Stop bit     : 1 bit
    // - Data inverse : No
    LCD_SPI->CR1.B[2] = (((uint8_t)URT_DataLength_8)  | 
                      ((uint8_t)URT_DataTyped_MSB) | 
                      ((uint8_t)URT_Parity_No)     | 
                      ((uint8_t)URT_StopBits_1_0));
    
    LCD_SPI->CR1.B[0] = (((uint8_t)URT_DataLength_8)  | 
                      ((uint8_t)URT_DataTyped_MSB) | 
                      ((uint8_t)URT_Parity_No)     | 
                      ((uint8_t)URT_StopBits_1_0));
    
    //RX / TX Data bit no inverse.
    LCD_SPI->CR4.B[0] = (LCD_SPI->CR4.B[0] & (~(URT_CR4_RDAT_INV_mask_b0|URT_CR4_TDAT_INV_mask_b0)));
 
 
    //URT mode is SYNC mode.
    URT_Mode_Select(LCD_SPI, URT_SYNC_mode);
    //URT data line is 2 line.
    URT_DataLine_Select(LCD_SPI, URT_DataLine_2);
    //{CPOL , CPHA} = { 0 , 0}
    URT_CPHAMode_Select(LCD_SPI , URT_CPHA0_LeadEdge);
    URT_CPOLMode_Select(LCD_SPI , URT_CPOL0_Low );
    // CLK function enable.
    URT_CLKSignal_Cmd(LCD_SPI,ENABLE);
    // Enable URT function.
    URT_Cmd(LCD_SPI, ENABLE);
    // DO / DI Pin swap.
    URT_RxTxSwap_Cmd(LCD_SPI,ENABLE);
    
    /*DMA Init (for LCD background update)*/
    DMA_Cmd( ENABLE);
    DMA_BaseInitStructure_Init(&LCD_DMA_Init);
    
    /*DMA Channel0 & Channel1 for LCD Backgroud update*/

    
    LCD_DMA_Init.DMAChx         = DMA_LCD_INChannel;
    LCD_DMA_Init.DMALoopCmd     = DISABLE;
    LCD_DMA_Init.SrcSINCSel     = DISABLE; 
    LCD_DMA_Init.DestDINCSel    = DISABLE; 
    LCD_DMA_Init.SrcSymSel      = DMA_SPI0_RX;
    LCD_DMA_Init.DestSymSel     = DMA_URT0_TX;
    LCD_DMA_Init.BurstDataSize  = DMA_BurstSize_1Byte;
    LCD_DMA_Init.DMATransferNUM = 0;
    DMA_Base_Init(&LCD_DMA_Init);
    
    DMA_Channel_Cmd( DMA_LCD_INChannel, ENABLE);

 
    LCD_DMA_Init.DMAChx         = DMA_Flash_INChannel;
    LCD_DMA_Init.SrcSymSel      = DMA_MEM_Read;
    LCD_DMA_Init.DestSymSel     = DMA_SPI0_TX;
    LCD_DMA_Init.DMATransferNUM = 0;
    LCD_DMA_Init.DMASourceAddr  = &LCD_DMA_Dummy;
    DMA_Base_Init(&LCD_DMA_Init);
    
    DMA_Channel_Cmd( DMA_Flash_INChannel, ENABLE);
      

    DMA_ClearFlag( DMA, ( DMA_LCD_INFlag | DMA_Flash_INFlag));
    

    /*Parameter Initial*/
    LCD_CTR.Reset         = BSP_LCD_Reset;
    LCD_CTR.BackLight     = BSP_LCD_BackLight;
    LCD_CTR.SelectReg     = BSP_LCD_SelectRegister;
    LCD_CTR.WriteData     = BSP_LCD_WriteData;
    LCD_CTR.WriteData8    = BSP_LCD_WriteData8;
    LCD_CTR.ReadData      = BSP_LCD_ReadData;
    LCD_CTR.WriteRegister = BSP_LCD_WriteRegister;
    LCD_CTR.PointColor    = WHITE;
    LCD_CTR.BackColor     = BLACK;
    LCD_CTR.ID            = 0x9341;

    /*LCD Power On Initial*/
    LCD_CTR.Reset(1);
    BSP_Delay(50);
    
    LCD_CTR.WriteRegister( 0x0000, 0x0001);
    BSP_LCDPowerOn_Init(&LCD_CTR);
    
    BSP_LCD_Display_Dir(&LCD_CTR, 0);
    LCD_CTR.BackLight(0x0000);
    BSP_LCD_Clear(&LCD_CTR, BLACK);
    LCD_CTR.BackLight(0xFFFF);
    

    BSP_LCD_InitCallback();    


}

/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
__WEAK void BSP_LCD_InitCallback(void)
{
    //=========================================================
    //NOTE : This function should not be modifyed, when the 
    //       callback is needed, the MID_URT_RxCpltCallback 
    //       can be implemented in the user file.
}
/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
__weak void BSP_LCD_UpdateFromFlashCallback(void)
{
    //=========================================================
    //NOTE : This function should not be modifyed, when the 
    //       callback is needed, the MID_URT_RxCpltCallback 
    //       can be implemented in the user file.
}
/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
__WEAK void BSP_LCD_UpdateFromFlashCpltCallback(void)
{
    //=========================================================
    //NOTE : This function should not be modifyed, when the 
    //       callback is needed, the MID_URT_RxCpltCallback 
    //       can be implemented in the user file.
}



/**
 *******************************************************************************
 * @brief	   LCD module Reset 
 * @details     
 * @param[in]  LCDRst_Time : LCD reset signal time.
 * @return      
 * @exception  No 
 * @note       Use the function must initial systick by middleware.
 *******************************************************************************
 */
static void BSP_LCD_Reset(uint32_t LCDRst_Time)
{
    __SPI_LCD_RESET_ENABLE();
    BSP_Delay(LCDRst_Time);
    __SPI_LCD_RESET_DISABLE();
}

/**
 *******************************************************************************
 * @brief	   Select control LCD register 
 * @details    
 * @param[in]  Register
 * @return      
 * @exception  No 
 * @note        
 *******************************************************************************
 */
static void BSP_LCD_SelectRegister(uint16_t Register)
{
    __LCD_RS_CLR();
    __LCD_CS_CLR();                                 //LCD_CS=0
    
    LCD_SPI->TDAT.B[0] = (uint8_t)Register;
    while((LCD_SPI->STA.W & LCD_SPI_TCF) == 0);
    
    __LCD_CS_SET();                                //LCD_CS=1
}

/**
 *******************************************************************************
 * @brief	  Output 16 bit data to LCD module.  
 * @details  
 * @param[in] Data : 16 bit output data.
 * @return      
 * @exception No  
 * @note        
 *******************************************************************************
 */
static void BSP_LCD_WriteData(uint16_t Data)
{
    __LCD_RS_SET();
    __LCD_CS_CLR();                                           //LCD_CS=0
    
    LCD_SPI->TDAT.B[0] = (uint8_t)(Data >> 8);
    while((LCD_SPI->STA.W & LCD_SPI_TXF) == 0);
    
    LCD_SPI->TDAT.B[0] = (uint8_t)Data;
    while((LCD_SPI->STA.W & LCD_SPI_TCF) == 0);

    __LCD_CS_SET();                                           //LCD_CS=1
}

/**
 *******************************************************************************
 * @brief	  Output 8 bit data to LCD module.   
 * @details     
 * @param[in] Data : 8 bit output data.
 * @return      
 * @exception No  
 * @note        
 *******************************************************************************
 */
static void BSP_LCD_WriteData8(uint8_t Data)   
{
    __LCD_RS_SET();
    __LCD_CS_CLR();  
    
    LCD_SPI->TDAT.B[0] = Data;
    while((LCD_SPI->STA.W & LCD_SPI_TCF) == 0);

    
    __LCD_CS_SET();  
}

/**
 *******************************************************************************
 * @brief	   Read 16-bti data from LCD module. 
 * @details     
 * @return      
 * @exception  No 
 * @note        
 *******************************************************************************
 */
static uint16_t BSP_LCD_ReadData(void)
{
    __LCD_RS_SET();
    __LCD_CS_CLR();  
    
    LCD_SPI->TDAT.B[0] = (uint8_t)(0xFF >> 8);
    while((LCD_SPI->STA.W & LCD_SPI_TXF) == 0);
    
    LCD_SPI->TDAT.B[0] = (uint8_t)0xFF;
    while((LCD_SPI->STA.B[0] & LCD_SPI_TCF) == 0);

    __LCD_CS_SET();  //LCD_CS=1
    return 0;
}

/**
 *******************************************************************************
 * @brief	   Write LCD register 
 * @details   
 * @param[in]  Register: which register.
 * @param[in]  Vaule : Write register value.
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
static void BSP_LCD_WriteRegister(uint16_t Register, uint16_t Value)
{
    __LCD_RS_SET();
    __LCD_CS_CLR();  
    
    LCD_SPI->TDAT.B[0] = (uint8_t)Register;
    while((LCD_SPI->STA.W & LCD_SPI_TCF) == 0);
    __LCD_CS_SET();  

    __LCD_RS_SET();
    
    __LCD_CS_CLR();  
    LCD_SPI->TDAT.B[0] = (uint8_t)Value;
    while((LCD_SPI->STA.W & LCD_SPI_TCF) == 0);
    __LCD_CS_SET();  
}

/**
 *******************************************************************************
 * @brief	  LCD power on initial.
 * @details     
 * @param[in] LCD_PW : LCD control parameter.
 * @return      
 * @exception No  
 * @note        
 *******************************************************************************
 */
static void BSP_LCDPowerOn_Init(Display_HandleTypeDef *LCD_PW)
{
    LCD_PW->SelectReg(0xCF);
    LCD_PW->WriteData8(0x00);
    LCD_PW->WriteData8(0xC1);
    LCD_PW->WriteData8(0X30);

    LCD_PW->SelectReg(0xED);
    LCD_PW->WriteData8(0x64);
    LCD_PW->WriteData8(0x03);
    LCD_PW->WriteData8(0X12);
    LCD_PW->WriteData8(0X81);

    LCD_PW->SelectReg(0xE8);
    LCD_PW->WriteData8(0x85);
    LCD_PW->WriteData8(0x10);
    LCD_PW->WriteData8(0x7A);

    LCD_PW->SelectReg(0xCB);
    LCD_PW->WriteData8(0x39);
    LCD_PW->WriteData8(0x2C);
    LCD_PW->WriteData8(0x00);
    LCD_PW->WriteData8(0x34);
    LCD_PW->WriteData8(0x02);

    LCD_PW->SelectReg(0xF7);
    LCD_PW->WriteData8(0x20);

    LCD_PW->SelectReg(0xEA);
    LCD_PW->WriteData8(0x00);
    LCD_PW->WriteData8(0x00);

    LCD_PW->SelectReg(0xC0);       // Power control
    LCD_PW->WriteData8(0x1B);      // VRH[5:0]

    LCD_PW->SelectReg(0xC1);       // Power control
    LCD_PW->WriteData8(0x01);      // SAP[2:0];BT[3:0]

    LCD_PW->SelectReg(0xC5);       // VCM control
    LCD_PW->WriteData8(0x30);      // 3F
    LCD_PW->WriteData8(0x30);      // 3C

    LCD_PW->SelectReg(0xC7);       // VCM control2
    LCD_PW->WriteData8(0XB7);

    LCD_PW->SelectReg(0x36);       // Memory Access Control
    LCD_PW->WriteData8(0x48);

    LCD_PW->SelectReg(0x3A);
    LCD_PW->WriteData8(0x55);

    LCD_PW->SelectReg(0xB1);
    LCD_PW->WriteData8(0x00);
    LCD_PW->WriteData8(0x1A);

    LCD_PW->SelectReg(0xB6);       // Display Function Control
    LCD_PW->WriteData8(0x0A);
    
    LCD_PW->WriteData8(0xE2);
    
    LCD_PW->SelectReg(0xF2);       // 3Gamma Function Disable
    LCD_PW->WriteData8(0x00);

    LCD_PW->SelectReg(0x26);       // Gamma curve selected
    LCD_PW->WriteData8(0x01);

    LCD_PW->SelectReg(0xE0);       // Set Gamma
    LCD_PW->WriteData8(0x0F);
    LCD_PW->WriteData8(0x2A);
    LCD_PW->WriteData8(0x28);
    LCD_PW->WriteData8(0x08);
    LCD_PW->WriteData8(0x0E);
    LCD_PW->WriteData8(0x08);
    LCD_PW->WriteData8(0x54);
    LCD_PW->WriteData8(0XA9);
    LCD_PW->WriteData8(0x43);
    LCD_PW->WriteData8(0x0A);
    LCD_PW->WriteData8(0x0F);
    LCD_PW->WriteData8(0x00);
    LCD_PW->WriteData8(0x00);
    LCD_PW->WriteData8(0x00);
    LCD_PW->WriteData8(0x00);

    LCD_PW->SelectReg(0XE1);        // Set Gamma
    LCD_PW->WriteData8(0x00);
    LCD_PW->WriteData8(0x15);
    LCD_PW->WriteData8(0x17);
    LCD_PW->WriteData8(0x07);
    LCD_PW->WriteData8(0x11);
    LCD_PW->WriteData8(0x06);
    LCD_PW->WriteData8(0x2B);
    LCD_PW->WriteData8(0x56);
    LCD_PW->WriteData8(0x3C);
    LCD_PW->WriteData8(0x05);
    LCD_PW->WriteData8(0x10);
    LCD_PW->WriteData8(0x0F);
    LCD_PW->WriteData8(0x3F);
    LCD_PW->WriteData8(0x3F);
    LCD_PW->WriteData8(0x0F);

    LCD_PW->SelectReg(0x2B);
    LCD_PW->WriteData8(0x00);
    LCD_PW->WriteData8(0x00);
    LCD_PW->WriteData8(0x01);
    LCD_PW->WriteData8(0x3f);

    LCD_PW->SelectReg(0x2A);
    LCD_PW->WriteData8(0x00);
    LCD_PW->WriteData8(0x00);
    LCD_PW->WriteData8(0x00);
    LCD_PW->WriteData8(0xef);

    LCD_PW->SelectReg(0x11);        // Exit Sleep
    BSP_Delay(10);
    LCD_PW->SelectReg(0x29);        // display on
}

/**
 *******************************************************************************
 * @brief	  LCD backlight control  
 * @details
 * @param[in] Dyte:
 *   @arg\b   0x0000 : Disable LCD backlight 
 *   @arg\b   0xFFFF : Enable LCD backlight.
 * @return      
 * @exception No  
 * @note        
 *******************************************************************************
 */
static void BSP_LCD_BackLight(uint16_t Duty)
{
    if(Duty == 0x0000)
        __SPI_LCD_BACKLIGHT_OFF();

    if(Duty == 0xFFFF)
        __SPI_LCD_BACKLIGHT_ON();
}

/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
static void BSP_LCD_Scan_Dir(Display_HandleTypeDef *DispX, uint8_t dir)
{
    uint16_t regval=0;
    uint16_t dirreg=0;
    uint16_t temp;  
    if(DispX->Direct == 1)
    {
        switch(dir)
        {
            case 0: dir = 6;break;
            case 1: dir = 7;break;
            case 2: dir = 4;break;
            case 3: dir = 5;break;
            case 4: dir = 1;break;
            case 5: dir = 0;break;
            case 6: dir = 3;break;
            case 7: dir = 2;break;
        }
    }

    switch(dir)
    {
        case L2R_U2D:
            regval|=(0<<7)|(0<<6)|(0<<5);
            break;
        case L2R_D2U:
            regval|=(1<<7)|(0<<6)|(0<<5);
            break;
        case R2L_U2D:
            regval|=(0<<7)|(1<<6)|(0<<5);
            break;
        case R2L_D2U:
            regval|=(1<<7)|(1<<6)|(0<<5);
            break;
        case U2D_L2R:
            regval|=(0<<7)|(0<<6)|(1<<5);
            break;
        case U2D_R2L:
            regval|=(0<<7)|(1<<6)|(1<<5);
            break;
        case D2U_L2R:
            regval|=(1<<7)|(0<<6)|(1<<5);
            break;
        case D2U_R2L:
            regval|=(1<<7)|(1<<6)|(1<<5);
            break;
    }

    if(DispX->ID == 0X5510) dirreg = 0X3600;
    else dirreg = 0X36;

    if((DispX->ID != 0X5310) && (DispX->ID != 0X5510))regval |= 0X08;

    if(DispX->ID == 0X6804)regval |= 0x02;

    DispX->WriteRegister(dirreg, regval);

    if(regval & 0X20)
    {
        if(DispX->Width < DispX->Height)
        {
            temp = DispX->Width;
            DispX->Width = DispX->Height;
            DispX->Height = temp;
        }
    }else
    {
        if(DispX->Width > DispX->Height)
        {
            temp = DispX->Width;
            DispX->Width = DispX->Height;
            DispX->Height = temp;
        }
    }

    DispX->SelectReg(DispX->SetXcmd);
    if(DispX->ID == 0X5510)
    {
        DispX->WriteData(0);
        DispX->SelectReg(DispX->SetXcmd + 1);
        DispX->WriteData(0);
        DispX->SelectReg(DispX->SetXcmd + 2);
        DispX->WriteData((DispX->Width - 1) >> 8);
        DispX->SelectReg(DispX->SetXcmd + 3);
        DispX->WriteData((DispX->Width - 1) & 0XFF);
        DispX->SelectReg(DispX->SetYcmd);
        DispX->WriteData(0);
        DispX->SelectReg(DispX->SetYcmd + 1);
        DispX->WriteData(0);
        DispX->SelectReg(DispX->SetYcmd + 2);
        DispX->WriteData((DispX->Height-1)>>8);
        DispX->SelectReg(DispX->SetYcmd + 3);
        DispX->WriteData((DispX->Height-1)&0XFF);
    }else
    {
        DispX->WriteData8(0);
        DispX->WriteData8(0);
        DispX->WriteData8((DispX->Width-1)>>8);
        DispX->WriteData8((DispX->Width-1)&0XFF);

        DispX->SelectReg(DispX->SetYcmd);
        DispX->WriteData8(0);
        DispX->WriteData8(0);
        DispX->WriteData8((DispX->Height-1)>>8);
        DispX->WriteData8((DispX->Height-1)&0XFF);
    }
}

/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
static void BSP_LCD_Display_Dir(Display_HandleTypeDef *DispX, uint8_t dir)
{
    if(dir == 0)                    
    {
        DispX->Direct  = 0;       
        DispX->Width   = 240;
        DispX->Height  = 320;
    }
    else                           
    {
        DispX->Direct  = 1;       
        DispX->Width   = 320;
        DispX->Height  = 240;

    }
    DispX->GRAMcmd = 0X2C;
    DispX->SetXcmd = 0X2A;
    DispX->SetYcmd = 0X2B;
    BSP_LCD_Scan_Dir(DispX, DFT_SCAN_DIR);  
}

/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
static void BSP_LCD_SetCursor(Display_HandleTypeDef *DispX, uint16_t Xpos, uint16_t Ypos)
{
    DispX->SelectReg(DispX->SetXcmd);
    DispX->WriteData8(Xpos>>8);
    DispX->WriteData8(Xpos&0XFF);
    
    DispX->SelectReg(DispX->SetYcmd);
    DispX->WriteData8(Ypos>>8);
    DispX->WriteData8(Ypos&0XFF);
}

/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
static void BSP_LCD_Clear(Display_HandleTypeDef *DispX, uint16_t color)
{
    __IO uint32_t index=0;
    __IO uint32_t totalpoint;

    totalpoint = DispX->Width;
    totalpoint *= DispX->Height;                        
    if((DispX->ID == 0X6804)&&(DispX->Direct != 0))     
    {
        DispX->Direct = 0;
        DispX->SetXcmd = 0X2A;
        DispX->SetYcmd = 0X2B;
        BSP_LCD_SetCursor(DispX, 0x00,0x0000);               
        DispX->Direct = 1;
        DispX->SetXcmd = 0X2B;
        DispX->SetYcmd = 0X2A;
    }else BSP_LCD_SetCursor(DispX, 0x00,0x0000);             
    DispX->SelectReg(DispX->GRAMcmd);                 

    for(index = 0; index < totalpoint; index++)
    {
        DispX->WriteData(color);
    }
}

/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
static void BSP_LCD_DrawPoint(Display_HandleTypeDef *DispX, uint16_t x, uint16_t y, uint16_t color)
{
    if((y >= DispX->Height) || (x >= DispX->Width))
        return;

    DispX->SelectReg(DispX->SetXcmd);
    DispX->WriteData8(x >> 8);
    DispX->WriteData8(x & 0XFF);
    DispX->SelectReg(DispX->SetYcmd);
    DispX->WriteData8(y >> 8);
    DispX->WriteData8(y & 0XFF);
    
    DispX->SelectReg(DispX->GRAMcmd);                   
    DispX->WriteData(color);                            
}

/**
 *******************************************************************************
 * @brief	    
 * @details     
 * @return      
 * @exception   
 * @note        
 *******************************************************************************
 */
static void BSP_LCD_DrawLine(Display_HandleTypeDef *DispX, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t Color)
{
    uint16_t t; 
    int xerr = 0, yerr = 0, delta_x, delta_y, distance; 
    int incx, incy; 
    uint16_t  uRow, uCol;
    
    delta_x = x2 - x1;                              
    delta_y = y2 - y1; 
    uRow = x1; 
    uCol = y1; 
    
    
    if(delta_x > 0)
    {
        incx=1;                         
    }
    else if(delta_x==0)
    {
        incx=0;                      
    }
    else
    {
        incx=-1;
        delta_x=-delta_x;
    } 
    
    
    if(delta_y>0)
    {
        incy=1;
    }        
    else if(delta_y==0)
    {
        incy=0;
    }        
    else
    {
        incy = -1; 
        delta_y = -delta_y;
    } 
    
    if(delta_x > delta_y) 
    {
        distance = delta_x;
    }        
    else 
    {
        distance = delta_y;
    }    
    
    for(t = 0; t <= distance + 1; t++ )             
    {  
        BSP_LCD_DrawPoint(DispX, uRow, uCol, Color);    
        xerr += delta_x ; 
        yerr += delta_y ; 
        if(xerr > distance) 
        { 
            xerr -= distance; 
            uRow += incx; 
        } 
        if(yerr > distance) 
        { 
            yerr -= distance; 
            uCol += incy; 
        } 
    }  
}


