STM32+RTThread+UGUI

博客 动态
0 128
羽尘
羽尘 2023-04-28 15:54:34
悬赏:0 积分 收藏

STM32 + RTThread + UGUI

一、概述

  • 开发板: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 驱动,所以这里我们只能根据标准的驱动进行编写了

  1. 驱动函数结构体

    /* 驱动函数实现的结构体 */
    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
    
  2. 注册 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;
        
    }
    
  3. 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;
    }
    
    
  4. LCD 驱动功能实现
    剩下的就比较简单了,只需要参考 LCD 提供的案例程序进行更改就好了,主要有实现如下

    • drv_lcd_init: 完成 LCD 的复位、初始化、首次清屏工作
    • drv_lcd_control: 完成 LCD 显示区域的刷新、屏幕参数的返回、亮屏和息屏等工作
      注意:具体实现参考后面的程序源码,相对比较简单,这里就不过多介绍了

四、UGUI 介绍

  1. 介绍
    μGUI 是一个用于嵌入式系统的免费开源图形库。 它独立于平台,可以轻松移植到几乎任何微控制器系统。 只要显示器能够显示图形,μGUI 就不受某种显示技术的限制。 因此,支持LCD、TFT、E-Paper、LED或OLED等显示技术。 整个模块由两个文件组成:ugui.c 和 ugui.h。
    注意:这里的介绍我直接引用了作者的描述

  2. 获取 UGUI
    github:https://github.com/xidongxu/ugui

  3. 文件目录

  4. 使用介绍

    • 移植: 我们主要实现 ugui_port.c,这里下载时已经提供了案例,所以我只需要在其中进行简单的修改
    • 使用: 使用相对比较简单,直接参考 “μGUI v0.3.pdf” 文档即可,直接没有难度

五、UGUI 移植

  1. 初始化
    直接在 ugui_port.c 文件中使用 INIT_COMPONENT_EXPORT(ugui_port_init) 进行自动初始化,如下图所示:

  2. lcd_open 函数
    这里不要做任何更改,从函数中可以看出 LCD 相关的参数获取,如下图所示:

  3. lcd_draw_pixel 函数
    主要功能是在缓冲区中写入一个像素点的颜色,如下图所示:

  4. 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 */



posted @ 2023-04-28 15:47  浇筑菜鸟  阅读(0)  评论(0编辑  收藏  举报
回帖
    羽尘

    羽尘 (王者 段位)

    2233 积分 (2)粉丝 (11)源码

     

    温馨提示

    亦奇源码

    最新会员