27 在H5上实现spi-tft屏的简单驱动

来源:互联网 发布:2017淘宝宝贝上传数量 编辑:程序博客网 时间:2024/06/05 16:52

屏的购买链接:https://item.taobao.com/item.htm?spm=a1z10.5-c-s.w4002-16248799892.67.1b6f9109XnyTYo&id=520967019281

这里写图片描述


内核里设备树关于spi屏的描述:

&spi1 {    #address-cells = <1>;    #size-cells = <0>;    status = "okay";    pinctrl-names = "default";    pinctrl-0 = <&spi1_pins &spi1_cs_pins>;    cs-gpios = <&pio 0 13 GPIO_ACTIVE_HIGH>;    myspidev {        compatible = "myspilcd";        reg = <0>;        status = "okay";        spi-max-frequency = <10000000>;        dc-gpios = <&pio  0  11  GPIO_ACTIVE_LOW>;         rs-gpios = <&pio  0  19  GPIO_ACTIVE_LOW>;        spi-cpha;  /* CPHA = 1 */        spi-cpol;  /* CPOL = 1 */        buswidth = <8>;    };  };

设备驱动源码:

/* mydrv.c */#include <linux/init.h>#include <linux/module.h>#include <linux/spi/spi.h>#include <linux/gpio.h>#include <linux/slab.h>#include <linux/delay.h>#define LCD_X_SIZE          176#define LCD_Y_SIZE          220#define X_MAX_PIXEL         LCD_Y_SIZE#define Y_MAX_PIXEL         LCD_X_SIZEstruct regdata_t{        u8  reg;        u16 data;        int delay_ms;}regdatas[] = {    {0x10, 0x0000, 0}, {0x11, 0x0000, 0}, {0x12, 0x0000, 0},    {0x13, 0x0000, 0}, {0x14, 0x0000, 40},    {0x11, 0x0018, 0}, {0x12, 0x1121, 0}, {0x13, 0x0063, 0},    {0x14, 0x3961, 0}, {0x10, 0x0800, 10}, {0x11, 0x1038, 30},    {0x02, 0x0100, 0}, {0x01, 0x001c, 0}, {0x03, 0x1038, 0},    {0x07, 0x0000, 0}, {0x08, 0x0808, 0}, {0x0b, 0x1100, 0},    {0x0c, 0x0000, 0}, {0x0f, 0x0501, 0}, {0x15, 0x0020, 0},    {0x20, 0x0000, 0}, {0x21, 0x0000, 0},    {0x30, 0x0000}, {0x31, 0x00db}, {0x32, 0x0000}, {0x33, 0x0000},    {0x34, 0x00db}, {0x35, 0x0000}, {0x36, 0x00af}, {0x37, 0x0000},    {0x38, 0x00db}, {0x39, 0x0000},    {0x50, 0x0603}, {0x51, 0x080d}, {0x52, 0x0d0c}, {0x53, 0x0205},    {0x54, 0x040a}, {0x55, 0x0703}, {0x56, 0x0300}, {0x57, 0x0400},    {0x58, 0x0b00}, {0x59, 0x0017},    {0x0f, 0x0701}, {0x07, 0x0012, 50}, {0x07, 0x1017},}; typedef struct {    struct gpio_desc *dc_gpio;    struct gpio_desc *reset_gpio;   }mypdata;void write_command(struct spi_device *spi, u8 cmd) //用于发出屏的驱动IC的寄存器地址{        mypdata *pdata = spi_get_drvdata(spi);    gpiod_set_value(pdata->dc_gpio, 1); //低电平        spi_write(spi, &cmd, 1);}void write_data(struct spi_device *spi, u8 *data, int len) //用于发出屏驱动Ic的寄存器值{    mypdata *pdata = spi_get_drvdata(spi);    gpiod_set_value(pdata->dc_gpio, 0); //高电平    while (len) //先发高字节,再发低字节        spi_write(spi, data+(--len), 1);}void write_regdata(struct spi_device *spi, u8 cmd,  unsigned short data){    write_command(spi, cmd);        write_data(spi, (u8 *)&data, 2);    }void Lcd_SetRegion(struct spi_device *spi, u8 xStar, u8 yStar,u8 xEnd,u8 yEnd){    write_regdata(spi, 0x38,xEnd);    write_regdata(spi, 0x39,xStar);    write_regdata(spi, 0x36,yEnd);    write_regdata(spi, 0x37,yStar);    write_regdata(spi, 0x21,xStar);    write_regdata(spi, 0x20,yStar);    write_command(spi, 0x22);}int myprobe(struct spi_device *spi){    mypdata *pdata = devm_kzalloc(&spi->dev, sizeof(mypdata), GFP_KERNEL);    int ret=-ENODEV, i, j;    u16 color = 0x001f; /* rgb565,  蓝色 */    pdata->dc_gpio = devm_gpiod_get(&spi->dev, "dc", GPIOD_OUT_LOW);    if (IS_ERR(pdata->dc_gpio))        goto err0;    pdata->reset_gpio = devm_gpiod_get(&spi->dev, "rs", GPIOD_OUT_HIGH);    if (IS_ERR(pdata->reset_gpio))        goto err1;    printk("in myprobe ...\n");     spi_set_drvdata(spi, pdata);/* lcd reset */    gpiod_set_value(pdata->reset_gpio, 1); //设低电平    msleep(100);    gpiod_set_value(pdata->reset_gpio, 0); //设高电平    msleep(50);/* lcd init */    for (i = 0; i < ARRAY_SIZE(regdatas); i++)    {        write_regdata(spi, regdatas[i].reg, regdatas[i].data);        if (regdatas[i].delay_ms)            msleep(regdatas[i].delay_ms);    }/* 刷图 */    Lcd_SetRegion(spi, 0,0,X_MAX_PIXEL-1,Y_MAX_PIXEL-1); //设置从屏哪个坐标开始显示,到哪个坐标结束 #define rgb(r, g, b)  ((((r>>3)&0x1f)<<11) | (((g>>2)&0x3f)<<5) | ((b>>3)&0x1f))    for(i=0 ; i<Y_MAX_PIXEL/2 ; i++)    {        color = rgb(255, 0, 255);         for(j=0; j<X_MAX_PIXEL/2; j++)            write_data(spi, (u8 *)&color, 2);        color = rgb(255, 255, 0);        for(j=X_MAX_PIXEL/2; j<X_MAX_PIXEL; j++)            write_data(spi, (u8 *)&color, 2);    }    for(i=Y_MAX_PIXEL/2 ; i<Y_MAX_PIXEL; i++)    {        color = rgb(0, 255, 255);        for(j=0; j<X_MAX_PIXEL/2; j++)            write_data(spi, (u8 *)&color, 2);        color = rgb(255, 0,0);        for(j=X_MAX_PIXEL/2; j<X_MAX_PIXEL; j++)            write_data(spi, (u8 *)&color, 2);    }    return 0;err1:    devm_gpiod_put(&spi->dev, pdata->dc_gpio);err0:    printk("probe failed\n");    return ret;}int myremove(struct spi_device *spi){    mypdata *pdata = spi_get_drvdata(spi);    printk("in myremove ...\n");    devm_gpiod_put(&spi->dev, pdata->dc_gpio);    devm_gpiod_put(&spi->dev, pdata->reset_gpio);    return 0;}struct of_device_id ids[] = {    {.compatible = "myspilcd"},    {},};struct spi_driver mydrv = {        .probe = myprobe,        .remove = myremove,        .driver = {            .owner = THIS_MODULE,            .name = "myspidrv",            .of_match_table = ids,        },};module_spi_driver(mydrv);MODULE_LICENSE("GPL");

效果图:
这里写图片描述



参考店家提供的51代码:

/* Lcd_Driver.h */#include<reg51.h>#include<absacc.h>#include<intrins.h>#include<string.h>#define uchar unsigned char#define uint unsigned int/*****************************************************************************//测试硬件平台:STC12C5A60S2/STC12LE5A60S2//主频:12MHZ//本测试程序接线定义如下://请认真检查接线//本程序最少只需要接4个IO即可驱动这款液晶屏(将液晶片选和背光接至高电平3.3V)//本程序采用STC12LE5A60S2/STC12C5A60S2 硬件SPI驱动,其中SCLK、MOSI两个引脚不可随意更改IO//其余控制引脚均可根据需要自行修改IO配置*******************************************************************************///---------------------------液晶屏接线说明-------------------------------------//sbit bl        =P3^2;//接模块LED引脚,背光可以采用IO控制或者PWM控制,也可以直接接到高电平常亮sbit scl       =P1^7;//接模块CLK引脚,sbit sda       =P1^5;//接模块SDI引脚,sbit rs        =P0^2;//接模块RS引脚,//sbit cs        =P0^3;//接模块CS引脚   //sbit reset     =P3^3;//接模块RST引脚//---------------------------End of液晶屏接线---------------------------------////测试硬件平台:STC12C5A60S2/STC12LE5A60S2//主频:12MHZ//单片机IO推挽输出设置定义#define MCU_STC12//如果您使用的单片机不是STC12系列(如STC89C52)请屏蔽此宏定义#define     MAIN_Fosc   22000000L   //定义时钟#ifdef MCU_STC12sfr P3M1  = 0xB1;   //P3M1.n,P3M0.n     =00--->Standard,    01--->push-pullsfr P3M0  = 0xB2;   //                  =10--->pure input,  11--->open drainsfr AUXR1 = 0xA2;#endif//-----------------------------SPI 总线配置--------------------------------------//#define USE_HARDWARE_SPI     1  //1:Enable Hardware SPI;0:USE Soft SPI//-------------------------屏幕物理像素设置--------------------------------------//#define LCD_X_SIZE          176#define LCD_Y_SIZE          220/////////////////////////////////////用户配置区///////////////////////////////////    //支持横竖屏快速定义切换#define USE_HORIZONTAL          1   //定义是否使用横屏      0,不使用.1,使用.#ifdef USE_HORIZONTAL//如果定义了横屏 #define X_MAX_PIXEL         LCD_Y_SIZE#define Y_MAX_PIXEL         LCD_X_SIZE#else#define X_MAX_PIXEL         LCD_X_SIZE#define Y_MAX_PIXEL         LCD_Y_SIZE#endif////////////////////////////////////////////////////////////////////////////////////STC单片机硬件SPI寄存器定义sfr SPSTAT = 0xCD;  //STC12C5A60S2系列sfr SPCTL  = 0xCE;  //STC12C5A60S2系列sfr SPDAT  = 0xCF;  //STC12C5A60S2系列//sfr SPCTL   = 0x85;   SPI控制寄存器//   7       6       5       4       3       2       1       0      Reset Value//  SSIG    SPEN    DORD    MSTR    CPOL    CPHA    SPR1    SPR0        0x00#define SSIG        1   //1: 忽略SS脚,由MSTR位决定主机还是从机       0: SS脚用于决定主从机。#define SPEN        1   //1: 允许SPI,                             0:禁止SPI,所有SPI管脚均为普通IO#define DORD        0   //1:LSB先发,                              0:MSB先发#define MSTR        1   //1:设为主机                                0:设为从机#define CPOL        1   //1: 空闲时SCLK为高电平,                   0:空闲时SCLK为低电平#define CPHA        1   //#define SPR1        0   //SPR1,SPR0   00: fosc/4,     01: fosc/16#define SPR0        0   //            10: fosc/64,    11: fosc/128#define SPEED_4     0   // fosc/4#define SPEED_16    1   // fosc/16#define SPEED_64    2   // fosc/64#define SPEED_128   3   // fosc/128//sfr SPSTAT  = 0xCD;   //SPI状态寄存器//   7       6      5   4   3   2   1   0       Reset Value//  SPIF    WCOL    -   -   -   -   -   -#define SPIF    0x80        //SPI传输完成标志。写入1清0。#define WCOL    0x40        //SPI写冲突标志。写入1清0。//常用颜色值定义#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  1111111111011111typedef unsigned int   u16;typedef unsigned char  u8;void Lcd_Clear(u16 Color);void Lcd_Init(void);void  delay_ms(unsigned char ms);void Gui_DrawPoint(u16 x,u16 y,u16 Data);void Lcd_SetRegion(u8 xStar, u8 yStar,u8 xEnd,u8 yEnd);void Lcd_SetXY(u16 Xpos, u16 Ypos);void Lcd_WriteData_16Bit(u16 Data);

/* Lcd_Driver.c */#include"Lcd_Driver.h"/*---------------------------液晶屏接线说明-------------------------------------//sbit bl        =P3^2;//接模块LED引脚,背光可以采用IO控制或者PWM控制,也可以直接接到高电平常亮//sbit scl       =P1^7;//接模块CLK引脚,//sbit sda       =P1^5;//接模块SDI引脚,//sbit rs        =P0^2;//接模块RS引脚,//sbit cs        =P0^3;//接模块CS引脚//sbit reset     =P3^3;//接模块RST引脚//VCC:可以接5V也可以接3.3V//LED:可以接5V也可以接3.3V或者使用任意空闲IO控制(高电平使能)//GND:接电源地//说明:如需要尽可能少占用IO,可以将LCD_CS接地,LCD_LED接3.3V,LCD_RST接至单片机复位端,//将可以释放3个可用IO//接口定义在Lcd_Driver.h内定义,//如需变更IO接法,请根据您的实际接线修改相应IO初始化LCD_GPIO_Init()//-----------------------------------------------------------------------------------------例程功能说明:1.  简单刷屏测试2.  英文显示测试示例3.  中文显示测试示例4.  数码管字体显示示例5.  图片显示示例6.  2D按键菜单示例7.  本例程支持横屏/竖屏切换(开启宏USE_HORIZONTAL,详见Lcd_Driver.h)8.  本例程支持软件模拟SPI/硬件SPI切换(开启宏USE_HARDWARE_SPI,详见Lcd_Driver.h)**********************************************************************************************///========================================================================// 函数: void SPI_init(void)// 描述: 配置硬件SPI,可通过修改SPEED_4值来更改SPI总线速度// 参数: none.// 返回: none.// 版本: VER1.0// 日期: 2012-12-15// 备注: SPEED_4为4分频最高速,SPEED_128为最低速//========================================================================////void    SPI_init(void)  {    SPCTL = (SSIG << 7) + (SPEN << 6) + (DORD << 5) + (MSTR << 4) + (CPOL << 3) + (CPHA << 2) + SPEED_4;}//========================================================================// 函数: void  delay_ms(unsigned char ms)// 描述: 延时函数。// 参数: ms,要延时的ms数.// 返回: none.// 版本: VER1.0// 日期: 2012-12-15// 备注: //========================================================================void  delay_ms(unsigned char ms){     unsigned int i;     do{          i = MAIN_Fosc / 14000;          while(--i)    ;   //14T per loop     }while(--ms);}/***************************************************************************** 名    称:void  SPIv_WriteData(u8 Data)* 功    能:STM32_模拟SPI写一个字节数据底层函数* 入口参数:Data* 出口参数:无* 说    明:STM32_模拟SPI读写一个字节数据底层函数****************************************************************************/void  SPIv_WriteData(u8 Data){    unsigned char i=0;    for(i=8;i>0;i--)    {        if(Data&0x80)           sda=1; //输出数据        else sda=0;        scl=0;               scl=1;        Data<<=1;     }}/***************************************************************************** 名    称:void SPI_WriteByte(uchar byte)* 功    能:STM32_硬件SPI写一个字节数据底层函数* 入口参数:byte* 出口参数:返回总线收到的数据* 说    明:STM32_硬件SPI写一个字节数据底层函数****************************************************************************/void SPI_WriteByte(uchar byte){                       SPDAT = byte;       //发送一个字节            while((SPSTAT & SPIF) == 0) ;   //等待发送完成            SPSTAT = SPIF + WCOL;           //清0 SPIF和WCOL标志}/***************************************************************************** 名    称:Lcd_WriteIndex(u8 Index)* 功    能:向液晶屏写一个8位指令* 入口参数:Index   寄存器地址* 出口参数:无* 说    明:调用前需先选中控制器,内部函数****************************************************************************/void Lcd_WriteIndex(u8 Index){   cs=0;   rs=0;#if USE_HARDWARE_SPI      SPI_WriteByte(Index);#else   SPIv_WriteData(Index);#endif    cs=1;}/***************************************************************************** 名    称:Lcd_WriteData(u8 Data)* 功    能:向液晶屏写一个8位数据* 入口参数:dat     寄存器数据* 出口参数:无* 说    明:向控制器指定地址写入数据,内部函数****************************************************************************/void Lcd_WriteData(u8 Data){   cs=0;   rs=1;#if USE_HARDWARE_SPI      SPI_WriteByte(Data);#else   SPIv_WriteData(Data);#endif    cs=1;}/***************************************************************************** 名    称:void Lcd_WriteData_16Bit(u16 Data)* 功    能:向液晶屏写一个16位数据* 入口参数:Data* 出口参数:无* 说    明:向控制器指定地址写入一个16位数据****************************************************************************/void Lcd_WriteData_16Bit(u16 Data){       Lcd_WriteData(Data>>8);    Lcd_WriteData(Data);    }/***************************************************************************** 名    称:void LCD_WriteReg(u8 Index,u16 Data)* 功    能:写寄存器数据* 入口参数:Index,Data* 出口参数:无* 说    明:本函数为组合函数,向Index地址的寄存器写入Data值****************************************************************************/void LCD_WriteReg(u8 Index,u16 Data){    Lcd_WriteIndex(Index);    Lcd_WriteData_16Bit(Data);}/***************************************************************************** 名    称:void Lcd_Reset(void)* 功    能:液晶硬复位函数* 入口参数:无* 出口参数:无* 说    明:液晶初始化前需执行一次复位操作****************************************************************************/void Lcd_Reset(){       reset=0;    delay_ms(100);    reset=1;    delay_ms(50);}/***************************************************************************** 名    称:void Lcd_Init(void)* 功    能:液晶初始化函数* 入口参数:无* 出口参数:无* 说    明:液晶初始化_ILI9225_176X220****************************************************************************/void Lcd_Init(void){   #if USE_HARDWARE_SPI //使用硬件SPI    SPI_init();#endif    Lcd_Reset(); //Reset before LCD Init.    //LCD Init For 2.2inch LCD Panel with ILI9225.      LCD_WriteReg(0x10, 0x0000); // Set SAP,DSTB,STB    LCD_WriteReg(0x11, 0x0000); // Set APON,PON,AON,VCI1EN,VC    LCD_WriteReg(0x12, 0x0000); // Set BT,DC1,DC2,DC3    LCD_WriteReg(0x13, 0x0000); // Set GVDD    LCD_WriteReg(0x14, 0x0000); // Set VCOMH/VCOML voltage    delay_ms(40); // Delay 20 ms    // Please follow this power on sequence    LCD_WriteReg(0x11, 0x0018); // Set APON,PON,AON,VCI1EN,VC    LCD_WriteReg(0x12, 0x1121); // Set BT,DC1,DC2,DC3    LCD_WriteReg(0x13, 0x0063); // Set GVDD    LCD_WriteReg(0x14, 0x3961); // Set VCOMH/VCOML voltage    LCD_WriteReg(0x10, 0x0800); // Set SAP,DSTB,STB    delay_ms(10); // Delay 10 ms    LCD_WriteReg(0x11, 0x1038); // Set APON,PON,AON,VCI1EN,VC    delay_ms(30); // Delay 30 ms    LCD_WriteReg(0x02, 0x0100); // set 1 line inversion#if USE_HORIZONTAL//如果定义了横屏    //R01H:SM=0,GS=0,SS=0 (for details,See the datasheet of ILI9225)    LCD_WriteReg(0x01, 0x001C); // set the display line number and display direction    //R03H:BGR=1,ID0=1,ID1=1,AM=1 (for details,See the datasheet of ILI9225)    LCD_WriteReg(0x03, 0x1038); // set GRAM write direction .#else//竖屏    //R01H:SM=0,GS=0,SS=1 (for details,See the datasheet of ILI9225)    LCD_WriteReg(0x01, 0x011C); // set the display line number and display direction     //R03H:BGR=1,ID0=1,ID1=1,AM=0 (for details,See the datasheet of ILI9225)    LCD_WriteReg(0x03, 0x1030); // set GRAM write direction.#endif    LCD_WriteReg(0x07, 0x0000); // Display off    LCD_WriteReg(0x08, 0x0808); // set the back porch and front porch    LCD_WriteReg(0x0B, 0x1100); // set the clocks number per line    LCD_WriteReg(0x0C, 0x0000); // CPU interface    LCD_WriteReg(0x0F, 0x0501); // Set Osc    LCD_WriteReg(0x15, 0x0020); // Set VCI recycling    LCD_WriteReg(0x20, 0x0000); // RAM Address    LCD_WriteReg(0x21, 0x0000); // RAM Address    //------------------------ Set GRAM area --------------------------------//    LCD_WriteReg(0x30, 0x0000);     LCD_WriteReg(0x31, 0x00DB);     LCD_WriteReg(0x32, 0x0000);     LCD_WriteReg(0x33, 0x0000);     LCD_WriteReg(0x34, 0x00DB);     LCD_WriteReg(0x35, 0x0000);     LCD_WriteReg(0x36, 0x00AF);     LCD_WriteReg(0x37, 0x0000);     LCD_WriteReg(0x38, 0x00DB);     LCD_WriteReg(0x39, 0x0000);     // ---------- Adjust the Gamma 2.2 Curve -------------------//    LCD_WriteReg(0x50, 0x0603);     LCD_WriteReg(0x51, 0x080D);     LCD_WriteReg(0x52, 0x0D0C);     LCD_WriteReg(0x53, 0x0205);     LCD_WriteReg(0x54, 0x040A);     LCD_WriteReg(0x55, 0x0703);     LCD_WriteReg(0x56, 0x0300);     LCD_WriteReg(0x57, 0x0400);     LCD_WriteReg(0x58, 0x0B00);     LCD_WriteReg(0x59, 0x0017);     LCD_WriteReg(0x0F, 0x0701); // Vertical RAM Address Position    LCD_WriteReg(0x07, 0x0012); // Vertical RAM Address Position    delay_ms(50); // Delay 50 ms    LCD_WriteReg(0x07, 0x1017); // Vertical RAM Address Position  }/*************************************************函数名:LCD_Set_XY功能:设置lcd显示起始点入口参数:xy坐标返回值:无*************************************************/void Lcd_SetXY(u16 Xpos, u16 Ypos){   #if USE_HORIZONTAL//如果定义了横屏                 LCD_WriteReg(0x21,Xpos);    LCD_WriteReg(0x20,Ypos);#else//竖屏       LCD_WriteReg(0x20,Xpos);    LCD_WriteReg(0x21,Ypos);#endif    Lcd_WriteIndex(0x22);       } /*************************************************函数名:LCD_Set_Region功能:设置lcd显示区域,在此区域写点数据自动换行入口参数:xy起点和终点返回值:无*************************************************///设置显示窗口void Lcd_SetRegion(u8 xStar, u8 yStar,u8 xEnd,u8 yEnd){#if USE_HORIZONTAL//如果定义了横屏     LCD_WriteReg(0x38,xEnd);    LCD_WriteReg(0x39,xStar);    LCD_WriteReg(0x36,yEnd);    LCD_WriteReg(0x37,yStar);    LCD_WriteReg(0x21,xStar);    LCD_WriteReg(0x20,yStar);#else//竖屏       LCD_WriteReg(0x36,xEnd);    LCD_WriteReg(0x37,xStar);    LCD_WriteReg(0x38,yEnd);    LCD_WriteReg(0x39,yStar);    LCD_WriteReg(0x20,xStar);    LCD_WriteReg(0x21,yStar);#endif    Lcd_WriteIndex(0x22);   }/*************************************************函数名:LCD_DrawPoint功能:画一个点入口参数:xy坐标和颜色数据返回值:无*************************************************/void Gui_DrawPoint(u16 x,u16 y,u16 Data){    Lcd_SetXY(x,y);    Lcd_WriteData_16Bit(Data);}    /*************************************************函数名:Lcd_Clear功能:全屏清屏函数入口参数:填充颜色COLOR返回值:无*************************************************/void Lcd_Clear(u16 Color)               {      unsigned int i,m;   Lcd_SetRegion(0,0,X_MAX_PIXEL-1,Y_MAX_PIXEL-1);   for(i=0;i<X_MAX_PIXEL;i++)    for(m=0;m<Y_MAX_PIXEL;m++)    {           Lcd_WriteData_16Bit(Color);    }   }
阅读全文
0 0
原创粉丝点击