[单片机芯片] 【CH32X035评估板测评】第三章 SPI驱动TFT液晶屏

[复制链接]
 楼主| qintian0303 发表于 2023-10-3 18:32 | 显示全部楼层 |阅读模式
本帖最后由 qintian0303 于 2023-10-3 18:32 编辑

      显示单元的驱动:本次测试选用的是1.54寸tft作为显示元件,主要参数是240*240分辨率,主控是7789,通过SPI/8080进行通信,在本次测试使用SPI进行通信,同时驱动部分也是对SPI功能的试用。这里面分别使用IO口模拟及硬件SPI来驱动。
      我们首先用IO口模拟SPI的方式进行屏幕的驱动:
      IO口模拟部分代码如下:
  1. #define SPI1_MASTER                     SPI1
  2. #define SPI1_MASTER_PERIPH              RCC_APB2_PERIPH_SPI1
  3. #define SPI1_MASTER_PERIPH_GPIO         RCC_APB2Periph_GPIOA
  4. #define SPI1_MASTER_GPIO                GPIOA
  5. #define SPI1_MOSI_GPIO_ALTERNATE        GPIO_AF1_SPI1
  6. #define SPI1_CLK_GPIO_ALTERNATE         GPIO_AF2_SPI1
  7. #define SPI1_MASTER_MISO_PIN            GPIO_Pin_6
  8. #define SPI1_MASTER_MOSI_PIN            GPIO_Pin_7
  9. #define SPI1_MASTER_CLK_PIN             GPIO_Pin_5
  10. #define SPI1_MASTER_NSS_PIN             GPIO_Pin_4

  11. #define TFT_BL_GPIO                     GPIOC
  12. #define TFT_BL_PERIPH_GPIO              RCC_APB2Periph_GPIOC
  13. #define TFT_BL_PIN                      GPIO_Pin_7
  14. #define TFT_RS_PIN                      GPIO_Pin_16
  15. #define TFT_RESET_PIN                   GPIO_Pin_17

  16. #define TFT_RS_reset            GPIO_WriteBit(TFT_BL_GPIO, TFT_RS_PIN,Bit_RESET)
  17. #define TFT_RS_set              GPIO_WriteBit(TFT_BL_GPIO, TFT_RS_PIN,Bit_SET)
  18. #define TFT_RESET_reset         GPIO_WriteBit(TFT_BL_GPIO, TFT_RESET_PIN,Bit_RESET)
  19. #define TFT_RESET_set           GPIO_WriteBit(TFT_BL_GPIO, TFT_RESET_PIN,Bit_SET)
  20. #define TFT_BL_SET              GPIO_WriteBit(TFT_BL_GPIO, TFT_BL_PIN,Bit_SET)
  21. #define TFT_BL_RESET            GPIO_WriteBit(TFT_BL_GPIO, TFT_BL_PIN,Bit_RESET)
  22. #define SPI1_CS_OUT0            GPIO_WriteBit(SPI1_MASTER_GPIO, SPI1_MASTER_NSS_PIN,Bit_RESET)
  23. #define SPI1_CS_OUT1            GPIO_WriteBit(SPI1_MASTER_GPIO, SPI1_MASTER_NSS_PIN,Bit_SET)

  24. #define SPI1_MOSI_OUT0          GPIO_WriteBit(SPI1_MASTER_GPIO, SPI1_MASTER_MOSI_PIN,Bit_RESET)
  25. #define SPI1_MOSI_OUT1          GPIO_WriteBit(SPI1_MASTER_GPIO, SPI1_MASTER_MOSI_PIN,Bit_SET)

  26. #define SPI1_CLK_OUT0           GPIO_WriteBit(SPI1_MASTER_GPIO, SPI1_MASTER_CLK_PIN,Bit_RESET)
  27. #define SPI1_CLK_OUT1           GPIO_WriteBit(SPI1_MASTER_GPIO, SPI1_MASTER_CLK_PIN,Bit_SET)

  28. void delay_us(uint32_t Data)
  29. {
  30.     Delay_Us(Data);
  31. }

  32. void delay_ms(uint32_t Data)
  33. {
  34.     Delay_Ms(Data);
  35. }

  36. //******************************************************************************
  37. //* 函数名称  : SPI1_IOInit()                                       
  38. //* 函数描述  : SPI对应的IO口初始化                           
  39. //* 输入参数  :                                                                 
  40. //* 参数描述  :                                                                 
  41. //* 输出参数  : 无                                                              
  42. //* 返回值    : 无                                                               
  43. //******************************************************************************      
  44. void SPI1_IOInit(void)
  45. {

  46.     GPIO_InitTypeDef GPIO_InitStructure = {0};
  47.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC, ENABLE);

  48.     GPIO_InitStructure.GPIO_Pin = SPI1_MASTER_NSS_PIN | SPI1_MASTER_MOSI_PIN | SPI1_MASTER_CLK_PIN;
  49.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  50.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  51.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  52.     GPIO_InitStructure.GPIO_Pin = TFT_BL_PIN |TFT_RS_PIN | TFT_RESET_PIN;
  53.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  54.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  55.     GPIO_Init(GPIOC, &GPIO_InitStructure);

  56.     SPI1_CLK_OUT0;
  57.     SPI1_MOSI_OUT0;
  58.     SPI1_CS_OUT1;
  59.     TFT_RS_reset;
  60.     TFT_RESET_reset;
  61.     TFT_BL_SET;
  62. }

  63. //******************************************************************************
  64. //* 函数名称  : SPI1_Send_Data(uint8_t Data)
  65. //* 函数描述  : SPI1发送8位数据
  66. //* 输入参数  : Data
  67. //* 参数描述  : 具体的指令代码
  68. //* 输出参数  : 无
  69. //* 返回值    : 无
  70. //******************************************************************************  
  71. void SPI1_Send_Data(uint8_t Data)
  72. {
  73.   
  74.     SPI1_CS_OUT0;                                                              //选中该从机
  75.     delay_us(2);

  76.     uint8_t i;
  77.     for (i = 0;i < 8;i++)
  78.     {
  79.         if ((Data << i) & 0x80)
  80.         {
  81.           SPI1_MOSI_OUT1;
  82.           SPI1_CLK_OUT0;//rising edge
  83.           SPI1_CLK_OUT1;
  84.         }
  85.         else
  86.         {
  87.           SPI1_MOSI_OUT0;
  88.           SPI1_CLK_OUT0;//rising edge
  89.           SPI1_CLK_OUT1;
  90.         }
  91.      }
  92.   
  93.     SPI1_CS_OUT1;
  94. }
     屏的驱动初始化程序由于芯片不同而又差异,这里就不做介绍了,只要8位数据时序成功基本上就可以。目前用的到包括SPI的CS/MOSI/CLK对应的也是复用功能的GPIOA的GPIO_Pin_4/GPIO_Pin_7/GPIO_Pin_5,其他控制字引脚就只是普通的IO控制,其中RS为数据/命令引脚(GPIOC-GPIO_Pin_16),复位引脚(GPIOC-GPIO_Pin_17),BL为背光控制引脚(GPIOC-GPIO_Pin_7),效果如下:
IO模拟SPI刷屏.gif
      可以看出来驱动成功了,不过对于240*240分辨率老说,这个刷新速度是不理想的,主要原因还是因为该芯片的主频只有48MHz,接下来我们看看使用硬件SPI的效果。
      然后咱们用硬件SPI体验一下刷屏:
      代码如下:
  1. //******************************************************************************
  2. //* 函数名称  : SPI1_IOInit()                                       
  3. //* 函数描述  : SPI1对应的IO口初始化                           
  4. //* 输入参数  :                                                                 
  5. //* 参数描述  :                                                                 
  6. //* 输出参数  : 无                                                              
  7. //* 返回值    : 无                                                               
  8. //******************************************************************************      
  9. void SPI1_IOInit(void)
  10. {
  11.     GPIO_InitTypeDef GPIO_InitStructure = {0};
  12.     SPI_InitTypeDef  SPI_InitStructure = {0};

  13.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1, ENABLE);

  14.     GPIO_InitStructure.GPIO_Pin = TFT_BL_PIN | TFT_RS_PIN | TFT_RESET_PIN ;
  15.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  16.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  17.     GPIO_Init(GPIOC, &GPIO_InitStructure);

  18.     GPIO_InitStructure.GPIO_Pin = SPI1_MASTER_NSS_PIN;
  19.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  20.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  21.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  22.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
  23.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  24.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  25.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  26.     SPI1_CS_OUT1;
  27.     TFT_RS_reset;
  28.     TFT_RESET_reset;
  29.     TFT_BL_SET;

  30.     SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
  31.     SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  32.     SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  33.     SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
  34.     SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
  35.     SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  36.     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
  37.     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  38.     SPI_InitStructure.SPI_CRCPolynomial = 7;
  39.     SPI_Init(SPI1, &SPI_InitStructure);

  40.     SPI_Cmd(SPI1, ENABLE);
  41.    
  42. }


  43. //******************************************************************************
  44. //* 函数名称  : SPI_Send_Data(uint8_t Data)
  45. //* 函数描述  : SPI发送8位数据
  46. //* 输入参数  : Data
  47. //* 参数描述  : 具体的指令代码
  48. //* 输出参数  : 无
  49. //* 返回值    : 无
  50. //******************************************************************************  
  51. void SPI1_Send_Data(uint8_t Data)
  52. {
  53.   
  54.   SPI1_CS_OUT0;                                                              //选中该从机
  55.   delay_us(1);
  56.   
  57.   SPI_I2S_SendData(SPI1_MASTER, Data);
  58.   while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
  59.   
  60.   delay_us(1);
  61.   SPI1_CS_OUT1;                                                            

  62. }
     看一看效果:
硬件SPI刷屏展示.gif
      对比IO口模拟SPI和硬件SPI的效果,使用硬件SPI刷屏的速度还是有明显的提升的。
      接下来通过SPI功能深度体验了一下MounRiver Studio这个开发环境,感觉还是很喜欢的。
截图.png
      比如Outline显示框,我们在进行对应文件的编写时,这个框里面就会把当前文件的所有头文件,变量,函数等内容集中显示,这样避免咱们总是上下拉文件来找,尤其是文件比较大的时候,查找会很方便;
      添加文件不在需要逐个添加,放到对应的文件夹下,添加一次就会把所有的刷新添加了,有好处也有弊端,好处是便捷,弊端是比如只想添加一个,多个都拉进来了  还得一个一个移除;
      下载和调试是分开的,习惯需要重新建立,下载器去除后并没有对应的报警提示;
      整体来说MounRiver Studio开发环境还是挺简洁实用的。


袁胜富 发表于 2023-10-4 22:43 来自手机 | 显示全部楼层
刷屏好慢,建议使用SPI DMA
 楼主| qintian0303 发表于 2023-10-5 09:26 | 显示全部楼层
袁胜富 发表于 2023-10-4 22:43
刷屏好慢,建议使用SPI DMA

全屏刷新适合用DMA,不过采取局部刷新或者字库DMA就发挥不了太大作用了,依然得一个一个点写,应该会有效果,不过效果不大
Bymyself 发表于 2023-10-5 20:37 | 显示全部楼层
这个主频,刷新速度算可以了,就算提高一倍主频,整屏刷也会看到痕迹
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:硬件工程师
简介:有着多年硬件开发经验的专业人员,专注于医疗电子领域,热衷于对新鲜事物的探索,喜欢DIY!

558

主题

2727

帖子

12

粉丝
快速回复 在线客服 返回列表 返回顶部