嵌入式学习--work11 关于SPI的深入学习及软件模拟SPI(LCD调试所遇)

来源:互联网 发布:不喝牛奶 知乎 编辑:程序博客网 时间:2024/05/16 11:33

在调试液晶LCD时,需要向LCD驱动通过硬件SPI发送9bits遇到的问题:
LCD是某清洋实业公司生产,在其液晶显示模块规格书里,
1、描述了尺寸为 1.22 inch,接口类型为 SPI 3Line2Lane Interface,SPI为三线两通道的SPI,液晶驱动IC是ST7789(Sitronix公司生产的)。
引脚如图所示:
ss
LCD厂家的时序图如下:
这里写图片描述
可以看出都是往SDA,输入数据,并且发送的数据位在9位!
2、我
们从LCD的驱动ST7789里找到关于 3-LIne的SPI时序图如下:三线SPI
这里写图片描述
关于三线SPI,就是只使用了SDA、SCK、CS三根线,SDA可以作为输入与输出引脚,在LCD的驱动里,我们只需要作为输出就行,所以可以设置为MOSI。这里说明以下,原以为SPI协议是只能作为全双工通信,其实不然,它也可以作为半双工通信方式,具体可以参考:《STM32F4xx中文参考手册》里关于SPI的说明,可以设置的。
小技巧,如果你不想去设置成半双工的通信方式,而驱动又没有用到MISO引脚,你可以选择直接配置成全双工,只是MISO直接不连就行了。
引脚如下:三线SPI与四线SPI的区别是DCX位四线的模式是另外设置一根引脚的,而三线模式下,DCX位它是SPI发送出去的。正因如此,它可以节省一个引脚,可它也给某些驱动带来了弊端。
这里写图片描述
唔觉得这里的引脚图有问题,我改过来了,这样子看引脚与时序图才是搭在一起的,下面的英文解释也印证了我的观点,:
这里写图片描述
这里写图片描述
这里写图片描述

这里我们先确定一些可以确定的东西,首先是时钟线起始为低,然后上升沿有效,因而,SPI的CPOL 与 CPHA 都应设为0,CPOL = 0,CPHA =0;并且,在配置SCK引脚时可以不上拉,及就设为NOPULL,GPIO_InitStructure.Pull = GPIO_NOPULL;如果CPOL与CPHA设置为1了,那么SCK引脚就要上拉,因为时序要求起始位为高电平状态。
下面我们看下引脚:
可以确定:PB5(MOSI)-SDA、PB3(SCK)-SCL、PA15(NSS)-CS。注意看上面的AF是06还是05。
这里写图片描述
其他引脚可以不使用。

/————以下—————分割线————-结论————/

主要的原因是之前的代码里,有人用软件模拟了一个SPI协议,代码如下,现在想直接调用库函数的方式来实现SPI。STM32F0系列有的可以设置8bits至16bits之间的任意位数,因而可以,可我使用的F411不可以,只能设置为8bits或者16bits,那么怎么办》?
方法1可以是,在每次write_command()或者write_data()时,改变GPIO的模式,改为通用IO口模式,然后往里面输入1/0,然后再改回复用SPI模式。可这样的操作太冗余,每次都在初始化与消除初始化,在我看来还不如直接用软件模拟SPI通信呢。
方法2,设置为16位输出,这个我不确定可以不可以,驱动是辨别9bits,我们通过SPI发送16位进去,怎么截取是个问题,还得将所有命令修改格式,也挺麻烦的。

void write_command(uint8_t addr) {  LCD_CS_High();  LCD_CS_Low();                   //片选拉低有效  LCD_SCLK_Low();                 //时钟线拉低  LCD_WR_Low();                   //D/C位拉低,写命令  LCD_SCLK_High();                //时钟线拉高  uint8_t i=0;  for(i=0;i<8;i++)                //模拟时钟的上升沿    {     LCD_SCLK_Low();              //时钟线拉低      if (addr&0x80)       {         //数为1则拉高          LCD_WR_High();          //拆分为8位,每一位依次做与运算        }         //数为0则拉低      else         {          LCD_WR_Low();           //WR拉低         }      addr=addr<<1;      //时钟拉高      LCD_SCLK_High();    }  LCD_CS_High();}void write_data(uint8_t data) {  LCD_CS_Low();  LCD_SCLK_Low();   LCD_WR_High();                       //D/C位(WR)拉 低高,写数据        LCD_SCLK_High();  uint8_t i=0;  for(i=0;i<8;i++)  {      LCD_SCLK_Low();      if (data & 0x80)        {        LCD_WR_High();        }      else        {        LCD_WR_Low();        }    data=data<<1;    LCD_SCLK_High();    }  LCD_CS_High();}
0 0
原创粉丝点击