blob: f54c609e93d4ff50f37d1ea8858432bfb2b3c996 [file] [log] [blame]
/* ----------------------------------------------------------------------------
* SAM Software Package License
* ----------------------------------------------------------------------------
* Copyright (c) 2014, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Implementation of ILI9488 driver.
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "board.h"
#include <string.h>
#include <stdio.h>
#ifdef BOARD_LCD_ILI9488
/*----------------------------------------------------------------------------
* Local variables
*----------------------------------------------------------------------------*/
#define ILI9488 SPI0
#define ILI9488_ID ID_SPI0
/** Pio pins to configure. */
static const Pin ILI9488_Reset[] = LCD_PIN_RESET;
static const Pin ILI9488_Pwm[] = BOARD_LCD_BACKLIGHT_PIN;
/** Pins to configure for the application. */
static const Pin spi_pins[] = BOARD_LCD_PINS;
/*----------------------------------------------------------------------------
* Local functions
*----------------------------------------------------------------------------*/
static void ILI9488_InitInterface(void)
{
PIO_Configure(ILI9488_Reset, PIO_LISTSIZE(ILI9488_Reset));
PIO_Configure(spi_pins, PIO_LISTSIZE(spi_pins));
PIO_Configure(ILI9488_Pwm, PIO_LISTSIZE(ILI9488_Pwm));
/* Enable PWM peripheral clock */
PMC_EnablePeripheral(ID_PWM0);
/* Set clock A and clock B */
// set for 14.11 KHz for CABC control
// mode = PWM_CLK_PREB(0x0A) | (PWM_CLK_DIVB(110)) |
// PWM_CLK_PREA(0x0A) | (PWM_CLK_DIVA(110));
PWMC_ConfigureClocks(PWM0, 14200, 0, BOARD_MCK);
/* Configure PWM channel 1 for LED0 */
PWMC_DisableChannel(PWM0, CHANNEL_PWM_LCD);
PWMC_ConfigureChannel(PWM0, CHANNEL_PWM_LCD, PWM_CMR_CPRE_CLKA,0,PWM_CMR_CPOL);
PWMC_SetPeriod(PWM0, CHANNEL_PWM_LCD, 16);
PWMC_SetDutyCycle(PWM0, CHANNEL_PWM_LCD, 8);
PWMC_EnableChannel(PWM0, CHANNEL_PWM_LCD);
SPI_Configure(ILI9488, ILI9488_ID, (SPI_MR_MSTR | SPI_MR_MODFDIS | SPI_PCS( ILI9488_cs )));
SPI_ConfigureNPCS( ILI9488, ILI9488_cs,
SPI_CSR_CPOL | SPI_CSR_BITS_9_BIT |
SPI_DLYBS(100, BOARD_MCK) | SPI_DLYBCT(100, BOARD_MCK) |
SPI_SCBR( 35000000, BOARD_MCK) ) ;
SPI_Enable(ILI9488);
}
/**
* \brief Send Command to ILI9488.
*
* \param reg Command Register address.
*
*/
static void ILI9488_SendCmd( uint8_t reg )
{
SPI_Write(ILI9488, ILI9488_cs, ILI9488_CMD(reg));
}
/**
* \brief Write Parameter to ILI9488 Register.
*
* \param data Data to be written.
*/
static void ILI9488_WriteReg( uint8_t data )
{
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(data));
}
/**
* \brief Write 16 bit Parameter to ILI9488 Register.
*
* \param data Data to be written.
*/
static void ILI9488_WriteReg16( uint16_t data )
{
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(((data & 0xFF00) >> 0x08)));
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM((data & 0xFF)));
}
/**
* \brief Write 24 bit Parameter to ILI9488 Register.
*
* \param data Data to be written.
*/
static void ILI9488_WriteReg24( uint32_t data )
{
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(((data & 0xFF0000) >> 0x10)));
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(((data & 0xFF00) >> 0x08)));
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM((data & 0xFF)));
}
/**
* \brief Write 32 bit Parameter to ILI9488 Register.
*
* \param data Data to be written.
*/
static void ILI9488_WriteReg32( uint32_t data )
{
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM((data >> 0x18) & 0xFF));
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(((data >> 0x10) & 0x00FF)));
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(((data >> 0x08) & 0x0000FF)));
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM((data & 0x000000FF)));
}
/**
* \brief Read data from ILI9488 Register.
*
* \param reg Register address.
*
* \return Readed data.
*/
static uint8_t ILI9488_ReadReg( uint8_t reg)
{
uint8_t value;
SPI_Write(ILI9488, ILI9488_cs, ILI9488_CMD(reg));
while(SPI_IsFinished(ILI9488) !=1);
SPI_Read(ILI9488);
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(0xFF));
while(SPI_IsFinished(ILI9488) !=1);
value = (uint8_t)SPI_Read(ILI9488);
ILI9488_SendCmd(ILI9488_CMD_SPI_READ_SETTINGS);
ILI9488_WriteReg(0);
return value;
}
/**
* \brief Read data from ILI9488 Register.
*
* \param reg Register address.
*
* \return Readed data.
*/
static uint16_t ILI9488_ReadReg16( uint8_t reg)
{
uint16_t value;
uint8_t SPI_CNT = 0x81;
ILI9488_SendCmd(ILI9488_CMD_SPI_READ_SETTINGS);
ILI9488_WriteReg(SPI_CNT);
value = (ILI9488_ReadReg(reg) << 0x08);
SPI_CNT++;
ILI9488_SendCmd(ILI9488_CMD_SPI_READ_SETTINGS);
ILI9488_WriteReg(SPI_CNT);
value |= ILI9488_ReadReg(reg);
ILI9488_SendCmd(ILI9488_CMD_SPI_READ_SETTINGS);
ILI9488_WriteReg(0);
return value;
}
/**
* \brief Read data from ILI9488 Register.
*
* \param reg Register address.
*
* \return Readed data.
*/
static uint32_t ILI9488_ReadReg24( uint8_t reg)
{
uint32_t value=0;
uint8_t SPI_CNT = 0x81;
//Set ILI9488 count to 0
ILI9488_SendCmd(ILI9488_CMD_SPI_READ_SETTINGS);
ILI9488_WriteReg(SPI_CNT);
// Send Command
value = (ILI9488_ReadReg(reg) << 0x10);
SPI_CNT++;
ILI9488_SendCmd(ILI9488_CMD_SPI_READ_SETTINGS);
ILI9488_WriteReg(SPI_CNT);
value |= (ILI9488_ReadReg(reg) << 0x08);
SPI_CNT++;
ILI9488_SendCmd(ILI9488_CMD_SPI_READ_SETTINGS);
ILI9488_WriteReg(SPI_CNT);
value |= ILI9488_ReadReg(reg);
ILI9488_SendCmd(ILI9488_CMD_SPI_READ_SETTINGS);
ILI9488_WriteReg(0);
return value;
}
/**
* \brief Read data from ILI9488 Register.
*
* \param reg Register address.
*
* \return Readed data.
*/
static uint32_t ILI9488_ReadReg32( uint8_t reg)
{
uint32_t value;
uint8_t SPI_CNT = 0x81;
ILI9488_SendCmd(ILI9488_CMD_SPI_READ_SETTINGS);
ILI9488_WriteReg(SPI_CNT);
value = ILI9488_ReadReg(reg) ;
value <<= 24;
SPI_CNT++;
ILI9488_SendCmd(ILI9488_CMD_SPI_READ_SETTINGS);
ILI9488_WriteReg(SPI_CNT);
value |= (ILI9488_ReadReg(reg) << 16);
SPI_CNT++;
ILI9488_SendCmd(ILI9488_CMD_SPI_READ_SETTINGS);
ILI9488_WriteReg(SPI_CNT);
value |= (ILI9488_ReadReg(reg) << 8);
SPI_CNT++;
ILI9488_SendCmd(ILI9488_CMD_SPI_READ_SETTINGS);
ILI9488_WriteReg(SPI_CNT);
value |= ILI9488_ReadReg(reg);
ILI9488_SendCmd(ILI9488_CMD_SPI_READ_SETTINGS);
ILI9488_WriteReg(0);
return value;
}
static void ILI9488_NOP(void)
{
ILI9488_SendCmd(ILI9488_CMD_NOP);
}
/**
* \brief Write data to ILI9488 Register.
*
* \param reg Register address.
* \param data Data to be written.
*/
void ILI9488_WriteSingle( LcdColor_t data )
{
ILI9488_SendCmd(ILI9488_CMD_MEMORY_WRITE);
ILI9488_WriteReg24(data);
}
/**
* \brief Prpare to write data to ILI9488 Register.
*
*/
void ILI9488_WriteRAM_Prepare(void)
{
ILI9488_SendCmd(ILI9488_CMD_MEMORY_WRITE);
}
/**
* \brief Prpare to write data to ILI9488 Register.
*
*/
void ILI9488_ReadRAM_Prepare(void)
{
ILI9488_SendCmd(ILI9488_CMD_MEMORY_READ);
}
/**
* \brief Write data to ILI9488 Register.
*
* \param reg Register address.
* \param data Data to be written.
*/
void ILI9488_WriteRAM( LcdColor_t data )
{
ILI9488_WriteReg24(data);
}
/**
* \brief Write data to ILI9488 Register.
*
* \param reg Register address.
* \param data Data to be written.
*/
void ILI9488_WriteRAMBuffer( const LcdColor_t *pBuf, uint32_t size)
{
uint32_t addr ;
for ( addr = 0 ; addr < size ; addr++ )
{
ILI9488_WriteRAM(pBuf[addr]);
}
}
void ILI9488_SetCursor(uint16_t x, uint16_t y)
{
/* Set Horizontal Address Start Position */
ILI9488_SendCmd(ILI9488_CMD_COLUMN_ADDRESS_SET);
ILI9488_WriteReg16(x);
ILI9488_WriteReg16(x+1);
ILI9488_NOP();
/* Set Horizontal Address End Position */
ILI9488_SendCmd(ILI9488_CMD_PAGE_ADDRESS_SET);
ILI9488_WriteReg16(y);
ILI9488_WriteReg16(y+1);
ILI9488_NOP();
}
/**
* \brief Initialize the ILI9488 controller.
*/
extern uint32_t ILI9488_Initialize( void )
{
uint32_t chipid;
ILI9488_InitInterface();
ILI9488_SendCmd(ILI9488_CMD_SOFTWARE_RESET);
Wait(200);
ILI9488_SendCmd(ILI9488_CMD_SLEEP_OUT);
Wait(200);
// make it tRGB and reverse the column order
ILI9488_SendCmd(ILI9488_CMD_MEMORY_ACCESS_CONTROL);
ILI9488_WriteReg(0x48);
Wait(100);
ILI9488_SendCmd(ILI9488_CMD_CABC_CONTROL_9); // set PWm to 14.11 KHz
ILI9488_WriteReg(0x04);
// ILI9488_SendCmd(ILI9488_CMD_COLMOD_PIXEL_FORMAT_SET); // set 16bit/pixel
// ILI9488_WriteReg(0x05);
/* Check ILI9488 chipid */
chipid = ILI9488_ReadReg24(ILI9488_CMD_READ_ID4); /* Driver Code Read */
if ( chipid != ILI9488_DEVICE_CODE )
{
printf( "Read ILI9488 chip ID (0x%04x) error, skip initialization.\r\n", chipid ) ;
assert(0);
return 1 ;
}
ILI9488_SendCmd(ILI9488_CMD_NORMAL_DISP_MODE_ON);
ILI9488_SendCmd(ILI9488_CMD_DISPLAY_ON);
return 0 ;
}
/**
* \brief Turn on the ILI9488.
*/
extern void ILI9488_On( void )
{
ILI9488_SendCmd(ILI9488_CMD_PIXEL_OFF);
ILI9488_SendCmd(ILI9488_CMD_DISPLAY_ON);
ILI9488_SendCmd(ILI9488_CMD_NORMAL_DISP_MODE_ON);
}
/**
* \brief Turn off the ILI9488.
*/
extern void ILI9488_Off( void )
{
ILI9488_SendCmd(ILI9488_CMD_DISPLAY_OFF);
ILI9488_SendCmd(ILI9488_CMD_DISPLAY_OFF);
}
/**
* \brief Power down the ILI9488.
*/
extern void ILI9488_PowerDown( void )
{
}
/**
* \brief Set a partial display window
*
* Initialize a partial window on ILI9488
* \param Start Starting address of window.
* \param End End address of window.
* \return 0 for successfull operation.
*/
extern void ILI9488_SetPartialWindow( uint16_t Start, uint16_t End)
{
ILI9488_SendCmd(ILI9488_CMD_POWER_CONTROL_PARTIAL_5);
ILI9488_WriteReg(0x44 ) ;
ILI9488_SendCmd(ILI9488_CMD_PARTIAL_AREA);
ILI9488_WriteReg16(Start ) ;
ILI9488_WriteReg16(End) ;
ILI9488_SendCmd(ILI9488_CMD_PARTIAL_MODE_ON);
Wait(10);
}
extern void ILI9488_SetWindow( uint16_t dwX, uint16_t dwY, uint16_t dwWidth, uint16_t dwHeight )
{
uint16_t ColStart, ColEnd, RowStart, RowEnd;
ColStart = dwX ;
ColEnd = dwWidth;
RowStart = dwY ;
RowEnd = dwHeight;
if ( ( ColEnd > (ILI9488_LCD_WIDTH)) || ( RowEnd > (ILI9488_LCD_HEIGHT)))
{
printf("\n\rWindow too large\n\r");
assert(1);
}
if ( ( ColEnd < ColStart) || ( RowEnd < RowStart) )
{
printf("\n\rWindow's hight or width is not large enough\n\r");
assert(1);
}
/* Set Horizontal Address Start Position */
ILI9488_SendCmd(ILI9488_CMD_COLUMN_ADDRESS_SET);
ILI9488_WriteReg16(ColStart);
ILI9488_WriteReg16(ColEnd);
ILI9488_NOP();
/* Set Horizontal Address End Position */
ILI9488_SendCmd(ILI9488_CMD_PAGE_ADDRESS_SET);
ILI9488_WriteReg16(RowStart);
ILI9488_WriteReg16(RowEnd);
ILI9488_NOP();
}
extern void ILI9488_SetDisplayLandscape( uint8_t dwRGB, uint8_t LandscaprMode )
{
uint8_t Value;
if(LandscaprMode)
{
if(dwRGB)
{
Value = 0xA8;
}
else
{
Value = 0xA0;
}
}
else
{
if(dwRGB)
{
Value = 0xE8;
}
else
{
Value = 0xE0;
}
}
// make it tRGB and reverse the column order
ILI9488_SendCmd(ILI9488_CMD_MEMORY_ACCESS_CONTROL);
ILI9488_WriteReg(Value);
Wait(50);
ILI9488_SetWindow( 0, 0, BOARD_LCD_WIDTH, BOARD_LCD_HEIGHT ) ;
}
extern void ILI9488_SetDisplayPortrait( uint8_t dwRGB )
{
uint8_t Value;
if(dwRGB)
{
Value = 0x48;
}
else
{
Value = 0x40;
}
// make it tRGB and reverse the column order
ILI9488_SendCmd(ILI9488_CMD_MEMORY_ACCESS_CONTROL);
ILI9488_WriteReg(Value);
Wait(50);
ILI9488_SetWindow( 0, 0, BOARD_LCD_WIDTH, BOARD_LCD_HEIGHT) ;
}
extern void ILI9488_SetVerticalScrollWindow( uint16_t dwStartAdd, uint16_t dwHeight )
{
ILI9488_SendCmd(ILI9488_CMD_VERT_SCROLL_DEFINITION);
ILI9488_WriteReg16(dwStartAdd-1);
ILI9488_WriteReg16(dwStartAdd);
ILI9488_WriteReg16((dwStartAdd + dwHeight + 1));
}
extern void ILI9488_VerticalScroll( uint16_t wY )
{
ILI9488_SendCmd(ILI9488_CMD_VERT_SCROLL_START_ADDRESS);
ILI9488_WriteReg16(wY);
}
extern void ILI9488_ExitScrollMode(void )
{
ILI9488_SendCmd(ILI9488_CMD_DISPLAY_OFF);
ILI9488_SendCmd(ILI9488_CMD_NORMAL_DISP_MODE_ON);
ILI9488_SendCmd(ILI9488_CMD_DISPLAY_ON);
}
extern void ILI9488_TestPattern(void)
{
uint32_t i, data;
ILI9488_SetWindow( 0, 0, 319, 479 ) ;
data = COLOR_WHITE;
ILI9488_SendCmd(ILI9488_CMD_MEMORY_WRITE);
for(i = 0; i< (BOARD_LCD_WIDTH * BOARD_LCD_HEIGHT); i++)
{
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(data >> 16));
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(data >> 8));
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(data & 0xFF));
}
ILI9488_SetWindow( 50, 50, 300, 300 ) ;
data = COLOR_BLUE;
ILI9488_SendCmd(ILI9488_CMD_MEMORY_WRITE);
for(i = 0; i< (BOARD_LCD_WIDTH * BOARD_LCD_HEIGHT); i++)
{
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(data >> 16));
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(data >> 8));
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(data & 0xFF));
}
ILI9488_SetWindow( 150, 150, 300, 300 ) ;
data = COLOR_GREEN;
ILI9488_SendCmd(ILI9488_CMD_MEMORY_WRITE);
for(i = 0; i< (BOARD_LCD_WIDTH * BOARD_LCD_HEIGHT); i++)
{
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(data >> 16));
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(data >> 8));
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(data & 0xFF));
}
ILI9488_SetWindow(200, 200, 300, 300 ) ;
data = COLOR_RED;
ILI9488_SendCmd(ILI9488_CMD_MEMORY_WRITE);
for(i = 0; i< (BOARD_LCD_WIDTH * BOARD_LCD_HEIGHT); i++)
{
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(data >> 16));
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(data >> 8));
SPI_Write(ILI9488, ILI9488_cs, ILI9488_PARAM(data & 0xFF));
}
}
#endif