freertos_f407/User/system/lib/lcd/lcd_tft_154.c

260 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "lcd_tft_154.h"
// 等待通讯完成
static void _wait_finish(spi_t *lcd_spi)
{
while ((lcd_spi->spi->Instance->SR & 0x0080) != RESET)
; // 等待通信完成
}
// 等待发送缓冲区清空
static void _wait_send_empty(spi_t *lcd_spi)
{
while ((lcd_spi->spi->Instance->SR & 0x0002) == 0)
; // 等待发送缓冲区清空
}
static void _write_command(spi_t *lcd_spi, uint8_t command)
{
_wait_finish(lcd_spi); // 等待通讯完成
lcd_spi->gpios.dc->reset(*lcd_spi->gpios.dc); // DC置低表示发送命令
(lcd_spi->spi)->Instance->DR = command; // 发送数据
_wait_send_empty(lcd_spi); // 等待发送缓冲区清空
_wait_finish(lcd_spi); // 等待通讯完成 等待通信完成
lcd_spi->gpios.dc->set(*lcd_spi->gpios.dc); // DC置高表示发送数据
}
static void _write_data_8bit(spi_t *lcd_spi, uint8_t data)
{
lcd_spi->spi->Instance->DR = data; // 发送数据
_wait_send_empty(lcd_spi); // 等待发送缓冲区清空
}
static void _write_data_16bit(spi_t *lcd_spi, uint16_t data)
{
lcd_spi->spi->Instance->DR = data >> 8; // 发送数据高8位
_wait_send_empty(lcd_spi); // 等待发送缓冲区清空
lcd_spi->spi->Instance->DR = data; // 发送数据低8位
_wait_send_empty(lcd_spi); // 等待发送缓冲区清空
}
static void _write_buff(lcd_t *lcd, uint16_t *data, uint16_t size)
{
uint32_t i;
lcd->info.spi->spi->Instance->CR1 &= 0xFFBF; // 关闭SPI
lcd->info.spi->spi->Instance->CR1 |= 0x0800; // 切换成16位数据格式
lcd->info.spi->spi->Instance->CR1 |= 0x0040; // 使能SPI
lcd->info.spi->gpios.cs->reset(*lcd->info.spi->gpios.cs);
for (i = 0; i < size; i++)
{
lcd->info.spi->spi->Instance->DR = data[i];
_wait_send_empty(lcd->info.spi); // 等待发送缓冲区清空
}
_wait_finish(lcd->info.spi); // 等待通讯完成
lcd->info.spi->gpios.cs->set(*lcd->info.spi->gpios.cs);
lcd->info.spi->spi->Instance->CR1 &= 0xFFBF; // 关闭SPI
lcd->info.spi->spi->Instance->CR1 &= 0xF7FF; // 切换成8位数据格式
lcd->info.spi->spi->Instance->CR1 |= 0x0040; // 使能SPI
}
// 设置方向
static void _set_dir(lcd_t *lcd, uint8_t scan_dir)
{
lcd->info.dir = scan_dir;
lcd->info.spi->gpios.cs->reset(*lcd->info.spi->gpios.cs);
if (scan_dir == Direction_H) // 横屏显示
{
_write_command(lcd->info.spi, 0x36); // 显存访问控制 指令,用于设置访问显存的方式
_write_data_8bit(lcd->info.spi, 0x70); // 横屏显示
lcd->info.x_offset = 0; // 设置控制器坐标偏移量
lcd->info.y_offset = 0;
}
else if (scan_dir == Direction_V)
{
_write_command(lcd->info.spi, 0x36); // 显存访问控制 指令,用于设置访问显存的方式
_write_data_8bit(lcd->info.spi, 0x00); // 垂直显示
lcd->info.x_offset = 0; // 设置控制器坐标偏移量
lcd->info.y_offset = 0;
}
else if (scan_dir == Direction_H_Flip)
{
_write_command(lcd->info.spi, 0x36); // 显存访问控制 指令,用于设置访问显存的方式
_write_data_8bit(lcd->info.spi, 0xA0); // 横屏显示并上下翻转RGB像素格式
lcd->info.x_offset = 80; // 设置控制器坐标偏移量
lcd->info.y_offset = 0;
}
else if (scan_dir == Direction_V_Flip)
{
_write_command(lcd->info.spi, 0x36); // 显存访问控制 指令,用于设置访问显存的方式
_write_data_8bit(lcd->info.spi, 0xC0); // 垂直显示 并上下翻转RGB像素格式
lcd->info.x_offset = 0; // 设置控制器坐标偏移量
lcd->info.y_offset = 80;
}
_wait_finish(lcd->info.spi); // 等待通讯完成
lcd->info.spi->gpios.cs->set(*lcd->info.spi->gpios.cs);
}
static void _set_address(lcd_t *lcd, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
lcd->info.spi->gpios.cs->reset(*lcd->info.spi->gpios.cs);
_write_command(lcd->info.spi, 0x2a); // 列地址设置即X坐标
_write_data_16bit(lcd->info.spi, x1 + lcd->info.x_offset);
_write_data_16bit(lcd->info.spi, x2 + lcd->info.x_offset);
_write_command(lcd->info.spi, 0x2b); // 行地址设置即Y坐标
_write_data_16bit(lcd->info.spi, y1 + lcd->info.y_offset);
_write_data_16bit(lcd->info.spi, y2 + lcd->info.y_offset);
_write_command(lcd->info.spi, 0x2c); // 开始写入显存,即要显示的颜色数据
_wait_finish(lcd->info.spi); // 等待通讯完成
lcd->info.spi->gpios.cs->set(*lcd->info.spi->gpios.cs);
}
// 写像素缓冲区
static void _write_pixels(lcd_t *lcd, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t *data)
{
uint32_t len = (uint32_t)(x2 - x1 + 1) * (y2 - y1 + 1);
lcd->driver.set_address(lcd, x1, y1, x2, y2);
_write_buff(lcd, data, len);
}
static void _clear(lcd_t *lcd)
{
uint32_t i;
lcd->driver.set_address(lcd, 0, 0, lcd->info.width - 1, lcd->info.height - 1);
lcd->info.spi->spi->Instance->CR1 &= 0xFFBF; // 关闭SPI
lcd->info.spi->spi->Instance->CR1 |= 0x0800; // 切换成16位数据格式
lcd->info.spi->spi->Instance->CR1 |= 0x0040; // 使能SPI
lcd->info.spi->gpios.cs->reset(*lcd->info.spi->gpios.cs);
for (i = 0; i < lcd->info.width * lcd->info.height; i++)
{
lcd->info.spi->spi->Instance->DR = lcd->info.back_color;
_wait_send_empty(lcd->info.spi); // 等待发送缓冲区清空
}
_wait_finish(lcd->info.spi); // 等待通讯完成
lcd->info.spi->gpios.cs->set(*lcd->info.spi->gpios.cs);
lcd->info.spi->spi->Instance->CR1 &= 0xFFBF; // 关闭SPI
lcd->info.spi->spi->Instance->CR1 &= 0xF7FF; // 切换成8位数据格式
lcd->info.spi->spi->Instance->CR1 |= 0x0040; // 使能SPI
}
static int32_t _init(lcd_t *lcd)
{
HAL_Delay(10);
lcd->info.spi->gpios.cs->reset(*lcd->info.spi->gpios.cs);
_write_command(lcd->info.spi, 0x36); // 显存访问控制 指令,用于设置访问显存的方式
_write_data_8bit(lcd->info.spi, 0x00); // 配置成 从上到下、从左到右RGB像素格式
_write_command(lcd->info.spi, 0x3A); // 接口像素格式 指令,用于设置使用 12位、16位还是18位色
_write_data_8bit(lcd->info.spi, 0x05); // 此处配置成 16位 像素格式
// 接下来很多都是电压设置指令,直接使用厂家给设定值
_write_command(lcd->info.spi, 0xB2);
_write_data_8bit(lcd->info.spi, 0x0C);
_write_data_8bit(lcd->info.spi, 0x0C);
_write_data_8bit(lcd->info.spi, 0x00);
_write_data_8bit(lcd->info.spi, 0x33);
_write_data_8bit(lcd->info.spi, 0x33);
_write_command(lcd->info.spi, 0xB7); // 栅极电压设置指令
_write_data_8bit(lcd->info.spi, 0x35); // VGH = 13.26VVGL = -10.43V
_write_command(lcd->info.spi, 0xBB); // 公共电压设置指令
_write_data_8bit(lcd->info.spi, 0x19); // VCOM = 1.35V
_write_command(lcd->info.spi, 0xC0);
_write_data_8bit(lcd->info.spi, 0x2C);
_write_command(lcd->info.spi, 0xC2); // VDV 和 VRH 来源设置
_write_data_8bit(lcd->info.spi, 0x01); // VDV 和 VRH 由用户自由配置
_write_command(lcd->info.spi, 0xC3); // VRH电压 设置指令
_write_data_8bit(lcd->info.spi, 0x12); // VRH电压 = 4.6+( vcom+vcom offset+vdv)
_write_command(lcd->info.spi, 0xC4); // VDV电压 设置指令
_write_data_8bit(lcd->info.spi, 0x20); // VDV电压 = 0v
_write_command(lcd->info.spi, 0xC6); // 正常模式的帧率控制指令
_write_data_8bit(lcd->info.spi, 0x0F); // 设置屏幕控制器的刷新帧率为60帧
_write_command(lcd->info.spi, 0xD0); // 电源控制指令
_write_data_8bit(lcd->info.spi, 0xA4); // 无效数据固定写入0xA4
_write_data_8bit(lcd->info.spi, 0xA1); // AVDD = 6.8V AVDD = -4.8V VDS = 2.3V
_write_command(lcd->info.spi, 0xE0); // 正极电压伽马值设定
_write_data_8bit(lcd->info.spi, 0xD0);
_write_data_8bit(lcd->info.spi, 0x04);
_write_data_8bit(lcd->info.spi, 0x0D);
_write_data_8bit(lcd->info.spi, 0x11);
_write_data_8bit(lcd->info.spi, 0x13);
_write_data_8bit(lcd->info.spi, 0x2B);
_write_data_8bit(lcd->info.spi, 0x3F);
_write_data_8bit(lcd->info.spi, 0x54);
_write_data_8bit(lcd->info.spi, 0x4C);
_write_data_8bit(lcd->info.spi, 0x18);
_write_data_8bit(lcd->info.spi, 0x0D);
_write_data_8bit(lcd->info.spi, 0x0B);
_write_data_8bit(lcd->info.spi, 0x1F);
_write_data_8bit(lcd->info.spi, 0x23);
_write_command(lcd->info.spi, 0xE1); // 负极电压伽马值设定
_write_data_8bit(lcd->info.spi, 0xD0);
_write_data_8bit(lcd->info.spi, 0x04);
_write_data_8bit(lcd->info.spi, 0x0C);
_write_data_8bit(lcd->info.spi, 0x11);
_write_data_8bit(lcd->info.spi, 0x13);
_write_data_8bit(lcd->info.spi, 0x2C);
_write_data_8bit(lcd->info.spi, 0x3F);
_write_data_8bit(lcd->info.spi, 0x44);
_write_data_8bit(lcd->info.spi, 0x51);
_write_data_8bit(lcd->info.spi, 0x2F);
_write_data_8bit(lcd->info.spi, 0x1F);
_write_data_8bit(lcd->info.spi, 0x1F);
_write_data_8bit(lcd->info.spi, 0x20);
_write_data_8bit(lcd->info.spi, 0x23);
_write_command(lcd->info.spi, 0x21); // 打开反显,因为面板是常黑型,操作需要反过来
// 退出休眠指令LCD控制器在刚上电、复位时会自动进入休眠模式 ,因此操作屏幕之前,需要退出休眠
_write_command(lcd->info.spi, 0x11); // 退出休眠 指令
HAL_Delay(120); // 需要等待120ms让电源电压和时钟电路稳定下来
// 打开显示指令LCD控制器在刚上电、复位时会自动关闭显示
_write_command(lcd->info.spi, 0x29); // 打开显示
_wait_finish(lcd->info.spi); // 等待通讯完成
lcd->info.spi->gpios.cs->set(*lcd->info.spi->gpios.cs);
// 以下进行一些驱动的默认设置
lcd->driver.set_dir(lcd, Direction_V); // 默认竖屏显示
lcd->info.back_color = 0x0000; // 默认背景色为黑色
lcd->driver.clear(lcd); // 清除屏幕
return 0;
}
void lcd_tft_154_init(lcd_driver_t *driver)
{
DBG_ASSERT(driver != NULL __DBG_LINE);
driver->init = _init; // 已实现
driver->set_dir = _set_dir; // 已实现
driver->set_address = _set_address; // 已实现
driver->write_pixels = _write_pixels; // 已实现
driver->clear = _clear; // 已实现
}