stm32cubemx|42-使用dma2d加速显存数据传输(代码片段)

Mculover666 Mculover666     2022-12-05     785

关键词:

一、使用CPU搬运数据到显存

在上一篇文章中讲述了如何配置 LTDC 驱动 RGB 屏幕:STM32CubeMX | 41-使用LTDC驱动TFT-LCD屏幕(RGB屏)

本节中我们接着上一节的实验,讲述如何使用 DMA2D 实现打点、画线、填充等函数,只需要单层全屏即可,修改LTDC层配置如下:

1. 编写lcd驱动头文件

创建lcd_rgb_ltdc_drv.h文件,存放关于操作LCD屏幕的一些宏定义配置和函数定义:

#ifndef _LCD_RGB_LTDC_DRV_H_
#define _LCD_RGB_LTDC_DRV_H_

#include "ltdc.h"

/**
 * @brief   Windows size on lcd.
*/
#define LCD_WIDTH       1024
#define LCD_HEIGHT      600

/**
 * @brief   Backlight control pin of lcd.
*/
#define LCD_BL_GPIO_PORT    GPIOB
#define LCD_BL_GPIO_PIN     GPIO_PIN_5

/**
 * @brief   start address of lcd framebuffer.
*/
#define LCD_FRAME_BUFFER    0xc0000000

/**
 * @brief   color
 * @note    rgb565   
*/
#define BLACK   0x0000
#define BLUE    0x001F
#define GREEN   0x07E0
#define GBLUE   0X07FF
#define GRAY    0X8430
#define BROWN   0XBC40
#define RED     0xF800
#define PINK    0XF81F
#define BRRED   0XFC07
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

/**
 * @brief       Control the lcd backlight.
 * @param[in]   brightness  the value of lcd backlight.
 * @return      None
*/
void lcd_backlight_control(uint8_t bightness);

/**
 * @brief       LCD initialization.
 * @param       None
 * @return      None
*/
void lcd_init(void);

/**
 * @brief       Clear lcd.
 * @param[in]   color   rgb565.
 * @return      None
*/
void lcd_clear(uint16_t color);

#endif /* _LCD_RGB_LTDC_DRV_H_ */

2. lcd驱动实现

创建lcd_rgb_ltdc_drv.c文件,存放关于操作LCD屏幕的函数实现。

首先是背光控制实现,应该使用pwm实现背光调节,本文中为了方便直接使用GPIO控制:

void lcd_backlight_control(uint8_t bightness)

    // todo: use pwm to control backlight

    if (bightness)     
        // turn on the backlight
        HAL_GPIO_WritePin(LCD_BL_GPIO_PORT, LCD_BL_GPIO_PIN, GPIO_PIN_SET);
     else             
        // turn off the backlight
        HAL_GPIO_WritePin(LCD_BL_GPIO_PORT, LCD_BL_GPIO_PIN, GPIO_PIN_RESET);
    

接着实现lcd清屏函数,使用CPU(循环)搬运数据到显存中

void lcd_clear(uint16_t color)

    uint16_t *ptr = (uint16_t*)LCD_FRAME_BUFFER;
    uint32_t i = 0;

    while (i++ < LCD_WIDTH*LCD_HEIGHT) 
        *(ptr+i) = color;
    

最后实现lcd初始化函数,先刷显存,然后开背光,防止设备上电时屏幕闪烁:

void lcd_init()

    lcd_clear(BLACK);
    lcd_backlight_control(255);

3. lcd单次清屏时间测试

在main.c中包含驱动头文件:

#include "lcd_rgb_ltdc_drv.h"

在main函数中的sdram初始化函数之后,添加lcd初始化函数,并使用HAL库自带的systick时间戳测量一次清屏的时间:

/* USER CODE BEGIN 2 */
printf("sdram test by mculover666\\r\\n");
SDRAM_Init();
printf("sdram init success\\r\\n");

lcd_init();

start_time = HAL_GetTick();
lcd_clear(PINK);
end_time = HAL_GetTick();

printf("lcd clear spend time:%ld ms\\r\\n", end_time - start_time);
/* USER CODE END 2 */

编译、运行,在串口助手可以看到使用CPU搬运数据到显存中,在-Og优化等级下单次清屏需要 155 ms左右,在-O0优化等级下单次清屏需要321ms左右:

二、使用DMA2D加速显存数据搬运

1. DMA2D

在STM32中,DMA2D外设专门用来给LCD显示加速,有LTDC外设的型号中,通常也会配套有DMA2D。

DMA2D外设主要提供了两个功能:

  • DMA数据搬运:支持从寄存器到存储器、存储器到存储器两种模式,快速高效,并且不占用cpu资源
  • 2D图形加速:支持快速格式转换和混合;

本文中主要使用到DMA2D外设的数据搬运功能,使用起来也是比较简单。

2. 开启DMA2D


重新生成工程,cubemx会自动生成并调用dma2d初始化函数,完成dma2d外设时钟使能以及dma2d传输模式配置。

3. 使用DMA2D实现lcd清屏函数

在lcd驱动头文件中添加一个宏定义,用于控制是否使能DMA2D:

/**
 * @brief   whether use dma2d to transfer data to lcd framebuffer.
*/
#define USE_DMA2D_EN        1

接着对DMA2D传输操作进行封装,编写一个DMA2D传输函数:

static void dma2d_transfer_data_r2m(uint32_t *addr, uint32_t xSize, uint32_t ySize, uint32_t offsetLine, uint16_t color)

    DMA2D->CR = DMA2D_R2M;   // dma2d mode: register to memory.
    DMA2D->OPFCCR = DMA2D_OUTPUT_RGB565;

    DMA2D->OCOLR = color;
    DMA2D->OMAR = (uint32_t)addr;
    DMA2D->OOR = offsetLine;
    DMA2D->NLR = (uint32_t)(xSize << 16) | (uint16_t)ySize;
    
    DMA2D->CR |= DMA2D_CR_START;
    while (DMA2D->CR & DMA2D_CR_START);

利用此DMA2D传输函数,重新添加清屏函数的实现:

void lcd_clear(uint16_t color)

#if USE_DMA2D_EN
    dma2d_transfer_data_r2m((uint32_t *)LCD_FRAME_BUFFER, LCD_WIDTH, LCD_HEIGHT, 0, color);
#else
    uint16_t *ptr = (uint16_t*)LCD_FRAME_BUFFER;
    uint32_t i = 0;

    while (i++ < LCD_WIDTH*LCD_HEIGHT) 
        *(ptr+i) = color;
    
#endif /* USE_DMA2D_EN */

上层测试代码不变,确保控制dma2d的宏使能:

#define USE_DMA2D_EN        1

编译、下载,在串口助手中查看清屏一次所需时间:

可以看到,刷屏一次只需31ms即可,并且在使用dma2d传输数据的情况下,数据传输时间和编译优化等级无关

三、LCD基本功能实现

LCD基本功能包括打点、读点、画线、绘图等函数。

1. 打点函数

打点函数的核心是计算当前用户给出的坐标位置在显存中的位置,两种实现如下:

void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color)

    uint32_t pos;
    uint16_t *ptr;

    // check position.
    if (x > LCD_WIDTH || y > LCD_HEIGHT) 
        return;
    

    // calculate the position offset in framebuffer.
    pos = x + y*LCD_WIDTH;
    ptr = (uint16_t*)LCD_FRAME_BUFFER;

    // modify the framebuffer.
#if USE_DMA2D_EN
    dma2d_transfer_data_r2m((uint32_t *)(ptr+pos), 1, 1, 0, color);
#else
    *(ptr+pos) = color;
#endif /* USE_DMA2D_EN */

2. 读点函数实现

读点函数实现的核心也是计算出用户给出的坐标位置在显存中的位置:

uint16_t lcd_read_point(uint16_t x, uint16_t y)

    uint32_t pos;
    uint16_t *ptr, data;

    // check position.
    if (x > LCD_WIDTH || y > LCD_HEIGHT) 
        return 0;
    

    // calculate the position offset in framebuffer.
    pos = x + y*LCD_WIDTH;
    ptr = (uint16_t*)LCD_FRAME_BUFFER;

    // read the framebuffer.
    data = *(ptr+pos);

    return data;

3. 画线、画矩形、画圆

这三个功能都是基于打点函数,使用 Bresenham 算法,代码篇幅过多,如有兴趣可直接查看本篇源码。

4. 测试

在main函数中添加测试代码:

lcd_draw_line(0, 0, 1024, 600, GREEN);
lcd_draw_line(0, 300, 1024, 300, RED);
lcd_draw_line(512, 0, 512, 600, BLUE);
lcd_draw_line(1024, 0, 0, 600, YELLOW);

lcd_draw_rect(256, 150, 1024-256, 600-150, PINK);

编译,下载,结果如下图:

stm32cubemx学习笔记(42)——eth接口+lwip协议栈使用(静态ip)(代码片段)

一、ETH简介STM32F4xx系列控制器内部集成了一个以太网外设,它实际是一个通过DMA控制器进行介质访问控制(MAC),它的功能就是实现MAC层的任务。借助以太网外设,STM32F4xx控制器可以通过ETH外设按照IEEE802.3-2002标准发送... 查看详情

使用stm32cubemx生成stm32工程(代码片段)

使用STM32CubeMX生成STM32工程引言介绍使用流程引言随着技术发展的越来越成熟,单片机开发已经出现越来越多好用的开发软件了。STM32CubeMX是一种图形工具,通过分步过程可以非常轻松地配置STM32微控制器和微处理生成相应... 查看详情

在 Atollic TrueStudio、STM32CubeMX 中导入 C 库

】在AtollicTrueStudio、STM32CubeMX中导入C库【英文标题】:ImportCLibraryinAtollicTrueStudio,STM32CubeMX【发布时间】:2019-05-0412:42:45【问题描述】:我目前正在开发一块STM32F767ZI-Nucleo板和一个小安全芯片(微芯片atecc508a),通过i2c连接。对于... 查看详情

stm32+lwip:使用stm32cubemx生成项目(代码片段)

系列文章:stm32+lwip(一):使用STM32CubeMX生成项目stm32+lwip(二):UDP测试stm32+lwip(三):TCP测试stm32+lwip(四):网页服务器测试stm32+lwip(五):以太网帧发送测试 STM32CubeMX是一个图形化的配置工具,根据用户配置可以生成相应的代码,可以帮助... 查看详情

stm32cubemx安装与使用

STM32CubeMX安装与使用1.1JRE安装​STM32CubeMX软件是基于JAVA环境运行的,所以需要安装JRE(JavaRuntimeEnvironment)才能使用。首先在官网上下载安装包https://www.java.com/en/download/manual.jsp然后点击进入安装界面,根据个人选择... 查看详情

STM32 CubeMX 自定义代码生成

】STM32CubeMX自定义代码生成【英文标题】:STM32CubeMXcustomcodegeneration【发布时间】:2016-10-0309:08:04【问题描述】:我正在使用STM32CubeMX并尝试使用generatemycustomcode(UM1718第141页)使用过的周边产品表。使用外围句柄和实例按预期用... 查看详情

stm32cubemx使用注意:

一注意堆栈大小,简单来说,栈空间用于局部变量空间(size=0x400一般够用),堆(size=0x200一般够用)空间用于alloc或者malloc函数动态申请变量空间  查看详情

使用stm32cubemx创建freertos项目(代码片段)

使用STM32CubeMX创建FreeRTOS项目介绍STM32CubeMXFreeRTOS使用流程后续介绍STM32CubeMXSTM32CubeMX是被广泛使用的。它集成了芯片选型、引脚分配和功能配置,中间件配置,时钟配置,初始代码和项目的功能。FreeRTOSFreeRTOS是与世界... 查看详情

使用stm32cubemx创建freertos项目(代码片段)

使用STM32CubeMX创建FreeRTOS项目介绍STM32CubeMXFreeRTOS使用流程后续介绍STM32CubeMXSTM32CubeMX是被广泛使用的。它集成了芯片选型、引脚分配和功能配置,中间件配置,时钟配置,初始代码和项目的功能。FreeRTOSFreeRTOS是与世界... 查看详情

STM32 cubeMX:使用中断触发SPI DMA中断

】STM32cubeMX:使用中断触发SPIDMA中断【英文标题】:STM32cubeMX:triggeringSPIDMAinterruptusinginterrupt【发布时间】:2019-05-2816:52:33【问题描述】:我目前正在练习使用SPI+DMA将数据发送到SPI显示器。显示的数据顺序如下:[pullCSlow]->[pullD/C... 查看详情

stm32f4hal库开发--stm32cubemx

一、STM32CubeMX简介STM32CubeMX是ST意法半导体近几年来大力推荐的STM32芯片图形化配置工具,允许用户使用图形化向导生成C初始化代码,可以大大减轻开发工作,时间和费用。STM32CubeMX几乎覆盖了STM32全系列芯片。它具有... 查看详情

STM32CubeMx:是不是可以使用 SPL(标准外设库)配置 ST 控制器

】STM32CubeMx:是不是可以使用SPL(标准外设库)配置ST控制器【英文标题】:STM32CubeMx:IsitpossibletoconfigureSTcontrollersusingSPL(StandardPeripheralLibrary)STM32CubeMx:是否可以使用SPL(标准外设库)配置ST控制器【发布时间】:2018-07-1012:46:58【... 查看详情

stm32cubemx介绍及安装

STM32CubeMX介绍及安装介绍STM32CubeMX下载安装下载安装安装HAL库后续介绍STM32CubeMX是被广泛使用的。它集成了芯片选型、引脚分配和功能配置,中间件配置,时钟配置,初始代码和项目的功能。其中STM32CubeMX和STM32Cubeprogram... 查看详情

stm32cubemx介绍及安装

STM32CubeMX介绍及安装介绍STM32CubeMX下载安装下载安装安装HAL库后续介绍STM32CubeMX是被广泛使用的。它集成了芯片选型、引脚分配和功能配置,中间件配置,时钟配置,初始代码和项目的功能。其中STM32CubeMX和STM32Cubeprogram... 查看详情

stm32cubemx软件包的制作---stm32packcreator的使用

...l中!),那么本节开始就来介绍如何使用STM32CubeMX制作软件包。STM32CubeMX是ST公司推出了专门用于生成STM32的HAL代码的代码生成软件& 查看详情

如何在 CubeMX STM32 中使用 LL(低级)驱动程序?

】如何在CubeMXSTM32中使用LL(低级)驱动程序?【英文标题】:HowtouseLL(lowlevel)driversinCubeMXSTM32?【发布时间】:2018-06-0622:57:26【问题描述】:我正在使用STM32CubeMX为STM32F103微控制器创建一个空白项目。使用HAL驱动程序(默认),我... 查看详情

STM32F103 GPIO 端口

...2002:42:43【问题描述】:我有一个STM32F103C8MCU,我想在没有CubeMX的情况下控制GPIO寄存器。MCU有一个嵌入式LED,我想控制它。我目前正在使用CubeMX和IAR软件,我使用以下代码将引脚作为输出(在CubeMX中):HAL_GPIO_TogglePin(Ld2_GPIO_Port,Ld... 查看详情

stm32cubemx软件工程描述_usart配置过程

Ⅰ、写在前面学习本文之前可以查看我前面的文章:STM32CubeMX介绍、下载与安装STM32CubeMX使用方法及功能介绍STM32CubeMX新建工程+基本IO配置过程 本文接着前面STM32CubeMX文章结合USART实例,讲述关于STM32CubeMX新建USART工程,以及新... 查看详情