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

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

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值