问题同标题
起因是之前我为了学习linux自己画了一个板子但是ic上只有两个spi一个给了flash一个给了esp8089,为了体验各种操作方式把spi都用了,也不知道ic上那个40pin的是模拟的还是硬件的,本着学习的目就用了模拟8080来驱动st7789,前几天用st7735当终端,但他始终是复用了spi,现在想让io快起来给添加到framebuffer,
现在附上代码供大佬检查主要还是io的方式是不是这样不太好
st7789.c
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include "st7789bus.h"
#define ST7789_CNT 1
#define ST7789_NAME "st7789"
struct st7789_dev st7789dev;
static struct file_operations st7789_fops = {
.owner = THIS_MODULE,
};
static int st7789_probe(struct platform_device *dev)
{
int ret;
printk("st7789_probe\r\n");
ret = alloc_chrdev_region(&st7789dev.devid, 0, ST7789_CNT, ST7789_NAME);
if(ret < 0){
printk("devid_err\r\n");
return -EINVAL;
}
st7789dev.major = MAJOR(st7789dev.devid);
printk("st7789 major:%d\r\n",st7789dev.major);
cdev_init(&st7789dev.cdev, &st7789_fops);
cdev_add(&st7789dev.cdev, st7789dev.devid, ST7789_CNT);
st7789dev.class = class_create(THIS_MODULE, ST7789_NAME);
if(IS_ERR(st7789dev.class)){
return PTR_ERR(st7789dev.class);
}
st7789dev.device = device_create(st7789dev.class, NULL, st7789dev.devid, NULL, ST7789_NAME);
if(IS_ERR(st7789dev.device)){
return PTR_ERR(st7789dev.device);
}
st7789_gpio_request(&st7789dev);
Lcd_Init();
LCD_Clear(0x07E0);
return 0;
}
static int st7789_remove(struct platform_device *dev)
{
int i;
printk("st7789_remove\r\n");
gpio_free(st7789dev.res);
gpio_free(st7789dev.cs);
gpio_free(st7789dev.dc);
gpio_free(st7789dev.wr);
gpio_free(st7789dev.rd);
for(i=0;i<8;i++){
gpio_free(st7789dev.db[j]);
}
device_destroy(st7789dev.class, st7789dev.devid);
class_destroy(st7789dev.class);
cdev_del(&st7789dev.cdev);
unregister_chrdev_region(st7789dev.devid, ST7789_CNT);
return 0;
}
static struct of_device_id st7789_of_match[] = {
{.compatible = "cxj,8080"},
{}
};
static struct platform_driver st7789_driver = {
.probe = st7789_probe,
.remove = st7789_remove,
.driver = {
.owner = THIS_MODULE,
.name = "st7789",
.of_match_table = st7789_of_match,
},
};
static int __init st7789_init(void)
{
return platform_driver_register(&st7789_driver);
}
static void __exit st7789_exit(void)
{
platform_driver_unregister(&st7789_driver);
}
module_init(st7789_init);
module_exit(st7789_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("CXJ");
st7789bus.h
#ifndef ST7789BUS_H
#define ST7789BUS_H
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
struct st7789_dev {
dev_t devid;
int major;
struct cdev cdev;
struct class *class;
struct device *device;
struct device_node *node;
int res;
int cs;
int dc;
int wr;
int rd;
int db[8];
};
extern struct st7789_dev st7789dev;
#define LCD_RST_SET gpio_set_value(st7789dev.res, 1)
#define LCD_CS_SET gpio_set_value(st7789dev.cs, 1)
#define LCD_DC_SET gpio_set_value(st7789dev.dc, 1)
#define LCD_WR_SET gpio_set_value(st7789dev.wr, 1)
#define LCD_RD_SET gpio_set_value(st7789dev.rd, 1)
#define LCD_RST_CLR gpio_set_value(st7789dev.res, 0)
#define LCD_CS_CLR gpio_set_value(st7789dev.cs, 0)
#define LCD_DC_CLR gpio_set_value(st7789dev.dc, 0)
#define LCD_WR_CLR gpio_set_value(st7789dev.wr, 0)
#define LCD_RD_CLR gpio_set_value(st7789dev.rd, 0)
#define LCD_W 240
#define LCD_H 240
int st7789_gpio_request(struct st7789_dev *dev);
void Lcd_Init(void);
void LCD_Clear(uint16_t Color);
#endif
st7789bus.c
#include "st7789bus.h"
/*中景园复制粘贴修修改改*/
int st7789_gpio_request(struct st7789_dev *dev)
{
int ret=1;
int i;
char name[10];
dev->node = of_find_node_by_path("/st7789");
if(dev->node == NULL){
printk("tree_node is not find\r\n");
return -EINVAL;
}
dev->res = of_get_named_gpio(dev->node, "res-gpios", 0);
if(dev->res < 0){
printk("can not get res-gpios\r\n");
}
dev->cs = of_get_named_gpio(dev->node, "cs-gpios", 0);
if(dev->cs < 0){
printk("can not get cs-gpios\r\n");
ret = -EINVAL;
}
dev->dc = of_get_named_gpio(dev->node, "dc-gpios", 0);
if(dev->dc < 0){
printk("can not get dc-gpios\r\n");
ret = -EINVAL;
}
dev->wr = of_get_named_gpio(dev->node, "wr-gpios", 0);
if(dev->wr < 0){
printk("can not get wr-gpios\r\n");
ret = -EINVAL;
}
dev->rd = of_get_named_gpio(dev->node, "rd-gpios", 0);
if(dev->rd < 0){
printk("can not get rd-gpios\r\n");
ret = -EINVAL;
}
for(i=0;i<8;i++){
dev->db[j] = of_get_named_gpio(dev->node, "db-gpios", i);
if(dev->db[j] < 0){
printk("can not get db[%d]-gpios\r\n",i);
ret = -EINVAL;
}
}
if(ret != -EINVAL){
printk("res:%d cs:%d dc:%d wr:%d rd:%d\r\n", dev->res, dev->cs, dev->dc, dev->wr, dev->rd);
for(i=0;i<8;i++){
printk("db[%d]:%d", i, dev->db[j]);
}
}
gpio_request(dev->res, "res");
gpio_direction_output(dev->res, 0);
gpio_request(dev->cs, "cs");
gpio_direction_output(dev->cs, 0);
gpio_request(dev->dc, "dc");
gpio_direction_output(dev->dc, 0);
gpio_request(dev->wr, "wr");
gpio_direction_output(dev->wr, 0);
gpio_request(dev->rd, "rd");
gpio_direction_output(dev->rd, 0);
for(i=0;i<8;i++){
sprintf(name,"db%d",i);
gpio_request(dev->db[j], name);
gpio_direction_output(dev->db[j], 0);
}
return ret;
}
void data_out(struct st7789_dev dev, uint8_t dat)
{
int i;
for(i=0;i<8;i++){
gpio_set_value(dev.db[j],dat&0x01);
dat = dat>>1;
}
}
/******************************************************************************
函数说明:LCD 8位并口数据写入函数
入口数据:dat 要写入的并行数据
返回值: 无
******************************************************************************/
void LCD_Writ_Bus(uint8_t dat)
{
LCD_CS_CLR;
LCD_RD_SET;
LCD_WR_CLR;
data_out(st7789dev, dat);
LCD_WR_SET;
LCD_CS_SET;
}
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值: 无
******************************************************************************/
void LCD_WR_DATA8(uint8_t dat)
{
LCD_DC_SET;//写数据
LCD_Writ_Bus(dat);
}
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值: 无
******************************************************************************/
void LCD_WR_DATA(uint16_t dat)
{
LCD_DC_SET;//写数据
LCD_Writ_Bus(dat>>8);
LCD_Writ_Bus(dat);
}
/******************************************************************************
函数说明:LCD写入命令
入口数据:dat 写入的命令
返回值: 无
******************************************************************************/
void LCD_WR_REG(uint8_t dat)
{
LCD_DC_CLR;//写命令
LCD_Writ_Bus(dat);
}
/******************************************************************************
函数说明:设置起始和结束地址
入口数据:x1,x2 设置列的起始和结束地址
y1,y2 设置行的起始和结束地址
返回值: 无
******************************************************************************/
void LCD_Address_Set(u16 x1,u16 y1,u16 x2,u16 y2)
{
LCD_WR_REG(0x2a);//列地址设置
LCD_WR_DATA(x1);
LCD_WR_DATA(x2);
LCD_WR_REG(0x2b);//行地址设置
LCD_WR_DATA(y1);
LCD_WR_DATA(y2);
LCD_WR_REG(0x2c);//储存器写
}
// int Lcd_Test(struct st7789_dev dev)
// {
// int ret;
// LCD_WR_REG(0x04); //read id
// /*移植中景园发现画屏
// 增加时序延迟不行画屏
// 怀疑时序出错但是这个是移植大概率不会有问题
// 阅读datasheet的8080时序发现好像没啥问题画屏就算有反应
// 准备读id看时序发现原来LCD_Writ_Bus里没有禁止读LCD_RD_SET;
// 加上就行了
// */
// return ret;
// }
/******************************************************************************
函数说明:LCD初始化函数
入口数据:无
返回值: 无
******************************************************************************/
void Lcd_Init(void)
{
LCD_RST_CLR;
mdelay(200);
LCD_RST_SET;
mdelay(200);
//************* Start Initial Sequence **********//
LCD_WR_REG(0x01);
mdelay(200);
LCD_WR_REG(0x36);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0x3A);
LCD_WR_DATA8(0x05);
LCD_WR_REG(0xB2);
LCD_WR_DATA8(0x0C);
LCD_WR_DATA8(0x0C);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x33);
LCD_WR_REG(0xB7);
LCD_WR_DATA8(0x35);
LCD_WR_REG(0xBB);
LCD_WR_DATA8(0x19);
LCD_WR_REG(0xC0);
LCD_WR_DATA8(0x2C);
LCD_WR_REG(0xC2);
LCD_WR_DATA8(0x01);
LCD_WR_REG(0xC3);
LCD_WR_DATA8(0x12);
LCD_WR_REG(0xC4);
LCD_WR_DATA8(0x20);
LCD_WR_REG(0xC6);
LCD_WR_DATA8(0x0F);
LCD_WR_REG(0xD0);
LCD_WR_DATA8(0xA4);
LCD_WR_DATA8(0xA1);
LCD_WR_REG(0xE0);
LCD_WR_DATA8(0xD0);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x0D);
LCD_WR_DATA8(0x11);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x2B);
LCD_WR_DATA8(0x3F);
LCD_WR_DATA8(0x54);
LCD_WR_DATA8(0x4C);
LCD_WR_DATA8(0x18);
LCD_WR_DATA8(0x0D);
LCD_WR_DATA8(0x0B);
LCD_WR_DATA8(0x1F);
LCD_WR_DATA8(0x23);
LCD_WR_REG(0xE1);
LCD_WR_DATA8(0xD0);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x0C);
LCD_WR_DATA8(0x11);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x2C);
LCD_WR_DATA8(0x3F);
LCD_WR_DATA8(0x44);
LCD_WR_DATA8(0x51);
LCD_WR_DATA8(0x2F);
LCD_WR_DATA8(0x1F);
LCD_WR_DATA8(0x1F);
LCD_WR_DATA8(0x20);
LCD_WR_DATA8(0x23);
LCD_WR_REG(0x21);
LCD_WR_REG(0x11);
//Delay (120);
LCD_WR_REG(0x29);
}
/******************************************************************************
函数说明:LCD清屏函数
入口数据:无
返回值: 无
******************************************************************************/
void MY_LCD_WR_DATA(uint16_t Color)
{
LCD_DC_SET;//写数据
LCD_CS_CLR;
LCD_RD_SET;
LCD_WR_CLR;
data_out(st7789dev, dat);
LCD_WR_SET;
LCD_CS_SET;
}
void LCD_Clear(uint16_t Color)
{
u16 i,j;
LCD_Address_Set(0,0,LCD_W-1,LCD_H-1);
for(i=0;i<LCD_W;i++)
{
for (j=0;j<LCD_H;j++)
{
//LCD_WR_DATA(Color); 里面很多多余动作
LCD_WR_DATA(Color);
}
}
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("CXJ");
代码难看不太像linux的风格,只是移植能用就行
在时序上明显有可以优化的地方但是我感觉这个问他题主要还是io的操作方式
离线
发帖的时候说[]i不能使用我就把i改成了j
离线
看了下其他帖子感觉不好办,要直接操作寄存器还是算了,感觉要到此为止了。
离线
好像晕哥看我积分少直接给我加了30,我也板子开源一下,之前只放了原理图
离线
@摸鱼moyu
摸鱼大佬新年好,8bit i80 lcd可以用官方tina sdk驱动,很流畅的。
小二新年快乐
离线
摸鱼moyu 说:哇酷小二 说:@摸鱼moyu
摸鱼大佬新年好,8bit i80 lcd可以用官方tina sdk驱动,很流畅的。小二新年快乐
主线Linux的LCD TCON驱动貌似只支持HV RGB,其他都不支持。
谢谢大佬我也就是图个学习过程的
离线