IMX6ULL + SPI LCD(驱动IC ILI9341)显示简单的QT界面

这篇具有很好参考价值的文章主要介绍了IMX6ULL + SPI LCD(驱动IC ILI9341)显示简单的QT界面。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 硬件:

使用正点原子的IMX6ULL Linux开发板

开发板底板原理图版本:V2.1

核心板原理图版本:V1.6

LCD :MSP2402 (IC ILI9341)

IMX6ULL + SPI LCD(驱动IC ILI9341)显示简单的QT界面

2. 查找可用引脚

开发板上引出的引脚是在JP6上,只看JP6会发现没有可用的SPI引脚,但是查看底板原理图中与核心板相连的位置会发现其实JP6上的UART2的TX/RX/CTS/RTS 四个引脚正好可以复用为ECSPI3的 MISO/MOSI/CLK/SS0四个引脚,SPI LCD还需要三个IO口作为Reset/DC/背光的控制引脚,如

下图所示(但是我是偷懒了,将背光引脚直接接的V3.3)

IMX6ULL + SPI LCD(驱动IC ILI9341)显示简单的QT界面IMX6ULL + SPI LCD(驱动IC ILI9341)显示简单的QT界面

3.添加支持SPI LCD的设备树节点(不废话,直接上干货)

    pinctrl_ecspi3: ecspi3grp {

            fsl,pins = <

                    MX6UL_PAD_UART2_RTS_B__ECSPI3_MISO        0x100b1  /* MISO*/

                    MX6UL_PAD_UART2_CTS_B__ECSPI3_MOSI        0x100b1  /* MOSI*/

                    MX6UL_PAD_UART2_RX_DATA__ECSPI3_SCLK      0x100b1  /* CLK*/

                    MX6UL_PAD_UART2_TX_DATA__GPIO1_IO20       0x100b0  /* CS*/

                    MX6UL_PAD_GPIO1_IO00__GPIO1_IO00          0x17059  /*back light*/

                    MX6UL_PAD_GPIO1_IO03__GPIO1_IO03          0x17059  /*data&command*/

                    MX6UL_PAD_GPIO1_IO08__GPIO1_IO08          0x17059 /* Reset IO */

            >;

    };


 

&ecspi3 {

        fsl,spi-num-chipselects = <1>;

        cs-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>;    ###特别注意,ATK出厂的设备树这里有问题,原有的cs-gpio 需要改成cs-gpios不然SPI将无法工作

        pinctrl-names = "default";

        pinctrl-0 = <&pinctrl_ecspi3>;

        status = "okay";

    spidev: icm20608@0 {

        compatible = "alientek,icm20608";

            spi-max-frequency = <8000000>;

            reg = <0>;

    };

    spi_lcd_msp2402@0 {

        compatible = "spi_lcd_msp2402";

        spi-max-frequency = <8000000>;  

        reg = <0>;            

        msp2402-bl-gpio = <&gpio1 0 GPIO_ACTIVE_HIGH>;          

        msp2402-dc-gpio = <&gpio1 3 GPIO_ACTIVE_HIGH>;    

        msp2402-rst-gpio = <&gpio1 8 GPIO_ACTIVE_HIGH>;                

    };

4.关键代码:

1.请先分析一下IMX6ULL的SPI设备驱动,网上太多了此处不再赘述

2. LCD初始化命令:

    命令序列是从淘宝客服给的单片机代码里摘出来的(没有去看ILI的芯片手册,太长了,五的初衷是学习驱动,而不是研究LCD,因此请不要问我命令都是实现什么功能的,因为我不知道)

struct spi_lcd_cmd{

    u8  reg_addr; // command

    u8  len;  //需要从spi_lcd_datas数组里发出数据字节数

    int delay_ms; //此命令发送数据完成后,需延时多久

}cmds[] = {

    {0xCF, 3, 0},

    {0xED, 4, 0},

    {0xE8, 3, 0},

    {0xCB, 5, 0},

    {0xF7, 1, 0},

    {0xEA, 2, 0},

    {0xC0, 1, 0},    

    {0xC1, 1, 0},

    {0xC5, 2, 0},    

    {0xC7, 1, 0},

    {0x36, 1, 0},

    {0x3A, 1, 0},

    {0xB1, 2, 0},

    {0xB6, 2, 0},

    {0xF2, 1, 0},

    {0x26, 1, 0},

    {0xE0, 15, 0},

    {0xE1, 15, 0},

    {0x2B, 9, 0},

    {0x11, 0, 120},  

    {0x29, 0, 0},  

};


 

u8 spi_lcd_datas[] = {

    0x00, 0xD9, 0x30,                       // command: 0xCF

    0x64, 0x03, 0x12, 0x81,                 // command: 0xED

    0x85, 0x10, 0x7A,                       // command: 0xE8

    0x39, 0x2C, 0x00, 0x34, 0x02,           // command: 0xCB

    0x20,                                   // command: 0xF7

    0x00, 0x00,                             // command: 0xEA

    0x1B,                                   // command: 0xC0      

    0x12,                                   // command: 0xC1

    0x08, 0x26,                             // command: 0xC5

    0xB7,                                   // command: 0xC7

    0x08,                                   // command: 0x36

    0x55,                                   // command: 0x3A

    0x00, 0x1A,                             // command: 0xB1

    0x0A, 0xA2,                             // command: 0xB6

    0x00,                                   // command: 0xF2

    0x01,                                   // command: 0x26

    0x0F, 0x1D, 0x1A, 0x0A, 0x0D, 0x07, 0x49, 0x66, 0x3B, 0x07, 0x11, 0x01, 0x09, 0x05, 0x04, //command: 0xE0

    0x00, 0x18, 0x1D, 0x02, 0x0F, 0x04, 0x36, 0x13, 0x4C, 0x07, 0x13, 0x0F, 0x2E, 0x2F, 0x05, //command: 0xE1

    0x00, 0x00, 0x01, 0x3F, 0x2A, 0x00, 0x00, 0x00, 0xEF, //command: 0x2B

};

3.大名鼎鼎的probe函数:

static int msp2402_probe(struct spi_device *spi)

{

    int ret =0;

    struct fb_info *fb;

    /*初始化spi_device */

    printk("File:%s Function:%s Line:%d \n",__FILE__,__FUNCTION__,__LINE__);

    if (msp2402_gpio_parse_dt(&msp2402lcd, &spi->dev) < 0) {

        printk(KERN_ERR "msp2402lcd gpio parse dt fail!\n");

        goto params_parse_fail;

    }

    /*

    Mode 0 CPOL=0, CPHA=0

    Mode 1 CPOL=0, CPHA=1

    Mode 2 CPOL=1, CPHA=0

    Mode 3 CPOL=1, CPHA=1

    */

    spi->mode = SPI_MODE_0; /*MODE0,CPOL=0,CPHA=0*/

    spi->bits_per_word = 8;

   // spi->dev.platform_data = msp2402lcd;

    ret = spi_setup(spi);

    if (ret < 0)

    {

        printk("spi_setup failed.\n");

    }

    /* 初始化msp2402内部寄存器 */

    msp2402lcd.spi = spi;

    msp2402_reginit(spi);

   lcd_fill_rect(spi,0, 0,LCD_W,LCD_H,RED);

   LCD_DrawLine(spi,0, 50, 240,50);

//至此,LCD的驱动部分就初始化完成了,屏幕上应该是红色背景,然后显示一条横线

// 下边是为了实现Framwbuffer的必要步骤:

   /*填充frambuffer对应项目 */

    fb = framebuffer_alloc(0, NULL);

    if (!fb) {

        printk(KERN_ERR "msp2402 lcd framebuffer alloc fail!\n");

        goto dma_alloc_fail;

    }

    //LCD基本参数设置

    fb->var.xres   = LCD_W;

    fb->var.yres   = LCD_H;

    fb->var.xres_virtual = LCD_W;

    fb->var.yres_virtual = LCD_H;

    fb->var.bits_per_pixel = 32;

    //LCD RGB格式设置, RGB888

    fb->var.red.offset = 16;

    fb->var.red.length = 8;

    fb->var.green.offset = 8;

    fb->var.green.length = 8;

    fb->var.blue.offset = 0;

    fb->var.blue.length = 8;

    //设置固定参数

    strcpy(fb->fix.id, "MSP2402,spilcd");

    fb->fix.type   = FB_TYPE_PACKED_PIXELS;

    fb->fix.visual = FB_VISUAL_TRUECOLOR;

    //设置显存

    fb->fix.line_length = LCD_W * 32 / 8;

    fb->fix.smem_len    = LCD_W * LCD_H * 32 / 8;

    printk("fb->fix.smem_len is %d\n", fb->fix.smem_len);

    dma_set_coherent_mask(&spi->dev, DMA_BIT_MASK(32));

    fb->screen_base = dma_alloc_coherent(&spi->dev, fb->fix.smem_len, (dma_addr_t*)&fb->fix.smem_start, GFP_KERNEL);

    if (!fb->screen_base) {

        printk(KERN_ERR "dma_alloc_coherent %d bytes fail!\n", fb->fix.smem_len);

        goto dma_alloc_fail;

    }

    printk("fb->screen_base is 0x%08x\n", (uint32_t)fb->screen_base);

    fb->screen_size = LCD_W * LCD_H * 32 / 8;

    printk("fb->screen_size is %ld\n", fb->screen_size);

    //操作函数集

    fb->fbops = &msp2402_fb_ops;

    spi_set_drvdata(spi, fb);

    ret = register_framebuffer(fb);

    if (ret < 0) {

        printk(KERN_ERR "register framebuffer fail!\n");

        goto register_fail;

    }

    msp2402lcd.thread = kthread_run(msp2402_refresh_kthread_func, fb, spi->modalias);

    printk("probe run successfully ...%s\n", spi->modalias);

    return 0;

register_fail:

    dma_free_coherent(&spi->dev, fb->fix.smem_len, fb->screen_base, fb->fix.smem_start);

dma_alloc_fail:

    framebuffer_release(fb);

params_parse_fail:

    gpio_free(msp2402lcd.data_command_io);

    gpio_free(msp2402lcd.reset_io);

    gpio_free(msp2402lcd.backlight_io);

return -1;

}

4. 清屏代码:

有两种写法建议都尝试以下就会发下差异(我就郁闷了一会)

方法一(这种方法清屏比较慢,需要7s左右,根本无法接受):

void LCD_Clear(struct spi_device *spi,u16 Color)

{

    unsigned int i,m;    

    LCD_SetWindows(spi,0, 0,LCD_W - 1,LCD_H - 1);

    gpio_set_value(msp2402lcd.reset_io, 1);

    for(i=0;i<LCD_H-1;i++){

        for(m=0;m<LCD_W-1;m++){

            Lcd_WriteData_16Bit(spi,Color);

        }

    }

}

方法二:

static void lcd_fill_rect(struct spi_device *spi,uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)

{

    uint32_t size, i;

    uint8_t data[] = {0};

    uint8_t *mem;

    size = (x2 - x1 + 1) * (y2 - y1 + 1) * 2;   // RGB888 3个字节

    data[1] = color >> 8;

    data[0] = color;

    mem = (uint8_t *)kzalloc(size, GFP_KERNEL);

    if (!mem) {

        printk(KERN_ERR "lcd_fill_rect: alloc %d bytes mem fail!\n", size);

    }

    for (i = 0; i < size/2 ; i++) {

        mem[i * 2] =  data[1];

        mem[i * 2 + 1] =  data[0];

    }

    LCD_SetWindows(spi,0, 0,LCD_W - 1,LCD_H - 1);

    gpio_set_value(msp2402lcd.data_command_io, 1);

    spi_write(spi,mem, size);

    kfree(mem);

}

完整源码地址(如果硬件相同可直接运行):

(48条消息) IMX6ULL+SPILCDMSP2402(驱动ICILI9341)显示简单的QT界面-C文档类资源-CSDN文库文章来源地址https://www.toymoban.com/news/detail-459135.html

到了这里,关于IMX6ULL + SPI LCD(驱动IC ILI9341)显示简单的QT界面的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【IMX6ULL驱动开发学习】02.IMX6ULL烧写Linux系统

    由于我买的是正点原子的IMX6ULL阿尔法开发板,但是我是看韦东山老师视频学习的驱动 所以这里我烧录的方法是按照韦东山老师的课程来的 这里给出烧写Linux系统用到的工具 链接:https://pan.baidu.com/s/1bD-xxn3K8xQAVkJSaJmTzQ 提取码:af6w 下载解压后,可以看到烧写工具 烧写Linux系统

    2024年02月13日
    浏览(59)
  • [imx6ull]SPI接口编程-回环测试

    SPI 是串行外设接口( Serial Peripheral Interface )的缩写。是 Motorola 公司推出的一种同步串行接口技术,是一种高速的,全双工,同步的通信总线。SPI通常由一个主设备和一个或多个从设备组成。主设备选择一个从设备进行同步通信,以完成数据的交换。SPI通信采用环形结构,至少

    2024年02月12日
    浏览(33)
  • 【IMX6ULL驱动开发学习】05.IMX6ULL驱动开发_编写第一个hello驱动【熬夜肝】

    经过以下四个步骤,终于可以开始驱动开发了 01.安装交叉编译环境【附下载地址】 02.IMX6ULL烧写Linux系统 03.设置IMX6ULL开发板与虚拟机在同一网段 04.IMX6ULL开发板与虚拟机互传文件 一、获取内核、编译内核 二、创建vscode工作区,添加内核目录和个人目录 三、了解驱动程序编写

    2024年02月06日
    浏览(52)
  • iMX6ULL驱动开发 | 让imx6ull开发板支持usb接口FC游戏手柄

    手边有一闲置的linux开发板iMX6ULL一直在吃灰,不用来搞点事情,总觉得对不住它。业余打发时间就玩起来吧,总比刷某音强。从某多多上买来一个usb接口的游戏手柄,让开发板支持以下它,后续就可以接着在上面玩童年经典游戏啦。  我使用的是正点原子的I.MX6U-ALPHA 开发板,

    2024年02月14日
    浏览(54)
  • 【IMX6ULL驱动开发学习】15.IMX6ULL驱动开发问题记录(sleep被kill_fasync打断)

    发现问题的契机: 学习异步通知的时候,自己实现一个功能:按键控制蜂鸣器,同时LED灯在闪烁 结果:LED好像也同时被按键控制了 最后调试结果发现: 应用层的 sleep 被驱动层的 kill_fasync 打断,所以sleep没有执行完就重新进入下一次循环了 修改代码后解决该问题 解决逻辑就

    2024年02月13日
    浏览(51)
  • 【IMX6ULL驱动开发学习】08.IMX6ULL通过GPIO子系统函数点亮LED

    通过GPIO子系统函数点亮LED 1、GPIO子系统函数 1.1 确定 led 的GPIO标号,查看内核中的gpiochip 查看 gpiochip ,以正点原子的IMX6ULL阿尔法开发板为例 查看原理图,发现led接的引脚是 GPIO1_IO3,对应 /sys/kernel/debug/gpio 中的 gpiochip0 组,gpiochip0 组从0开始算起, 所以 GPIO1_IO3 对应的标号就

    2024年02月10日
    浏览(78)
  • 【IMX6ULL驱动开发学习】22.IMX6ULL开发板读取ADC(以MQ-135为例)

    IMX6ULL一共有两个ADC,每个ADC都有八个通道,但他们共用一个ADC控制器 在imx6ull.dtsi文件中已经帮我们定义好了adc1的节点部分信息 注意 num-channels = 2; ,这个表示指定使用ADC1的两个通道,即通道1和通道2 如果你要使用多个ADC通道,修改这个值即可 配置ADC引脚的 pinctrl ,在自己的

    2024年02月12日
    浏览(63)
  • 【IMX6ULL驱动开发学习】03.设置IMX6ULL开发板与虚拟机在同一网段(设置开发板静态IP)

    为什么要设置IMX6ULL与虚拟机通信? 因为要把在虚拟机下编译的文件传到IMX6ULL开发板上运行 设置好同一网段,可以互ping后,可以参考这篇博客,实现开发板与虚拟机的文件互传 IMX6ULL开发板与虚拟机互传文件 一、设置windows有线网卡 二、配置虚拟机双网卡(原本有一个NAT网卡

    2024年02月07日
    浏览(69)
  • 【IMX6ULL驱动开发学习】19.mmap内存映射

    mmap将一个文件或者其它对象映射进内存 ,使得应用层可以直接读取到驱动层的数据,无需通过copy_to_user函数 可以用于像LCD这样的外设, 需要读写大量数据的 一、应用层 mmap用法: 用open系统调用打开文件, 并返回描述符fd. 用mmap建立内存映射, 并返回映射首地址指针start. 对映

    2024年02月16日
    浏览(52)
  • 【IMX6ULL驱动开发学习】12.Linux驱动之设备树

    承接上一篇博客 【IMX6ULL驱动开发学习】11.驱动设计之面向对象_分层思想(学习设备树过渡部分) 代码获取: https://gitee.com/chenshao777/imx6-ull_-drivers 我后面将三个层合并了(实际上只有前两层),合并成一个dev_drv.c了,暂时没有加GPIO操作,只是个框架 合并前的代码在 11.butt

    2024年02月13日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包