硬件SPI控制ST7789V

文章目录

  • 前言
  • 一、能用的方法有那些?
    • 1.利用硬件UART模拟SPI,实现9位数据发送
    • 2.搭建一个数字逻辑电路,人为实现9位spi发送
    • 3.发送两组8位SPI
  • 二、具体操作
    • 1.具体实现
  • 总结


前言

这段时间闲着没事,决定自己做个手表玩玩,参考了一些开源项目和数据手册,决定主控使用STM32F411CEU6,屏幕选用了淘宝一家商家的ST7789V主控的240*240分辨率的圆形tft屏幕。利用商家给的软件spi例程成功将屏幕点亮之后,尝试使用改为硬件spi的方式,加快屏幕的刷新速度但是尝试了多种方案后始终无法点亮,后来查看了例程和ST7789V的数据手册才发现。和一般的屏幕不一样,ST7789V使用了9位spi的格式,通过第一位的0和1代表了当前发送的是命令还是数据。而STM32F411CE只能使用8或者16位SPI。而软件SPI的速度过慢,因此开始了相关的研究,有了本文。

一、能用的方法有那些?

发现这一问题后,通过上网查询资料以及和学长进行讨论等途径,大致确定了一下三种方案

1.利用硬件UART模拟SPI,实现9位数据发送

这一思路的来源是一篇博客,连接如下:https://www.cnblogs.com/libra13179/p/7064321.html
博主是利用了UART的同步模式和SPI协议时序图非常相似这一特点,实现了9位SPI数据的发送,这种方法可以通过调节波特率的方法实现SPI发送速度的调节。配合DMA的话应该可以达到一个比较理想的速度。

2.搭建一个数字逻辑电路,人为实现9位spi发送

光看名字大家可能有点没理解什么意思,因此给大家做个详细的说明,一般的屏幕都会采用5线spi的方案,简单来说就是MOSI(数据线) 、RES(清屏线)、CS(片选信号线)、W/R(读/写控制线)、RS(数据/命令控制线)(不同的屏幕叫法不一样,但大致都有着五种)其中可以通过控制RS线的高低来控制当前spi总线发送的8位数据是命令还是数据。所以我们可以通过搭建数字电路的方式,将一根信号线的高低,人为的模拟成9位SPI数据中的第一位,控制之后的8个数据位的含义位数据还是命令。后面8位数据使用标准硬件SPI发送模式。配合DMA,应该还是可以获得一个比较不错的效果。至于数字逻辑电路,我觉得理论上一个与门应该就可以实现。

3.发送两组8位SPI

这个思路的来源是在扒论坛的时候找到的,9位SPI这种奇奇怪怪的协议相信屏幕驱动公司自己也知道没有多少MCU支持,所以也针对这一问题进行了适配。我们可以在CS不断开的情况下连续发送两组8位的SPI 数据,后面的7位SPI数据不用管,只要前9位SPI数据是严格按照屏幕驱动IC的数据进行发送数据即可。总的来说,这种方法是本文讨论的3种方法种最简单的一个了,不需要任何多余的硬件电路,也不需要占用其他外设进行模拟。但缺点也很明显,16位数据种有7位数据为无用位,有大约40%的性能浪费。

二、具体操作

1.具体实现

上文中讨论了3种理论上可行的方案,由于时间有限,这里我测试了最后一种方案,其他两种方案等日后进行测试再发文章和大家交流。话不多说直接上代码


/**
 * @brief   写命令到LCD
 * @param   cmd —— 需要发送的命令
 * @return  none
 */
void WriteComm(unsigned char i)	  //spec page 46
{
     
		uint16_t com = 0;
		uint8_t com1,com2;
   		LCD_CS(0);
		com = i;
		com = com<<7;
		com1 = (com&0xff00)>>8;
		com2 = (com&0x00ff);		
		SPI_WriteByte(&com1,1);
		SPI_WriteByte(&com2,1);
   		LCD_CS(1);
}


/**
 * @brief   写命令到LCD
 * @param   cmd —— 需要发送的命令
 * @return  none
 */
void WriteData(unsigned char i)
{
     
		uint16_t data = 0;
		uint8_t data1,data2;
   		LCD_CS(0);
		data = i;
		data = data<<7;
		data |= 0x8000; 
		data1 = (data&0xff00)>>8;
		data2 = (data&0x00ff);		
		SPI_WriteByte(&data1,1);
		SPI_WriteByte(&data2,1);
   		LCD_CS(1);
}

代码部分其实比较简单,就是利用c语言的位运算进行了一些计算实现的。我们需要发送的值存储在i这个变量中传入函数,但是i为uchar,只有8位,所以首先需要把i赋值给16位的data/com变量。接着,把data/com左移7位,空出后7位无用数据位。接着如果我们希望表明需要发送的8位是代表数据,需要将spi传输的第一位数据置1,也就有了WriteData()函数的 data|= 0x8000。利用或运算的方式,将第一位置1。

经过测试,这方法配合硬件SPI可以实现ST7789V 9位SPI的控制。同时,由于F411的硬件SPI速度可以达到50M,虽然有40%的性能损失,但总体上还是可以接收的。不过通过示波器测量发现,SPI数据发送的速度虽然很快,大约有50M,但是每一组数据相互之间会相差很多,每组数据的发送频率大约需要400K,这个问题第一点应该是我没有使用DMA进行传输,所以速度相对比较慢,而且我也没有使用SPI的16位传输模式进行传输,同时,由于我目前是测试方案可行性,使用的是HAL库,效率有点低,如果手写寄存器进行改进了之后,应该性能会提升很多。

总结

以上就是今天要讲的内容,本文仅仅简单介绍了SY7789V 9位SPI可能的解决方案,实验了其中的一种,效果基本满意,希望能为遇到同样问题的朋友一些帮助。

你可能感兴趣的:(STM32开发)