SSD201适配ST7701S 3线SPI+RGB小屏
3线SPI+RGB屏 和普通的RGB屏区别在于SPI+RGB屏需要通过初始化配置一些东西才能作为正常的RGB屏使用。下面我们介绍在SSD201平台上点亮SPI+RGB屏的详细过程。
一、以字符设备驱动的方式编写SPI屏的初始化代码。这样的话在linux系统启动时就可以加载驱动模块实现对屏的初始化配置。驱动代码如下:

#include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ide.h> #include <linux/init.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/gpio.h> #include <asm/mach/map.h> #include <asm/uaccess.h> #include <asm/io.h> /*************************************************************** st7701 spi 初始化驱动. 文件名 :st7701s.c 作者 : 任晓朋 版本 : V1.0 描述 : 初始化配置ST7701s屏。 其他 : 无 时间 :2022.7.24 ***************************************************************/ #define LED_MAJOR 200 /* 主设备号 */ #define LED_NAME "st7701" /* 设备名字 */ //3线spi用到的三个IO口和一个RET管脚 #define SPI_DSIO 10 #define SPI_SCLK 9 #define SPI_CS 8 #define RST_PANEL 13 //单字节发送 static void spi_st7701s_SendData(unsigned char i) { unsigned char n; for(n = 0; n < 8; n++) { if(i & 0x80) { // printf("this bit is 1 \r\n"); gpio_set_value(SPI_DSIO, 1); } else { // printf("this bit is 0 \r\n"); gpio_set_value(SPI_DSIO, 0); } i<<= 1; gpio_set_value(SPI_SCLK, 0); udelay(1); gpio_set_value(SPI_SCLK, 1); udelay(1); } } /* static unsigned char Spi_St7701s_ReadByte(unsigned char id) { unsigned char i,tmp = 0; gpio_set_value(SPI_CS, 0); gpio_set_value(SPI_DSIO, 0); gpio_set_value(SPI_SCLK, 0); udelay(1); gpio_set_value(SPI_SCLK, 1); udelay(1); spi_st7701s_SendData(id); //先写寄存器地址0x04 gpio_set_value(SPI_SCLK, 0); gpio_set_value(SPI_DSIO, 1);//设为高阻态输入模式? udelay(1); gpio_direction_input(SPI_DSIO); for(i = 0;i < 8;i++) { gpio_set_value(SPI_SCLK, 1); tmp <<= 1; //移位 // printf("value is %d \r\n",value); if(gpio_get_value(SPI_DSIO)) { tmp |= 1; //读取一位数据 } gpio_set_value(SPI_SCLK, 0); } gpio_direction_output(SPI_DSIO,1); gpio_set_value(SPI_SCLK, 1); udelay(1); gpio_set_value(SPI_SCLK, 0); gpio_set_value(SPI_DSIO, 1); gpio_set_value(SPI_CS, 1); return tmp; //返回数据 } */ //写指令 static void SPI_WriteComm( unsigned char i) { gpio_set_value(SPI_CS, 0); gpio_set_value(SPI_DSIO, 0); gpio_set_value(SPI_SCLK, 0); udelay(1); gpio_set_value(SPI_SCLK, 1); udelay(1); spi_st7701s_SendData(i); gpio_set_value(SPI_CS, 1); } //写数据 static void SPI_WriteData( unsigned char i) { gpio_set_value(SPI_CS, 0); gpio_set_value(SPI_DSIO, 1); gpio_set_value(SPI_SCLK, 0); udelay(1); gpio_set_value(SPI_SCLK, 1); udelay(1); spi_st7701s_SendData(i); gpio_set_value(SPI_CS, 1); } //初始化 void ST7701S_Init(void) { //unsigned char ID1,ID2,ID3; gpio_request(SPI_DSIO,"SPI_DSIO"); gpio_request(SPI_SCLK,"SPI_SCLK"); gpio_request(SPI_CS,"SPI_CS"); gpio_request(RST_PANEL,"RST_PANEL"); gpio_direction_output(SPI_DSIO,1); gpio_direction_output(SPI_SCLK,1); gpio_direction_output(SPI_CS,1); gpio_direction_output(RST_PANEL,1); gpio_set_value(RST_PANEL,0); mdelay(200); gpio_set_value(RST_PANEL,1); mdelay(200); // ID1 = Spi_St7701s_ReadByte(0xDA); // ID2 = Spi_St7701s_ReadByte(0xDB); // ID3 = Spi_St7701s_ReadByte(0xDC); // printk("sssss\r\n"); // printk("ssss:0x%d 0x%d 0x%d\r\n", ID1,ID2,ID3); // HW_Reset(); //VBP>=11, VFP>=7 mdelay(120); SPI_WriteComm(0xFF); SPI_WriteData(0x77); SPI_WriteData(0x01); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x10); SPI_WriteComm(0xC0); SPI_WriteData(0x3B);//屏的分辨率 SPI_WriteData(0x00); SPI_WriteComm(0xC1); SPI_WriteData(0x0B); //VBP 如果配置为>0B屏幕上边有黑边显示不完整 SPI_WriteData(0x02); SPI_WriteComm(0xC2); SPI_WriteData(0x07); SPI_WriteData(0x02); SPI_WriteComm(0xC3); //配置工作模式为DE模式,供应商给的驱动源码并没有设置该 地址 。 SPI_WriteData(0x0C); SPI_WriteData(0x02); SPI_WriteData(0x00); SPI_WriteComm(0xCC); SPI_WriteData(0x10); SPI_WriteComm(0xCD);//RGB format SPI_WriteData(0x08); //用565时屏蔽 666打开 SPI_WriteComm(0xB0); // IPS SPI_WriteData(0x00); // 255 SPI_WriteData(0x11); // 251 SPI_WriteData(0x16); // 247 down SPI_WriteData(0x0e); // 239 SPI_WriteData(0x11); // 231 SPI_WriteData(0x06); // 203 SPI_WriteData(0x05); // 175 SPI_WriteData(0x09); // 147 SPI_WriteData(0x08); // 108 SPI_WriteData(0x21); // 80 SPI_WriteData(0x06); // 52 SPI_WriteData(0x13); // 24 SPI_WriteData(0x10); // 16 SPI_WriteData(0x29); // 8 down SPI_WriteData(0x31); // 4 SPI_WriteData(0x18); // 0 SPI_WriteComm(0xB1);// IPS SPI_WriteData(0x00);// 255 SPI_WriteData(0x11);// 251 SPI_WriteData(0x16);// 247 down SPI_WriteData(0x0e);// 239 SPI_WriteData(0x11);// 231 SPI_WriteData(0x07);// 203 SPI_WriteData(0x05);// 175 SPI_WriteData(0x09);// 147 SPI_WriteData(0x09);// 108 SPI_WriteData(0x21);// 80 SPI_WriteData(0x05);// 52 SPI_WriteData(0x13);// 24 SPI_WriteData(0x11);// 16 SPI_WriteData(0x2a);// 8 down SPI_WriteData(0x31);// 4 SPI_WriteData(0x18);// 0 SPI_WriteComm(0xFF); SPI_WriteData(0x77); SPI_WriteData(0x01); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x11); SPI_WriteComm(0xB0); //VOP 3.5375+ *x 0.0125 SPI_WriteData(0x6d); //5D SPI_WriteComm(0xB1); //VCOM amplitude setting SPI_WriteData(0x37); // SPI_WriteComm(0xB2); //VGH Voltage setting SPI_WriteData(0x81); //12V SPI_WriteComm(0xB3); SPI_WriteData(0x80); SPI_WriteComm(0xB5); //VGL Voltage setting SPI_WriteData(0x43); //-8.3V SPI_WriteComm(0xB7); SPI_WriteData(0x85); SPI_WriteComm(0xB8); SPI_WriteData(0x20); SPI_WriteComm(0xC1); SPI_WriteData(0x78); SPI_WriteComm(0xC2); SPI_WriteData(0x78); SPI_WriteComm(0xD0); SPI_WriteData(0x88); SPI_WriteComm(0xE0); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x02); SPI_WriteComm(0xE1); SPI_WriteData(0x03); SPI_WriteData(0xA0); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x04); SPI_WriteData(0xA0); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x20); SPI_WriteData(0x20); SPI_WriteComm(0xE2); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteComm(0xE3); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x11); SPI_WriteData(0x00); SPI_WriteComm(0xE4); SPI_WriteData(0x22); SPI_WriteData(0x00); SPI_WriteComm(0xE5); SPI_WriteData(0x05); SPI_WriteData(0xEC); SPI_WriteData(0xA0); SPI_WriteData(0xA0); SPI_WriteData(0x07); SPI_WriteData(0xEE); SPI_WriteData(0xA0); SPI_WriteData(0xA0); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteComm(0xE6); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x11); SPI_WriteData(0x00); SPI_WriteComm(0xE7); SPI_WriteData(0x22); SPI_WriteData(0x00); SPI_WriteComm(0xE8); SPI_WriteData(0x06); SPI_WriteData(0xED); SPI_WriteData(0xA0); SPI_WriteData(0xA0); SPI_WriteData(0x08); SPI_WriteData(0xEF); SPI_WriteData(0xA0); SPI_WriteData(0xA0); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteComm(0xEB); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x40); SPI_WriteData(0x40); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteComm(0xED); SPI_WriteData(0xFF); SPI_WriteData(0xFF); SPI_WriteData(0xFF); SPI_WriteData(0xBA); SPI_WriteData(0x0A); SPI_WriteData(0xBF); SPI_WriteData(0x45); SPI_WriteData(0xFF); SPI_WriteData(0xFF); SPI_WriteData(0x54); SPI_WriteData(0xFB); SPI_WriteData(0xA0); SPI_WriteData(0xAB); SPI_WriteData(0xFF); SPI_WriteData(0xFF); SPI_WriteData(0xFF); SPI_WriteComm(0xEF); SPI_WriteData(0x10); SPI_WriteData(0x0D); SPI_WriteData(0x04); SPI_WriteData(0x08); SPI_WriteData(0x3F); SPI_WriteData(0x1F); SPI_WriteComm(0xFF); SPI_WriteData(0x77); SPI_WriteData(0x01); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x13); SPI_WriteComm(0xEF); SPI_WriteData(0x08); SPI_WriteComm(0xFF); SPI_WriteData(0x77); SPI_WriteData(0x01); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteData(0x00); SPI_WriteComm(0x11); mdelay(120); //SPI_WriteComm(0x23); SPI_WriteComm(0x29); SPI_WriteComm(0x36); SPI_WriteData(0x08); SPI_WriteComm(0x3A); SPI_WriteData(0x66); //55/50=16bit(RGB565);66=18bit(RGB666);77或默认不写3AH是=24bit(RGB888) printk("st7701s init finished!!!"); } /* * @description : 打开设备 * @param - inode : 传递给驱动的inode * @param - filp : 设备文件,file结构体有个叫做private_data的成员变量 * 一般在open的时候将private_data指向设备结构体。 * @return : 0 成功;其他 失败 */ static int st7701_open(struct inode *inode, struct file *filp) { return 0; } /* * @description : 从设备读取数据 * @param - filp : 要打开的设备文件(文件描述符) * @param - buf : 返回给用户空间的数据缓冲区 * @param - cnt : 要读取的数据长度 * @param - offt : 相对于文件首地址的偏移 * @return : 读取的字节数,如果为负值,表示读取失败 */ static ssize_t st7701_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) { return 0; } /* * @description : 向设备写数据 * @param - filp : 设备文件,表示打开的文件描述符 * @param - buf : 要写给设备写入的数据 * @param - cnt : 要写入的数据长度 * @param - offt : 相对于文件首地址的偏移 * @return : 写入的字节数,如果为负值,表示写入失败 */ static ssize_t st7701_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { return 0; } /* * @description : 关闭/释放设备 * @param - filp : 要关闭的设备文件(文件描述符) * @return : 0 成功;其他 失败 */ static int st7701_release(struct inode *inode, struct file *filp) { return 0; } /* 设备操作函数 */ static struct file_operations st7701_fops = { .owner = THIS_MODULE, .open = st7701_open, .read = st7701_read, .write = st7701_write, .release = st7701_release, }; /* * @description : 驱动出口函数 * @param : 无 * @return : 无 */ static int __init st7701_init(void) { int retvalue = 0; ST7701S_Init(); /* 6、注册字符设备驱动 */ retvalue = register_chrdev(200, "st7701", &st7701_fops); if(retvalue < 0){ printk("register chrdev failed!\r\n"); return -EIO; } return 0; } /* * @description : 驱动出口函数 * @param : 无 * @return : 无 */ static void __exit st7701_exit(void) { /* 注销字符设备驱动 */ unregister_chrdev(200, "st7701"); } module_init(st7701_init); module_exit(st7701_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("tank");

KERNELDIR := /home/tank/qm/ssd201r/kernel CURRENT_PATH := $(shell pwd) obj-m := st7701s.o build: kernel_modules kernel_modules: $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules clean: $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean ~
二、修改屏参头文件,修改后的源码如下:(系统系统后如果需要运行QT程序,则需要运行dispInit程序初始化显示模块,并且注意分辨率的设置,不然QT程序不能正常显示)

#include "mi_panel_datatype.h" MI_PANEL_ParamConfig_t stPanelParam = { "SAT070AT50_800x480_60", // const char *m_pPanelName; ///< PanelName 0, //MS_U8 m_bPanelDither :1; ///< PANEL_DITHER, keep the setting E_MI_PNL_LINK_TTL, //MHAL_DISP_ApiPnlLinkType_e m_ePanelLinkType :4; ///< PANEL_LINK /////////////////////////////////////////////// // Board related setting /////////////////////////////////////////////// 1, //MS_U8 m_bPanelDualPort :1; ///< VOP_21[8], MOD_4A[1], PANEL_DUAL_PORT, refer to m_bPanelDoubleClk 0, //MS_U8 m_bPanelSwapPort :1; ///< MOD_4A[0], PANEL_SWAP_PORT, refer to "LVDS output app note" A/B channel swap 0, //MS_U8 m_bPanelSwapOdd_ML :1; ///< PANEL_SWAP_ODD_ML 0, //MS_U8 m_bPanelSwapEven_ML :1; ///< PANEL_SWAP_EVEN_ML 0, //MS_U8 m_bPanelSwapOdd_RB :1; ///< PANEL_SWAP_ODD_RB 0, //MS_U8 m_bPanelSwapEven_RB :1; ///< PANEL_SWAP_EVEN_RB 0, //MS_U8 m_bPanelSwapLVDS_POL :1; ///< MOD_40[5], PANEL_SWAP_LVDS_POL, for differential P/N swap 0, //MS_U8 m_bPanelSwapLVDS_CH :1; ///< MOD_40[6], PANEL_SWAP_LVDS_CH, for pair swap 0, //MS_U8 m_bPanelPDP10BIT :1; ///< MOD_40[3], PANEL_PDP_10BIT ,for pair swap 1, //MS_U8 m_bPanelLVDS_TI_MODE :1; ///< MOD_40[2], PANEL_LVDS_TI_MODE, refer to "LVDS output app note" /////////////////////////////////////////////// // For TTL Only /////////////////////////////////////////////// 0, //MS_U8 m_ucPanelDCLKDelay; ///< PANEL_DCLK_DELAY 0, //MS_U8 m_bPanelInvDCLK :1; ///< MOD_4A[4], PANEL_INV_DCLK 0, //MS_U8 m_bPanelInvDE :1; ///< MOD_4A[2], PANEL_INV_DE 0, //MS_U8 m_bPanelInvHSync :1; ///< MOD_4A[12], PANEL_INV_HSYNC 0, //MS_U8 m_bPanelInvVSync :1; ///< MOD_4A[3], PANEL_INV_VSYNC /////////////////////////////////////////////// // Output driving current setting /////////////////////////////////////////////// // driving current setting (0x00=4mA, 0x01=6mA, 0x02=8mA, 0x03=12mA) 1, //MS_U8 m_ucPanelDCKLCurrent; ///< define PANEL_DCLK_CURRENT 1, //MS_U8 m_ucPanelDECurrent; ///< define PANEL_DE_CURRENT 1, //MS_U8 m_ucPanelODDDataCurrent; ///< define PANEL_ODD_DATA_CURRENT 1, //MS_U8 m_ucPanelEvenDataCurrent; ///< define PANEL_EVEN_DATA_CURRENT /////////////////////////////////////////////// // panel on/off timing /////////////////////////////////////////////// 30, //MS_U16 m_wPanelOnTiming1; ///< time between panel & data while turn on power 400, //MS_U16 m_wPanelOnTiming2; ///< time between data & back light while turn on power 80, //MS_U16 m_wPanelOffTiming1; ///< time between back light & data while turn off power 30, //MS_U16 m_wPanelOffTiming2; ///< time between data & panel while turn off power /////////////////////////////////////////////// // panel timing spec. /////////////////////////////////////////////// // sync related 10, //MS_U8 m_ucPanelHSyncWidth; ///< VOP_01[7:0], PANEL_HSYNC_WIDTH 50, //MS_U8 m_ucPanelHSyncBackPorch; ///< PANEL_HSYNC_BACK_PORCH, no register setting, provide value for query only ///< not support Manuel VSync Start/End now ///< VOP_02[10:0] VSync start = Vtt - VBackPorch - VSyncWidth ///< VOP_03[10:0] VSync end = Vtt - VBackPorch 2, //MS_U8 m_ucPanelVSyncWidth; ///< define PANEL_VSYNC_WIDTH 11, //MS_U8 m_ucPanelVBackPorch; ///< define PANEL_VSYNC_BACK_PORCH // DE related 60, //MS_U16 m_wPanelHStart; ///< VOP_04[11:0], PANEL_HSTART, DE H Start (PANEL_HSYNC_WIDTH + PANEL_HSYNC_BACK_PORCH) 13, //MS_U16 m_wPanelVStart; ///< VOP_06[11:0], PANEL_VSTART, DE V Start 480, //MS_U16 m_wPanelWidth; ///< PANEL_WIDTH, DE width (VOP_05[11:0] = HEnd = HStart + Width - 1) 480, //MS_U16 m_wPanelHeight; ///< PANEL_HEIGHT, DE height (VOP_07[11:0], = Vend = VStart + Height - 1) // DClk related 610, //MS_U16 m_wPanelMaxHTotal; ///< PANEL_MAX_HTOTAL. Reserved for future using. 610, //MS_U16 m_wPanelHTotal; ///< VOP_0C[11:0], PANEL_HTOTAL 610, //MS_U16 m_wPanelMinHTotal; ///< PANEL_MIN_HTOTAL. Reserved for future using. 496, //MS_U16 m_wPanelMaxVTotal; ///< PANEL_MAX_VTOTAL. Reserved for future using. 496, //MS_U16 m_wPanelVTotal; ///< VOP_0D[11:0], PANEL_VTOTAL 496, //MS_U16 m_wPanelMinVTotal; ///< PANEL_MIN_VTOTAL. Reserved for future using. 27, //MS_U8 m_dwPanelMaxDCLK; ///< PANEL_MAX_DCLK. Reserved for future using. 24, //MS_U8 m_dwPanelDCLK; ///< LPLL_0F[23:0], PANEL_DCLK ,{0x3100_10[7:0], 0x3100_0F[15:0]} 4, //MS_U8 m_dwPanelMinDCLK; ///< PANEL_MIN_DCLK. Reserved for future using. ///< spread spectrum 25, //MS_U16 m_wSpreadSpectrumStep; ///< move to board define, no use now. 192, //MS_U16 m_wSpreadSpectrumSpan; ///< move to board define, no use now. 160, //MS_U8 m_ucDimmingCtl; ///< Initial Dimming Value 257, //MS_U8 m_ucMaxPWMVal; ///< Max Dimming Value 80, //MS_U8 m_ucMinPWMVal; ///< Min Dimming Value 0, //MS_U8 m_bPanelDeinterMode :1; ///< define PANEL_DEINTER_MODE, no use now E_MI_PNL_ASPECT_RATIO_WIDE, //MHAL_DISP_PnlAspectRatio_e m_ucPanelAspectRatio; ///< Panel Aspect Ratio, provide information to upper layer application for aspect ratio setting. /* * * Board related params * * If a board ( like BD_MST064C_D01A_S ) swap LVDS TX polarity * : This polarity swap value = * (LVDS_PN_SWAP_H<<8) | LVDS_PN_SWAP_L from board define, * Otherwise * : The value shall set to 0. */ 0, //MS_U16 m_u16LVDSTxSwapValue; E_MI_PNL_TI_8BIT_MODE, //MHAL_DISP_ApiPnlTiBitMode_e m_ucTiBitMode; ///< MOD_4B[1:0], refer to "LVDS output app note" E_MI_PNL_OUTPUT_8BIT_MODE, //MHAL_DISP_ApiPnlOutPutFormatBitMode_e m_ucOutputFormatBitMode; 3, //MS_U8 m_bPanelSwapOdd_RG :1; ///< define PANEL_SWAP_ODD_RG 2, //MS_U8 m_bPanelSwapEven_RG :1; ///< define PANEL_SWAP_EVEN_RG 1, //MS_U8 m_bPanelSwapOdd_GB :1; ///< define PANEL_SWAP_ODD_GB 0, //MS_U8 m_bPanelSwapEven_GB :1; ///< define PANEL_SWAP_EVEN_GB /** * Others */ 1, //MS_U8 m_bPanelDoubleClk :1; ///< LPLL_03[7], define Double Clock ,LVDS dual mode 0x001c848e, //MS_U32 m_dwPanelMaxSET; ///< define PANEL_MAX_SET 0x0018eb59, //MS_U32 m_dwPanelMinSET; ///< define PANEL_MIN_SET E_MI_PNL_CHG_VTOTAL, //MHAL_DISP_ApiPnlOutTimingMode_e m_ucOutTimingMode; ///<Define which panel output timing change mode is used to change VFreq for same panel 0, //MS_U8 m_bPanelNoiseDith :1; ///< PAFRC mixed with noise dither disable (MI_PANEL_ChannelSwapType_e)0, (MI_PANEL_ChannelSwapType_e)1, (MI_PANEL_ChannelSwapType_e)2, (MI_PANEL_ChannelSwapType_e)3, (MI_PANEL_ChannelSwapType_e)4, }; MI_PANEL_MipiDsiConfig_t stMipiDsiConfig = { };
三、关键点
DE模式下的时序如下:图中可以看到 DE 信号和CLK是高电平有效 ,HS 和VS是低电平有效
因此SPI初始化配置寄存器C3 为 0X0C