SPI的控制器驱动由平台设备与平台驱动来实现. 驱动后用spi_master对象来描述.在设备驱动中就可以通过函数spi_write, spi_read, spi_w8r16, spi_w8r8等函数来调用控制器.

"include/linux/spi/spi.h"

//让spi->master指向的控制器对象发出len个字节数据,数据缓冲区地址由buf指针指向

static inline int spi_write(struct spi_device *spi, const void *buf, size_t len);

//让spi->master指向的控制器对象接收len个字节数据,由buf指向指向的数据缓冲区存放

static inline int spi_read(struct spi_device *spi, void *buf, size_t len);

//让spi->master指向的控制器对象发出数据后再接收数据

int spi_write_then_read(struct spi_device *spi, const void *txbuf, unsigned n_tx,

void *rxbuf, unsigned n_rx);

//让spi->master控制器对象同时收发8位数据

static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd);

//让spi->master控制器对象同时发8位,接收16位数据.

static inline ssize_t spi_w8r16(struct spi_device *spi, u8 cmd);

屏:

流程: 命令/数据 –> spi控制器 —> 屏驱动ic的spi接口 —> ILI9340C(屏的驱动ic) –> 屏

屏的驱动ic的作用:根据接收到的命令和数据,配置屏的时序参数及在屏上刷出相应的像素数据.

也就是我们只要通过spi接口把屏的命令和数据交给屏的驱动ic即可, 让驱动IC完成刷屏的操作.

//所有的lcd屏都会用到驱动IC的

//ILI9340C驱动ic内部有配置寄存器,我们需要通过spi接口配置驱动ic内部寄存器的值

模块的引脚与板的连接:

reset --> PA8 //用于复位模块

D/C --> PA7 //通过高低电平来区分数据线上的数据类型, command:0, data:1 .

//command其实就是表示数据线上发过去的是驱动ic内部寄存器的地址

//data表示数据线上发过去的数据就是寄存器要设的值

CS --> spi0_CS0 //片选线

SDI --> spi0_MOSI //数据线,发出驱动ic的寄存器地址和要设置的值

SDO --> spi0_MISO // 如不需要读取驱动ic寄存器的值,可不接

SCLK --> spi0_CLK //时钟线

LED --> 3.3v //背光电源

VCC --> 3.3v

GND --> GND

//通过时序图可得知,模块支持三线/四线的工作方式,四线是用D/C线区分数据线上的数据是寄存器地址或数据. spi的工作时序方式是SPI_MODE_0(CPOL=0, CPHA=0), 也可以得知传输是以8位为单位.

//在内核里描述spi屏设备,并通过spi_board_info的platform_data提供连接屏reset和D/C引脚的GPIO.

描述设备的代码:

#include

#include

struct sunxi_spi_config {

int bits_per_word; //8bit

int max_speed_hz; //80MHz

int mode; // pha,pol,LSB,etc..

} sunxi_data = {

8, 10000000, SPI_MODE_0

};

struct myspi_lcd_pdata {

int dc_io;

int reset_io;

}spi_lcd_pdata = {

GPIOA(7), GPIOA(8),

};

struct spi_board_info spi_infos[] = {

{

.modalias = "myspi_lcd",

.platform_data = &spi_lcd_pdata,

.controller_data = &sunxi_data,

.max_speed_hz = 10000000,

.bus_num = 0,

.chip_select = 0,

.mode = SPI_MODE_0,

},

};

static void __init sunxi_dev_init(void)

{

...

// 在最后一行

spi_register_board_info(spi_infos, ARRAY_SIZE(spi_infos));

}

//设备驱动的实现//

店家提供的c51里初始化屏的驱动代码:

void write_command(uchar c) //发送驱动ic的寄存器地址

{

cs=0;

rs=0; // D/C 低电平

bitdata=c;

sda=bit7;scl=0;scl=1;

sda=bit6;scl=0;scl=1;

sda=bit5;scl=0;scl=1;

sda=bit4;scl=0;scl=1;

sda=bit3;scl=0;scl=1;

sda=bit2;scl=0;scl=1;

sda=bit1;scl=0;scl=1;

sda=bit0;scl=0;scl=1;

cs=1;

}

void write_data(uchar d) //给驱动ic传输数据使用

{

cs=0;

rs=1; // D/C 高电平

bitdata=d;

sda=bit7;scl=0;scl=1;

sda=bit6;scl=0;scl=1;

sda=bit5;scl=0;scl=1;

sda=bit4;scl=0;scl=1;

sda=bit3;scl=0;scl=1;

sda=bit2;scl=0;scl=1;

sda=bit1;scl=0;scl=1;

sda=bit0;scl=0;scl=1;

cs=1;

}

void lcd_initial()

{

reset=0;

delay(100);

reset=1;

delay(100);

write_command(0xCB);

write_data(0x39);

write_data(0x2C);

write_data(0x00);

write_data(0x34);

write_data(0x02);

write_command(0xCF);

write_data(0x00);

write_data(0XC1);

write_data(0X30);

write_command(0xE8);

write_data(0x85);

write_data(0x00);

write_data(0x78);

write_command(0xEA);

write_data(0x00);

write_data(0x00);

write_command(0xED);

write_data(0x64);

write_data(0x03);

write_data(0X12);

write_data(0X81);

write_command(0xF7);

write_data(0x20);

write_command(0xC0); //Power control

write_data(0x23); //VRH[5:0]

write_command(0xC1); //Power control

write_data(0x10); //SAP[2:0];BT[3:0]

write_command(0xC5); //VCM control

write_data(0x3e); //¶Ô±È¶Èµ÷œÚ

write_data(0x28);

write_command(0xC7); //VCM control2

write_data(0x86); //--

write_command(0x36); // Memory Access Control

//ŽË²ÎÊýΪºáÆÁÊúÆÁÉšÃ跜ʜÇл»¹ØŒü²ÎÊý

//0x48 0x68ÊúÆÁ

//0x28 0xE8 ºáÆÁ

write_data(0x48); //ÉèÖÃĬÈÏÊúÆÁÉšÃ跜ʜ

write_command(0x3A);

write_data(0x55);

write_command(0xB1);

write_data(0x00);

write_data(0x18);

write_command(0xB6); // Display Function Control

write_data(0x08);

write_data(0x82);

write_data(0x27);

write_command(0xF2); // 3Gamma Function Disable

write_data(0x00);

write_command(0x26); //Gamma curve selected

write_data(0x01);

write_command(0xE0); //Set Gamma

write_data(0x0F);

write_data(0x31);

write_data(0x2B);

write_data(0x0C);

write_data(0x0E);

write_data(0x08);

write_data(0x4E);

write_data(0xF1);

write_data(0x37);

write_data(0x07);

write_data(0x10);

write_data(0x03);

write_data(0x0E);

write_data(0x09);

write_data(0x00);

write_command(0XE1); //Set Gamma

write_data(0x00);

write_data(0x0E);

write_data(0x14);

write_data(0x03);

write_data(0x11);

write_data(0x07);

write_data(0x31);

write_data(0xC1);

write_data(0x48);

write_data(0x08);

write_data(0x0F);

write_data(0x0C);

write_data(0x31);

write_data(0x36);

write_data(0x0F);

write_command(0x11); //Exit Sleep

delay(120);

write_command(0x29); //Display on

write_command(0x2c);

}

///

参考上面驱动代码实现的linux设备驱动:

#include

#include

#include

#include

#include

struct myspi_lcd_pdata {

int dc_io;

int reset_io;

};

struct spi_lcd_cmd{

u8 reg_addr; // command

u8 len; //需要从spi_lcd_datas数组里发出数据字节数

int delay_ms; //此命令发送数据完成后,需延时多久

}cmds[] = {

{0xCB, 5, 0},

{0xCF, 3, 0},

{0xEB, 3, 0},

{0xEA, 2, 0},

{0xED, 4, 0},

{0xF7, 1, 0},

{0xC0, 1, 0},

{0xC1, 1, 0},

{0xC5, 2, 0},

{0xC7, 1, 0},

{0x36, 1, 0},

{0x3A, 1, 0},

{0xB1, 2, 0},

{0xB6, 3, 0},

{0xF2, 1, 0},

{0x26, 1, 0},

{0xE0, 15, 0},

{0xE1, 15, 0},

{0x11, 0, 120},

{0x29, 0, 0},

{0x2c, 0, 0},

};

u8 spi_lcd_datas[] = {

0x39, 0x2c, 0x00, 0x34, 0x20, // command: 0xCB要发出的数据

0x00, 0xC1, 0x30, // command: 0xCF

0x85, 0x00, 0x78, // command: 0xEB

0x00, 0x00, // command: 0xEA

0x64, 0x03, 0x12, 0x81, // command: 0xED

0x20, // command: 0xF7

0x23, // command: 0xC0

0x10, // command: 0xC1

0x3e, 0x28, // command: 0xC5

0x86, // command: 0xC7

0x48, // command: 0x36

0x55, // command: 0x3A

0x00, 0x18, // command: 0xB1

0x08, 0x82, 0x27, // command: 0xB6

0x00, // command: 0xF2

0x01, // command: 0x26

0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, //command: 0xE0

0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, //command: 0xE1

};

void write_command(struct spi_device *spi, u8 cmd)

{

struct myspi_lcd_pdata *pdata = spi->dev.platform_data;

// dc , command:0

gpio_direction_output(pdata->dc_io, 0);

spi_write(spi, &cmd, 1);

}

void write_data(struct spi_device *spi, u8 data)

{

struct myspi_lcd_pdata *pdata = spi->dev.platform_data;

// dc , data:1

gpio_direction_output(pdata->dc_io, 1);

spi_write(spi, &data, 1);

}

//初始化spi_lcd

void spi_lcd_init(struct spi_device *spi)

{

struct myspi_lcd_pdata *pdata = spi->dev.platform_data;

int i, j, n;

// 屏复位

gpio_direction_output(pdata->reset_io, 0);

mdelay(100);

gpio_set_value(pdata->reset_io, 1);

mdelay(100);

n = 0; // n用于记录数据数组spi_lcd_datas的位置

//发命令,并发出命令所需的数据

for (i = 0; i < ARRAY_SIZE(cmds); i++) //命令

{

write_command(spi, cmds[i].reg_addr);

for (j = 0; j < cmds[i].len; j++) //发出命令后,需要发出的数据

write_data(spi, spi_lcd_datas[n++]);

if (cmds[i].delay_ms) //如有延时则延时

mdelay(cmds[i].delay_ms);

}

}

//设置要刷屏的开始坐标

void addset(struct spi_device *spi, unsigned int x,unsigned int y)

{

write_command(spi, 0x2a); //发出x坐标

write_data(spi, x>>8);

write_data(spi, x&0xff);

write_command(spi, 0x2b); //发出y坐标

write_data(spi, y>>8);

write_data(spi, y&0xff);

write_command(spi, 0x2c);

}

int myprobe(struct spi_device *spi)

{

struct myspi_lcd_pdata *pdata = spi->dev.platform_data;

int ret;

int x, y;

u16 color0 = 0x001f; // RGB565, blue

u16 color1 = 0xf800; // red

u16 color2 = 0x07e0; // green

u16 color3 = 0xffff; // white

u16 color;

ret = gpio_request(pdata->reset_io, spi->modalias);

if (ret < 0)

goto err0;

ret = gpio_request(pdata->dc_io, spi->modalias);

if (ret < 0)

goto err1;

spi_lcd_init(spi); //初始化屏

addset(spi, 0, 0); //从屏的0,0坐标开始刷

//刷屏, 把整屏分成4块,每块颜色不同

// gpio_direction_output(pdata->dc_io, 1);

for (y = 0; y < 320; y++)

{

for (x = 0; x < 240; x++)

{

if (x < 120)

color = (y < 160) ? color0 : color1;

else

color = (y < 160) ? color2 : color3;

write_data(spi, color >> 8);

write_data(spi, color & 0xff);

}

}

printk("probe ...%s\n", spi->modalias);

return 0;

err1:

gpio_free(pdata->reset_io);

err0:

return ret;

}

int myremove(struct spi_device *spi)

{

struct myspi_lcd_pdata *pdata = spi->dev.platform_data;

gpio_free(pdata->dc_io);

gpio_free(pdata->reset_io);

printk("%s remove\n", spi->modalias);

return 0;

}

struct spi_device_id ids[] = {

{"myspi_lcd"},

{},

};

struct spi_driver myspi_drv = {

.driver = {

.owner = THIS_MODULE,

.name = "myspi_drv",

},

.probe = myprobe,

.remove = myremove,

.id_table = ids,

};

module_spi_driver(myspi_drv);

MODULE_LICENSE("GPL");

效果图:

linux spi屏驱动程序,65 linux spi设备驱动之spi LCD屏驱动相关推荐

  1. 【解决方案】STM32L152单片机驱动段码LCD屏,执行HAL_LCD_Init函数失败返回HAL_TIMEOUT,长时间卡在LCD_FLAG_RDY的while循环里面的解决办法

    STM32L152单片机驱动段码LCD屏,HAL_LCD_Init函数执行失败,卡在LCD_FLAG_RDY里面,函数返回HAL_TIMEOUT /*!< Wait Until the LCD ...

  2. linux 图像采集卡驱动程序,基于Linux操作系统的视频采集卡驱动程序设计

    DMA结构: struct saa7146_video_dma { u32 base_odd; u32 base_even; u32 prot_addr; u32 pitch; u32 base_pa ...

  3. linux中scsi驱动程序,探索 Linux 通用 SCSI 驱动器

    转载:https://www.ibm.com/developerworks/cn/linux/l-scsi-api/#ibm-pcon SCSI 客户机/服务器模型 在主机和存储介质进行通信期间,主机 ...

  4. 段码LCD研究 | 用HT1621B驱动段码LCD屏

    [本文发布地址https://blog.csdn.net/Stack_/article/details/117532877,未经许可不得转载,转载须注明出处] 一.探索 这是一个从乐心血压计上拆下来的 ...

  5. STC8a8K单片机c语言驱动彩屏,用STC单片机驱动笔段式LCD屏

    #include//接口定义 //1602的数据接口为P0 sbit RSPIN = P2^0; sbit RWPIN = P2^1; sbit EPIN =  P2^2; unsigned char ...

  6. 驱动程序开发:LCD屏显示驱动

    1.简介   在 Linux 中应用程序最终也是通过操作 RGB LCD 的显存来实现在 LCD 上显示字符.图片等信息.在裸机中我们可以随意的分配显存,但是在 Linux 系统中内存的管理很严格,显 ...

  7. 插拔usb设备计算机管理无反应,插拔USB设备引起死机蓝屏0x000000FE分析解决措施...

    我们操作电脑故障中最常见的那就是蓝屏,导致蓝屏的原因有很多,更新驱动.安装软件.系统补丁.甚至外接USB设备等等都会有可能导致蓝屏.今天介绍的蓝屏故障0x000000FE就是外接设备USB所引起的故障 ...

  8. STM32 FSMC接口驱动4.3寸TFT LCD屏

    STM32 FSMC接口驱动4.3寸TFT LCD屏 STM32的FSMC接口是并行总线接口,可以用于驱动存储芯片如FLASH/SRAM等,也可以用于驱动并口LCD屏. 这里以STM32F103VET ...

  9. keil5 stm32f03c8t6 printf重定向到串口和TFT 1.44 LCD屏

    效果 keil5工程设置,这一步很重要: 在任意的源文件里重写int fputc(int ch, FILE* f)函数 代码: print.h #ifndef __PRINT_H__ #define ...

最新文章

  1. 数学——函数极限知识以及sympy库的limit
  2. 它是本草纲目里的名药,也是如今让上千万人疯狂迷恋的夺命零食
  3. 《分布式系统:概念与设计》一1.6 实例研究:万维网
  4. JavaEE Servlet 并发问题
  5. 11步教你选择最稳定的MySQL版本
  6. matlab实现id3,MATLAB简单实现ID3
  7. java线程深入_深入聊聊Java多线程
  8. ExecutorService--线程池
  9. 如何用简单易懂的例子解释隐马尔可夫模型?(进阶篇)
  10. java io 高级,JavaSE - [10] 高级部分之IO流
  11. android使用Itext库生成PDF文件
  12. 用BoundsChecker检测内存泄漏
  13. Maven之(五)Maven仓库
  14. 解决Centos7网络连接的问题
  15. YOUChain有链与朗新天霁共建区块链职信数字资产平台
  16. 探探提醒对方账号异常_我告诉你探探中对方账号异常怎么回事
  17. echarts tooltip层级
  18. vue 在线访问word,excel,pdf 文件以及打印
  19. 阿里云服务器CPU超分型专有宿主机创建v5实例
  20. hashmap中的key是有序的么_关于HashMap中KEY的有序排列的反思和总结(对应TreeMap)

热门文章

  1. c++注释快捷键_Java编程之常用快捷键
  2. php主键自增sql语句,sql语句id自增的问题
  3. Python计算 1的9999999次方,不到1s就得出答案!是如何处理的?
  4. Python属性、方法和类管理系列之----属性初探
  5. OpenCASCADE:形状愈合之修复
  6. OpenCASCADE:拓扑 API之缝纫
  7. boost::safe_numerics模块实现相等的constexpr的测试程序
  8. boost::multiprecision模块gmp相关的测试程序
  9. boost::mpl模块实现upper_bound相关的测试程序
  10. boost::hana::unfold_right用法的测试程序