[AT32F423] 【AT-START-F423测评】 + IO口模拟方式,测试SPI-OLED刷新速度

[复制链接]
2300|15
 楼主| suncat0504 发表于 2023-11-7 16:49 | 显示全部楼层 |阅读模式
本帖最后由 suncat0504 于 2023-11-7 18:07 编辑

#申请原创# @21小跑堂
本次使用SPI接口的OLED测试显示刷新速度。依旧使用128*64点阵的OLED,
0f6198143e419dfd8317276a7279e81d
f17f670d131a0268c4b1cf57dc0c6643
接口定义:
828289fec39ea07323218e00133d9ed3 这个OLED的时钟信号要求,SCK时钟最小支持到20ns,完全不用担心和这个开发板的匹配问题。
图片1.png 图片2.png
为了减少接口连接线,CS固定接地。使用4个GPIO口模拟SPI时钟、SPI数据、RESET、DC。感觉如果不是考虑到RESET和DC数据/指令选择,好像和IIC方式也没啥区别了。测试程序使用Work Bench进行重新设计。
使用定时器1溢出中断,用来实现1秒的计时。
使用GPIO的C0、C1、C2、C3模拟通讯口的SCK时钟、SDA(数据)、RESET(复位信号)、DC(数据、指令选择)。CS常态接地,就不用程序控制了。
为了方便观察,注册是刷新图像过程中,加入标试点的显示,以证明刷新在不断进行中。
以下是主程序处理代码:
  1. /* add user code begin Header */
  2. /**
  3.   **************************************************************************
  4.   * [url=home.php?mod=space&uid=288409]@file[/url]     main.c
  5.   * [url=home.php?mod=space&uid=247401]@brief[/url]    main program
  6.   **************************************************************************
  7.   *                       Copyright notice & Disclaimer
  8.   *
  9.   * The software Board Support Package (BSP) that is made available to
  10.   * download from Artery official website is the copyrighted work of Artery.
  11.   * Artery authorizes customers to use, copy, and distribute the BSP
  12.   * software and its related documentation for the purpose of design and
  13.   * development in conjunction with Artery microcontrollers. Use of the
  14.   * software is governed by this copyright notice and the following disclaimer.
  15.   *
  16.   * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
  17.   * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
  18.   * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
  19.   * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
  20.   * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
  21.   * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
  22.   *
  23.   **************************************************************************
  24.   */
  25. /* add user code end Header */

  26. /* Includes ------------------------------------------------------------------*/
  27. #include "at32f423_wk_config.h"
  28. #include "delay.h"
  29. #include "spi_oled.h"
  30. #include "bmp.h"

  31. /* private includes ----------------------------------------------------------*/
  32. /* add user code begin private includes */

  33. /* add user code end private includes */

  34. /* private typedef -----------------------------------------------------------*/
  35. /* add user code begin private typedef */

  36. /* add user code end private typedef */

  37. /* private define ------------------------------------------------------------*/
  38. /* add user code begin private define */

  39. /* add user code end private define */

  40. /* private macro -------------------------------------------------------------*/
  41. /* add user code begin private macro */

  42. /* add user code end private macro */

  43. /* private variables ---------------------------------------------------------*/
  44. /* add user code begin private variables */
  45. uint32_t gi_us=0;           // 微秒计数
  46. uint32_t gi_us_dao=0;       // 微秒倒计时
  47. uint32_t gi_ms_dao=0;       // 微秒倒计时
  48. uint8_t gi_1sflag=0;                // 1秒中断标志
  49. /* add user code end private variables */

  50. /* private function prototypes --------------------------------------------*/
  51. /* add user code begin function prototypes */

  52. /* add user code end function prototypes */

  53. /* private user code ---------------------------------------------------------*/
  54. /* add user code begin 0 */

  55. /* add user code end 0 */


  56. /**
  57.   * [url=home.php?mod=space&uid=247401]@brief[/url]  take some delay for waiting power stable, delay is about 60ms with frequency 8MHz.
  58.   * @param  none
  59.   * @retval none
  60.   */
  61. static void wk_wait_for_power_stable(void)
  62. {
  63.   volatile uint32_t delay = 0;
  64.   for(delay = 0; delay < 50000; delay++);
  65. }

  66. /**
  67.   * [url=home.php?mod=space&uid=247401]@brief[/url] main function.
  68.   * @param  none
  69.   * @retval none
  70.   */
  71. int main(void) {
  72.   /* add user code begin 1 */
  73.   uint32_t cnt = 0, pos=0,dir=0;

  74.   /* add user code end 1 */

  75.   /* add a necessary delay to ensure that Vdd is higher than the operating
  76.      voltage of battery powered domain (2.57V) when the battery powered
  77.      domain is powered on for the first time and being operated. */
  78.   wk_wait_for_power_stable();
  79.   
  80.   /* system clock config. */
  81.   wk_system_clock_config();

  82.   /* config periph clock. */
  83.   wk_periph_clock_config();

  84.   /* nvic config. */
  85.   wk_nvic_config();

  86.   /* init usart1 function. */
  87.   wk_usart1_init();

  88.   /* init gpio function. */
  89.   wk_gpio_config();

  90.   /* init tmr1 function. */
  91.   wk_tmr1_init();

  92.   /* init tmr2 function. */
  93.   //wk_tmr2_init();

  94.   /* add user code begin 2 */
  95.   cnt=0;    // 清除计数次数变量
  96.   SPI_OLED_Init();  // 初始化SPI OLED
  97.   gi_1sflag=0;    // 清除1秒计数标志
  98.   gi_us=0;        // 清除10微秒计数标志
  99.   /* add user code end 2 */
  100.   while(1) {
  101.     /* add user code begin 3 */
  102.           for (int i=0;i<128;i++) {
  103.                   BMP[i]=0;
  104.           }
  105.           // 动态标识标试点,以证明刷新处理进行中
  106.           BMP[pos] = 1;
  107.           // 显示手的图案
  108.           SPI_OLED_DrawBMP(0,0,128,64,BMP);
  109.           cnt++;
  110.           if (dir) {
  111.                   // 反向移动标识点
  112.                   pos--;
  113.                   if (pos==0) {
  114.                           dir=0;
  115.                           pos=1;
  116.                   }
  117.           } else {
  118.                   // 正向移动标识点
  119.                   pos++;
  120.                   if (pos==128) {
  121.                           dir=1;
  122.                           pos=126;
  123.                   }
  124.           }

  125.           // 一秒时间到
  126.           if (gi_1sflag>0) {
  127.                   // 串口输出刷新次数
  128.                   usart_data_transmit(USART1, '=');
  129.                   while ((USART1->sts & 0x80)==0);
  130.                   usart_data_transmit(USART1, (cnt/100)+48);
  131.                   while ((USART1->sts & 0x80)==0);
  132.                   usart_data_transmit(USART1, ((cnt%100)/10)+48);
  133.                   while ((USART1->sts & 0x80)==0);
  134.                   usart_data_transmit(USART1, (cnt%10)+48);
  135.                   while ((USART1->sts & 0x80)==0);
  136.                   usart_data_transmit(USART1, 10);
  137.                   while ((USART1->sts & 0x80)==0);
  138.                   usart_data_transmit(USART1, 13);
  139.                   while ((USART1->sts & 0x80)==0);

  140.                   // 清除中间记录信息和标志
  141.           cnt=0;
  142.                   gi_1sflag = 0;
  143.                   gi_us=0;

  144.           }
  145.     /* add user code end 3 */
  146.   }
  147. }
定时器处理的代码:
  1. void TMR1_OVF_TMR10_IRQHandler(void)
  2. {
  3.   /* add user code begin TMR1_OVF_TMR10_IRQ 0 */
  4.          if(tmr_flag_get(TMR1, TMR_OVF_FLAG) == SET) {
  5.                  gpio_bits_toggle(LED2_GPIO_PORT, LED2_PIN);

  6.                  if (gi_us_dao>0) {
  7.                          gi_us_dao--;
  8.                  }
  9.                  if (gi_ms_dao>0) {
  10.                           gi_ms_dao--;
  11.                  }

  12.                  gi_us++;
  13.                  //gpio_bits_toggle(LED2_GPIO_PORT, LED2_PIN);
  14.                  if (gi_us == 100000) {
  15.                          // 1秒
  16.                          gi_1sflag = 1;
  17.                          gi_us = 0;
  18.                          gpio_bits_toggle(LED4_GPIO_PORT, LED4_PIN);
  19.                  }
  20.                  if (gi_us == 50000) {
  21.                          // 0.5秒
  22.                          gpio_bits_toggle(LED3_GPIO_PORT, LED3_PIN);
  23.                  }

  24.             // 清除溢出标志
  25.             tmr_flag_clear(TMR1, TMR_OVF_FLAG);
  26.         }

实测刷新能力为每秒111帧。这里面如果去掉标试点的处理部分,可以提高到112帧。刷新一页图片的时间在9ms以下。可以看到刷新速度比IIC方式快了近一倍。
8533d6f74485ed832ac553ac759098f1
以下是OLED上的测试结果:
24c9411e2ac6020207fb67091771f470
068313207b854848c95ac3c4e7220451

附上工程: SPIOLED.zip (6.12 MB, 下载次数: 16)



claretttt 发表于 2023-12-3 22:49 | 显示全部楼层
可以通过计时器或者其他方式来测量每次刷新所需的时间。这个时间就是OLED的刷新速度。
51xlf 发表于 2023-12-4 10:20 | 显示全部楼层
SPI速度相较于IIC会快上一些,硬件IIC相较于模拟IIC速度又会快上一些。
geraldbetty 发表于 2023-12-4 15:28 | 显示全部楼层
配置IO口模拟SPI通信              
 楼主| suncat0504 发表于 2023-12-5 08:46 | 显示全部楼层
51xlf 发表于 2023-12-4 10:20
SPI速度相较于IIC会快上一些,硬件IIC相较于模拟IIC速度又会快上一些。

做过IIC硬件外设的通讯处理,感觉挺麻烦的。需要判断中间状态。还是觉得软件模拟来得方便一些。
houjiakai 发表于 2023-12-5 11:58 | 显示全部楼层
在程序中设置正确的SPI模式,以确保数据的正确传输和接收。
i1mcu 发表于 2023-12-5 13:37 | 显示全部楼层
使用合适的SPI缓冲器,以避免出现数据包丢失或错误的情况。
eefas 发表于 2023-12-5 14:40 | 显示全部楼层
可以通过计算每秒刷新的次数来得到OLED的刷新频率
xiaoyaodz 发表于 2023-12-5 16:53 | 显示全部楼层
减少不必要的延时和等待时间,避免在刷新过程中执行其他任务等。
macpherson 发表于 2023-12-5 18:46 | 显示全部楼层
在模拟SPI接口时,可能会产生噪声和干扰,需要注意如何消除这些噪声和干扰
houjiakai 发表于 2023-12-5 20:11 | 显示全部楼层
通常需要通过SPI接口发送一组特定的命令来完成。
 楼主| suncat0504 发表于 2023-12-6 08:40 | 显示全部楼层
macpherson 发表于 2023-12-5 18:46
在模拟SPI接口时,可能会产生噪声和干扰,需要注意如何消除这些噪声和干扰 ...

谢谢提醒
 楼主| suncat0504 发表于 2023-12-6 08:41 | 显示全部楼层
houjiakai 发表于 2023-12-5 20:11
通常需要通过SPI接口发送一组特定的命令来完成。

是,相比IIC操作,SPI还是要好很多
 楼主| suncat0504 发表于 2023-12-6 08:42 | 显示全部楼层
xiaoyaodz 发表于 2023-12-5 16:53
减少不必要的延时和等待时间,避免在刷新过程中执行其他任务等。

其实使用DMA方式传输SPI数据,更方便。也无需分担中央处理器的时间片
jonas222 发表于 2023-12-6 15:48 | 显示全部楼层
测试SPI-OLED刷新速度需要注意以上几个方面。只有正确设置和调整参数,才能确保测试结果的准确性和可靠性。
 楼主| suncat0504 发表于 2023-12-7 00:44 | 显示全部楼层
jonas222 发表于 2023-12-6 15:48
测试SPI-OLED刷新速度需要注意以上几个方面。只有正确设置和调整参数,才能确保测试结果的准确性和可靠性。 ...

谢谢大佬提醒。有时间需要在这方面下下功夫。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:大连伊飞特信息技术有限公司软件工程师
简介:本人于1993年毕业于大连理工大学。毕业后从事单片机开发工作5年,之后转入软件开发工作至今。

158

主题

4507

帖子

6

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