平台: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");
最后再附上一张效果图,有瑕疵
还有屏幕的接线图: