linux驱动开发 ST7789 LCD驱动移植(I.MX6ULL平台)

前言

I.MX6ULL的板子未选配RGB的屏幕,无法在板子上进行GUI的开发调试,不过手头上有块控制器为ST7789V3的LCD屏幕(1.3inch),通过简易接线后可以很方便进行驱动的移植

如有异议,欢迎留言指正

ST7789 LCD控制器

ST7789是一款单芯片TFT-LCD控制器,支持并口与SPI通信方式

特性
  • 控制器支持显示区域340x320(LCD屏幕实际为240X240)
  • RGB565、16bit、65K真彩
  • 支持SPI通信
  • LCD控制引脚
NO. 引脚 描述
1 BLK 背光调节亮度
2 CS 片选
3 RES 复位
4 SDA 数据引脚
5 SCL 串行时钟
6 DC 数据命令选择

修改设备树

修改&ecspi1
  • 板子上通过SPI1接到LCD上,设备树路径 arch/arm/boot/dts/100ask_imx6ull-14x14.dts,修改&ecspi1,增加 cs-gpiosdc-gpiosrst-gpio引脚(dc与rst也可以单独放到root节点下)
&ecspi1 {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_ecspi1>;
    fsl,spi-num-chipselects = <1>;
    cs-gpios = <&gpio4 24 GPIO_ACTIVE_LOW>;
    dc-gpios = <&gpio4 21 GPIO_ACTIVE_HIGH>;
    rst-gpio = <&gpio4 23 GPIO_ACTIVE_HIGH>;
    status = "okay";
    spidev: st7789s@0{
        compatible = "100ask, st7789s";
        spi-max-frequency = <25000000>;
        reg = <0>;
    };
};
修改pinctrl
  • 修改设备树中pinctrl_ecspi1,增加dcrst的IO配置(dc与rst的配置也可以单独放到root节点下,需要屏蔽掉其他地方复用防止引起的冲突)
pinctrl_ecspi1: spi_st7789s {
             fsl,pins = <
         MX6UL_PAD_CSI_DATA04__ECSPI1_SCLK          0x000010B1/*sclk*/
         MX6UL_PAD_CSI_DATA06__ECSPI1_MOSI          0x000010B1/*mosi*/
         MX6UL_PAD_CSI_DATA07__ECSPI1_MISO          0x000010B1/*miso*/
         MX6UL_PAD_CSI_DATA03__GPIO4_IO24           0x000010B0/*cs*/
         MX6UL_PAD_CSI_DATA00__GPIO4_IO21           0x000010B0/*dc*/
         MX6UL_PAD_CSI_DATA02__GPIO4_IO23           0x000010B0/*rst*/
     >;
 };

SPI驱动框架

注册spi
  • Linux内核使用spi_driver标识spi设备驱动(匹配方式、probe、remove函数),通过 spi_register_driver向内核进行注册
/* SPI驱动结构体 */  
static struct spi_driver st7789s_driver = {
    .probe = st7789s_probe,
    .remove = st7789s_remove,
    .driver = {
            .owner = THIS_MODULE,
            .name = ST7789S_NAME,
            .of_match_table = st7789s_of_match,
           },
    .id_table = st7789s_id,
};
/*
 * @description : 驱动入口函数
 * @param       : 无
 * @return      : 无
 */
static int __init st7789s_init(void)
{
    return spi_register_driver(&st7789s_driver);
}
数据发送
  • 将待发送数据添加到spi_message队列中,并使用同步(堵塞方式)发送
static int st7789_write_regs(struct st7789_dev *dev,unsigned char *buf, int len)
{
    int ret;
    struct spi_message m;
    struct spi_transfer *t;
    struct spi_device *spi = (struct spi_device *)dev->private_data;
    
    t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);   /* 申请内存 */
    t->tx_buf = buf;            /* 要写入的数据 */
    t->len = len;               /* 写入的字节数 */
    spi_message_init(&m);       /* 初始化spi_message */
    spi_message_add_tail(t, &m);/* 将spi_transfer添加到spi_message队列 */
    ret = spi_sync(spi, &m);    /* 同步发送 */
    kfree(t);                   /* 释放内存 */
    return ret;
}

probe函数

  • 设备与驱动匹配成功后,在probe中注册设备并进行刷屏
static int st7789s_probe(struct spi_device *spi)
{
    int ret = 0;
    printk("st7789 probe \n");
    /* 1、构建设备号 */
    if (st7789sdev.major) {
        st7789sdev.devid = MKDEV(st7789sdev.major, 0);
        register_chrdev_region(st7789sdev.devid, ST7789S_CNT, ST7789S_NAME);
    } else {
        alloc_chrdev_region(&st7789sdev.devid, 0, ST7789S_CNT, ST7789S_NAME);
        st7789sdev.major = MAJOR(st7789sdev.devid);
    }
    /* 2、注册设备 */
    cdev_init(&st7789sdev.cdev, &st7789s_ops);
    cdev_add(&st7789sdev.cdev, st7789sdev.devid, ST7789S_CNT);
    /* 3、创建类 */
    st7789sdev.class = class_create(THIS_MODULE, ST7789S_NAME);
    if (IS_ERR(st7789sdev.class)) {
        return PTR_ERR(st7789sdev.class);
    }
    /* 4、创建设备 */
    st7789sdev.device = device_create(st7789sdev.class, NULL, st7789sdev.devid, NULL, ST7789S_NAME);
    if (IS_ERR(st7789sdev.device)) {
        return PTR_ERR(st7789sdev.device);
    }
    /* 获取设备树中cs片选信号 */
    st7789sdev.nd = of_find_node_by_path("/soc/aips-bus@02000000/spba-bus@02000000/ecspi@02008000");
    if(st7789sdev.nd == NULL) {
        printk("ecspi1 node not find!\r\n");
        return -EINVAL;
    }
    /* 2、 获取设备树中的gpio属性,得到BEEP所使用的BEEP编号 */
    st7789sdev.cs_gpio = of_get_named_gpio(st7789sdev.nd, "cs-gpios", 0);
    if(st7789sdev.cs_gpio < 0) {
        printk("can't get cs-gpio");
        return -EINVAL;
    }
   
    st7789sdev.res_gpio = of_get_named_gpio(st7789sdev.nd, "rst-gpios", 0);
    if(st7789sdev.res_gpio < 0) {
        printk("can't get res-gpio");
        return -EINVAL;
    }
    st7789sdev.dc_gpio = of_get_named_gpio(st7789sdev.nd, "dc-gpios", 0);
    if(st7789sdev.dc_gpio < 0) {
        printk("can't get dc-gpio");
        return -EINVAL;
    }
    /* 3、设置GPIO为输出,并且输出高电平 */
    ret = gpio_direction_output(st7789sdev.cs_gpio, 1);//
    if(ret < 0) {
        printk("can't set cs gpio!\r\n");
    }
    gpio_set_value(st7789sdev.cs_gpio,1);
    ret = gpio_direction_output(st7789sdev.res_gpio, 1);
    if(ret < 0) {
        printk("can't set res gpio!\r\n");
    }
    ret = gpio_direction_output(st7789sdev.dc_gpio, 1);
    if(ret < 0) {
        printk("can't set dc gpio!\r\n");
    }
    /*初始化spi_device */
    spi->mode = SPI_MODE_2; /*MODE0,CPOL=0,CPHA=0 */
    spi_setup(spi);
    st7789sdev.private_data = spi; /* 设置私有数据 */
    /* 初始化st7789s内部寄存器 */
    st7789s_reginit(&st7789sdev);     
    return 0;
}

编译运行

模块拷贝到板子中,由于在加载内核驱动中增加了刷图代码,所以加载驱动后LCD会显示如下图
linux驱动开发 ST7789 LCD驱动移植(I.MX6ULL平台)_第1张图片

后续章节贴完整源码

你可能感兴趣的:(Linux,驱动开发,st7789驱动移植,linux,i.mx6ull)