STM32 的图形加速器 DMA2D

1. 背景

​ 在实际使用 LTDC 控制器控制液晶屏时,配置好的显存地址写入要显示的像素数据,LTDC 就会把这些数据从显存中搬运到液晶面板进行显示。实际上要显示的数据量非常的大,我们常常以纯软件的方式填充显存(指定那个位置要显示什么颜色),这样非常影响绘图速度,因此我们希望能用 DMA 来操作,针对这个需求,STM32 专门定制了 DMA2D 外设,它可以用于快速绘制矩形、执行、分层数据混合、数据复制以及进行图像数据格式转换,可以把它理解为图形专用的 DMA。

2. DMA2D 工作模式

  • 寄存器到存储器(此模式通常同于清屏,将寄存器中保存的颜色值搬运到显存中的某个位置,或者整个显存)
  • 存储器到存储器(将内存中的数据搬到显存中)
  • 存储器到存储区并执行像素格式转换
  • 存储器到存储器并执行像素格式转换和混合

3. DMA2D 控制

​ 通过对 DMA2D 控制器寄存(DMA2D_CR)配置 DMA2D 控制器,用户可以执行下列操作:

  • 选择工作模式
  • 使能/禁止 DMA2D 中断
  • 启动/挂起/中止进行中的数据传输

4. DMA2D 前景层 FIFO 和背景层 FIFO

​ DMA2D 前景层(FG) FIFO 和 背景(BG)FIFO 获取要处理的输入数据。这些 FIFO 根据相应像素格式转换器(PFC)中定义的颜色格式获取像素。通过如下一组寄存器对他们进行编程:

  • DMA2D 前景层存储地址寄存器(DMA2D_FGMAR 此寄存器存的是前景层数据地址)

  • DMA2D 前景层偏移寄存器(DMA2D_FGOR )

  • DMA2D 背景层存储地址寄存器(DMA2D_BGMAR )

  • DMA2D 背景层偏移寄存器

    DMA2D 在寄存器到存储器模式下工作时,不激活任何 FIFO。

    DMA2D 在存储器到存储器模式下工作时(没有像素格式转换和混合操作时),仅激活FG FIFO,并将其作用为缓冲区。

    DMA2D 在存储器到存储器模式下工作时并支持像素格式转换时(无混合操作),不会激活
    BG FIFO。

5. DMA2D 工作原理

5.1 register to memory

​ 说了那么多理论,我们看一下实际上 DMA2D 的优势到底在那里。当我们想要在 LCD 显示屏的中间画上几个矩形时,或者清屏时,都是使用的纯软件循环填充framnbuffer 的空间比如:

    for(y = y0; y <= y1; y++){for(x = x0; x <= x1; x++)framebuffer[y][x] = color; }

这样的代码非常耗时,根据两个坐标(x0,y0),(x1,y1) 两个坐标,确定一个平面之后,两层循环填充 frambuffer。当我们清屏时,我们可能想到用 memset 函数去填充 frambuffer,当然这样是明智的选择,也是可行的。但是,如果不想清楚整块 frambuffer(操作 frambuffer 就相当于操作 LCD屏幕了)呢?memset 只适用于连续的地址空间。比如下面这种情况
我只想要蓝色这块区域填充成红色,就不能简单的使用 memset(frambuffer,0xf800, sizeof(frambuffer)) (像素格式RGB565)了吧。因为此块区域地址不连续,因此只能使用上述循环大法,确定左上角坐标,与右下角坐标,循环填充 frambuffer 中的这块地址。

让我们看看 DMA2D 是怎么干的。

首先我们给出这块地址的首地址,也就是红色方块的地址。由于地址不连续,只想画出蓝色区域,因此告诉 DMA2D 填充完成一行后,需要跨过多少个格子才开始画下一行(注意:一个格子对应一个像素点)。比如,蓝色的一行有6个格子,因此需要跨过18、19、20、21 这四个格子之后才开始继续填充。跨越的像素个数有一个简单的计算方式,即一行像素的总个数减去要这一行要显示的像素个数,对应上图为 10 — 6 = 4。

因此画出上面的区域我们可以这样配置 DMA2D:

由于仅仅只是矩形的填充,我们将 DMA2D 配置在 寄存器到存储区模式下

DMA2D->CR   = (0x3UL << 16);

然后,告诉 DMA2D 要填充的frambuffer 地址和填充的矩形区域的宽高

DMA2D->OMAR = (uint32_t)(&frambuffer[x][y]);
DMA2D->NLR = (uint32_t)(width << 16) | (uint16_t)height;

紧接着告诉画一行要跳过多少像素,由输出偏移寄存器控制,用于确定下一行的起始地址

DMA2D->ORR = LCD_PIXEL_WIDTH - Width

然后告诉DMA2D 这块区域需要的颜色以及颜色格式

DMA2D->OCOLR = color
DMA2D->OPFCCR = 0x2;// RGB565

现在可以启动 DMA2D 传输了,只需要将 CR 寄存器的 bit0 置1即可,传输结束时,此位由硬件清0,因此,还可利用此位判断是否传输完成

DMA2D->CR |= 0x1;
while(DMA2D->CR & 0x1);//等待传输完成

将上面代码整理并封装成 api,,由于是最基本的填充函数,因此将会经常调用到,所以我们将设置为内联函数,减少函数调用的开销

static inline void dma2d_fill( void * fb, uint32_t width, uint32_t height, uint32_t lineoffect, uint32_t pixelformat,  uint32_t color) {/* DMA2D配置 */  DMA2D->CR      = 0x00030000UL;    // 配置为寄存器到储存器模式DMA2D->OCOLR   = color;        // 设置填充使用的颜色DMA2D->OMAR    = (uint32_t)fb; // 填充区域的起始内存地址DMA2D->OOR     = lineoffect;  // 行偏移,即跳过的像素(像素为单位)DMA2D->OPFCCR  = pixelformat;  // 设置颜色格式DMA2D->NLR     = (uint32_t)(width << 16) | (uint16_t)height;    // 设置填充区域的宽和高,单位是像素/* 启动传输 */DMA2D->CR   |= DMA2D_CR_START;   /* 等待DMA2D传输完成 */while (DMA2D->CR & DMA2D_CR_START) {}
}/* 填充颜色,此处我的 fb 是uint8类型的,由于采用 RGB565格式存储像素点,因此,一个像素占用两个字节,因此下面地址偏移乘了2* 也可强转位 uint16 然后就不用乘 2 了* w :待填充区域的宽度* h :待填充区域的高度
*/
void fill_rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color){void* distfb = &framebuffer[2*(y*800 + x)];dma2d_fill(distfb, w, h, 800 - w, LTDC_PIXEL_FORMAT_RGB565, color);
}int dma2d_file_rect_test(void)
{fill_rect(0, 0, 800, 480, 0x0000);//清屏fill_rect(300, 80, 20, 280, 0x001f);fill_rect(340, 100, 20, 200, 0x001f);fill_rect(380, 40, 20, 260, 0x001f);fill_rect(420, 60, 20, 240, 0x001f);fill_rect(260, 300, 240, 1, 0x0000);return 0;
}
MSH_CMD_EXPORT(dma2d_file_rect_test,dma2d_file_rect_test);//导出到 shell 命令

运行结果如下:

5.2 memory to memory

DMA2D 还可以工作在 memory to memory 模式下,此模式可用于将图片数据搬运到 fb 中指定的地址中去,因此我们做如下配置

DMA2D->CR = (0 << 16);

然后我们得告诉我的图片放到了内存中的那里,以及要将图片搬到我的那里,因此做如下配置

DMA2D->BGMAR = (uint32_t)srcaddr;
DMA2D->OMAR    = (uint32_t)dstaddr; // 目标地址
DMA2D->FGOR    = offlinesrc;     // 源数据偏移(像素)
DMA2D->OOR     = offlinedst;     // 目标地址偏移(像素)
DMA2D->FGPFCCR = pixelformat;  //颜色格式
DMA2D->NLR     = (uint32_t)(width << 16) | (uint16_t)height;// 图片的宽高

将其封装成 API

static void dma2d_memcopy(uint32_t pixelformat, void * psrc, void * pdst, int width, int height, int offLinesrc, int offLinedst)
{DMA2D->CR      = 0x00000000UL;DMA2D->FGMAR   = (uint32_t)psrc;DMA2D->OMAR    = (uint32_t)pdst;DMA2D->FGOR    = offLinesrc;DMA2D->OOR     = offLinedst;DMA2D->FGPFCCR = pixelformat;DMA2D->NLR     = (uint32_t)(width << 16) | (uint16_t)height;DMA2D->CR   |= DMA2D_CR_START;while (DMA2D->CR & DMA2D_CR_START) {}
}
/** sky_animation_mask1 为原图片地址* _lcd.front_buf 为显存* 原图片地址不偏移* 目的地址偏移
*/
int dma2d_m2m(void)
{dma2d_memcopy(LTDC_PIXEL_FORMAT_RGB565,sky_animation_mask1,_lcd.front_buf,LOGO1_W,LOGO1_H,0,800-LOGO1_W);
}
MSH_CMD_EXPORT(dma2d_m2m,dma2d_m2m);

执行效果如下:

如果想移动图片的位置,可以操作 fb 地址,这里给的目的地址就是 fb 的首地址,也就是左上角。

5.3 memory to mrmory 图片混合

​ 通过将两张图片混合,并且设置图片透明度,可以达到图片渐变的效果,因此需要将 DMA2D 设置在待混合的模式下

DMA2D->CR = (0x2 << 16);

​ 然后设置背景、背景偏移、前景、前景偏移、目的地址

DMA2D->BGMAR = (uint32_t)bgaddr;//背景 src addr
DMA2D->BGOR  = offsetlineBg;// 背景偏移
DMA2D->FGMAR = (uint32_t)ggaddr;// 前景 src addr
DMA2D->FGOR  = offsetlinefg;// 前景偏移
DMA2D->OMAR = dstaddr;// 目的地址
DMA2D->OOR = offlinedist; // 输出偏移,行便宜将添加到行末尾,用于确认下一行的起始地址
DMA2D->NLR     = (uint32_t)(width << 16) | (uint16_t)height;

由于两幅图片需要混合,因此需要设置前景层图片透明度,这里我们需要设置FGPFCCR 寄存器

DMA2D->FGPFCCR = (opa << 24) | (1 << 16) | (pixelformat << 0)// 将第16位置1,强制图片透明度为opa
DMA2D->BGPFCCR = pixelformat; // 设置背景颜色格式
DMA2D->OPFCCR = pixelformat; // 设置输出颜色格式

将面的步骤整理成 api 如下:

void dma2d_mixcolorsbulk(void* pfg, void* pbg, void* pdst,uint32_t offlinefg, uint32_t offlinebg, uint32_t offlinedist,uint16_t width, uint16_t height,uint32_t pixelformat, uint8_t opa) { // opa 透明度DMA2D->CR    = 0x00020000UL;                DMA2D->FGMAR = (uint32_t)pfg;               DMA2D->BGMAR = (uint32_t)pbg;               DMA2D->OMAR  = (uint32_t)pdst;              DMA2D->FGOR  = offlinefg;                   DMA2D->BGOR  = offlinebg;                   DMA2D->OOR   = offlinedist;                 DMA2D->NLR = (uint32_t)(width << 16) | (uint16_t)height; DMA2D->FGPFCCR = pixelformat | (1UL << 16) | ((uint32_t)opa << 24);            DMA2D->BGPFCCR = pixelformat;               DMA2D->OPFCCR  = pixelformat;                DMA2D->CR   |= DMA2D_CR_START;while (DMA2D->CR & DMA2D_CR_START) {}
}int dma2d_test(void)
{ dma2d_mixcolorsbulk(sky_animation_mask,sky_animation_mask1,&_lcd.front_buf[_lcd.lcd_info.width*200+400],0,0,800-LOGO_W,LOGO1_W,LOGO1_H,LTDC_PIXEL_FORMAT_RGB565,128);
}
MSH_CMD_EXPORT(dma2d_test,dma2d_test);

效果如下:

STM32 的图形加速器 DMA2D相关推荐

  1. 【STM32H7教程】第55章 STM32H7的图形加速器DMA2D的基础知识和HAL库API

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第55章       STM32H7的图形加速器DMA2D的基 ...

  2. DMA2D 图形加速器简介

    DMA2D 图形加速器简介 在实际使用 LTDC 控制器控制液晶屏时,使 LTDC 正常工作后,往配置好的显存地址 写入要显示的像素数据, LTDC 就会把这些数据从显存搬运到液晶面板进行显示,而显示 ...

  3. I.MX RT1170 PXP 图形加速器

    一.PXP介绍 在图像显示在显示器之前,i.MX RT1170 可以通过 2D矢量图形.PXP 或者 LCDIF 等图形加速器来生成.合成和混合图形的内容,本文将介绍其中 PXP 图形加速器. PXP ...

  4. STM32F429图形加速器(DMA2D)

    在stm32f429中有一个Chrom-Art Accelerator™ controller(DMA2D),这个控制器是一款专门用于图像处理的DMA(也可以和普通的DMA一样用于数据传输),能够用于 ...

  5. 安富莱v6开发板网口通讯_【STM32-V6】STM32F429BIT6开发板开源, 丰富软件资源, 强劲硬件配置, 配套600多实例, 17套手册持续更新中2020-12-14...

    STM32-V6 开发板HAL版教程 ********************************************************************************* ...

  6. 第27章 LTDC/DMA2D—液晶显示—零死角玩转STM32-F429系列

    第27章     LTDC/DMA2D-液晶显示 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.co ...

  7. 基础篇001. STM32概述

    目录 1. ARM简介 2.  ARM处理器的特点 3.  STM32概要 3.1  STM32主流系列概述 3.2  STM32无线MCU 3.3  STM32超低功耗MCU 3.4 STM32高性 ...

  8. 英特尔AMD竞相为笔记本处理器添加图形功能

    英特尔计划明年末推出一款集成有图形加速器的双核笔记本电脑处理器.而它的竞争对手AMD不甘示弱,也表示将推出一款类似的即时通讯产品. 英特尔在此间举行的"英特尔开发商论坛"上展示了一 ...

  9. 加速器 (Accelerator or Offload Engine)

    加速器 (Accelerator or Offload Engine) 是一块专用的硬件电路,它可实现各种功能,以便于在执行一组操作时,获得比通用微处理器更高的性能或更好的能效比. 通过软件调用加速器 ...

最新文章

  1. 中原工学院c语言期末考试题,中原工学院软件学院 2010年C语言 试卷A
  2. SVN钩子HOOK设置自动备份,服务本地可以看到所有更新内容。
  3. linux_manjaro常用软件安装
  4. 编程基本功:带着本子却不记录,你以为听懂了记住了,不可能的
  5. tensorflow应用问题记录
  6. python 身份证验证系统_用Python写一个身份证号码校验系统
  7. 数据中心供配电系统继电保护基础知识
  8. 自回归模型的两种策略——马尔科夫假设与隐变量自回归模型
  9. LayaBox---Dialog弹窗
  10. Android Studio制作一个简单的计算器APP
  11. 核桃的营养价值,核桃的功效与作用
  12. 初学MSP430SPI通信
  13. 395. Longest Substring with At Least K Repeating Characters 1
  14. Linux进程管理、防火墙
  15. laravel 请求出现 post The page has expired due to inactivity.
  16. 人工智能到底是什么?AI可以涵盖哪些领域?
  17. 音频多声道数据的操作
  18. QT 制作 Excel 表格常用操作方法
  19. 互联网公司为什么普遍996而不是666
  20. Scrapy 爬取贴吧的例子

热门文章

  1. 如何求置换奇偶性、对换乘积
  2. ie浏览器rgba不能显示的一种情况
  3. 腾讯云轻量应用服务器开启root远程登录
  4. 手把手教你用Unet实现语义分割(Pytorch版)
  5. Swift上写百度地图记录
  6. 从南极到你家,易开得,一支“中国芯”的奇幻漂流
  7. Vant组件NavBar导航栏使用时去除下方白线问题
  8. Failed to apply plugin [id 'com.gradle.build-scan']
  9. 飞行棋程序(附源码)
  10. 报警:Component 'MSCOMCTLOCX' or one of its dependencies .....及解决方法