520 lines
13 KiB
C
520 lines
13 KiB
C
#include "lcds.h"
|
||
#include "delay.h"
|
||
|
||
#define LCD_CMD_CLEAR 0x56 // 0b01010110
|
||
#define LCD_CMD_UPDATE 0x93 // 0b10010011
|
||
#define LCD_CMD_NOP 0x00
|
||
#define CLEAR_COLOR 0xff
|
||
|
||
static uint8_t *change_line;
|
||
|
||
#if defined(SRAM2_BASE)
|
||
volatile static uint8_t pri[COL_DOT_MAX_400 * LIN_DOT_MAX_240 / 8] __attribute__((section(".sram2"))); // 显示缓存
|
||
volatile static uint8_t pri_send[COL_DOT_MAX_400 * LIN_DOT_MAX_240 / 8]; // 发送缓存
|
||
volatile static uint8_t pri_template[COL_DOT_MAX_400 * LIN_DOT_MAX_240 / 8]; // 模版
|
||
#endif
|
||
|
||
/**
|
||
* @brief 夏普LCD片选
|
||
* @param {sharp_t} *lcd
|
||
* @param {uint8_t} sta
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static int32_t sharp_chip_select(lcd_t *lcd, uint8_t sta)
|
||
{
|
||
DBG_ASSERT(lcd != NULL __DBG_LINE);
|
||
DBG_ASSERT(lcd->info.spi != NULL __DBG_LINE);
|
||
if (sta == 1)
|
||
{
|
||
lcd->info.spi->gpios.cs->set(*lcd->info.spi->gpios.cs);
|
||
}
|
||
else
|
||
{
|
||
lcd->info.spi->gpios.cs->reset(*lcd->info.spi->gpios.cs);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 夏普LCD单字节传输
|
||
* @param {sharp_t} *lcd
|
||
* @param {uint8_t} data
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static BOOL sharp_transmit_byte(lcd_t *lcd, uint8_t data)
|
||
{
|
||
uint16_t j = 0;
|
||
BOOL ret = TRUE;
|
||
DBG_ASSERT(lcd != NULL __DBG_LINE);
|
||
DBG_ASSERT(lcd->info.spi != NULL __DBG_LINE);
|
||
LL_SPI_TransmitData8(lcd->info.spi->spi, data);
|
||
while (LL_SPI_IsActiveFlag_TXE(lcd->info.spi->spi) == 0)
|
||
{
|
||
j++;
|
||
if (j > 1000)
|
||
{
|
||
ret = FALSE;
|
||
return ret;
|
||
}
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
/**
|
||
* @brief lcd清屏
|
||
* @param {sharp_t} *lcd
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static int32_t _clear(lcd_t *lcd)
|
||
{
|
||
DBG_ASSERT(lcd != NULL __DBG_LINE);
|
||
DBG_ASSERT(lcd->info.spi != NULL __DBG_LINE);
|
||
sharp_chip_select(lcd, TRUE);
|
||
sharp_transmit_byte(lcd, LCD_CMD_CLEAR);
|
||
sharp_transmit_byte(lcd, LCD_CMD_NOP);
|
||
sharp_transmit_byte(lcd, LCD_CMD_NOP);
|
||
sharp_chip_select(lcd, FALSE);
|
||
|
||
lcd->info.clear_flag = FALSE;
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 初始化,包括硬件初始化和软件初始化
|
||
* @param {lcd_t} *lcd
|
||
* @return {*}
|
||
*/
|
||
static int32_t _init(lcd_t *lcd)
|
||
{
|
||
lcd->info.on = 0xff;
|
||
uint16_t size = (lcd->info.width / 8) * (lcd->info.height);
|
||
#if defined(SRAM2_BASE)
|
||
lcd->info.pri = (void *)pri;
|
||
lcd->info.pri_send = (void *)pri_send;
|
||
lcd->info.pri_template = (void *)pri_template;
|
||
#else
|
||
lcd->info.pri = (uint8_t *)osel_mem_alloc(size);
|
||
lcd->info.pri_send = (uint8_t *)osel_mem_alloc(size);
|
||
lcd->info.pri_template = (uint8_t *)osel_mem_alloc(size);
|
||
#endif
|
||
|
||
osel_memset((uint8_t *)lcd->info.pri, CLEAR_COLOR, size);
|
||
osel_memset((uint8_t *)lcd->info.pri_send, CLEAR_COLOR, size);
|
||
osel_memset((uint8_t *)lcd->info.pri_template, CLEAR_COLOR, size);
|
||
|
||
change_line = (uint8_t *)osel_mem_alloc(lcd->info.height);
|
||
osel_memset((uint8_t *)change_line, 0, lcd->info.height);
|
||
|
||
lcd->driver.onoff(lcd, TRUE);
|
||
lcd->driver.clear(lcd);
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 拷贝模板
|
||
* @param {lcd_t} *lcd
|
||
* @param {uint8_t} dir dir 0,拷贝pri_template到pri;1,拷贝pri到pri_template; 其余清空
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static void _copy_templete(lcd_t *lcd, uint8_t dir)
|
||
{
|
||
uint16_t size = (lcd->info.width / 8) * (lcd->info.height);
|
||
if (dir == 0)
|
||
{
|
||
osel_memcpy((uint8_t *)lcd->info.pri_template, (uint8_t *)lcd->info.pri, size);
|
||
}
|
||
else if (dir == 1)
|
||
{
|
||
// 判断pri_template和pri不一致的地方将change_line置1
|
||
for (uint16_t i = 0; i < size; i++)
|
||
{
|
||
if (((uint8_t *)lcd->info.pri_template)[i] != ((uint8_t *)lcd->info.pri)[i])
|
||
{
|
||
change_line[i / (lcd->info.width / 8)] = 1;
|
||
}
|
||
}
|
||
osel_memcpy((uint8_t *)lcd->info.pri, (uint8_t *)lcd->info.pri_template, size);
|
||
}
|
||
else
|
||
{
|
||
osel_memset((uint8_t *)lcd->info.pri, CLEAR_COLOR, size);
|
||
osel_memset((uint8_t *)lcd->info.pri_template, CLEAR_COLOR, size);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 清除显存
|
||
* @param {lcd_t} *lcd
|
||
* @param {uint16_t} min_row 最小行
|
||
* @param {uint16_t} max_row 最大行
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static void _clear_ram(lcd_t *lcd, uint16_t min_row, uint16_t max_row)
|
||
{
|
||
uint8_t(*lcd_gram)[lcd->info.width / 8] = (uint8_t(*)[lcd->info.width / 8]) lcd->info.pri;
|
||
for (uint16_t i = min_row; i < max_row; i++)
|
||
{
|
||
osel_memset((uint8_t *)lcd_gram[i], CLEAR_COLOR, (lcd->info.width / 8));
|
||
change_line[i] = 1;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief
|
||
* @param {lcd_t} *lcd
|
||
* @param {uint16_t} *color
|
||
* @param {uint32_t} len
|
||
* @return {*}
|
||
*/
|
||
static void _flush(lcd_t *lcd)
|
||
{
|
||
lcd->info.flush_use_time = sys_millis();
|
||
uint16_t tmp = 0;
|
||
uint32_t length = 0;
|
||
DBG_ASSERT(lcd != NULL __DBG_LINE);
|
||
DBG_ASSERT(lcd->info.spi != NULL __DBG_LINE);
|
||
uint16_t l = lcd->info.height;
|
||
uint16_t r = lcd->info.width / 8;
|
||
uint8_t(*lcd_gram)[lcd->info.width / 8] = (uint8_t(*)[lcd->info.width / 8]) lcd->info.pri;
|
||
uint8_t *lcd_gram_send = (uint8_t *)lcd->info.pri_send;
|
||
sharp_chip_select(lcd, TRUE);
|
||
// LL_mDelay(2);
|
||
*lcd_gram_send++ = LCD_CMD_UPDATE;
|
||
for (uint16_t line = 0; line < l; line++)
|
||
{
|
||
tmp = line + 1; // 行移动
|
||
if (change_line != NULL && change_line[line] == 1)
|
||
{
|
||
*lcd_gram_send++ = (uint8_t)tmp;
|
||
osel_memcpy(lcd_gram_send, lcd_gram[line], r);
|
||
lcd_gram_send += r;
|
||
*lcd_gram_send++ = LCD_CMD_NOP;
|
||
change_line[line] = 0;
|
||
}
|
||
}
|
||
*lcd_gram_send++ = LCD_CMD_NOP;
|
||
*lcd_gram_send++ = LCD_CMD_NOP;
|
||
length = (uint32_t)lcd_gram_send - (uint32_t)lcd->info.pri_send;
|
||
if (length > 4)
|
||
{
|
||
lcd->info.spi->interface.spi_dma_send(lcd->info.spi, (uint8_t *)lcd->info.pri_send, (uint32_t)lcd_gram_send - (uint32_t)lcd->info.pri_send);
|
||
}
|
||
|
||
// LL_mDelay(2);
|
||
sharp_chip_select(lcd, FALSE);
|
||
lcd->info.flush_use_time = sys_millis() - lcd->info.flush_use_time;
|
||
}
|
||
|
||
static void _flush_clear(lcd_t *lcd)
|
||
{
|
||
lcd->driver.flush(lcd);
|
||
uint16_t size = (lcd->info.width / 8) * (lcd->info.height);
|
||
osel_memset((uint8_t *)lcd->info.pri, CLEAR_COLOR, size);
|
||
osel_memset((uint8_t *)change_line, 1, lcd->info.height);
|
||
}
|
||
|
||
/**
|
||
* @brief 读点
|
||
* @param {lcd_t} *lcd
|
||
* @param {uint16_t} x
|
||
* @param {uint16_t} y
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
// static int32_t _get_point(lcd_t *lcd, uint16_t x, uint16_t y)
|
||
// {
|
||
// uint16_t xtmp, ytmp;
|
||
// uint16_t line, row;
|
||
// DBG_ASSERT(lcd != NULL __DBG_LINE);
|
||
// DBG_ASSERT(lcd->info.pri != NULL __DBG_LINE);
|
||
// uint8_t(*lcd_gram)[lcd->info.width / 8] = (uint8_t(*)[lcd->info.width / 8]) lcd->info.pri;
|
||
// if (x > lcd->info.width || y > lcd->info.height)
|
||
// {
|
||
// return -1;
|
||
// }
|
||
// xtmp = y;
|
||
// ytmp = x;
|
||
|
||
// line = xtmp; // 行地址
|
||
// row = ytmp / 8; // 列地址
|
||
|
||
// if (lcd_gram[line][row] & (0x01 << (ytmp % 8)))
|
||
// {
|
||
// return (uint8_t)WHITE; // 该点为白色
|
||
// }
|
||
// else
|
||
// {
|
||
// return (uint8_t)BLACK; // 该点为黑色
|
||
// }
|
||
// }
|
||
|
||
static int32_t _get_point(lcd_t *lcd, uint16_t x, uint16_t y)
|
||
{
|
||
// 优化后的读点函数
|
||
// 直接计算点的索引和位位置
|
||
uint16_t index = y;
|
||
uint8_t bit_pos = x % 8;
|
||
uint8_t mask = 0x01 << bit_pos;
|
||
uint8_t(*lcd_gram)[lcd->info.width / 8] = (uint8_t(*)[lcd->info.width / 8]) lcd->info.pri;
|
||
|
||
// 直接操作位而不使用中间变量
|
||
if (lcd_gram[index][x / 8] & mask)
|
||
{
|
||
return (uint8_t)WHITE; // 该点为白色
|
||
}
|
||
else
|
||
{
|
||
return (uint8_t)BLACK; // 该点为黑色
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 画点
|
||
* @param {lcd_t} *lcd
|
||
* @param {uint16_t} x
|
||
* @param {uint16_t} y
|
||
* @param {uint16_t} color
|
||
* @return {*}
|
||
*/
|
||
// static int32_t _set_point(lcd_t *lcd, uint16_t x, uint16_t y, uint16_t color)
|
||
// {
|
||
// uint16_t xtmp, ytmp;
|
||
// uint16_t line, row;
|
||
// DBG_ASSERT(lcd != NULL __DBG_LINE);
|
||
// DBG_ASSERT(lcd->info.pri != NULL __DBG_LINE);
|
||
// uint8_t(*lcd_gram)[lcd->info.width / 8] = (uint8_t(*)[lcd->info.width / 8]) lcd->info.pri;
|
||
// if (x > lcd->info.width || y > lcd->info.height)
|
||
// {
|
||
// return -1;
|
||
// }
|
||
// xtmp = y;
|
||
// ytmp = x;
|
||
|
||
// line = xtmp; // 行地址
|
||
// row = ytmp / 8; // 列地址
|
||
// uint8_t col = (uint8_t)WHITE;
|
||
// uint16_t coo;
|
||
// coo = _get_point(lcd, x, y);
|
||
// if (color == coo)
|
||
// {
|
||
// return 0; // 该点已经是该颜色,不需要再次设置
|
||
// }
|
||
|
||
// if (color == col)
|
||
// {
|
||
// lcd_gram[line][row] |= (0x01 << (ytmp % 8));
|
||
// }
|
||
// else
|
||
// {
|
||
// lcd_gram[line][row] &= ~(0x01 << (ytmp % 8));
|
||
// }
|
||
|
||
// if (change_line != NULL)
|
||
// {
|
||
// change_line[line] = 1;
|
||
// }
|
||
|
||
// return 0;
|
||
// }
|
||
static int32_t _set_point(lcd_t *lcd, uint16_t x, uint16_t y, uint16_t color)
|
||
{
|
||
// 优化后的画点函数
|
||
// 直接计算点的索引和位位置
|
||
uint16_t index = y;
|
||
uint8_t bit_pos = x % 8;
|
||
uint8_t mask = 0x01 << bit_pos;
|
||
uint8_t(*lcd_gram)[lcd->info.width / 8] = (uint8_t(*)[lcd->info.width / 8]) lcd->info.pri;
|
||
|
||
// 直接操作位而不使用中间变量
|
||
if (color == (uint8_t)WHITE)
|
||
{
|
||
lcd_gram[index][x / 8] |= mask;
|
||
}
|
||
else
|
||
{
|
||
lcd_gram[index][x / 8] &= ~mask;
|
||
}
|
||
|
||
// 如果change_line数组可用,则将行标记为已更改
|
||
if (change_line != NULL)
|
||
{
|
||
change_line[index] = 1;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 将一块区域设定为某种颜色
|
||
* @param {lcd_t} *lcd
|
||
* @param {uint16_t} sx
|
||
* @param {uint16_t} ex
|
||
* @param {uint16_t} sy
|
||
* @param {uint16_t} ey
|
||
* @param {uint16_t} color
|
||
* @return {*}
|
||
*/
|
||
static int32_t _color_fill(lcd_t *lcd, uint16_t sx, uint16_t ex, uint16_t sy, uint16_t ey, uint16_t color)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 显示或关闭
|
||
* @param {lcd_t} *lcd
|
||
* @param {uint8_t} sta
|
||
* @return {*}
|
||
*/
|
||
static int32_t _onoff(lcd_t *lcd, uint8_t sta)
|
||
{
|
||
if (lcd->info.on != sta)
|
||
{
|
||
lcd->info.on = sta;
|
||
if (sta == 1)
|
||
{
|
||
lcd->info.disp->set(*lcd->info.disp);
|
||
}
|
||
else
|
||
{
|
||
lcd->info.disp->reset(*lcd->info.disp);
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 设置显存扫描方向
|
||
* @param {lcd_t} *lcd
|
||
* @param {uint8_t} scan_dir 0 = 0度扫描,1 = 180度扫描
|
||
* @return {*}
|
||
*/
|
||
static void _set_dir(lcd_t *lcd, uint8_t scan_dir)
|
||
{
|
||
if (lcd->info.scandir != scan_dir)
|
||
{
|
||
lcd->info.scandir = scan_dir;
|
||
lcd->info.need_build = TRUE;
|
||
if (scan_dir == 0)
|
||
{
|
||
}
|
||
else
|
||
{
|
||
}
|
||
uint16_t size = (lcd->info.width / 8) * (lcd->info.height);
|
||
osel_memset((uint8_t *)lcd->info.pri, CLEAR_COLOR, size);
|
||
lcd->driver.clear(lcd);
|
||
}
|
||
}
|
||
|
||
static uint8_t _get_dir(lcd_t *lcd)
|
||
{
|
||
return lcd->info.scandir;
|
||
}
|
||
|
||
/**
|
||
* @brief
|
||
* @param {lcd_t} *lcd
|
||
* @param {uint16_t} color
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static void _full_fill(lcd_t *lcd, uint16_t color)
|
||
{
|
||
uint16_t size = (lcd->info.width / 8) * (lcd->info.height);
|
||
osel_memset((uint8_t *)lcd->info.pri, (uint8_t)color, size);
|
||
osel_memset((uint8_t *)change_line, 1, lcd->info.height);
|
||
}
|
||
|
||
/**
|
||
* @brief 填充矩形区域,这个函数是用来填充数据的
|
||
* @param {lcd_t} *lcd
|
||
* @param {uint16_t} sx
|
||
* @param {uint16_t} ex
|
||
* @param {uint16_t} sy
|
||
* @param {uint16_t} ey
|
||
* @param {uint16_t} *color
|
||
* @return {*}
|
||
*/
|
||
static int32_t _fill(lcd_t *lcd, uint16_t x, uint16_t y, uint8_t font_width, uint8_t font_hight, uint8_t *buf)
|
||
{
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief
|
||
* @param {lcd_t} *lcd
|
||
* @param {uint16_t} sx
|
||
* @param {uint16_t} ex
|
||
* @param {uint16_t} sy
|
||
* @param {uint16_t} ey
|
||
* @return {*}
|
||
*/
|
||
static int32_t _prepare_display(lcd_t *lcd, uint16_t sx, uint16_t ex, uint16_t sy, uint16_t ey)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief
|
||
* @param {lcd_t} *lcd
|
||
* @param {uint8_t} sta
|
||
* @return {*}
|
||
*/
|
||
static void _backlight(lcd_t *lcd, uint8_t sta) {}
|
||
|
||
/**
|
||
* @brief 设置清屏标志
|
||
* @param {lcd_t} *lcd
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static void _set_clear_flag(lcd_t *lcd)
|
||
{
|
||
lcd->info.clear_flag = TRUE;
|
||
uint16_t size = (lcd->info.width / 8) * (lcd->info.height);
|
||
osel_memset((uint8_t *)lcd->info.pri, CLEAR_COLOR, size);
|
||
osel_memset((uint8_t *)change_line, 0, lcd->info.height);
|
||
}
|
||
|
||
/**
|
||
* @brief 获取清屏标志
|
||
* @param {lcd_t} *lcd
|
||
* @return {*}
|
||
* @note
|
||
*/
|
||
static BOOL _get_clear_flag(lcd_t *lcd)
|
||
{
|
||
return lcd->info.clear_flag;
|
||
}
|
||
|
||
void lcd_sharp_init(lcd_driver_t *driver)
|
||
{
|
||
DBG_ASSERT(driver != NULL __DBG_LINE);
|
||
driver->init = _init; // 已实现
|
||
driver->set_point = _set_point; // 已实现
|
||
driver->get_point = _get_point; // 已实现
|
||
driver->color_fill = _color_fill; // 已实现
|
||
driver->onoff = _onoff; // 已实现
|
||
driver->set_dir = _set_dir; // 已实现
|
||
driver->get_dir = _get_dir; // 已实现
|
||
driver->flush = _flush; // 已实现
|
||
driver->flush_clear = _flush_clear; // 已实现
|
||
driver->clear = _clear; // 已实现
|
||
driver->set_clear_flag = _set_clear_flag; // 已实现
|
||
driver->get_clear_flag = _get_clear_flag; // 已实现
|
||
driver->full_fill = _full_fill; // 已实现
|
||
driver->copy_templete = _copy_templete; // 已实现
|
||
driver->clear_ram = _clear_ram; // 已实现
|
||
|
||
// 以下不实现
|
||
driver->fill = _fill;
|
||
driver->prepare_display = _prepare_display;
|
||
driver->backlight = _backlight;
|
||
}
|