【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结

目录

  • SPI版
    • OLED SPI 端口定义
      • 七针OLED引脚定义
      • 六针OLED引脚定义
    • 软件SPI
    • 硬件SPI
      • 启用DMA
        • 帧率测试
  • I2C 版
    • 软件I2C
    • 硬件I2C
      • DMA

STM32F103VET6
STM32 Cube IDE


SPI版

OLED SPI 端口定义

本节引自STM32驱动0.96寸OLED液晶屏(12864液晶屏) —— 小牧同学
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第1张图片
两种屏幕的引脚数不一样,左边的有7个引脚,而右边的只有6个。其次,端口的标号也不完全一样,第一个分别标为GND,VCC,D0,D1,RES,DC和CS第二个分别标为GND,VCC,SCL,SDA,RST,D/C。

七针OLED引脚定义

GND — 接地端口
VCC — 接3.3V电源端口
D0 — CLK时钟信号(等同于上面的SCL)
D1 — 数据端口(等同于上面的SDA)
RES — 复位端口(等同于上面的RST)
DC — 数据/命令选择引脚(等同于上面的D/C)
CS — 片选引脚(低电平有效,也就是所需要接低电平,我实际试验过不接该引脚也是可以正常使用的)

六针OLED引脚定义

GND — 接地端口
VCC — 接3.3V电源端口
SCL — CLK时钟信号端口
SDA — MOSI数据端口
RST — 复位端口
D/C — 数据/命令选择引脚

软件SPI

       指令解读见【51单片机快速入门指南】4.2: SSD1306 OLED屏(0.96寸、1.3寸)的I2C控制详解

       各引脚初始化如下,均为推挽输出:
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第2张图片
       从【51单片机快速入门指南】5:软件SPI获取软件SPI程序。

修改控制电平的函数:

    GPIOx->BSRR = GPIO_Pin;

    GPIOx->BSRR = (uint32_t)GPIO_Pin << 16u;

由于我们需要的只是单向的、半双工的SPI,只需修改部分函数即可
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第3张图片

       从SPI驱动0.96/1.3寸 OLED屏幕,易修改为DMA控制获取SPI版驱动程序。
将51特色的code改为const
在这里插入图片描述
修改对应引脚
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第4张图片
修改延时函数
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第5张图片
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第6张图片
在主函数中添加测试程序:
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第7张图片
如图,屏幕已轻松点亮。
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第8张图片
帧率为180(见后文)
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第9张图片
使用虚拟显存是时为46帧
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第10张图片

硬件SPI

如图,使用硬件SPI
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第11张图片
移除软件SPI的程序,修改OLED_WR_Byte函数
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第12张图片

extern SPI_HandleTypeDef hspi1;
void OLED_WR_Byte(uint8_t dat, uint8_t cmd)
{
    OLED_CS_L();
    if (cmd)
        OLED_DC_H();
    else
        OLED_DC_L();
//    SOFT_SPI_RW_MODE2(dat);
    HAL_SPI_Transmit(&hspi1, &dat, 1, 10);
    OLED_DC_H();
    OLED_CS_H();
}

再次测试:
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第13张图片
成功点亮
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第14张图片
帧率为410
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第15张图片

在oled.h中启用虚拟显存
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第16张图片
修改OLED_Refresh_Gram函数,实现1024 Byte 显存连续写入
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第17张图片

extern SPI_HandleTypeDef hspi1;
void OLED_Refresh_Gram(void)
{
#if OLED_BUFFER_MODE
//    uint16_t i;
    OLED_Set_Pos(0, 128);
//    for (i = 0; i < Max_Row / 8 * Max_Column; i++)
//    {
//        OLED_WR_Byte(OLED_GRAM[0][i], OLED_DATA);
//    }
    OLED_CS_L();
    OLED_DC_H();
    HAL_SPI_Transmit(&hspi1, OLED_GRAM[0], Max_Row / 8 * Max_Column, 10);
    OLED_DC_H();
    OLED_CS_H();
#endif
}

再次测试,仍能成功点亮,帧率为969。
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第18张图片

启用DMA

【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第19张图片

再次修改OLED_Refresh_Gram函数

extern SPI_HandleTypeDef hspi1;
void OLED_Refresh_Gram(void)
{
#if OLED_BUFFER_MODE
//    uint16_t i;
    OLED_Set_Pos(0, 128);
//    for (i = 0; i < Max_Row / 8 * Max_Column; i++)
//    {
//        OLED_WR_Byte(OLED_GRAM[0][i], OLED_DATA);
//    }
    OLED_CS_L();
    OLED_DC_H();
//    HAL_SPI_Transmit(&hspi1, OLED_GRAM[0], Max_Row / 8 * Max_Column, 10);
    HAL_SPI_Transmit_DMA(&hspi1, OLED_GRAM[0], Max_Row / 8 * Max_Column);
    while(hspi1.State != HAL_SPI_STATE_READY);
    OLED_DC_H();
    OLED_CS_H();
#endif
}

帧率测试

帧率的显示:
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第20张图片
在1ms中断中统计1s内的帧数
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第21张图片
在每次更新屏幕内容时FPS_Count自加1
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第22张图片
这个帧率已经远远超过屏幕本身所能提供的刷新率了。
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第23张图片

I2C 版

软件I2C

将SCL设为推挽输出,SDA设为开漏上拉输出
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第24张图片

从【51单片机快速入门指南】4.2: SSD1306 OLED屏(0.96寸、1.3寸)的I2C控制详解和【51单片机快速入门指南】4: 软件 I2C获取控制程序。

修改对应引脚,其他部分同SPI的步骤。
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第25张图片

//SCL拉高 移植时需修改
void I2C_SCL_H(void)
{
	OLED_SCL_GPIO_Port->BSRR = OLED_SCL_Pin;
}

//SCL拉低 移植时需修改
void I2C_SCL_L(void)
{
	OLED_SCL_GPIO_Port->BSRR = (uint32_t)OLED_SCL_Pin << 16u;
}

//SDA拉高 移植时需修改
void I2C_SDA_H(void)
{
	OLED_SDA_GPIO_Port->BSRR = OLED_SDA_Pin;
}

//SDA拉低 移植时需修改
void I2C_SDA_L(void)
{
	OLED_SDA_GPIO_Port->BSRR = (uint32_t)OLED_SDA_Pin << 16u;
}

//读取SDA 移植时需修改
uint8_t I2C_SDA_Read(void)
{
	OLED_SDA_GPIO_Port->BSRR = (uint32_t)OLED_SDA_Pin << 16u;
	i2c_delay();
	return ((OLED_SDA_GPIO_Port->IDR & OLED_SDA_Pin) == 0?0:1);
}

测试:
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第26张图片
帧率约为60帧
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第27张图片

硬件I2C

【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第28张图片
修改OLED_WR_Byte函数

extern I2C_HandleTypeDef hi2c1;
void OLED_WR_Byte(uint8_t dat, uint8_t cmd)
{
	if (cmd)
		HAL_I2C_Mem_Write(&hi2c1, OLED_ADDRESS << 1, OLED_WriteData_Addr, I2C_MEMADD_SIZE_8BIT, &dat, 1, 10);
	else
		HAL_I2C_Mem_Write(&hi2c1, OLED_ADDRESS << 1, OLED_WriteCom_Addr, I2C_MEMADD_SIZE_8BIT, &dat, 1, 10);
}

此时帧率为49
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第29张图片
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第30张图片
开虚拟显存模式,修改OLED_Refresh_Gram函数

extern I2C_HandleTypeDef hi2c1;
void OLED_Refresh_Gram(void)
{
#if OLED_BUFFER_MODE
//    uint16_t i;
    OLED_Set_Pos(0, 128);
//    for (i = 0; i < Max_Row / 8 * Max_Column; i++)
//    {
//        OLED_WR_Byte(OLED_GRAM[0][i], OLED_DATA);
//    }
    HAL_I2C_Mem_Write(&hi2c1, OLED_ADDRESS << 1, OLED_WriteData_Addr, I2C_MEMADD_SIZE_8BIT, OLED_GRAM[0], Max_Row / 8 * Max_Column, 1000);
#endif
}

发现会更慢
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第31张图片

DMA

【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第32张图片
开中断
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第33张图片

再次修改OLED_Refresh_Gram函数

extern I2C_HandleTypeDef hi2c1;
void OLED_Refresh_Gram(void)
{
#if OLED_BUFFER_MODE
//    uint16_t i;
    OLED_Set_Pos(0, 128);
//    for (i = 0; i < Max_Row / 8 * Max_Column; i++)
//    {
//        OLED_WR_Byte(OLED_GRAM[0][i], OLED_DATA);
//    }
//    HAL_I2C_Mem_Write(&hi2c1, OLED_ADDRESS << 1, OLED_WriteData_Addr, I2C_MEMADD_SIZE_8BIT, OLED_GRAM[0], Max_Row / 8 * Max_Column, 1000);
    while(hi2c1.State != HAL_I2C_STATE_READY);
    HAL_I2C_Mem_Write_DMA(&hi2c1, OLED_ADDRESS << 1, OLED_WriteData_Addr, I2C_MEMADD_SIZE_8BIT, OLED_GRAM[0], Max_Row / 8 * Max_Column);
#endif
}

如图,瓶颈应为400kHz的I2C速度
【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结_第34张图片

你可能感兴趣的:(屏幕,电赛,stm32,单片机,oled,spi,i2c)