快速导航
单片机菜鸟的博客快速索引(快速找到你要的)

如果觉得有用,麻烦点赞收藏,您的支持是博主创作的动力。

1. 前言

【Arduino TFT】 记录使用DMA优化TFT屏帧率-LMLPHP

在上一篇

【Arduino TFT】 记录使用DMA优化TFT屏帧率-LMLPHP
one.h文件内容:

编码有点多,这里不贴出来。

2. 优化前ino代码

#include <TFT_eSPI.h>
#include <SPI.h>
#include <TJpg_Decoder.h>
#include <Arduino.h>
#include "one.h"  //引入gif生成的.h文件

typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
// LCD屏幕相关设置是什么屏幕什么驱动
// 引脚需配置tft_espi库中的 User_Setup.h文件
TFT_eSPI tft = TFT_eSPI();
//动画更新时间记录
int Amimate_reflash_Time = 0;
int Animate_key = -1; //初始化图标显示帧数

//从动图数组里面获取一帧图像数据
void imgAnim(const uint8_t **Animate_value, uint32_t *Animate_size){
    Animate_key++;
    *Animate_value = one[Animate_key];
    *Animate_size = one_size[Animate_key];
    if (Animate_key >= (sizeof(one)/sizeof(one[0])-1))  //gif动图帧数
            Animate_key = -1;
}

// TFT屏幕输出函数
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap){
    if (y >= tft.height())
        return 0;
    tft.pushImage(x, y, w, h, bitmap);
    return 1;
}

void setup(){
    Serial.begin(115200);
    tft.begin();
    tft.invertDisplay(1); //反转所有显示颜色1反转0正常
    tft.setRotation(0);
    tft.fillScreen(0x0000);
    TJpgDec.setJpgScale(1);
    TJpgDec.setSwapBytes(true);
    TJpgDec.setCallback(tft_output);
    tft.fillScreen(TFT_BLACK);
}

void loop(){
    const uint8_t *Animate_value; //指向关键帧的指针
    uint32_t Animate_size;        //指向关键帧大小的指针
    if (millis() - Amimate_reflash_Time > 30){
    Amimate_reflash_Time = millis();
    imgAnim(&Animate_value, &Animate_size);
    TJpgDec.drawJpg(0, 0, Animate_value, Animate_size);
    }
}

3. 优化后ino代码

#include <TFT_eSPI.h>
#include <SPI.h>
#include <TJpg_Decoder.h>
#include <Arduino.h>
#include "one.h"  //引入gif生成的.h文件

typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
// LCD屏幕相关设置是什么屏幕什么驱动
// 引脚需配置tft_espi库中的 User_Setup.h文件
TFT_eSPI tft = TFT_eSPI();
//动画更新时间记录
int Amimate_reflash_Time = 0;
int Animate_key = -1; //初始化图标显示帧数

// DMA 双缓冲模式
// DMA 直接内存搬运技术,使数据不经过cpu,直接从内存搬运到spi的发送的寄存器里面,这样做的好处是减少cpu的负担,而且能大大提升显示屏的刷新速率
uint16_t dmaBuffer1[32 * 32]{};  // Toggle buffer for 32*32 MCU block, 1024bytes
uint16_t dmaBuffer2[32 * 32]{};  // Toggle buffer for 32*32 MCU block, 1024bytes
uint16_t *dmaBufferPtr = dmaBuffer1;
// 当前使用的DMA缓冲
bool dmaBufferSel = 0;

//从动图数组里面获取一帧图像数据
void imgAnim(const uint8_t **Animate_value, uint32_t *Animate_size){
    Animate_key++;
    *Animate_value = one[Animate_key];
    *Animate_size = one_size[Animate_key];
    if (Animate_key >= (sizeof(one)/sizeof(one[0])-1))  //gif动图帧数
            Animate_key = -1;
}

// TFT屏幕输出函数
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t *bitmap){
    if (y >= tft.height())
        return 0;
    if (dmaBufferSel) {
        dmaBufferPtr = dmaBuffer2;
    } else {
        dmaBufferPtr = dmaBuffer1;
    }
    dmaBufferSel = !dmaBufferSel;
    tft.pushImageDMA(x, y, w, h, bitmap, dmaBufferPtr);
    return 1;
}

void setup(){
    Serial.begin(115200);
    tft.begin();
    tft.invertDisplay(1); //反转所有显示颜色1反转0正常
    tft.setRotation(0);
    tft.initDMA();
    tft.fillScreen(0x0000);
    TJpgDec.setJpgScale(1);
    TJpgDec.setSwapBytes(true);
    TJpgDec.setCallback(tft_output);
    tft.fillScreen(TFT_BLACK);
}

void loop(){
    const uint8_t *Animate_value; //指向关键帧的指针
    uint32_t Animate_size;        //指向关键帧大小的指针
    if (millis() - Amimate_reflash_Time > 30){
    Amimate_reflash_Time = millis();
    imgAnim(&Animate_value, &Animate_size);
    // 必须先使用startWrite,以便TFT芯片选择保持低的DMA和SPI通道设置保持配置
    tft.startWrite();
    // 在左上角的0,0处绘制图像——在这个草图中,DMA请求在回调tft_output()中处理
    TJpgDec.drawJpg(0, 0, Animate_value, Animate_size);
    // 必须使用endWrite来释放TFT芯片选择和释放SPI通道
    tft.endWrite();
    }
}
10-18 13:00