SPI的控制器驅(qū)動(dòng)由平臺(tái)設(shè)備與平臺(tái)驅(qū)動(dòng)來(lái)實(shí)現(xiàn). 驅(qū)動(dòng)后用spi_master對(duì)象來(lái)描述.在設(shè)備驅(qū)動(dòng)中就可以通過(guò)函數(shù)spi_write, spi_read, spi_w8r16, spi_w8r8等函數(shù)來(lái)調(diào)用控制器.
"include/linux/spi/spi.h"http://讓spi->master指向的控制器對(duì)象發(fā)出len個(gè)字節(jié)數(shù)據(jù),數(shù)據(jù)緩沖區(qū)地址由buf指針指向static inline int spi_write(struct spi_device *spi, const void *buf, size_t len);//讓spi->master指向的控制器對(duì)象接收l(shuí)en個(gè)字節(jié)數(shù)據(jù),由buf指向指向的數(shù)據(jù)緩沖區(qū)存放static inline int spi_read(struct spi_device *spi, void *buf, size_t len);//讓spi->master指向的控制器對(duì)象發(fā)出數(shù)據(jù)后再接收數(shù)據(jù)int spi_write_then_read(struct spi_device *spi, const void *txbuf, unsigned n_tx, void *rxbuf, unsigned n_rx);//讓spi->master控制器對(duì)象同時(shí)收發(fā)8位數(shù)據(jù)static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd);//讓spi->master控制器對(duì)象同時(shí)發(fā)8位,接收16位數(shù)據(jù).static inline ssize_t spi_w8r16(struct spi_device *spi, u8 cmd);
////////////////////////////////////////////////////////////////
屏:
流程: 命令/數(shù)據(jù) –> spi控制器 —> 屏驅(qū)動(dòng)ic的spi接口 —> ILI9340C(屏的驅(qū)動(dòng)ic) –> 屏
屏的驅(qū)動(dòng)ic的作用:根據(jù)接收到的命令和數(shù)據(jù),配置屏的時(shí)序參數(shù)及在屏上刷出相應(yīng)的像素?cái)?shù)據(jù).
也就是我們只要通過(guò)spi接口把屏的命令和數(shù)據(jù)交給屏的驅(qū)動(dòng)ic即可, 讓驅(qū)動(dòng)IC完成刷屏的操作.
//所有的lcd屏都會(huì)用到驅(qū)動(dòng)IC的
//ILI9340C驅(qū)動(dòng)ic內(nèi)部有配置寄存器,我們需要通過(guò)spi接口配置驅(qū)動(dòng)ic內(nèi)部寄存器的值
模塊的引腳與板的連接:
reset --> PA8 //用于復(fù)位模塊 D/C --> PA7 //通過(guò)高低電平來(lái)區(qū)分?jǐn)?shù)據(jù)線(xiàn)上的數(shù)據(jù)類(lèi)型, command:0, data:1 . //command其實(shí)就是表示數(shù)據(jù)線(xiàn)上發(fā)過(guò)去的是驅(qū)動(dòng)ic內(nèi)部寄存器的地址 //data表示數(shù)據(jù)線(xiàn)上發(fā)過(guò)去的數(shù)據(jù)就是寄存器要設(shè)的值 CS --> spi0_CS0 //片選線(xiàn) SDI --> spi0_MOSI //數(shù)據(jù)線(xiàn),發(fā)出驅(qū)動(dòng)ic的寄存器地址和要設(shè)置的值 SDO --> spi0_MISO // 如不需要讀取驅(qū)動(dòng)ic寄存器的值,可不接 SCLK --> spi0_CLK //時(shí)鐘線(xiàn) LED --> 3.3v //背光電源 VCC --> 3.3v GND --> GND
//通過(guò)時(shí)序圖可得知,模塊支持三線(xiàn)/四線(xiàn)的工作方式,四線(xiàn)是用D/C線(xiàn)區(qū)分?jǐn)?shù)據(jù)線(xiàn)上的數(shù)據(jù)是寄存器地址或數(shù)據(jù). spi的工作時(shí)序方式是SPI_MODE_0(CPOL=0, CPHA=0), 也可以得知傳輸是以8位為單位.
//在內(nèi)核里描述spi屏設(shè)備,并通過(guò)spi_board_info的platform_data提供連接屏reset和D/C引腳的GPIO.
描述設(shè)備的代碼:
#include <linux/spi/spi.h>#include <mach/gpio.h>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));}
//////////////////////////設(shè)備驅(qū)動(dòng)的實(shí)現(xiàn)//////////////////////////////////
店家提供的c51里初始化屏的驅(qū)動(dòng)代碼:void write_command(uchar c) //發(fā)送驅(qū)動(dòng)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) //給驅(qū)動(dòng)ic傳輸數(shù)據(jù)使用{ 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 //??2?êy?aoá?áêú?áé??è·?ê??D??1??ü2?êy //0x48 0x68êú?á //0x28 0xE8 oá?á 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); }
///////////////////////////////////////
參考上面驅(qū)動(dòng)代碼實(shí)現(xiàn)的linux設(shè)備驅(qū)動(dòng):
#include <linux/init.h>#include <linux/module.h>#include <linux/spi/spi.h>#include <linux/delay.h>#include <linux/gpio.h>struct myspi_lcd_pdata { int dc_io; int reset_io;};struct spi_lcd_cmd{ u8 reg_addr; // command u8 len; //需要從spi_lcd_datas數(shù)組里發(fā)出數(shù)據(jù)字節(jié)數(shù) int delay_ms; //此命令發(fā)送數(shù)據(jù)完成后,需延時(shí)多久}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要發(fā)出的數(shù)據(jù) 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_lcdvoid spi_lcd_init(struct spi_device *spi){ struct myspi_lcd_pdata *pdata = spi->dev.platform_data; int i, j, n; // 屏復(fù)位 gpio_direction_output(pdata->reset_io, 0); mdelay(100); gpio_set_value(pdata->reset_io, 1); mdelay(100); n = 0; // n用于記錄數(shù)據(jù)數(shù)組spi_lcd_datas的位置 //發(fā)命令,并發(fā)出命令所需的數(shù)據(jù) for (i = 0; i < ARRAY_SIZE(cmds); i++) //命令 { write_command(spi, cmds[i].reg_addr); for (j = 0; j < cmds[i].len; j++) //發(fā)出命令后,需要發(fā)出的數(shù)據(jù) write_data(spi, spi_lcd_datas[n++]); if (cmds[i].delay_ms) //如有延時(shí)則延時(shí) mdelay(cmds[i].delay_ms); }}//設(shè)置要刷屏的開(kāi)始坐標(biāo)void addset(struct spi_device *spi, unsigned int x,unsigned int y){ write_command(spi, 0x2a); //發(fā)出x坐標(biāo) write_data(spi, x>>8); write_data(spi, x&0xff); write_command(spi, 0x2b); //發(fā)出y坐標(biāo) 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坐標(biāo)開(kāi)始刷//刷屏, 把整屏分成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");
效果圖:
聯(lián)系客服