硬件SPI控制ST7789V

本文探讨了如何在STM32F411CEU6微控制器上处理ST7789V屏幕的9位SPI协议问题。作者列举了三种方案:1) 使用UART模拟SPI,2) 建立数字逻辑电路,3) 发送两组8位SPI。最终,作者实现了通过发送两组8位SPI数据来模拟9位SPI,并提供了相关代码实现。这种方法虽然存在约40%的性能浪费,但在不增加额外硬件的情况下达到了预期效果。
摘要由CSDN通过智能技术生成


前言

这段时间闲着没事,决定自己做个手表玩玩,参考了一些开源项目和数据手册,决定主控使用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可能的解决方案,实验了其中的一种,效果基本满意,希望能为遇到同样问题的朋友一些帮助。

  • 8
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是使用STM32F103C8T6生成ST7789VW驱动程序的步骤: 1. 首先,需要在STM32CubeIDE中创建一个新的工程,并选择正确的芯片型号。 2. 在工程中添加ST7789VW驱动程序的库文件,并将其包含在主文件中。 3. 在主文件中,需要初始化GPIO引脚和SPI总线,并设置SPI总线的参数,例如时钟速度和数据传输格式等。 4. 接下来,需要编写ST7789VW驱动程序的初始化函数,该函数将设置ST7789VW的各种参数,例如显示分辨率、像素格式、扫描方向等。 5. 然后,需要编写函数来向ST7789VW发送数据和命令。这可以通过SPI总线来实现。 6. 最后,需要编写函数来向ST7789VW发送像素数据,以在显示屏上显示图像。 下面是一个简单的示例代码,用于在STM32F103C8T6上生成ST7789VW驱动程序: ```c #include "stm32f10x.h" #include "st7789.h" int main(void) { // 初始化GPIO引脚和SPI总线 GPIO_InitTypeDef GPIO_InitStruct; SPI_InitTypeDef SPI_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1, ENABLE); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_14; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStruct); SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStruct.SPI_Mode = SPI_Mode_Master; SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB; SPI_Init(SPI1, &SPI_InitStruct); // 初始化ST7789VW驱动程序 ST7789_Init(); // 向ST7789VW发送数据和命令 ST7789_SendCommand(0x11); // 关闭睡眠模式 ST7789_SendCommand(0x29); // 打开显示 // 向ST7789VW发送像素数据 uint16_t pixels[240 * 240]; // 填充像素数据 ST7789_SendPixels(pixels, 240 * 240); while (1) { // 主循环 } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值