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

news2025/8/12 21:13:38

1. 硬件:

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

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

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

LCD :MSP2402 (IC ILI9341)

2. 查找可用引脚

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

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

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文库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/33385.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【前端内容学习】vue的引用,下载,语法

&#xff08;1&#xff09;vue的使用方式 原版本应该是三种使用方式&#xff0c;但是现在vue官网好像已经找不到关于本地下载的内容了 1&#xff0c;直接在官网上引用网络CDN文件&#xff0c;注意这种引用方式&#xff0c;要把这一段写在所有使用vue的部分前面 <script s…

蓝鲸研运体系在腾讯内的应用实践

蓝鲸是腾讯IEG十多年研运探索的经验与成果&#xff0c;积累了很多人的智慧与付出。由于腾讯IEG的业务特殊性&#xff0c;蓝鲸体系天生地展现出对异构业务的友好&#xff0c;避免了需要重复造轮子才能完成对多业务的支持。本次分享主要介绍蓝鲸研运体系在腾讯内的发展、应用及未…

【Linux】Linux常用命令

目录一.帮助命令1.man获取帮助信息2.help获取shell内置命令的帮助信息3.怎么判断命令的类型4.使用man查看内置命令5.常用快捷键二.文件目录类命令1.pwd 显示当前工作目录的绝对路径2.cd 切换路径3.ls 列出目录的内容4.mkdir 创建一个新的目录(文件夹)5.rmdir 删除目录(文件夹)6…

linux64/ubuntu20.04安装NVIDIA驱动详细过程

每次安装Nvidia驱动的时候都要查询&#xff0c;各种各样的教程可能也不大适合自己&#xff0c;故记录一下安装过程&#xff1b; 本人所使用的系统为ubuntu20.04&#xff0c;64bit&#xff1b; 1、查看是否存在nvidia的显卡信息 命令&#xff1a;lspci | grep NVIDIA 2、根据显…

奥迪Q3电瓶损坏问题解决思路

背景 最近自己的小Q3坏了&#xff0c;具体场景就是无钥匙进入感应不生效&#xff0c;所有钥匙按键失灵&#xff0c;通过机械钥匙可以开启门锁但是汽车完全无法启动&#xff0c;方向盘锁死&#xff0c;灯光没有反应。初步推断电瓶损坏&#xff0c;或者漏电导致完全亏电。 怎么判…

数理统计笔记6:假设检验

引言 数理统计笔记的第6篇先介绍了假设检验&#xff0c;给出了各种常用的假设检验的方法&#xff0c;最后介绍了用置信区间和p值来进行假设检验的方法。 引言假设检验描述什么是假设什么是假设检验假设检验的基本思想假设检验的步骤假设检验的原理假设检验的两类错误双侧检验和…

【微电网优化】粒子群优化算法的微电网调度(光伏、储能、电动车、电网交互)【含Matlab源码 2190期】

⛄一、粒子群算法求解电联供型微电网经济运行优化简介 0 引言 热电联供 (combined heat and power, CHP) 系统建立在能源梯级利用的概念基础上, 统一解决了电能和热能的供应问题, 是一种经济节能、环境友好的用能方式, 具有良好的社会和经济效益, 在国内外引起广泛关注。在发展…

ShareSDK for Flutter

前言 这是一个基于ShareSDK功能的扩展的Flutter插件。使用此插件能够帮助您在使用Flutter开发应用时,快速地实现社会化功能,例如第三方授权登录,获取用户信息以及社交平台的分享等功能。 Demo例子&#xff1a;https://github.com/MobClub/ShareSDK-For-Flutter 开始集成 引入…

C++ 语言学习 day11 复习(3)

1.第一个是昨天的作业&#xff1a; 用类实现一个双向循环链表&#xff0c; 完成对应的功能&#xff0c;&#xff08;增删查改 &#xff09; 代码&#xff1a; list.h #ifndef LIST_H #define LIST_H #include <iostream> #include <string.h> using namespace s…

WebRTC入门教学和一对一通话实现

WebRTC入门学习 简介 大体架构 互联网实时通信平台&#xff0c;html5标准之一&#xff0c;使用简单的API就可以实现音频通信。 紫色部分的是Web应用开发者需要关注的部门&#xff0c;也就是WebRTC提供给开发者的接口蓝色部分是提供给浏览器厂商的接口&#xff0c;浏览器厂…

2023年天津理工大学中环信息学院专升本专业课报名考试须知

天津理工大学中环信息学院 2023年高职升本科专业课考试须知 根据《2023年天津市高职升本科招生实施办法》的相关要求&#xff0c;为做好高职升本科专业考试的报考工作&#xff0c;全面服务考生&#xff0c;保障考生权益&#xff0c;结合疫情防控要求&#xff0c;现将考试具体事…

14天学习训练营之 入门Pygame

目录 学习知识点 pygame 的 “hello world” pygame 模块概览 事件 理解事件 事件检索 处理鼠标事件 处理键盘事件 事件过滤 产生事件 模板代码 写一个把所有发生的事件输出的程序 使用方向键来移动图片 产生一个完全自定义的全新事件 这个程序让 “hello world”…

Linux--信号量

1.信号量的定义: 信号量是一个特殊的变量&#xff0c;一般取正数值。它的值代表允许访问的资源数目&#xff0c; 获取资源时&#xff0c;需要对信号量的值进行原子减一&#xff0c;该操作被称为p操作。当信号量值为0时&#xff0c;代表没有资源可用&#xff0c;p操作会阻塞。释…

Flutter高仿微信-第31篇-单聊-表情

Flutter高仿微信系列共59篇&#xff0c;从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。 详情请查看 效果图&#xff1a; 详情请参考 Flutter高仿微信-第29篇-单聊 &#xff0c; 这里只是提取表情实现的…

骨感传导蓝牙耳机怎么样,骨感传导耳机对于我们耳道有保护吗

人们对于自身健康越来越重视&#xff0c;更多的人意识到传统耳机对于我们耳道的危害&#xff0c;纷纷加入了新型的骨感传导耳机阵容中&#xff0c;但还是存在不少对于骨传导耳机保持顾虑的小伙伴们&#xff0c;认为骨感传导对于耳道还是有损害&#xff0c;那么今天小编就和大家…

【Redis】Redis 的基础数据结构 以及 各种数据结构常用命令使用示例

本文主要介绍 Redis 基础&#xff0c;包括什么是 Redis 、Redis 数据结构有那些 以及 各种Redis 数据结构的常用操作命令 1. 初始 Redis 1.1 NoSQL 数据库 —— 非关系型数据库 SQL 1&#xff09; 结构化 -—— 例如 MySQL 中的表结构 &#xff08;不建议修改&#xff0c;初始…

锐捷MPLS跨域方案A、B实验配置

目录 MPLS域内配置 MPLS域1配置 MPLS域2配置 域间方式A配置 域间方式B配置 MPLS隧道——跨域解决方案A、B讲解_静下心来敲木鱼的博客-CSDN博客_跨域a方案https://blog.csdn.net/m0_49864110/article/details/127601807?spm1001.2014.3001.5501 MPLS域内配置 MPLS域内配置…

同态加密库Seal库的安装(win11+VS2022)

先说一下&#xff0c;seal库是微软开发的同态加密库&#xff0c;目前支持三种算法bfv&#xff0c;bgv和ckks。提供的语言版本是C艹和C#。 工具准备 这是github上提供的要求。 要准备的东西有 vs2022&#xff08;社区版就行了&#xff0c;网上一堆教程&#xff09;&#xff0c…

使用 Python 和 Matplotlib下载美股数据

介绍&#xff1a; 提示&#xff1a;例如 这是关于使用机器学习创建交易策略的系列文章中的第一篇。关于机器学习在交易中的实际应用&#xff0c;我主要参考的是 Marco Lopez de Prado 的金融机器学习进展。 尽管在人工智能方面有多年经验&#xff0c;但我从未将其应用于交易…

Spring Boot中@Import三种使用方式

Import是一个非常有用的注解&#xff0c;它的长处在于你可以通过配置来控制是否注入该Bean&#xff0c;也可以通过条件来控制注入哪些Bean到Spring容器中。 比如我们熟悉的&#xff1a;EnableAsync 、EnableCaching、EnableScheduling等等统一采用的都是借助Import注解来实现的…