Linux下SPI子系统配置1.8寸LCD屏

平台:rk3288-firefly
内核:Linux4.4
编译工具:arm-linux-gnueabihf-
小屏幕:128x160lcd ST7735

配置设备树:

&spi0 {
        status = "okay";
        max-freq = <48000000>;
         spidev@00 {
                compatible = "spi,oled";
                reg = <0x00>;
                spi-max-frequency = <48000000>;
                spi-cpha = <1>;
                spi-cpol = <1>;
                poll_mode = <0>;
                type = <0>;
                spi-rst = <&gpio5 8 GPIO_ACTIVE_LOW>;
                spi-dc = <&gpio5 9 GPIO_ACTIVE_LOW>;
		 	};
    };

代码:“显示部分已经改进,但是坐标设置不太准确”

#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
// #include "picc.h"
// LCD TFT 4-line-serial mode
#define RED  	0xf800
#define GREEN	0x07e0
#define BLUE 	0x001f
#define WHITE	0xffff
#define BLACK	0x0000
#define YELLOW  0xFFE0
#define GRAY0   0xEF7D   	//灰色0 3165 00110 001011 00101
#define GRAY1   0x8410      	//灰色1      00000 000000 00000
#define GRAY2   0x4208      	//灰色2  1111111111011111

#define DRIVER_NAME     "spi-lcd_driver"
#define LCDDEV_CNT     1
#define LCDDEV_NAME    "gpio-lcd-kevin"

#define Width       128
#define Height      160

struct spi_lcd_dev {
    dev_t               devid;
    struct cdev         cdev;
    struct class*       class;
    struct device*      device;
    struct device_node  *nd;
    int                 major;
    int                 minor;
    void                *private_data;      //私有数据
    int                 dc_gpio;
    int                 rest_gpio;
};

static struct spi_lcd_dev lcd_dev;




static int LCD_WriteCommand(struct spi_lcd_dev *dev, unsigned char c)
{
    int ret;
    struct spi_message m;
    struct spi_transfer *t;
    struct spi_device *spi = dev->private_data;
    unsigned char txdata = c;
    t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);   /* 申请内存 */
    if(t == NULL)
    {
        printk(KERN_ALERT "alloc spi transfer failed !\r\n");
        return -EINVAL;
    }

    gpio_set_value(dev->dc_gpio, 0);    /* 拉低发命令 */

    t->tx_buf = &txdata;
    t->len = 1;
    t->bits_per_word = 8;

    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;
}

static int LCD_WriteData(struct spi_lcd_dev *dev, unsigned char dat)
{
    int ret;
    struct spi_message m;
    struct spi_transfer *t;
    struct spi_device *spi = dev->private_data;
    unsigned char txdata = dat;

    t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);   /* 申请内存 */
    if(t == NULL)
    {
        printk(KERN_ALERT "alloc spi transfer failed !\r\n");
        return -EINVAL;
    }

    gpio_set_value(dev->dc_gpio, 1);    /* 拉高发数据 */

    t->tx_buf = &txdata;
    t->len = 1;
    t->bits_per_word = 8;

    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;

}

static int LCD_WriteData_16bit(struct spi_lcd_dev *dev, unsigned short dat)
{
    int ret;
    struct spi_message m;
    struct spi_transfer *t;
    struct spi_device *spi = dev->private_data;
    unsigned char txdata = dat>>8;

    t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);   /* 申请内存 */
    if(t == NULL)
    {
        printk(KERN_ALERT "alloc spi transfer failed !\r\n");
        return -EINVAL;
    }

    gpio_set_value(dev->dc_gpio, 1);    /* 拉高发数据 */

    t->tx_buf = &txdata;
    t->len = 1;
    t->bits_per_word = 8;

    spi_message_init(&m);   /* 初始化spi_message */
    spi_message_add_tail(t, &m);    /* 将spi_transfer添加到spi_message队列 */

    ret = spi_sync(spi, &m);        /* 使用同步发送 */

    txdata = dat&0xFF;
    t->tx_buf = &txdata;
    ret = spi_sync(spi, &m);        /* 使用同步发送 */



    kfree(t);
    return ret;

}



static void LCD_Set_Window(struct spi_lcd_dev *dev,u16 xstart,u16 ystart,u16 xend,u16 yend)
{
    LCD_WriteCommand(dev, 0x2A);
    LCD_WriteData(dev, 0x00);   //测试
    LCD_WriteData(dev, xstart);
    LCD_WriteData(dev, 0x00); 
    LCD_WriteData(dev, xend);  

    LCD_WriteCommand(dev, 0x2B); 
    LCD_WriteData(dev, 0x00); 
    LCD_WriteData(dev, ystart); 
    LCD_WriteData(dev, 0x00); 
    LCD_WriteData(dev, yend);   

    LCD_WriteCommand(dev, 0x2C); 
}



void LCD_Disp_Pic(void)
{
    struct spi_lcd_dev *dev = &lcd_dev;
    int i,j;
    static char pic[128];

    for(i=0; i<128; i++)
    {
        pic[i] = 0xf8;
    }

    /* 设置屏幕和显示部分 */
    LCD_Set_Window(dev, 0, 0, 159, 127);
    for(i=0; i<128; i++)
    {
        for(j=0; j<160;j++)
        {
            LCD_WriteData_16bit(dev, GRAY2);
        }
    }




    LCD_Set_Window(dev, 0, 0, 79, 63);
    for(i=0; i<79; i++)
    {
        for(j=0; j<63;j++)
        {
            LCD_WriteData_16bit(dev, WHITE);
        }
    }

    LCD_Set_Window(dev, 0, 63, 79, 127);
    for(i=0; i<79; i++)
    {
        for(j=0; j<63;j++)
        {
            LCD_WriteData_16bit(dev, RED);
        }
    }

    LCD_Set_Window(dev, 79, 0, 159, 63);
    for(i=0; i<79; i++)
    {
        for(j=0; j<63;j++)
        {
            LCD_WriteData_16bit(dev, GREEN);
        }
    }

    LCD_Set_Window(dev, 79, 63, 159, 127);
    for(i=0; i<79; i++)
    {
        for(j=0; j<63;j++)
        {
            LCD_WriteData_16bit(dev, YELLOW);
        }
    }


    mdelay(10);




    printk(KERN_ALERT "LCD display picture ok!\r\n");
}



static void lcd_reg_init(void)
{
    struct spi_lcd_dev *dev = &lcd_dev;
    printk(KERN_ALERT "This is lcd reg init func!\r\n");

    gpio_set_value(lcd_dev.rest_gpio, 1);
    mdelay(5);
    gpio_set_value(lcd_dev.rest_gpio, 0);
    mdelay(5);
    gpio_set_value(lcd_dev.rest_gpio, 1);
    mdelay(20);
    /******************************/
    LCD_WriteCommand(dev, 0x01);    // software reset
    mdelay(20);
    LCD_WriteCommand(dev, 0x11);    //sleep out
    mdelay(50);

    LCD_WriteCommand(dev, 0xB1);    //Frame Rate Control (In normal mode/ Full colors)
    LCD_WriteData(dev, 0x02); 
    LCD_WriteData(dev, 0x35); 
    LCD_WriteData(dev, 0x36); 
    LCD_WriteCommand(dev, 0xB2); 
    LCD_WriteData(dev, 0x02); 
    LCD_WriteData(dev, 0x35); 
    LCD_WriteData(dev, 0x36); 
    LCD_WriteCommand(dev, 0xB3); 
    LCD_WriteData(dev, 0x02); 
    LCD_WriteData(dev, 0x35); 
    LCD_WriteData(dev, 0x36); 
    LCD_WriteData(dev, 0x02); 
    LCD_WriteData(dev, 0x35); 
    LCD_WriteData(dev, 0x36); 

    LCD_WriteCommand(dev, 0xB4); //Dot inversion 
    LCD_WriteData(dev, 0x03); 

    LCD_WriteCommand(dev, 0xC0); 
    LCD_WriteData(dev, 0xA2); 
    LCD_WriteData(dev, 0x02); 
    LCD_WriteData(dev, 0x84); 
    LCD_WriteCommand(dev, 0xC1); 
    LCD_WriteData(dev, 0XC5); 
    LCD_WriteCommand(dev, 0xC2); 
    LCD_WriteData(dev, 0x0D); 
    LCD_WriteData(dev, 0x00); 
    LCD_WriteCommand(dev, 0xC3); 
    LCD_WriteData(dev, 0x8D); 
    LCD_WriteData(dev, 0x2A); 
    LCD_WriteCommand(dev, 0xC4); 
    LCD_WriteData(dev, 0x8D); 
    LCD_WriteData(dev, 0xEE); 

    LCD_WriteCommand(dev, 0xC5); //VCOM 
    LCD_WriteData(dev, 0x0A);    //1a
    LCD_WriteCommand(dev, 0x36); //MX, MY, RGB mode 
    // LCD_WriteData(dev, 0xEC); 
    LCD_WriteData(dev, 0xE0);   //change test

    LCD_WriteCommand(dev, 0xE0); //Gamma
    LCD_WriteData(dev, 0x12); 
    LCD_WriteData(dev, 0x1C); 
    LCD_WriteData(dev, 0x10); 
    LCD_WriteData(dev, 0x18); 
    LCD_WriteData(dev, 0x33); 
    LCD_WriteData(dev, 0x2C); 
    LCD_WriteData(dev, 0x25); 
    LCD_WriteData(dev, 0x28); 
    LCD_WriteData(dev, 0x28); 
    LCD_WriteData(dev, 0x27); 
    LCD_WriteData(dev, 0x2F); 
    LCD_WriteData(dev, 0x3C); 
    LCD_WriteData(dev, 0x00); 
    LCD_WriteData(dev, 0x03); 
    LCD_WriteData(dev, 0x03); 
    LCD_WriteData(dev, 0x10); 
    LCD_WriteCommand(dev, 0xE1); 
    LCD_WriteData(dev, 0x12); 
    LCD_WriteData(dev, 0x1C); 
    LCD_WriteData(dev, 0x10); 
    LCD_WriteData(dev, 0x18); 
    LCD_WriteData(dev, 0x2D); 
    LCD_WriteData(dev, 0x28); 
    LCD_WriteData(dev, 0x23); 
    LCD_WriteData(dev, 0x28); 
    LCD_WriteData(dev, 0x28); 
    LCD_WriteData(dev, 0x26); 
    LCD_WriteData(dev, 0x2F); 
    LCD_WriteData(dev, 0x3B); 
    LCD_WriteData(dev, 0x00); 
    LCD_WriteData(dev, 0x03); 
    LCD_WriteData(dev, 0x03); 
    LCD_WriteData(dev, 0x10); 

    LCD_WriteCommand(dev, 0x3A); //65k mode 5:6:5
    LCD_WriteData(dev, 0x05);   //18bit
    LCD_WriteCommand(dev, 0x29); //Display on 

    mdelay(50);



    printk(KERN_ALERT "LCD init ok!\r\n");
    LCD_Disp_Pic();
}




static int lcd_gpio_init(struct spi_device *spi)
{
    int ret;
    int flag1,flag2;
    lcd_dev.nd = spi->dev.of_node;  //找到设备树中节点
    if(lcd_dev.nd == NULL)
    {
        printk(KERN_ALERT "lcd node cant find !\r\n");
        return -EINVAL;
    }
    printk(KERN_ALERT "find lcd node okay !\r\n");

    /* 获取GPIO */
    lcd_dev.dc_gpio = of_get_named_gpio_flags(lcd_dev.nd, "spi-dc", 0, (enum of_gpio_flags *)&flag1);
    ret = gpio_is_valid(lcd_dev.dc_gpio);
    if(ret < 0)
    {
        printk(KERN_ALERT "get dc gpio failed !\r\n");
        return -EINVAL;
    }
    ret = gpio_request(lcd_dev.dc_gpio,"spi-dc");
    if(ret < 0)
    {
        printk(KERN_ALERT "request gpio dc failed !\r\n");
        gpio_free(lcd_dev.dc_gpio);
    }
    printk(KERN_ALERT "dc gpio num is %d !\r\n",lcd_dev.dc_gpio);

    lcd_dev.rest_gpio = of_get_named_gpio_flags(lcd_dev.nd, "spi-rst", 0, (enum of_gpio_flags *)&flag2);
    ret = gpio_is_valid(lcd_dev.rest_gpio);
    if(ret < 0)
    {
        printk(KERN_ALERT "get rest gpio failed !\r\n");
        return -EINVAL;
    }
    ret = gpio_request(lcd_dev.rest_gpio,"spi-rst");
    if(ret < 0)
    {
        printk(KERN_ALERT "request gpio rest failed !\r\n");
        gpio_free(lcd_dev.rest_gpio);
    }
    printk(KERN_ALERT "rest gpio num is %d !\r\n",lcd_dev.rest_gpio);

    /* 设置方向 */
	gpio_direction_output(lcd_dev.dc_gpio,0);
	gpio_direction_output(lcd_dev.rest_gpio,0);

    return ret;
}






// static int lcd_open(struct inode *inode, struct file *filp)
// {
//     filp->private_data = &lcd_dev;
    
//     return 0;
// }

static struct file_operations lcd_dev_fops = {
    .owner = THIS_MODULE,
    // .open = lcd_open,
    // .write = lcd_write,
};



static int spi_lcd_probe(struct spi_device *spi)
{
    int ret = 0;
    if(!spi)
    {
        return -ENOMEM;
    }   
    /**************************字符设备框架**********************************/
    alloc_chrdev_region(&lcd_dev.devid, 0, LCDDEV_CNT, LCDDEV_NAME);
    lcd_dev.major = MAJOR(lcd_dev.devid);
    lcd_dev.minor = MINOR(lcd_dev.devid);
    printk(KERN_ALERT "lcd_dev:major = %d \r\n",lcd_dev.major);
    printk(KERN_ALERT "lcd_dev:minor = %d \r\n",lcd_dev.minor);

    lcd_dev.cdev.owner = THIS_MODULE;

    cdev_init(&lcd_dev.cdev, &lcd_dev_fops);
    ret = cdev_add(&lcd_dev.cdev, lcd_dev.devid, LCDDEV_CNT);
    if(ret < 0)
    {
        printk(KERN_ALERT "add cdev failed!\r\n");
        unregister_chrdev_region(lcd_dev.devid, LCDDEV_CNT);
        return ret;
    }

    lcd_dev.class = class_create(THIS_MODULE, LCDDEV_NAME);
    if(IS_ERR(lcd_dev.class))
    {
        cdev_del(&lcd_dev.cdev);
        unregister_chrdev_region(lcd_dev.devid, LCDDEV_CNT);
        return PTR_ERR(lcd_dev.class);
    }

    lcd_dev.device = device_create(lcd_dev.class, NULL, lcd_dev.devid, NULL, LCDDEV_NAME);
    if(IS_ERR(lcd_dev.device))
    {
        cdev_del(&lcd_dev.cdev);
        unregister_chrdev_region(lcd_dev.devid, LCDDEV_CNT);
        class_destroy(lcd_dev.class);
        return PTR_ERR(lcd_dev.device);
    }
    /******************************************************************/

    /* 初始化spi_device */
    spi->mode = SPI_MODE_0;
    spi_setup(spi);

    /* 设置私有数据 */
    lcd_dev.private_data = spi;

    /* 初始化lcd屏的dc rest管脚 */
    lcd_gpio_init(spi);

    /* 内部寄存器初始化 */
    lcd_reg_init();


    printk(KERN_ALERT "spi_lcd_probe ok!\r\n");
    return 0;
}


static int spi_lcd_remove(struct spi_device *spi)
{
    gpio_free(lcd_dev.dc_gpio);
    gpio_free(lcd_dev.rest_gpio);
    cdev_del(&lcd_dev.cdev);
    unregister_chrdev_region(lcd_dev.devid, LCDDEV_CNT);
    device_destroy(lcd_dev.class, lcd_dev.devid);
    class_destroy(lcd_dev.class);
    return 0;
}


static const struct of_device_id spi_lcd_of_match[] = {
    {.compatible = "spi,oled",},
    {/* 空 */},
};

static struct spi_driver spi_lcd_driver = {
    .driver = {
        .owner = THIS_MODULE,
        .name = DRIVER_NAME,
        .of_match_table = of_match_ptr(spi_lcd_of_match),
    },
    .probe = spi_lcd_probe, 
    .remove = spi_lcd_remove,
};

static int __init spi_lcd_drv_init(void)
{
    printk(KERN_ALERT "This is spi-lcd-driver init func ...\r\n");
    return spi_register_driver(&spi_lcd_driver);	//SPI驱动注册进内核
}

static void __exit spi_lcd_drv_exit(void)
{
    spi_unregister_driver(&spi_lcd_driver);  //从内核中注销SPI驱动
}

module_init(spi_lcd_drv_init);
module_exit(spi_lcd_drv_exit);

MODULE_AUTHOR("Kevin");
MODULE_LICENSE("GPL");


最后再附上一张效果图,有瑕疵
在这里插入图片描述
还有屏幕的接线图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值