rt-thread-official/bsp/raspberry-pico/board/ports/lcd/drv_lcd.c

445 lines
12 KiB
C

#include <drv_lcd.h>
#include <stdlib.h>
#define SPI_PORT spi1
uint slice_num;
LCD_ATTRIBUTES LCD;
/******************************************************************************
function : Hardware reset
parameter:
******************************************************************************/
static void LCD_Reset(void)
{
DEV_Digital_Write(LCD_RST_PIN, 1);
rt_thread_mdelay(100);
DEV_Digital_Write(LCD_RST_PIN, 0);
rt_thread_mdelay(100);
DEV_Digital_Write(LCD_RST_PIN, 1);
rt_thread_mdelay(100);
}
/******************************************************************************
function : send command
parameter:
Reg : Command register
******************************************************************************/
static void LCD_SendCommand(UBYTE Reg)
{
DEV_Digital_Write(LCD_DC_PIN, 0);
DEV_Digital_Write(LCD_CS_PIN, 0);
DEV_SPI_WriteByte(Reg);
DEV_Digital_Write(LCD_CS_PIN, 1);
}
/******************************************************************************
function : send data
parameter:
Data : Write data
******************************************************************************/
static void LCD_SendData_8Bit(UBYTE Data)
{
DEV_Digital_Write(LCD_DC_PIN, 1);
DEV_Digital_Write(LCD_CS_PIN, 0);
DEV_SPI_WriteByte(Data);
DEV_Digital_Write(LCD_CS_PIN, 1);
}
/******************************************************************************
function : send data
parameter:
Data : Write data
******************************************************************************/
static void LCD_SendData_16Bit(UWORD Data)
{
DEV_Digital_Write(LCD_DC_PIN, 1);
DEV_Digital_Write(LCD_CS_PIN, 0);
DEV_SPI_WriteByte((Data >> 8) & 0xFF);
DEV_SPI_WriteByte(Data & 0xFF);
DEV_Digital_Write(LCD_CS_PIN, 1);
}
/******************************************************************************
function : Initialize the lcd register
parameter:
******************************************************************************/
static void LCD_InitReg(void)
{
LCD_SendCommand(0x3A);
LCD_SendData_8Bit(0x05);
LCD_SendCommand(0xB2);
LCD_SendData_8Bit(0x0C);
LCD_SendData_8Bit(0x0C);
LCD_SendData_8Bit(0x00);
LCD_SendData_8Bit(0x33);
LCD_SendData_8Bit(0x33);
LCD_SendCommand(0xB7); // Gate Control
LCD_SendData_8Bit(0x35);
LCD_SendCommand(0xBB); // VCOM Setting
LCD_SendData_8Bit(0x19);
LCD_SendCommand(0xC0); // LCM Control
LCD_SendData_8Bit(0x2C);
LCD_SendCommand(0xC2); // VDV and VRH Command Enable
LCD_SendData_8Bit(0x01);
LCD_SendCommand(0xC3); // VRH Set
LCD_SendData_8Bit(0x12);
LCD_SendCommand(0xC4); // VDV Set
LCD_SendData_8Bit(0x20);
LCD_SendCommand(0xC6); // Frame Rate Control in Normal Mode
LCD_SendData_8Bit(0x01); // 110hz
LCD_SendCommand(0xD0); // Power Control 1
LCD_SendData_8Bit(0xA4);
LCD_SendData_8Bit(0xA1);
LCD_SendCommand(0xE0); // Positive Voltage Gamma Control
LCD_SendData_8Bit(0xD0);
LCD_SendData_8Bit(0x04);
LCD_SendData_8Bit(0x0D);
LCD_SendData_8Bit(0x11);
LCD_SendData_8Bit(0x13);
LCD_SendData_8Bit(0x2B);
LCD_SendData_8Bit(0x3F);
LCD_SendData_8Bit(0x54);
LCD_SendData_8Bit(0x4C);
LCD_SendData_8Bit(0x18);
LCD_SendData_8Bit(0x0D);
LCD_SendData_8Bit(0x0B);
LCD_SendData_8Bit(0x1F);
LCD_SendData_8Bit(0x23);
LCD_SendCommand(0xE1); // Negative Voltage Gamma Control
LCD_SendData_8Bit(0xD0);
LCD_SendData_8Bit(0x04);
LCD_SendData_8Bit(0x0C);
LCD_SendData_8Bit(0x11);
LCD_SendData_8Bit(0x13);
LCD_SendData_8Bit(0x2C);
LCD_SendData_8Bit(0x3F);
LCD_SendData_8Bit(0x44);
LCD_SendData_8Bit(0x51);
LCD_SendData_8Bit(0x2F);
LCD_SendData_8Bit(0x1F);
LCD_SendData_8Bit(0x1F);
LCD_SendData_8Bit(0x20);
LCD_SendData_8Bit(0x23);
LCD_SendCommand(0x21); // Display Inversion On
LCD_SendCommand(0x11); // Sleep Out
LCD_SendCommand(0x29); // Display On
}
/********************************************************************************
function: Set the resolution and scanning method of the screen
parameter:
Scan_dir: Scan direction
********************************************************************************/
static void LCD_SetAttributes(UBYTE Scan_dir)
{
// Get the screen scan direction
LCD.SCAN_DIR = Scan_dir;
UBYTE MemoryAccessReg = 0x00;
// Get GRAM and LCD width and height
if (Scan_dir == HORIZONTAL)
{
LCD.HEIGHT = LCD_WIDTH;
LCD.WIDTH = LCD_HEIGHT;
MemoryAccessReg = 0X70;
}
else
{
LCD.HEIGHT = LCD_HEIGHT;
LCD.WIDTH = LCD_WIDTH;
MemoryAccessReg = 0X00;
}
// Set the read / write scan direction of the frame memory
LCD_SendCommand(0x36); // MX, MY, RGB mode
LCD_SendData_8Bit(MemoryAccessReg); // 0x08 set RGB
}
/********************************************************************************
function : Initialize the lcd
parameter:
********************************************************************************/
void LCD_Init(UBYTE Scan_dir)
{
DEV_SET_PWM(50);
// Hardware reset
LCD_Reset();
// Set the resolution and scanning method of the screen
LCD_SetAttributes(Scan_dir);
// Set the initialization register
LCD_InitReg();
}
void LCD_SetWindows(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend)
{
// set the X coordinates
LCD_SendCommand(0x2A);
LCD_SendData_8Bit((Xstart >> 8) & 0xFF);
LCD_SendData_8Bit(Xstart & 0xFF);
LCD_SendData_8Bit(((Xend - 1) >> 8) & 0xFF);
LCD_SendData_8Bit((Xend - 1) & 0xFF);
// set the Y coordinates
LCD_SendCommand(0x2B);
LCD_SendData_8Bit((Ystart >> 8) & 0xFF);
LCD_SendData_8Bit(Ystart & 0xFF);
LCD_SendData_8Bit(((Yend - 1) >> 8) & 0xFF);
LCD_SendData_8Bit((Yend - 1) & 0xFF);
LCD_SendCommand(0X2C);
}
/******************************************************************************
function : Clear screen
parameter:
******************************************************************************/
void LCD_Clear(UWORD Color)
{
UWORD j, i;
UWORD Image[LCD.WIDTH * LCD.HEIGHT];
Color = ((Color << 8) & 0xff00) | (Color >> 8);
for (j = 0; j < LCD.HEIGHT * LCD.WIDTH; j++)
{
Image[j] = Color;
}
LCD_SetWindows(0, 0, LCD.WIDTH, LCD.HEIGHT);
DEV_Digital_Write(LCD_DC_PIN, 1);
DEV_Digital_Write(LCD_CS_PIN, 0);
for (j = 0; j < LCD.HEIGHT; j++)
{
DEV_SPI_Write_nByte((uint8_t *) &Image[j * LCD.WIDTH], LCD.WIDTH * 2);
}
DEV_Digital_Write(LCD_CS_PIN, 1);
}
/******************************************************************************
function : Sends the image buffer in RAM to displays
parameter:
******************************************************************************/
void LCD_Display(UWORD *Image)
{
UWORD j;
LCD_SetWindows(0, 0, LCD.WIDTH, LCD.HEIGHT);
DEV_Digital_Write(LCD_DC_PIN, 1);
DEV_Digital_Write(LCD_CS_PIN, 0);
for (j = 0; j < LCD.HEIGHT; j++)
{
DEV_SPI_Write_nByte((uint8_t *) &Image[j * LCD.WIDTH], LCD.WIDTH * 2);
}
DEV_Digital_Write(LCD_CS_PIN, 1);
LCD_SendCommand(0x29);
}
/******************************************************************************
function : Sends the image buffer in RAM to displays
parameter:
Xstart : X direction Start coordinates
Ystart : Y direction Start coordinates
Xend : X direction end coordinates
Yend : Y direction end coordinates
Image : Written content
******************************************************************************/
void LCD_DisplayWindows(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD *Image)
{
// display
UDOUBLE Addr = 0;
UWORD j;
LCD_SetWindows(Xstart, Ystart, Xend, Yend);
DEV_Digital_Write(LCD_DC_PIN, 1);
DEV_Digital_Write(LCD_CS_PIN, 0);
for (j = Ystart; j < Yend - 1; j++)
{
Addr = Xstart + j * LCD.WIDTH;
DEV_SPI_Write_nByte((uint8_t *) &Image[Addr], (Xend - Xstart) * 2);
}
DEV_Digital_Write(LCD_CS_PIN, 1);
}
/******************************************************************************
function : Change the color of a point
parameter:
X : X coordinates
Y : Y coordinates
Color : Color
******************************************************************************/
void LCD_DisplayPoint(UWORD X, UWORD Y, UWORD Color)
{
LCD_SetWindows(X, Y, X, Y);
LCD_SendData_16Bit(Color);
}
void Handler_LCD(int signo)
{
// System Exit
rt_kprintf("\r\nHandler:Program stop\r\n");
DEV_Module_Exit();
exit(0);
}
/**
* GPIO read and write
**/
void DEV_Digital_Write(UWORD Pin, UBYTE Value)
{
gpio_put(Pin, Value);
}
UBYTE DEV_Digital_Read(UWORD Pin)
{
return gpio_get(Pin);
}
/**
* GPIO Mode
**/
void DEV_GPIO_Mode(UWORD Pin, UWORD Mode)
{
gpio_init(Pin);
if (Mode == 0 || Mode == GPIO_IN)
{
gpio_set_dir(Pin, GPIO_IN);
}
else
{
gpio_set_dir(Pin, GPIO_OUT);
}
}
/**
* SPI
**/
void DEV_SPI_WriteByte(UBYTE Value)
{
spi_write_blocking(SPI_PORT, &Value, 1);
}
void DEV_SPI_Write_nByte(UBYTE pData[], UDOUBLE Len)
{
spi_write_blocking(SPI_PORT, pData, Len);
}
void DEV_GPIO_Init(void)
{
DEV_GPIO_Mode(LCD_RST_PIN, 1);
DEV_GPIO_Mode(LCD_DC_PIN, 1);
DEV_GPIO_Mode(LCD_CS_PIN, 1);
DEV_GPIO_Mode(LCD_BL_PIN, 1);
DEV_Digital_Write(LCD_CS_PIN, 1);
DEV_Digital_Write(LCD_DC_PIN, 0);
DEV_Digital_Write(LCD_BL_PIN, 1);
}
/******************************************************************************
function: Module Initialize, the library and initialize the pins, SPI protocol
parameter:
Info:
******************************************************************************/
UBYTE DEV_Module_Init(void)
{
// SPI Config
spi_init(SPI_PORT, 80000 * 1000);
gpio_set_function(LCD_CLK_PIN, GPIO_FUNC_SPI);
gpio_set_function(LCD_MOSI_PIN, GPIO_FUNC_SPI);
// GPIO Config
DEV_GPIO_Init();
// PWM Config
gpio_set_function(LCD_BL_PIN, GPIO_FUNC_PWM);
slice_num = pwm_gpio_to_slice_num(LCD_BL_PIN);
pwm_set_wrap(slice_num, 100);
pwm_set_chan_level(slice_num, PWM_CHAN_B, 1);
pwm_set_clkdiv(slice_num, 50);
pwm_set_enabled(slice_num, true);
rt_kprintf("DEV_Module_Init OK \r\n");
return 0;
}
void DEV_SET_PWM(UBYTE Value)
{
if (Value < 0 || Value > 100)
{
rt_kprintf("DEV_SET_PWM Error \r\n");
}
else
{
pwm_set_chan_level(slice_num, PWM_CHAN_B, Value);
}
}
UBYTE SPI_Init(void)
{
DEV_Module_Init();
return 0;
}
bool _swapBytes;
UDOUBLE dma_tx_channel;
dma_channel_config dma_tx_config;
/***************************************************************************************
** Function name: dmaWait
** Description: Wait until DMA is over (blocking!)
***************************************************************************************/
void dmaWait(void)
{
while (dma_channel_is_busy(dma_tx_channel))
;
// For SPI must also wait for FIFO to flush and reset format
while (spi_get_hw(SPI_PORT)->sr & SPI_SSPSR_BSY_BITS)
{
};
spi_set_format(SPI_PORT, 16, (spi_cpol_t) 0, (spi_cpha_t) 0, SPI_MSB_FIRST);
}
/***************************************************************************************
** Function name: pushPixelsDMA
** Description: Push pixels to TFT
***************************************************************************************/
void pushPixelsDMA(UWORD* image, UDOUBLE len)
{
if ((len == 0))
return;
dmaWait();
channel_config_set_bswap(&dma_tx_config, !_swapBytes);
dma_channel_configure(dma_tx_channel, &dma_tx_config, &spi_get_hw(SPI_PORT)->dr, (UWORD*) image, len, true);
}
bool initDMA(bool ctrl_cs)
{
dma_tx_channel = dma_claim_unused_channel(true);
dma_tx_config = dma_channel_get_default_config(dma_tx_channel);
channel_config_set_transfer_data_size(&dma_tx_config, DMA_SIZE_16);
channel_config_set_dreq(&dma_tx_config, spi_get_index(SPI_PORT) ? DREQ_SPI1_TX : DREQ_SPI0_TX);
return true;
}