一、概述
- 开发板:STM32F103C8T6
- 显示器:ST7735S
- RT-Thread:5.0.0
玩过 GUI 的小伙伴都知道,界面的显示是一个个像素点组合起来的,那么直接构建出来炫酷的 GUI 还是相对比较困难的,所以我们一般都会使用一些 GUI 库来实现,比如 LVGL、QT、UGUI等,这样对于驱动开发的人员来说就相对比较简单了,
图形库应用的核心思想只需要提供一帧的缓冲区,我们只需要不断的将缓冲区的数据写入到 LCD 中即可,而缓冲区的内容由图形库实现,需要注意的是这个缓冲的创建方式,有的图形库会自己创建缓冲区,我们只需要负责刷新 LCD 的显示即可,而有的图形库是由驱动提供缓冲区,图形库负责写入。
二、RT-Thread 移植
移植 RT-Thread 不是此文章的重点,可以参考一下我之前的笔记,或者直接使用 RT-Thread Studio、STM32CubeMX等工具直接生成,这里我就不过多介绍了
三、LCD 驱动
使用过 RT-Thread 的小伙伴,都知道 RT-Thread 目前还不能直接使用工具生成我们想要的 LCD 驱动,所以这里我们只能根据标准的驱动进行编写了
-
驱动函数结构体
/* 驱动函数实现的结构体 */
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops lcd_ops =
{
drv_lcd_init,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
drv_lcd_control
};
#endif
-
注册 LCD 设备
int drv_lcd_hw_init(void)
{
rt_err_t result = RT_EOK;
rt_uint32_t lcd_buff_size = lcd_buff_size = LCD_HEIGHT * LCD_WIDTH * 2;
/* 创建LCD设备对象 */
struct rt_device *device = &_lcd.lcd_dev;
memset(&_lcd, 0x00, sizeof(_lcd));
LOG_D("drv_lcd_hw_init!\n");
/* 初始化lcd_lock信号量 */
result = rt_sem_init(&_lcd.lcd_lock, "lcd_lock", 0, RT_IPC_FLAG_FIFO);
if (result != RT_EOK)
{
LOG_E("init semaphore failed!\n");
result = -RT_ENOMEM;
goto __exit;
}
/* 设置 LCD 设备信息 */
_lcd.lcd_info.height = LCD_HEIGHT;
_lcd.lcd_info.width = LCD_WIDTH;
_lcd.lcd_info.bits_per_pixel = LCD_BITS_PER_PIXEL;
_lcd.lcd_info.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565; // 图像的格式(RGB:565)
/* LCD 显示缓冲区,大小为显示一帧图像所需空间 */
_lcd.lcd_info.smem_len = lcd_buff_size;
_lcd.lcd_info.framebuffer = rt_malloc(lcd_buff_size);
if (_lcd.lcd_info.framebuffer == RT_NULL)
{
LOG_E("init frame buffer failed!\n");
result = -RT_ENOMEM;
goto __exit;
}
/* 将缓冲区初始化为 0xFF */
memset(_lcd.lcd_info.framebuffer, 0xFF, lcd_buff_size);
#ifdef RT_USING_DEVICE_OPS
device->ops = &lcd_ops;
#else
device->init = drv_lcd_init;
device->control = drv_lcd_control;
#endif
/* 注册 LCD 设备 */
rt_device_register(device, "lcd", RT_DEVICE_FLAG_RDWR);
__exit:
if (result != RT_EOK)
{
rt_sem_detach(&_lcd.lcd_lock);
if (_lcd.lcd_info.framebuffer)
{
rt_free(_lcd.lcd_info.framebuffer);
}
}
return result;
}
-
LCD 控制函数的实现
static rt_err_t drv_lcd_control(struct rt_device *device, int cmd, void *args)
{
// struct drv_lcd_device *lcd = LCD_DEVICE(device);
LOG_D("drv_lcd_control cmd is: %d\n", cmd);
switch (cmd)
{
case RTGRAPHIC_CTRL_RECT_UPDATE:
{
rt_sem_take(&_lcd.lcd_lock, RT_TICK_PER_SECOND / 20);
/* 刷新缓冲区 */
rt_sem_release(&_lcd.lcd_lock);
}
break;
case RTGRAPHIC_CTRL_POWERON:
{
/* LCD 退出睡眠模式 */
}
break;
case RTGRAPHIC_CTRL_POWEROFF:
{
/* LCD 进入睡眠模式 */
}
break;
case RTGRAPHIC_CTRL_GET_INFO:
{
/* 获取 LCD 参数 */
memcpy(args, &_lcd.lcd_info, sizeof(_lcd.lcd_info));
}
break;
default:
return -RT_EINVAL;
}
return RT_EOK;
}
-
LCD 驱动功能实现
剩下的就比较简单了,只需要参考 LCD 提供的案例程序进行更改就好了,主要有实现如下- drv_lcd_init: 完成 LCD 的复位、初始化、首次清屏工作
- drv_lcd_control: 完成 LCD 显示区域的刷新、屏幕参数的返回、亮屏和息屏等工作
注意:具体实现参考后面的程序源码,相对比较简单,这里就不过多介绍了
四、UGUI 介绍
-
介绍
µGUI 是一个用于嵌入式系统的免费开源图形库。 它独立于平台,可以轻松移植到几乎任何微控制器系统。 只要显示器能够显示图形,μGUI 就不受某种显示技术的限制。 因此,支持LCD、TFT、E-Paper、LED或OLED等显示技术。 整个模块由两个文件组成:ugui.c 和 ugui.h。
注意:这里的介绍我直接引用了作者的描述 -
获取 UGUI
github:GitHub - xidongxu/ugui: Open source graphics library ugui ported to rtthread -
文件目录
-
使用介绍
- 移植: 我们主要实现 ugui_port.c,这里下载时已经提供了案例,所以我只需要在其中进行简单的修改
- 使用: 使用相对比较简单,直接参考 “µGUI v0.3.pdf” 文档即可,直接没有难度
五、UGUI 移植
-
初始化
直接在 ugui_port.c 文件中使用INIT_COMPONENT_EXPORT(ugui_port_init)
进行自动初始化,如下图所示: -
lcd_open 函数
这里不要做任何更改,从函数中可以看出 LCD 相关的参数获取,如下图所示: -
lcd_draw_pixel 函数
主要功能是在缓冲区中写入一个像素点的颜色,如下图所示: -
ugui_port_thread_entry 函数
这是线程的入口函数,主要目的是定期将缓冲区的数据写入到 LCD 中,下图所示:
注意:从以上步奏可以看出,移植 UGUI 时不需要更改任何参数,只需要在初始化时调用 ugui_port_init
函数即可。
六、程序源码
drv_lcd_st7735s.h
/** | |
* @file drv_lcd_st7735s.h | |
* | |
*/ | |
#ifndef __DRV_LCD_ST7735S_H__ | |
#define __DRV_LCD_ST7735S_H__ | |
#include <rtthread.h> | |
#define LCD_HEIGHT 20 // LCD 高像素 | |
#define LCD_WIDTH 128 // LCD 宽像素 | |
#define LCD_BITS_PER_PIXEL 16 // 像素点的数据宽度 | |
#define LCD_CS_PIN_TYPE GPIOA // CS 引脚所在的组 | |
#define LCD_CS_PIN GPIO_PIN_4 // 引脚编号 | |
#define LCD_BCK_PIN GET_PIN(B, 1) // 背光引脚 | |
#define LCD_DC_PIN GET_PIN(B, 8) // 数据引脚 | |
#define LCD_RES_PIN GET_PIN(B, 9) // 复位引脚 | |
#define WHITE 0xFFFF | |
#define BLACK 0x0000 | |
#define BLUE 0x001F | |
#define BRED 0XF81F | |
#define GRED 0XFFE0 | |
#define GBLUE 0X07FF | |
#define RED 0xF800 | |
#define MAGENTA 0xF81F | |
#define GREEN 0x07E0 | |
#define CYAN 0x7FFF | |
#define YELLOW 0xFFE0 | |
#define BROWN 0XBC40 | |
#define BRRED 0XFC07 | |
#define GRAY 0X8430 | |
#define GRAY175 0XAD75 | |
#define GRAY151 0X94B2 | |
#define GRAY187 0XBDD7 | |
#define GRAY240 0XF79E | |
#endif /* __DRV_LCD_ST7735S_H__ */ | |
drv_lcd_st7735s.c
/*************************************************************** | |
文件名 : drv_lcd_st7735s.c | |
作者 : jiaozhu | |
版本 : V1.0 | |
描述 : st7735s 显示驱动 | |
其他 : 无 | |
日志 : 初版 V1.0 2023/04/28 | |
***************************************************************/ | |
#include <board.h> | |
#include <rtthread.h> | |
#ifdef BSP_USING_LCD | |
#include "drv_spi.h" | |
#include <string.h> | |
#include "drv_lcd_st7735s.h" | |
//#define DRV_DEBUG | |
#define LOG_TAG "drv.lcd" | |
#include <drv_log.h> | |
static struct rt_spi_device *spi_dev_lcd; | |
struct drv_lcd_device | |
{ | |
struct rt_device lcd_dev; | |
struct rt_device_graphic_info lcd_info; | |
struct rt_semaphore lcd_lock; | |
}; | |
struct drv_lcd_device _lcd; | |
/** | |
* @brief LCD 命令写入,写入时数据引脚为低电平 | |
* | |
* @param cmd 命令 | |
* @retval 返回执行结果 | |
*/ | |
static rt_err_t lcd_write_cmd(const rt_uint8_t cmd) | |
{ | |
rt_size_t len; | |
rt_pin_write(LCD_DC_PIN, PIN_LOW); | |
len = rt_spi_send(spi_dev_lcd, &cmd, 1); | |
if (len != 1) | |
{ | |
LOG_I("lcd_write_cmd error. %d", len); | |
return -RT_ERROR; | |
} | |
else | |
{ | |
return RT_EOK; | |
} | |
} | |
/** | |
* @brief LCD 数据写入,写入时数据引脚为高电平 | |
* | |
* @param cmd 命令 | |
* @retval 返回执行结果 | |
*/ | |
static rt_err_t lcd_write_data(const rt_uint8_t data) | |
{ | |
rt_size_t len; | |
rt_pin_write(LCD_DC_PIN, PIN_HIGH); | |
len = rt_spi_send(spi_dev_lcd, &data, 1); | |
if (len != 1) | |
{ | |
LOG_I("lcd_write_data error. %d", len); | |
return -RT_ERROR; | |
} | |
else | |
{ | |
return RT_EOK; | |
} | |
} | |
/** | |
* @brief LCD 板级初始化 | |
* | |
* @param None | |
* @retval int 初始化结果 | |
*/ | |
static int lcd_dev_init(void) | |
{ | |
lcd_write_cmd(0x11); //Sleep out | |
rt_thread_delay(12); //Delay 12ms | |
//------------------------------------ST7735S Frame Rate-----------------------------------------// | |
lcd_write_cmd(0xB1); | |
lcd_write_data(0x05); | |
lcd_write_data(0x3C); | |
lcd_write_data(0x3C); | |
lcd_write_cmd(0xB2); | |
lcd_write_data(0x05); | |
lcd_write_data(0x3C); | |
lcd_write_data(0x3C); | |
lcd_write_cmd(0xB3); | |
lcd_write_data(0x05); | |
lcd_write_data(0x3C); | |
lcd_write_data(0x3C); | |
lcd_write_data(0x05); | |
lcd_write_data(0x3C); | |
lcd_write_data(0x3C); | |
//------------------------------------End ST7735S Frame Rate-----------------------------------------// | |
lcd_write_cmd(0xB4); //Dot inversion | |
lcd_write_data(0x03); | |
lcd_write_cmd(0xC0); | |
lcd_write_data(0x28); | |
lcd_write_data(0x08); | |
lcd_write_data(0x04); | |
lcd_write_cmd(0xC1); | |
lcd_write_data(0XC0); | |
lcd_write_cmd(0xC2); | |
lcd_write_data(0x0D); | |
lcd_write_data(0x00); | |
lcd_write_cmd(0xC3); | |
lcd_write_data(0x8D); | |
lcd_write_data(0x2A); | |
lcd_write_cmd(0xC4); | |
lcd_write_data(0x8D); | |
lcd_write_data(0xEE); | |
//---------------------------------End ST7735S Power Sequence-------------------------------------// | |
lcd_write_cmd(0xC5); //VCOM | |
lcd_write_data(0x1A); | |
lcd_write_cmd(0x36); //MX, MY, RGB mode | |
lcd_write_data(0xC0); | |
//------------------------------------ST7735S Gamma Sequence-----------------------------------------// | |
lcd_write_cmd(0xE0); | |
lcd_write_data(0x04); | |
lcd_write_data(0x22); | |
lcd_write_data(0x07); | |
lcd_write_data(0x0A); | |
lcd_write_data(0x2E); | |
lcd_write_data(0x30); | |
lcd_write_data(0x25); | |
lcd_write_data(0x2A); | |
lcd_write_data(0x28); | |
lcd_write_data(0x26); | |
lcd_write_data(0x2E); | |
lcd_write_data(0x3A); | |
lcd_write_data(0x00); | |
lcd_write_data(0x01); | |
lcd_write_data(0x03); | |
lcd_write_data(0x13); | |
lcd_write_cmd(0xE1); | |
lcd_write_data(0x04); | |
lcd_write_data(0x16); | |
lcd_write_data(0x06); | |
lcd_write_data(0x0D); | |
lcd_write_data(0x2D); | |
lcd_write_data(0x26); | |
lcd_write_data(0x23); | |
lcd_write_data(0x27); | |
lcd_write_data(0x27); | |
lcd_write_data(0x25); | |
lcd_write_data(0x2D); | |
lcd_write_data(0x3B); | |
lcd_write_data(0x00); | |
lcd_write_data(0x01); | |
lcd_write_data(0x04); | |
lcd_write_data(0x13); | |
//------------------------------------End ST7735S Gamma Sequence-----------------------------------------// | |
lcd_write_cmd(0x3A); //65k mode | |
lcd_write_data(0x05); | |
lcd_write_cmd(0x29); //Display on | |
return RT_EOK; | |
} | |
/** | |
* @brief 初始化 LCD 所需的引脚,并通过引脚复位 LCD | |
* | |
* @param None | |
* @retval None | |
*/ | |
static void lcd_gpio_init(void) | |
{ | |
/* 配置引脚模式 */ | |
rt_pin_mode(LCD_DC_PIN, PIN_MODE_OUTPUT); | |
rt_pin_mode(LCD_RES_PIN, PIN_MODE_OUTPUT); | |
rt_pin_mode(LCD_BCK_PIN, PIN_MODE_OUTPUT); | |
/* 通过引脚复位 LCD */ | |
rt_pin_write(LCD_BCK_PIN, PIN_LOW); | |
rt_pin_write(LCD_RES_PIN, PIN_LOW); | |
rt_thread_mdelay(12); | |
rt_pin_write(LCD_RES_PIN, PIN_HIGH); | |
/* 复位后延时一段时间,确保屏幕正常工作 */ | |
rt_thread_mdelay(12); | |
} | |
/** | |
* @brief 初始化 LCD 所需的 SPI 外设 | |
* | |
* @param None | |
* @retval int 操作结果 | |
*/ | |
static int lcd_spi_init(void) | |
{ | |
/* 配置 SPI 端口,并指定 CS 引脚为 PA4 */ | |
__HAL_RCC_GPIOA_CLK_ENABLE(); | |
rt_hw_spi_device_attach("spi1", "spi10", LCD_CS_PIN_TYPE, LCD_CS_PIN); | |
/* 查找设备 */ | |
spi_dev_lcd = (struct rt_spi_device *)rt_device_find("spi10"); | |
if(RT_NULL == spi_dev_lcd) | |
{ | |
LOG_E("Unable to find SPI device required for LCD"); | |
return RT_ERROR; | |
} | |
/* 配置 SPI */ | |
struct rt_spi_configuration cfg; | |
cfg.data_width = 8; | |
cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB; | |
cfg.max_hz = 42 * 1000 * 1000; /* 42M,SPI max 42MHz,lcd 4-wire spi */ | |
spi_dev_lcd->bus ->owner = spi_dev_lcd; | |
rt_spi_configure(spi_dev_lcd, &cfg); | |
return RT_EOK; | |
} | |
/** | |
* @brief 设置需要绘图的区域 | |
* | |
* @param x1 start of x position | |
* @param y1 start of y position | |
* @param x2 end of x position | |
* @param y2 end of y position | |
* @retval None | |
*/ | |
static void lcd_draw_area_set(rt_uint16_t x1, rt_uint16_t y1, rt_uint16_t x2, rt_uint16_t y2) | |
{ | |
lcd_write_cmd(0x2a); | |
lcd_write_data(x1 >> 8); | |
lcd_write_data(x1); | |
lcd_write_data(x2 >> 8); | |
lcd_write_data(x2); | |
lcd_write_cmd(0x2b); | |
lcd_write_data(y1 >> 8); | |
lcd_write_data(y1); | |
lcd_write_data(y2 >> 8); | |
lcd_write_data(y2); | |
lcd_write_cmd(0x2C); | |
} | |
/** | |
* @brief LCD 清屏,将整个屏幕设定为指定颜色 | |
* | |
* @param color 清空的颜色 | |
* @retval None | |
*/ | |
static void lcd_clear_screen(rt_uint16_t color) | |
{ | |
rt_uint16_t i, j; | |
rt_uint8_t data[2] = {0}; | |
data[0] = (color >> 8) & 0xFF; | |
data[1] = color & 0xFF; | |
/* 设置整个屏幕区域 */ | |
lcd_draw_area_set(0, 0, LCD_WIDTH - 1, LCD_HEIGHT - 1); | |
/* 这里直接通过 SPI 发送数据,所以需要单独将数据引脚拉高 */ | |
rt_pin_write(LCD_DC_PIN, PIN_HIGH); | |
if (_lcd.lcd_info.framebuffer != RT_NULL) | |
{ | |
/* 重置缓冲区 */ | |
// memset(_lcd.lcd_info.framebuffer, color, _lcd.lcd_info.smem_len); | |
for (j = 0; j < _lcd.lcd_info.smem_len / 2; j++) | |
{ | |
_lcd.lcd_info.framebuffer[j * 2] = data[0] ; | |
_lcd.lcd_info.framebuffer[j * 2 + 1] = data[1]; | |
} | |
rt_spi_send(spi_dev_lcd, _lcd.lcd_info.framebuffer, _lcd.lcd_info.smem_len); | |
} | |
else | |
{ | |
for (i = 0; i < LCD_HEIGHT; i++) | |
{ | |
for (j = 0; j < LCD_WIDTH; j++) | |
{ | |
rt_spi_send(spi_dev_lcd, data, 2); | |
} | |
} | |
} | |
} | |
/** | |
* @brief 点亮 LED 屏幕 | |
* @param None | |
* @retval None | |
*/ | |
static void lcd_display_on(void) | |
{ | |
rt_pin_write(LCD_BCK_PIN, PIN_HIGH); | |
} | |
/** | |
* @brief 熄灭 LED 屏幕 | |
* @param None | |
* @retval None | |
*/ | |
static void lcd_display_off(void) | |
{ | |
rt_pin_write(LCD_BCK_PIN, PIN_LOW); | |
} | |
/** | |
* @brief 液晶显示器进入最小功耗模式,背光关闭 | |
* @param None | |
* @retval None | |
*/ | |
static void lcd_enter_sleep(void) | |
{ | |
rt_pin_write(LCD_BCK_PIN, PIN_LOW); | |
rt_thread_mdelay(5); | |
lcd_write_cmd(0x10); | |
} | |
/** | |
* @brief 液晶显示器关闭睡眠模式,背光灯打开 | |
* @param None | |
* @retval None | |
*/ | |
static void lcd_exit_sleep(void) | |
{ | |
rt_pin_write(LCD_BCK_PIN, PIN_HIGH); | |
rt_thread_mdelay(5); | |
lcd_write_cmd(0x11); | |
rt_thread_mdelay(120); | |
} | |
/** | |
* @brief 设置光标位置 | |
* @param Xpos 横坐标 | |
* @param Ypos 纵坐标 | |
* @retval None | |
*/ | |
// static void lcd_cursor_set(rt_uint16_t Xpos, rt_uint16_t Ypos) | |
// { | |
// lcd_write_cmd(0x2A); | |
// lcd_write_data(Xpos>>8); | |
// lcd_write_data(Xpos&0XFF); | |
// lcd_write_cmd(0x2B); | |
// lcd_write_data(Ypos>>8); | |
// lcd_write_data(Ypos&0XFF); | |
// } | |
/** | |
* @brief LCD 驱动初始化 | |
* @param device LCD 设备结构体 | |
* @retval None | |
*/ | |
static rt_err_t drv_lcd_init(struct rt_device *device) | |
{ | |
LOG_D("drv_lcd_init!\n"); | |
if (lcd_spi_init() != RT_EOK) | |
{ | |
return -RT_EINVAL; | |
} | |
lcd_gpio_init(); | |
if (lcd_dev_init() != RT_EOK) | |
{ | |
return -RT_EINVAL; | |
} | |
/* 清屏 */ | |
lcd_clear_screen(WHITE); | |
/* 初始化完成后,点亮屏幕 */ | |
rt_pin_write(LCD_BCK_PIN, PIN_HIGH); | |
return RT_EOK; | |
} | |
/** | |
* @brief LCD 驱动的操作函数 | |
* @param device LCD 设备结构体 | |
* @param cmd 操作命令 | |
* @param args 传入的参数 | |
* @retval None | |
*/ | |
static rt_err_t drv_lcd_control(struct rt_device *device, int cmd, void *args) | |
{ | |
// struct drv_lcd_device *lcd = LCD_DEVICE(device); | |
LOG_D("drv_lcd_control cmd is: %d\n", cmd); | |
switch (cmd) | |
{ | |
case RTGRAPHIC_CTRL_RECT_UPDATE: | |
{ | |
rt_sem_take(&_lcd.lcd_lock, RT_TICK_PER_SECOND / 20); | |
/* 刷新缓冲区 */ | |
if (_lcd.lcd_info.framebuffer) | |
{ | |
/* 设置整个屏幕区域 */ | |
lcd_draw_area_set(0, 0, LCD_WIDTH - 1, LCD_HEIGHT - 1); | |
/* 这里直接通过 SPI 发送数据,所以需要单独将数据引脚拉高 */ | |
rt_pin_write(LCD_DC_PIN, PIN_HIGH); | |
rt_spi_send(spi_dev_lcd, _lcd.lcd_info.framebuffer, _lcd.lcd_info.smem_len); | |
} | |
/* 释放锁信号 */ | |
rt_sem_release(&_lcd.lcd_lock); | |
} | |
break; | |
case RTGRAPHIC_CTRL_POWERON: | |
{ | |
/* LCD 退出睡眠模式 */ | |
lcd_display_on(); | |
lcd_exit_sleep(); | |
} | |
break; | |
case RTGRAPHIC_CTRL_POWEROFF: | |
{ | |
/* LCD 进入睡眠模式 */ | |
lcd_display_off(); | |
lcd_enter_sleep(); | |
} | |
break; | |
case RTGRAPHIC_CTRL_GET_INFO: | |
{ | |
/* 获取 LCD 参数 */ | |
memcpy(args, &_lcd.lcd_info, sizeof(_lcd.lcd_info)); | |
} | |
break; | |
default: | |
return -RT_EINVAL; | |
} | |
return RT_EOK; | |
} | |
/* 驱动函数实现的结构体 */ | |
#ifdef RT_USING_DEVICE_OPS | |
const static struct rt_device_ops lcd_ops = | |
{ | |
drv_lcd_init, | |
RT_NULL, | |
RT_NULL, | |
RT_NULL, | |
RT_NULL, | |
drv_lcd_control | |
}; | |
#endif | |
/** | |
* @brief LCD 设备注册 | |
* | |
* @param None | |
* @retval int 注册结果 | |
*/ | |
int drv_lcd_hw_init(void) | |
{ | |
rt_err_t result = RT_EOK; | |
rt_uint32_t lcd_buff_size = lcd_buff_size = LCD_HEIGHT * LCD_WIDTH * 2; | |
/* 创建LCD设备对象 */ | |
struct rt_device *device = &_lcd.lcd_dev; | |
memset(&_lcd, 0x00, sizeof(_lcd)); | |
LOG_D("drv_lcd_hw_init!\n"); | |
/* 初始化lcd_lock信号量 */ | |
result = rt_sem_init(&_lcd.lcd_lock, "lcd_lock", 0, RT_IPC_FLAG_FIFO); | |
if (result != RT_EOK) | |
{ | |
LOG_E("init semaphore failed!\n"); | |
result = -RT_ENOMEM; | |
goto __exit; | |
} | |
/* 设置 LCD 设备信息 */ | |
_lcd.lcd_info.height = LCD_HEIGHT; | |
_lcd.lcd_info.width = LCD_WIDTH; | |
_lcd.lcd_info.bits_per_pixel = LCD_BITS_PER_PIXEL; | |
_lcd.lcd_info.pixel_format = RTGRAPHIC_PIXEL_FORMAT_RGB565; // 图像的格式(RGB:565) | |
/* LCD 显示缓冲区,大小为显示一帧图像所需空间 */ | |
_lcd.lcd_info.smem_len = lcd_buff_size; | |
_lcd.lcd_info.framebuffer = rt_malloc(lcd_buff_size); | |
if (_lcd.lcd_info.framebuffer == RT_NULL) | |
{ | |
LOG_E("init frame buffer failed!\n"); | |
result = -RT_ENOMEM; | |
goto __exit; | |
} | |
/* 将缓冲区初始化为 0xFF */ | |
memset(_lcd.lcd_info.framebuffer, 0xFF, lcd_buff_size); | |
#ifdef RT_USING_DEVICE_OPS | |
device->ops = &lcd_ops; | |
#else | |
device->init = drv_lcd_init; | |
device->control = drv_lcd_control; | |
#endif | |
/* 注册 LCD 设备 */ | |
rt_device_register(device, "lcd", RT_DEVICE_FLAG_RDWR); | |
__exit: | |
if (result != RT_EOK) | |
{ | |
rt_sem_detach(&_lcd.lcd_lock); | |
if (_lcd.lcd_info.framebuffer) | |
{ | |
rt_free(_lcd.lcd_info.framebuffer); | |
} | |
} | |
return result; | |
} | |
INIT_DEVICE_EXPORT(drv_lcd_hw_init); | |
#endif /* BSP_USING_LCD */ | |