This repository has been archived on 2025-02-28. You can view files and clone it, but cannot push or open issues or pull requests.
controller-hd/User/lib/lcd/lcd_st7525.c

446 lines
11 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 "lcds.h"
#include "delay.h"
#define ST_DISP_ON 0xAF // 显示开
#define ST_DISP_OFF 0xAE // 显示关
#define ST_START_LINE 0x40 // 设置Start Line
#define ST_PAGE_ADDR 0xB0 // 设置Page Address
#define ST_COL_ADDRM 0x10 // 设置Column Address MSB
#define ST_COL_ADDRL 0x00 // 设置Column Address LSB
#define ST_DISP_NORMAL 0xA6 // 正常显示,1-显示
#define ST_DISP_REVERSE 0xA7 // 反向显示,0-显示
#define ST_DISP_ALL_OFF 0xA4 // 正常显示
#define ST_DISP_ALL_ON 0xA5 // 不管RAM内容全部显示
#define ST_RESET 0xE2 // 软件复位
#define ST_BOOST 0x2F // 内部升压
#define ST_DISP_0 0xC4 // 0度正常显示
#define ST_DISP_180 0xC2 // 旋转180度显示
#define ST_SET_EV 0x81 // 对比度控制
#pragma pack(1)
/*
驱动使用的数据结构,不对外
*/
struct _cog_drv_data
{
uint8_t gram[8][COL_DOT_MAX_192];
/*刷新区域*/
uint16_t sx;
uint16_t ex;
uint16_t sy;
uint16_t ey;
uint16_t disx;
uint16_t disy;
};
#pragma pack()
/**
* @brief 写命令
* @param {uint8_t} cmd
* @return {*}
*/
static void write_cmd(spi_t *handle, uint8_t cmd)
{
handle->interface.u.lcd.write_cmd(handle, cmd);
}
static void write_data(spi_t *handle, uint8_t *data, uint16_t len)
{
handle->interface.u.lcd.write_data(handle, data, len);
}
/**
* @brief 设置起始页
* @param {uint8_t} page
* @return {*}
*/
static void start_page(spi_t *handle, uint8_t page)
{
page &= 0x07; // 定义低3 位
page |= ST_PAGE_ADDR; // 第一页
write_cmd(handle, page);
}
/**
* @brief 设置起始列
* @param {uint8_t} Column
* @return {*}
*/
static void start_column(spi_t *handle, uint8_t column)
{
uint8_t temp, cmd;
temp = column;
cmd = (temp & 0x0F); // 定义A3-A0;
cmd += ST_COL_ADDRL;
write_cmd(handle, cmd);
temp >>= 4;
cmd = (temp & 0x0F); // 定义A7-A4;
cmd += ST_COL_ADDRM;
write_cmd(handle, cmd);
}
/**
* @brief 设置起始行
* @param {uint8_t} line
* @return {*}
*/
static void start_line(spi_t *handle, uint8_t line)
{
line &= 0x3F; // 定义低6 位
line |= ST_START_LINE; // 第一行或
write_cmd(handle, line);
}
/**
* @brief 初始化,包括硬件初始化和软件初始化
* @param {lcd_t} *lcd
* @return {*}
*/
static int32_t _init(lcd_t *lcd)
{
lcd->info.spi->gpios.rst->set(*lcd->info.spi->gpios.rst);
delay_tick(50);
lcd->info.spi->gpios.rst->reset(*lcd->info.spi->gpios.rst);
delay_tick(50);
lcd->info.spi->gpios.rst->set(*lcd->info.spi->gpios.rst);
delay_tick(50);
lcd->info.on = 0;
lcd->info.pri = (void *)osel_mem_alloc(sizeof(struct _cog_drv_data));
uint8_t *p = (uint8_t *)lcd->info.pri;
osel_memset(p, 0x00, (lcd->info.height / 8) * lcd->info.width);
write_cmd(lcd->info.spi, ST_RESET); // 软件复位
delay_ms(20);
write_cmd(lcd->info.spi, ST_BOOST); // 内部升压
delay_ms(20);
write_cmd(lcd->info.spi, ST_DISP_OFF); // display Off
lcd->info.on = 0;
write_cmd(lcd->info.spi, 0xa0);
delay_ms(20);
write_cmd(lcd->info.spi, ST_SET_EV);
write_cmd(lcd->info.spi, 0x79);
write_cmd(lcd->info.spi, 0xeb);
start_line(lcd->info.spi, 0); // display start line=0
write_cmd(lcd->info.spi, ST_DISP_NORMAL); // 正常显示,1-显示
write_cmd(lcd->info.spi, ST_DISP_ALL_OFF); // 正常显示
write_cmd(lcd->info.spi, ST_DISP_0); // 0度正常显示
lcd->info.scandir = 0;
// 应用层去清空并显示
// lcd->driver.color_fill(lcd, 0, lcd->info.width, 0, lcd->info.height, WHITE);
// lcd->driver.onoff(lcd, 1);
return 0;
}
/**
*@brief refresh_gram
*@details: 刷新指定区域到屏幕上
坐标是横屏模式坐标
*@param[in] uint16_t sc
uint16_t ec
uint16_t sp
uint16_t ep
*@param[out] 无
*@retval: static
*/
static uint32_t refresh_gram(lcd_t *lcd, uint16_t sc, uint16_t ec, uint16_t sp, uint16_t ep)
{
struct _cog_drv_data *drvdata;
uint8_t i;
drvdata = (struct _cog_drv_data *)lcd->info.pri;
for (i = sp / 8; i <= ep / 8; i++)
{
// 设置页地址。每页是8行。一个画面的64行被分成8个页。我们平常所说的第1页在LCD驱动IC里是第0页
start_page(lcd->info.spi, i);
// 设置列地址的高4位 和列地址的低4位
start_column(lcd->info.spi, sc);
write_data(lcd->info.spi, &(drvdata->gram[i][sc]), (ec - sc + 1));
}
return 0;
}
/**
* @brief 画点
* @param {lcd_t} *lcd
* @param {uint16_t} x
* @param {uint16_t} y
* @param {uint16_t} color
* @return {*}
*/
static int32_t _draw_point(lcd_t *lcd, uint16_t x, uint16_t y, uint16_t color)
{
uint16_t xtmp, ytmp;
uint16_t page, colum;
struct _cog_drv_data *drvdata;
drvdata = (struct _cog_drv_data *)lcd->info.pri;
if (x > lcd->info.width)
return -1;
if (y > lcd->info.height)
return -1;
if (lcd->info.dir == W_LCD)
{
xtmp = x;
ytmp = y;
}
else // 如果是竖屏XY轴跟显存的映射要对调
{
xtmp = y;
ytmp = lcd->info.width - 1 - x;
}
page = ytmp / 8; // 页地址
colum = xtmp; // 列地址
if (color == BLACK)
{
drvdata->gram[page][colum] |= (0x01 << (ytmp % 8));
}
else
{
drvdata->gram[page][colum] &= ~(0x01 << (ytmp % 8));
}
// 设置页地址。每页是8行。一个画面的64行被分成8个页。我们平常所说的第1页在LCD驱动IC里是第0页
start_page(lcd->info.spi, page);
// 设置列地址的高4位 和列地址的低4位
start_column(lcd->info.spi, colum);
write_data(lcd->info.spi, &drvdata->gram[page][colum], 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)
{
uint16_t i, j;
uint16_t xtmp, ytmp;
uint16_t page, colum;
struct _cog_drv_data *drvdata;
drvdata = (struct _cog_drv_data *)lcd->info.pri;
/*防止坐标溢出*/
if (sy >= lcd->info.height)
{
sy = lcd->info.height - 1;
}
if (sx >= lcd->info.width)
{
sx = lcd->info.width - 1;
}
if (ey >= lcd->info.height)
{
ey = lcd->info.height - 1;
}
if (ex >= lcd->info.width)
{
ex = lcd->info.width - 1;
}
for (j = sy; j <= ey; j++)
{
for (i = sx; i <= ex; i++)
{
if (lcd->info.dir == W_LCD)
{
xtmp = i;
ytmp = j;
}
else // 如果是竖屏XY轴跟显存的映射要对调
{
xtmp = j;
ytmp = lcd->info.width - 1 - i;
}
page = ytmp / 8; // 页地址
colum = xtmp; // 列地址
if (color == BLACK)
{
drvdata->gram[page][colum] |= (0x01 << (ytmp % 8));
}
else
{
drvdata->gram[page][colum] &= ~(0x01 << (ytmp % 8));
}
}
}
/*
只刷新需要刷新的区域
坐标范围是横屏模式
*/
if (lcd->info.dir == W_LCD)
{
refresh_gram(lcd, sx, ex, sy, ey);
}
else
{
refresh_gram(lcd, sy, ey, lcd->info.width - ex - 1, lcd->info.width - sx - 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 _fill(lcd_t *lcd, uint16_t x, uint16_t y, uint8_t font_width, uint8_t font_hight, uint8_t *buf)
{
uint8_t i, j, n;
n = y;
for (i = 0; i < font_hight / 8; i++)
{
start_page(lcd->info.spi, x);
for (j = 0; j < font_width; j++)
{
start_column(lcd->info.spi, y);
write_data(lcd->info.spi, &buf[j + i * font_width], 1);
y++;
}
x++;
y = n;
}
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 {uint16_t} *color
* @param {uint32_t} len
* @return {*}
*/
static void _flush(lcd_t *lcd)
{
}
/**
* @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)
{
write_cmd(lcd->info.spi, ST_DISP_ON); // display On
}
else
{
write_cmd(lcd->info.spi, ST_DISP_OFF); // display Off
}
}
return 0;
}
/**
* @brief 设置显存扫描方向
* @param {lcd_t} *lcd
* @param {uint8_t} scan_dir 0 = 0度扫描1 = 180度扫描
* @return {*}
*/
void _set_dir(lcd_t *lcd, uint8_t scan_dir)
{
if (lcd->info.scandir != scan_dir)
{
lcd->info.scandir = scan_dir;
if (scan_dir == 0)
{
write_cmd(lcd->info.spi, ST_DISP_0); // 0度扫描
}
else
{
write_cmd(lcd->info.spi, ST_DISP_180); // 180度扫描
}
}
}
void _full_fill(lcd_t *lcd, uint16_t color)
{
uint16_t i;
uint8_t val;
val = color > 0 ? 0x00 : 0xff;
for (i = 0; i < lcd->info.height / 8; i++)
{
// 设置页地址。每页是8行。一个画面的64行被分成8个页。我们平常所说的第1页在LCD驱动IC里是第0页
start_page(lcd->info.spi, i);
// 设置列地址的高4位 和列地址的低4位
start_column(lcd->info.spi, 0);
write_data(lcd->info.spi, &val, lcd->info.width);
}
}
/**
* @brief
* @param {lcd_t} *lcd
* @param {uint8_t} sta
* @return {*}
*/
void _backlight(lcd_t *lcd, uint8_t sta) {}
void lcd_st7525_init(lcd_driver_t *driver)
{
driver->init = _init; // 已实现
driver->set_point = _draw_point; // 已实现
driver->color_fill = _color_fill; // 已实现
driver->fill = _fill; // 已实现
driver->prepare_display = _prepare_display;
driver->flush = _flush;
driver->onoff = _onoff; // 已实现
driver->set_dir = _set_dir;
driver->backlight = _backlight;
driver->full_fill = _full_fill;
}