你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32H7的图形加速器DMA2D的基础知识和HAL库API

[复制链接]
STMCU小助手 发布时间:2021-12-24 17:00
55.1 初学者重要提示; _: ~0 m4 M& a2 k
  DMA2D是专门用于LCD加速的,特别是刷单色屏,刷图片,刷Alpah(透明)混合效果全靠它,而且可以大大降低CPU利用率。
9 }( g* e% l/ P  测评STM32H7的LTDC+DMA2D性能,100Hz以上无压力,刷800*480图片和色块仅需2.6ms一张  [# U) K, H. l7 W; S6 z2 k: |
  H7的DMA2D与F429的DMA2D最大区别是支持了ARGB和ABGR互转,而且支持H7的硬解JEPG输出格式YCbCr转RGB,方便LCD显示。
' _- f. K% B9 j5 h  特别注意,大家只需对HAL库提供的DMA2D操作API有个了解即可,实际工程中,并不使用这些API,我们需要使用更加高效的寄存器直接操作,在下一章节会为大家说明。2 [* {+ o# e* P2 b4 e
55.2 DMA2D基础知识
& l' K- G4 p) u$ vDMA2D主要实现了两个功能,一个是DMA数据传输功能,另一个是2D图形加速功能。. R; }) \& j, e; W; h6 W) O
- K! O" C% B% L4 s
  DMA数据传输
& b, z0 ~0 m) m主要是两种方式,一个是寄存器到存储器,另一个是存储器到存储器。通过DMA可以大大降低CPU的利用率。
; ^( h4 z& N/ v2 ]
5 m( [$ d9 W. M  2D图形加速功能" M0 W  O" I" H* Q4 j5 r
支持硬件的颜色格式转换和Alpha混合效果。
: L; c7 `' m, |7 w& z7 M% e: ?5 J" _
55.2.1 DMA2D硬件框图
4 f/ K3 R; Y+ O9 r, ^6 k认识一个外设,最好的方式就是看它的框图,方便我们快速地了解DMA2D的基本功能,然后再看手册了解细节。框图如下所示:7 p6 M' x, j4 Y; O
! E/ b9 M' R# L$ g% t
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

; I: J. e% A3 S4 V9 i. o; |$ k- @2 \6 z9 \2 ^/ E: A" ~
通过这个框图,我们可以得到如下信息:& x1 L$ r' E0 ^3 i
4 ?6 n8 a+ Z8 Q' c6 Q
  dma2d_aclk
& A% g. `" P7 j- _4 YAXI 总线时钟输入。1 {5 B# o3 r0 `* d* Z! L

) |) y* k2 e9 `  dma2d_gbl_it% X, z8 R( @0 L" i3 \
DMA2D全局中断输出。
- _7 {  b7 X! {) p
6 Q; t7 Q1 D# C- l! R$ B  dma2d_clut_trg
/ B6 T" i; v0 m" r( h( i1 B7 m: B$ OCLUT传输完成信号输出,可以触发MDMA。! Z: K# }4 h$ I5 [3 }* ?9 p4 C

! T  j: f' p4 m) i  dma2d_tc_trg  ]+ u0 {( F: ~( b
传输完成信号输出,可以触发MDMA。3 c! w( O4 k+ ?! H. l$ @/ X1 K5 p# |

" _: ]0 I; }; p  dma2d_tw_trg 2 u/ H. n' Z# a
传输watermark信号输出,可以触发MDMA。
$ j+ O- a+ x" G2 ~; m& O: e% O* O5 Y1 E- N( u( c" [  B
将这个硬件框图简化一下,就是下面这样:4 t3 Q! X  R' U2 s# E

6 E5 Y" E) j" V- C% p) @* h, ?( h
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

4 w  {0 y: c$ Q$ W* N
- J4 f- B& i3 \! e& Z  Y. N下面按照简化的硬件框图,对每个部分做个说明。
9 N( R* r6 i# t& C# D8 V" F: ?
% Q0 r* a) U+ q7 Y! a0 i55.2.2 DMA2D工作模式7 {0 k  r; F* L7 ^1 g. ?
DMA2D支持的工作模式如下:
9 R' J/ c3 \7 Z" R- G2 h! X$ K
- l: M- u& ]2 N: l! l  模式1:寄存器到存储器模式- b$ r2 Q  H0 E+ q% o! a, G
这个模式主要用于清屏,也即是将显示屏清为单色效果。6 S6 X) y+ \! W2 e

+ E$ E- I" ~& E% ~) |  模式2:存储器到存储器模式" c5 |- `# |5 f
这个模式用于从一个存储器复制一块数据到另一个存储器,比如将摄像头OV7670的输出图像复制到LCD显存就可以采用这种方式。, T# }6 t" W: B2 A

( W  l. d, _" h4 @3 v3 s  模式3:存储器到存储器模式,带颜色格式转换$ m- L1 T# t7 ]" o$ g; o: F& p  s
这个模式比模式2多了一个颜色格式转换,比如我们要显示一幅RGB888颜色格式的位图到RGB565颜色格式的显示屏,就需要用到这个模式,只需输入端配置为RGB888,输出端配置RGB565即可。位图颜色格式转换后会显示到显示屏上。
7 m6 v  B6 X( t
4 a0 a9 k4 l7 c% V$ ?  模式4:存储器到存储器模式,带颜色格式转换和混合6 N  P7 ?" M) u! U4 G2 ^4 \. \4 N8 b
这个模式比模式3多了一个混合操作,通过混合,可以将两种效果进行混合显示。  d6 [4 e+ R" N2 g/ T+ W! G4 [

. W' k) O/ W  ^0 L+ i! {  模式5:存储器到存储器模式,带颜色格式转换和混合,前景色是固定的
0 l" ]. q% j8 L+ C# A) r; B同模式4,只是前景色的颜色值是固定的。7 o% `# _6 S0 R

8 {" Y, [5 r4 l: y. J55.2.3 前景层和背景层的输入以及颜色格式转换
; n# G; x4 \- c; p前景层和背景层是指的用户绘制图形时的前景色和背景色,比如我们显示汉字,字体会有一个颜色,也就是前景色,还有一个背景色。又比如我们绘制两幅图片,想将两幅图片混合,那就可以将一幅图片作为前景层,另一个幅图片作为背景层。
2 S4 y/ D/ Y0 V! e, G
3 o/ w' @7 U# T) e0 N4 p, f( aDMA2D支持的输入颜色格式如下,前景层和背景层一样:
* n+ t' K/ L8 ]' _8 R0 l0 f! q4 y! ~! K
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
7 v1 B* \" G5 M- e/ g; b  W

0 m' ^$ w5 F4 I6 Q' P前8种颜色格式在第50章的第2小节开头有介绍,这里把后四种做个说明:' ^- k% T: I1 P1 Q/ U
8 t' X! g# ~) q' N
  L4 (4-bit luminance or CLUT)
  _- w6 Q# N7 U, V$ i5 H3 H4位颜色格式,实际上仅仅是4位索引值,范围0–15,而每个索引值的具体颜色值在查色表CLUT里面存储。
) k) m7 r. R1 x6 q. c* U! t' C
2 q' f& V4 s2 I6 t3 J* ^  A4和A8/ A: M, ~7 D) ~/ d/ S
A4和A8用于特定的Alpha模式,既不存储颜色信息,也没有索引值。
7 q/ t0 U" U% C2 V. E* E) t  _7 s. o* \( f# `1 h
  YCbCr% d3 L  x6 X/ s
这个是H7的硬件JPEG输出的颜色格式,后面JPEG章节为大家专门做讲解。
( J; \4 A) ]+ j& {
* R5 v5 o- |; @; U' E这里特别注意一点,输入颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。
! b8 d+ ?0 F7 t# Y% C- f/ r5 L+ v) L7 o; Q* ]4 j: ]" O
55.2.4 前景层和背景层混合4 k/ `; d8 Y/ A) Q. [4 U$ [
DMA2D混合器用于混合前景色和背景色,这个功能不需要任何配置,仅需要通过DMA2D_CR寄存器使能即可。混合公式如下:( {5 E& l* x, A9 M/ ~9 R
; Z0 Y. ^$ R. @5 E( Y5 K7 |5 i5 ^. ?  d& F
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
" t5 L& \5 D7 N

  M5 q' A- f4 n3 _7 P1 K55.2.5 DMA2D输出颜色格式
9 E/ t9 ?; B& ?4 [0 J+ o6 wDMA2D支持的输出颜色格式如下:
+ j: Q+ j4 |0 a
) R5 e! W4 n0 A, t& u# k
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
: k% i6 H, G% [" `
' \* h8 _' }3 Y5 m! a4 ^
这里特别注意一点,输出颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。- M9 b. S9 I8 P7 ?) H2 Z1 [# H4 m3 A

" l+ c4 _$ S2 {$ z% X55.3 DMA2D的HAL库用法8 u0 ~- Y6 w  E, H1 ?- x6 Z
DMA2D的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断。下面我们逐一展开为大家做个说明。
$ m( x0 i  y- d! c  j
: _( z5 z8 c% C55.3.1 DMA2D寄存器结构体DMA2D_TypeDef, Y) W3 l; P1 P3 N; U- I1 X3 ~# t; b8 `
DMA2D相关的寄存器是通过HAL库中的结构体DMA2D_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:- J" \5 `8 s5 F4 y  ], a  T" u
2 s7 L8 t9 q# A" R: L6 w# g! ?* Z2 t
  1. typedef struct
    $ |5 A% t9 u- H: ~9 }5 w! D" O
  2. {
    ( o8 F7 O% A, }* |; o- ^
  3.   __IO uint32_t CR;            /*!< DMA2D Control Register,                         Address offset: 0x00 */
    $ U* T& F; N: [: k2 s2 X$ `" s
  4.   __IO uint32_t ISR;           /*!< DMA2D Interrupt Status Register,                Address offset: 0x04 */
    ' A( Y; Y- ]0 N, R
  5.   __IO uint32_t IFCR;          /*!< DMA2D Interrupt Flag Clear Register,            Address offset: 0x08 */
    , y4 i$ c/ u1 B5 [  O
  6.   __IO uint32_t FGMAR;         /*!< DMA2D Foreground Memory Address Register,       Address offset: 0x0C */
    ) j% M8 [, N: w  M% h1 Z( n- y) S
  7.   __IO uint32_t FGOR;          /*!< DMA2D Foreground Offset Register,               Address offset: 0x10 */3 j) f! e) e7 P) c% ~" c
  8.   __IO uint32_t BGMAR;         /*!< DMA2D Background Memory Address Register,       Address offset: 0x14 */* K7 Y9 h4 \4 |2 }
  9.   __IO uint32_t BGOR;          /*!< DMA2D Background Offset Register,               Address offset: 0x18 */
    ' w" q( f  ?) i  W* ^) G( [
  10.   __IO uint32_t FGPFCCR;       /*!< DMA2D Foreground PFC Control Register,          Address offset: 0x1C */* G. V9 \* P4 |+ y8 N
  11.   __IO uint32_t FGCOLR;        /*!< DMA2D Foreground Color Register,                Address offset: 0x20 */
    $ W, c9 a; }" o1 D5 @4 T2 G
  12.   __IO uint32_t BGPFCCR;       /*!< DMA2D Background PFC Control Register,          Address offset: 0x24 */2 B  ]) E# M5 ?5 ^" F# V+ X
  13.   __IO uint32_t BGCOLR;        /*!< DMA2D Background Color Register,                Address offset: 0x28 */
      ]0 f( x* v! [% ~) J! w
  14.   __IO uint32_t FGCMAR;        /*!< DMA2D Foreground CLUT Memory Address Register,  Address offset: 0x2C */' e* U% ^" [  |
  15.   __IO uint32_t BGCMAR;        /*!< DMA2D Background CLUT Memory Address Register,  Address offset: 0x30 */
    ( I8 C0 e4 B0 v/ B# U; |
  16.   __IO uint32_t OPFCCR;        /*!< DMA2D Output PFC Control Register,              Address offset: 0x34 */
    7 k* y) ~, j3 f1 T- V. X# \
  17.   __IO uint32_t OCOLR;         /*!< DMA2D Output Color Register,                    Address offset: 0x38 */
    ( K$ h% L9 S0 |+ [# l
  18.   __IO uint32_t OMAR;          /*!< DMA2D Output Memory Address Register,           Address offset: 0x3C */
    % G: N8 |- d1 M& e+ E8 Y
  19.   __IO uint32_t OOR;           /*!< DMA2D Output Offset Register,                   Address offset: 0x40 */
    5 j# ?/ C/ r" w9 r2 V; ^
  20.   __IO uint32_t NLR;           /*!< DMA2D Number of Line Register,                  Address offset: 0x44 */# Q/ ^7 K2 V5 h  I  y: J4 a; H
  21.   __IO uint32_t LWR;           /*!< DMA2D Line Watermark Register,                  Address offset: 0x48 */! o( E8 F# d- ?& E8 F
  22.   __IO uint32_t AMTCR;         /*!< DMA2D AHB Master Timer Configuration Register,  Address offset: 0x4C */6 [" M' g5 S3 L( D8 f
  23.   uint32_t      RESERVED[236]; /*!< Reserved, 0x50-0x3FF */
    3 n, @$ j8 f1 \
  24.   __IO uint32_t FGCLUT[256];   /*!< DMA2D Foreground CLUT,                          Address offset:400-7FF */
    . \  Z0 T( K9 W* `4 [6 f* e' l
  25.   __IO uint32_t BGCLUT[256];   /*!< DMA2D Background CLUT,                          Address offset:800-BFF */& p  {+ \, j3 c
  26. } DMA2D_TypeDef;
复制代码

( @5 G1 C' t" @1 [. I$ V! ~% k5 A- ]% ?! Z
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:7 Q7 E' C" e, V  V" m1 u( B6 O
) q  _/ V- f7 }- T
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */. x) @: O- b* F2 s
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

' b" a4 y2 x; G/ J% F! t下面我们再看DMA2D的定义,在stm32h743xx.h文件。
  1. #define PERIPH_BASE              ((uint32_t)0x40000000)
    + `1 G# W5 h* F
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000)4 J% S* E) Y; a4 C/ v- [7 k. t' ]' [( Y& d
  3. #define DMA2D_BASE               (D1_AHB1PERIPH_BASE + 0x1000)! |+ d+ r; `6 u/ v- g! v0 g
  4. #define DMA2D                    ((DMA2D_TypeDef *) DMA2D_BASE) <----- 展开这个宏,(DMA2D_TypeDef *) 0x52001000
复制代码

# O5 I: K! z5 h我们访问DMA2D的ISR寄存器可以采用这种形式:DMA2D->ISR = 0。. w3 N4 P, B; ?/ c* `

* u8 U- j+ @; E8 ?. B5 B. ]$ {3 |+ h0 @55.3.2 DMA2D参数初始化结构体DMA2D_InitTypeDef
- g( d. K9 R0 C9 g, Q9 p3 j此结构体用于配置DMA2D的基本参数,具体定义如下:
9 h2 n5 C% \" X* m9 a
; c! S! d* P, J7 j' M" \2 y
  1. typedef struct; l- n" t. S+ w
  2. {$ p6 \3 h" Z/ @% s: M& P
  3.   uint32_t             Mode;              ! {2 F* f2 a( F  S! D, _0 X
  4.   uint32_t             ColorMode;        9 H0 R/ V4 N, s1 w0 {
  5.   uint32_t             OutputOffset;      
    : @) F/ M4 a9 e! _
  6.   uint32_t             AlphaInverted;    $ b* w1 w) Z( H2 f  K
  7.   uint32_t             RedBlueSwap;      
    . A& |+ m+ l% P) P# e, Q
  8. } DMA2D_InitTypeDef;
复制代码
0 T) }9 Y) D) y
下面将这几个参数逐一为大家做个说明:( ~  N% h5 t7 @% S! O

, L. S+ B$ s' b+ l$ J0 g  uint32_t   Mode6 g0 A$ k$ ^0 t# Z
此参数用于设置DMA2D的传输模式,具体支持的参数如下:* p% u) B3 l7 |3 m& ~

) Q2 @1 d) Z1 k0 k
  1. #define DMA2D_M2M        ((uint32_t)0x00000000U)  /*存储器到存储传输模式 */; F* t3 m$ {4 S) o/ U
  2. #define DMA2D_M2M_PFC     DMA2D_CR_MODE_0         /*存储器到存储器传输模式,并执行FPC像素格式转 */. W* w# u$ D3 R( r$ f
  3. #define DMA2D_M2M_BLEND   DMA2D_CR_MODE_1         /* 存储器到存储器模式,并执行像素格式转换和混合 */
    * _' O" K+ ^7 o3 T& {# {
  4. #define DMA2D_R2M         DMA2D_CR_MODE           /* 寄存器到存储器传输模式 */4 h6 X5 T) _* K" H8 e2 o2 A
复制代码

% c: b; r! P1 r7 w" s
: M& m2 k0 h' ~( V  uint32_t   ColorMode
$ ~6 c  R, }# K7 G+ V  q此参数用于设置DMA2D的输出颜色格式,具体支持的参数如下:* _2 V& j  e" w' P) i& [/ f

3 h7 @6 X2 J7 P- w9 S
  1. #define DMA2D_OUTPUT_ARGB8888       ((uint32_t)0x00000000U)               /* ARGB8888 */" ^; u' @& I  Z" m* f0 L
  2. #define DMA2D_OUTPUT_RGB888         DMA2D_OPFCCR_CM_0                     /* RGB888 */
    6 K; F7 {9 m9 @& h7 ?
  3. #define DMA2D_OUTPUT_RGB565         DMA2D_OPFCCR_CM_1                     /* RGB565 */$ E/ U4 F) O7 c* l% P- {
  4. #define DMA2D_OUTPUT_ARGB1555       (DMA2D_OPFCCR_CM_0|DMA2D_OPFCCR_CM_1) /* ARGB1555 */
    8 N( G, Q+ O9 W. Q3 H8 R" T
  5. #define DMA2D_OUTPUT_ARGB4444       DMA2D_OPFCCR_CM_2                     /* ARGB4444 */' s' t3 g; ]% x0 D
复制代码

8 G! R7 N) c& p
! L7 F9 Q7 b5 H/ {! @  uint32_t   OutputOffset' ?% d) x7 p5 I3 y
此参数用于设置输出位置的偏移值,参数范围0x0000到0x3FFF。# ~( t3 z' _) g

" C, Z& s# j% R- g( l* \  uint32_t   AlphaInverted) r4 w- g4 Y' Q) @# z5 W, y
此参数用于设置DMA2D的输出颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     + ^' y2 ~6 b) n4 ]  V3 J

8 Z1 b% h  Q8 c! v4 O
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */
    ) v* |# X: I7 M  N6 v6 K
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */
复制代码

# E7 {8 W  o6 ?1 ^; B" M  uint32_t   RedBlueSwap: g1 A* ?9 m! h, {
此参数用于设置DMA2D的输出颜色格式中R通道和B通道的交换,具体支持的参数如下:
5 `, \5 z5 t; D9 K7 ^' [( y. E% ~# }1 b
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */3 A2 o8 m0 D# @# u, {
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码

# j- I% ?1 ~3 ?55.3.3 DMA2D的图层结构体DMA2D_LayerCfgTypeDef
$ \' R$ V7 T9 }, _$ X此结构体用于配置前景色和背景色。
% H  z2 _7 r; H( L) s5 T# _: D! c. u3 Y3 c* t7 s& \/ w
  1. typedef struct
    + h+ c3 }6 _. i3 I. h8 ]5 w/ w: H: m
  2. {! o" J# C, g0 s8 M
  3.   uint32_t             InputOffset;       8 Y% S% M7 X) D! `! g2 E
  4.   uint32_t             InputColorMode;    $ g! ]. ~# Q: F0 E3 Z/ _: T
  5.   uint32_t             AlphaMode;        
    4 C; z/ c7 G9 N6 j( c& M& ~
  6.   uint32_t             InputAlpha;        , ]# q$ H9 Q9 z2 @8 s
  7.   uint32_t             AlphaInverted;   
    5 v% a; F! j/ m
  8.   uint32_t             RedBlueSwap;       3 H. ~% q  ~+ O, \
  9.   uint32_t             ChromaSubSampling;( S# ]4 |; D9 X3 q) H
  10. } DMA2D_LayerCfgTypeDef;
复制代码
8 ~- G* n* O+ @' `' [
下面将这几个参数逐一为大家做个说明。
0 ]% `: O4 ^: N" B) M2 i+ I
/ c1 C) E) j: T6 w# q) q  r  uint32_t  InputOffset
9 z% u& o% X2 p, Q" |& }* o% V设置前景色或者背景色的输入偏移,范围0x000到0x3FFF。
. \; C% W: o+ O/ V
0 w# u$ e  j( N! G, ?) u! ~  uint32_t  InputColorMode
% r& h7 q: v1 |6 A- I. f设置前景色或者背景色的输入颜色格式,具体支持的参数如下:
$ o" @" }1 B! e2 ]" r) E6 V. W1 f! D1 d$ ^7 ]
  1. #define DMA2D_INPUT_ARGB8888        ((uint32_t)0x00000000U)  /* ARGB8888 */
    1 W. w. p" U7 _
  2. #define DMA2D_INPUT_RGB888          ((uint32_t)0x00000001U)  /* RGB888   */
    5 H# h) Z$ z+ R8 J2 f- ?
  3. #define DMA2D_INPUT_RGB565          ((uint32_t)0x00000002U)  /* RGB565   */
    . S1 w" a+ @& a) i5 c9 V" z3 @+ ?
  4. #define DMA2D_INPUT_ARGB1555        ((uint32_t)0x00000003U)  /* ARGB1555 */& E( K) p  F% p4 W4 K
  5. #define DMA2D_INPUT_ARGB4444        ((uint32_t)0x00000004U)  /* ARGB4444 */5 O) P! e3 K5 r9 F1 _
  6. #define DMA2D_INPUT_L8              ((uint32_t)0x00000005U)  /* L8       */2 ^' a3 U* |8 {$ {# ?+ z
  7. #define DMA2D_INPUT_AL44            ((uint32_t)0x00000006U)  /* AL44     */
    - p' n! \; g2 B+ U1 r  ^$ T3 Q- Y
  8. #define DMA2D_INPUT_AL88            ((uint32_t)0x00000007U)  /* AL88     */3 b, E5 J" }: ?
  9. #define DMA2D_INPUT_L4              ((uint32_t)0x00000008U)  /* L4       */* K1 v2 C& F3 k8 |
  10. #define DMA2D_INPUT_A8              ((uint32_t)0x00000009U)  /* A8       */
    ; q5 [0 p2 `) l/ v! O# z* T  [, h
  11. #define DMA2D_INPUT_A4              ((uint32_t)0x0000000AU)  /* A4       */
    ( p- w9 ]! b; |
  12. #define DMA2D_INPUT_YCBCR           ((uint32_t)0x0000000BU)  /* YCbCr    */
复制代码
' ?, G8 R4 x/ e8 R% i6 ]& _
  uint32_t AlphaMode
, F+ n5 M+ _* Z$ L6 K* g: ~& [0 e6 i7 F设置前景色或者背景色的Alpha模式,具体支持的参数如下:
3 y/ z3 s  B8 a% Y
, R6 N$ t! c7 Z8 _
  1. #define DMA2D_NO_MODIF_ALPHA   ((uint32_t)0x00000000U)  /* 不修改Alpha通道值 */- ]# {0 ]* @& n! g0 H
  2. #define DMA2D_REPLACE_ALPHA    ((uint32_t)0x00000001U)  /* 用新设置的Alpha值替换原始Alpha值 */
    5 _( h( S$ @. c- N2 P, _/ {
  3. #define DMA2D_COMBINE_ALPHA    ((uint32_t)0x00000002U)  /* 用新设置的Alpha值与原始Alpha值的乘积替换原始Alaha值*/
复制代码

) p6 u* F% ~) k  uint32_t  InputAlpha1 E" F# c' M' I' P6 P- N
设置前景色或者背景色的Alpha值,范围0x00到0xFF,如果颜色格式是A4或者A8,那么此参数的范围是0x00000000到0xFFFFFFFF,标准的ARGB8888格式。
' D. C  m" e2 c) D2 B$ p% _1 F- }; ^& G; U0 f# N. V' J' ]( C
  uint32_t AlphaInverted& }5 X* i4 i. ]) e; g7 E
设置前景色或者背景色的输入颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     $ `7 R. }9 _* L. z

9 |8 v: h! Z4 ~+ F* U# o
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */6 d: C4 L7 m4 X7 y3 L
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */     
复制代码
' d( b7 q' N7 b+ ]; [
  uint32_t   RedBlueSwap
$ i# I+ q! l" f4 f) C3 S设置前景色或者背景色颜色格式中R通道和B通道的交换,具体支持的参数如下:
5 X& Z5 F3 B1 n" x/ i: ~* T+ |' _2 J0 j+ L: F7 L
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */
    8 m4 G; ?2 f7 @& G/ [
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码
4 {$ o9 k" o8 A$ i( S
  uint32_t   ChromaSubSampling% f( ]* H# c3 d$ M2 H7 ~) [
设置前景色或者背景色中YCbCr 颜色模式的采样格式,具体支持的参数如下:
  1. #define DMA2D_NO_CSS               ((uint32_t)0x00000000)  /* 4:4:4 */  W3 r4 ^" s# A) S1 }/ W
  2. #define DMA2D_CSS_422              ((uint32_t)0x00000001)  /* 4:2:2 */* u5 H$ f$ O* Z4 m
  3. #define DMA2D_CSS_420              ((uint32_t)0x00000002)  /* 4:2:0 */  
复制代码
7 q! M) \; u/ L; i! ?1 {. H
55.3.4 DMA2D句柄结构体DMA2D_HandleTypeDef

# i' b$ `% l2 @) wHAL库在DMA2D_TypeDef, DMA2D_InitTypeDef和DMA2D_LayerCfgTypeDef的基础上封装了一个结构体DMA2D_HandleTypeDef,定义如下:
$ L& h) ]1 y3 a; K8 a
. _; @' ^3 ~3 a
  1. typedef struct __DMA2D_HandleTypeDef5 A% R- z/ L1 A/ h5 g+ R9 U2 p
  2. {  J+ O/ K4 [; b# @/ q
  3.   DMA2D_TypeDef               *Instance;                                                                                                                                                                                          
    . ?' y) C  B) K8 H
  4.   DMA2D_InitTypeDef           Init;                                                        4 f% _" [; ]' L. R  M# T
  5.   void                        (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                                                                             
    & F: X' p0 D' E" p" X, H, }2 X
  6.   void                        (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                      # N' {# x3 v" p! n# e
  7.   DMA2D_LayerCfgTypeDef       LayerCfg[MAX_DMA2D_LAYER];                                    ( O. _8 b) v/ p( o
  8.   HAL_LockTypeDef             Lock;                                                                                                                                                                                                    2 Y* G4 X, s5 }' L
  9.   __IO HAL_DMA2D_StateTypeDef State;                                                                                                                                                                                                   
    # h5 P3 b! M9 ?7 N' u$ Q
  10.   __IO uint32_t               ErrorCode;                                                   } DMA2D_HandleTypeDef;7 {, X$ u5 U3 d' V) Z" J. T
复制代码

# g1 x/ X$ ~/ r! L( [: i下面将这几个参数逐一做个说明。
* h, ]& o  E1 ^- H7 W7 ^: j4 U, M
+ J$ y$ m% ~+ o) C  DMA2D_TypeDef  *Instance
. I* K. J* c  v2 Y这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。' G, S* n: ^4 Z$ B
. h; s' ^) d& ?# I) c
  DMA2D_InitTypeDef  Init;  
6 X( L6 B' m# Q/ u6 j这个参数是用户接触较多的,用于配置DMA2D的基本参数,详见本章3.2小节。
% `: X1 R; n0 c0 G; b+ F- H- j& P" A, I& r6 o
  void     (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);6 E4 ^" ^: n! q; R) ?0 ?! D
  void     (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);6 i1 V, W, J3 c
DMA2D中断服务程序里面执行的回调函数,一个是传输完成回调,另一个是传输错误回调。; G. F4 J, k6 a  Y5 e1 x2 W
- E. B, ^  o: I* ~0 t* G
  DMA2D_LayerCfgTypeDef   LayerCfg[MAX_DMA2D_LAYER]
3 n, m( E! a; O2 t9 L. F. N' ^" V5 |这个参数用于前景色和背景色的设置,MAX_DMA2D_LAYER=2,详见本章3.3小节。0 W. T' j1 ^7 O/ n( j

+ m; W0 Z$ s0 S+ j  |/ t  HAL_LockTypeDef   Lock% s8 c. M& o/ M  k' ~; X
__IO uint32_t    State;
0 w6 M; P3 `6 O- R  x
1 O) \! i) n+ A! u8 R' A5 L__IO uint32_t    ErrorCode
! |' r! d: m% B) F9 G* R+ l6 _- g' T8 j2 O
这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置DMA2D通信状态,而ErrorCode用于配置代码错误。
8 G, J4 V. N' Z$ Y# [- E
& D; C2 P  m6 ~9 T1 L55.3.5 DMA2D初始化流程总结
$ ~. t1 ?4 k7 }7 d8 H1 u
对于DMA2D来说,其实不需要初始化流程,每个功能都可以直接封装出一个函数来,下个章节会为大家专门讲解,也是实际项目比较推荐的方式。
- s  t1 R9 c1 ?# ~
2 @- v' D% W$ l! u8 t) A$ K* O& W% Y; I/ s55.4 源文件stm32h7xx_hal_dma2d.c
' [# e% m. I/ ]) o: F这里把我们把如下几个常用到的函数做个说明:
& x+ [# n# x0 L- N% i) m( f4 m( x$ O0 H! L, T+ r4 z
  HAL_DMA2D_Init- V" V2 T* y, F
  HAL_DMA2D_ConfigLayer
/ e& m0 S/ h; W  HAL_DMA2D_Start_IT: J" o+ A0 k/ w1 ~1 L8 i! C, |
  HAL_DMA2D_BlendingStart_IT' z+ E0 B6 w, o

* y) D6 y! k* F9 |  b/ G1 K. [9 d55.4.1 函数HAL_DMA2D_Init7 K/ V3 D9 T3 `/ D5 f! s
函数原型:
. Z8 X& i" U; v2 K, {) B8 g  Z6 D( g3 _/ R# G' ?" X
  1. HAL_StatusTypeDef HAL_DMA2D_Init(DMA2D_HandleTypeDef *hdma2d)
    8 G  F9 Z2 A. x# n. C3 g
  2. {
    . d1 d( `: u( K

  3. 2 C. P/ }& }1 ^4 k- y
  4. /*  检测参数是否有效 */
    7 [% J$ O  J/ g4 f+ F8 T4 G- y$ o
  5.   if(hdma2d == NULL)
    & Z; i. C0 r1 q: n
  6.   {
    : q  h! @, m3 Y. s4 {8 p
  7.      return HAL_ERROR;
    3 O5 [7 f+ L1 ~! L, g) [& j
  8.   }, D; w- |; g8 O+ O' I

  9. : k8 D/ G4 S0 G7 v3 Q* o
  10.   /* 检测函数形参 */
    9 y! D4 s! ^1 P9 B: x2 S9 I
  11.   assert_param(IS_DMA2D_ALL_INSTANCE(hdma2d->Instance));3 l; F! h& u. R3 b
  12.   assert_param(IS_DMA2D_MODE(hdma2d->Init.Mode));9 Q6 K5 `( U& z+ B. X$ M2 h$ k- M
  13.   assert_param(IS_DMA2D_CMODE(hdma2d->Init.ColorMode));
    " \8 t- D& D4 f8 Q# f3 V0 i, T/ e
  14.   assert_param(IS_DMA2D_OFFSET(hdma2d->Init.OutputOffset));
      w4 _5 V( {4 P, s

  15. 9 ~: S  A% `6 w& _. Z0 {/ ?
  16.   if(hdma2d->State == HAL_DMA2D_STATE_RESET)6 z& s! J5 H0 c  S
  17.   {
    $ G( n) }! d4 x0 Q
  18.     hdma2d->Lock = HAL_UNLOCKED;, o; f( n) D( H1 y) N7 q3 r" [
  19.     /* 初始化GPIO,NVIC等 */
    % ]& G7 P- [& F% t
  20.     HAL_DMA2D_MspInit(hdma2d);( Y- i+ Z5 E* n3 t: M
  21.   }- C8 ?4 h6 {: x- P1 w7 |5 Z

  22. 5 X, n& h( @0 k2 I- \
  23.   /* 设置DAM2D外设状态 */  r$ p: Q% E3 H" A" K8 d
  24.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  . M' e) k. m5 N  }. {

  25. % W2 _+ H' V6 X8 {* O: _( D$ B
  26.   /* 设置DAM2D工作模式 -------------------------------------------*/
    9 m$ @' C9 g* J% \$ i2 Q5 z: X) O
  27.   MODIFY_REG(hdma2d->Instance->CR, DMA2D_CR_MODE, hdma2d->Init.Mode);
    * Q* l+ i8 \+ ]+ O  t4 P& d

  28. 4 [, _" O: ]& k1 |& r
  29.   /* 设置输出颜色格式 ---------------------------------------*/
    % @0 Y0 B1 _& p* s) }) \
  30.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_CM, hdma2d->Init.ColorMode);
    # _6 D' x0 d3 Q9 I! w

  31. % Q! X0 b( \; e# M
  32.   /* 设置输出偏移 ------------------------------------------*/  1 V2 u  ~( U7 {6 p, C
  33.   MODIFY_REG(hdma2d->Instance->OOR, DMA2D_OOR_LO, hdma2d->Init.OutputOffset);  
    5 n; i( S# j# l* X! {# }

  34. 5 H9 `* v9 Y; s2 t7 N1 @5 b% ^
  35.   /* 设置输出颜色格式中的Alpah值反转 */
    " }+ B  M/ v5 D  F& e( V  T
  36.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_AI, (hdma2d->Init.AlphaInverted << DMA2D_POSITION_OPFCCR_AI));$ N* o+ ]: }5 L' k# k$ B
  37. + w* y" k6 e( b" o+ C2 {5 E  C# \6 w
  38.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_RBS,(hdma2d->Init.RedBlueSwap << DMA2D_POSITION_OPFCCR_RBS));' d7 K0 Y( m1 D) y$ M
  39. ( H; L9 W1 Q- B; K; |9 G; i
  40. ) F. K& U$ {+ M) j/ k  w
  41.   /* 无错误 */. i2 y/ u0 ~' ~9 |+ W  M/ ^
  42.   hdma2d->ErrorCode = HAL_DMA2D_ERROR_NONE;
    8 z6 Y8 ]9 ]4 D. A# S  k

  43. 6 d, ?7 b, ?8 n+ w. ~, y6 e
  44.   /* DAM2D就绪 */
    0 l0 u$ D; J' K. h3 j
  45.   hdma2d->State  = HAL_DMA2D_STATE_READY;$ {: u2 B2 b$ ]

  46. ( f& y0 B0 M) G
  47.   return HAL_OK;4 Q; {) i- q7 A; [4 }; |; W' V2 n
  48. }
复制代码

% s& H5 l6 T0 [5 u1 U函数描述:% n" E$ h. B" D' e. `3 ~; w
4 `9 L! M8 s2 d2 S
此函数用于初始化DMA2D的工作模式和输出颜色格式。; V* u8 m( R$ h) z) C8 n0 u

9 S0 F+ }' }8 x- H1 q7 R函数参数:
: ]4 G9 ^* i) m# H8 k( z6 D1 i- ]
* c0 @2 z/ W+ r$ {% J6 J2 F  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。9 k; {. t0 K  I: n/ o' S" v/ l+ {4 G
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。' q* W+ Z5 R* |) k; \' h
注意事项:2 W: ~$ j/ @9 L9 I  Z

* Z1 z$ e" {$ }" {函数HAL_DMA2D_MspInit用于初始化DMA2D的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
: j, }; U% B, P. ?如果形参hdma2d的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量DMA2D_HandleTypeDef Dma2dHandle。4 Q% [0 S% ]4 V* d
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_DMA2D_STATE_RESET  = 0x00U。
8 V8 z1 r) a! b/ w  s: C
4 b# `6 V) {/ c" o  l1 ?8 D# [9 Z1 c1 m解决办法有三
& T- L# J) l* ?, Z+ Y1 D# v8 b
; ?& z% @6 U# p4 O方法1:用户自己初始DMA2D底层。9 l/ ]! G/ G! T+ Q9 |+ R* @

; A+ S: r8 }  I6 H/ i0 i$ G方法2:定义DMA2D_HandleTypeDef LtdcHandle为全局变量。. @$ i9 `( H6 p
  ^1 V/ j2 \4 K0 M' Y
方法3:下面的方法
  1. if(HAL_DMA2D_DeInit(&Dma2dHandle) != HAL_OK)! |% D# _8 M9 k& a  n+ f& O
  2. {
    + M8 \) M1 V( V: s6 h# ]3 s* D
  3.     Error_Handler();6 M. z6 j/ }1 @) z' e
  4. }  
    % n# e, r9 s' }6 R8 k
  5. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
      t. |; T% t0 a7 v) V0 x0 o, N0 x' F( w
  6. {
    3 G( L0 b4 ~9 Z4 S
  7.     Error_Handler();
    % \) x- P* f$ c
  8. }
复制代码
1 p' c- f2 ]0 h
, }8 H! ]' `9 t- x4 f0 W! ~
使用举例:# l6 [5 k# i3 E7 M) k

8 \1 q/ R% ?/ `& \+ F5 c
  1. DMA2D_HandleTypeDef Dma2dHandle;
    : Q! M) f$ h( p; k- O. ?

  2. " D2 K9 Z) Q7 C% r
  3. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/
      y4 i4 r: {7 |, L; L$ q3 Z! h
  4. Dma2dHandle.Instance = DMA2D;
    2 r5 P7 g7 O; h+ m, S/ a
  5. 5 O# y- A- l' a: U/ ^4 F9 H
  6. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */! E5 k* @# ~: H% t
  7. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */
    7 y' l1 @3 _- c8 g: u# ~" {# p
  8. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */
    - n  q4 T' C4 ]2 C( v  a: G, g
  9. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */0 y, C/ M! Z6 b' |2 c+ T) Y
  10. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */( W& C' j; ?7 o! ?/ E
  11. . L9 y* a$ Z7 M3 X4 w% [) X$ M. G
  12. /*##-2- DMA2D 回调函数配置 ######################################*/
    8 R# f! R8 {2 t9 S" U
  13. Dma2dHandle.XferCpltCallback  = TransferComplete;+ F8 U  S* W, z% p
  14. Dma2dHandle.XferErrorCallback = TransferError;
    & t1 Z/ ?9 x; e6 h

  15. 7 X/ w. ]' |! E- C+ \
  16. /*##-3- 前景层配置 ###########################################*/' l" I$ m2 {* s/ P5 w
  17. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 *// k1 n  N& B1 u- m
  18. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */' f% j# z- D+ a5 N
  19. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */' b+ ?7 D! H  ]2 s
  20. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */
    + H9 r( J& w, A% ^4 S
  21. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/
    ; C4 `5 ^/ ]5 G5 e5 e6 }
  22. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/
    6 k" x/ ?8 a. ?6 d

  23. & t# ?( O/ g  Y9 f  v/ ?2 C

  24. ; E! \2 I" F' C9 \( X' _9 B
  25. /*##-4- DMA2D 初始化 ###############################################*/
    $ a& j; u) S3 h5 @7 X6 L% v
  26. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
    . i2 |4 w8 C, g
  27. {% @, v* U! C: G4 j
  28.     Error_Handler();0 |$ J; m7 s% j6 @2 k
  29. }
复制代码
0 D0 b6 l* m9 a; N
55.4.2 函数HAL_DMA2D_ConfigLayer
/ \# t: u! o' {  B8 h8 m  w函数原型:& {+ R  j4 ]) o- F- i% v; P

% S: q, C- M& W' P. {1 j5 }
  1. HAL_StatusTypeDef HAL_DMA2D_ConfigLayer(DMA2D_HandleTypeDef *hdma2d, uint32_t LayerIdx)
    ) B' J/ l" O* ~* N8 X
  2. { $ j# y7 e6 ?0 J+ D/ v  a& g
  3.   DMA2D_LayerCfgTypeDef *pLayerCfg = &hdma2d->LayerCfg[LayerIdx];
    * e1 ]  ~# ]- g9 f, G
  4. & @' s  \& I. y5 k  j: D
  5.   uint32_t regMask = 0, regValue = 0;' k" ?+ t& l( N( k8 {6 r

  6. 7 a* P; l# I: Y5 L
  7.   /* 检查参数 */
    + D) P/ M* a7 t9 ~9 [4 `; W; Y
  8.   assert_param(IS_DMA2D_LAYER(LayerIdx));  
    - s  `9 y2 _+ y( X2 y- b1 ?" L% k. ?
  9.   assert_param(IS_DMA2D_OFFSET(pLayerCfg->InputOffset));  $ ^8 i' g  Z$ {8 t  \: Q3 `0 A: \
  10.   if(hdma2d->Init.Mode != DMA2D_R2M)" W1 ~: Z" J( W  g0 c1 T" }
  11.   {  ) |6 X, w: |) L. r+ F9 ^/ V+ k
  12.     assert_param(IS_DMA2D_INPUT_COLOR_MODE(pLayerCfg->InputColorMode));9 c! Q& }' u) {4 o
  13.     if(hdma2d->Init.Mode != DMA2D_M2M)) g! |, E/ L- I) ^, z" C+ U7 G
  14.     {
    % f5 X6 e# R4 e3 E8 W! y
  15.       assert_param(IS_DMA2D_ALPHA_MODE(pLayerCfg->AlphaMode));
    ) k& g1 |# l) G7 C7 t
  16.     }
    5 C* O& n2 R; Z" b# c7 W" D
  17.   }
    & r# S5 V  Z1 s; i4 c7 u& t
  18. # r& ?/ _- E. X
  19.   /* 上锁 */
      H1 M- @  P# d6 S% J! y/ y6 d
  20.   __HAL_LOCK(hdma2d);
      t: z0 @0 h& D' Q' \
  21. " m5 ]  H* P+ H1 f
  22.   /* 设置DMA2D外设状态 */4 x: z# _: [. i: h% S5 \
  23.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  
    & [6 p7 w( V2 i; z! r
  24. 6 r' e3 k( ]; M
  25.   /* 准备好背景层或者前景层FPC寄存器配置参数*/
    ! y, M6 R# b7 ~
  26.   regValue = pLayerCfg->InputColorMode | (pLayerCfg->AlphaMode << DMA2D_POSITION_BGPFCCR_AM) | \
    8 B& m7 f2 S" a% D/ K' ~
  27.             (pLayerCfg->AlphaInverted << DMA2D_POSITION_BGPFCCR_AI) | \
    8 L5 g" t: M: n6 r
  28.             (pLayerCfg->RedBlueSwap << DMA2D_POSITION_BGPFCCR_RBS);& |$ h+ l, k* h

  29. , r; a' |, h* `5 `; o+ y
  30.   regMask  = DMA2D_BGPFCCR_CM | DMA2D_BGPFCCR_AM | DMA2D_BGPFCCR_ALPHA | DMA2D_BGPFCCR_AI | DMA2D_BGPFCCR_RBS;3 `* \; Y  c, o

  31. ) [0 n0 m4 |/ n( Y7 O, B2 F9 R* `
  32.   if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))+ C* L$ Y$ \- i
  33.   {8 C$ }7 Y' Z7 w7 B: W
  34.     regValue |= (pLayerCfg->InputAlpha & DMA2D_BGPFCCR_ALPHA);
    1 X- l( b- `, n2 f
  35.   }
    % ?' Z9 S2 z5 P( \
  36.   else, o, k; T7 e. S" v0 w. j# @, W
  37.   {
    * d0 Q! F) w, Q, G/ ~
  38.     regValue |=  (pLayerCfg->InputAlpha << DMA2D_POSITION_BGPFCCR_ALPHA);
    * u" K5 p' Q# D! D5 x* j
  39.   }
    4 o' `3 q; K. I: h3 J& n8 ~3 ?* O

  40. , y/ K: O* R: H8 C8 l- z  _- M( f/ z7 P6 F& s
  41.   /* 配置背景层 */; f' q$ ], ]$ M
  42.   if(LayerIdx == 0)
    ' f+ _" X# `) m8 t+ _5 D/ {
  43.   {
    * A, {6 {) k; o1 U3 ^
  44.     /* DMA2D BGPFCCR 寄存器 */
    % z9 K' [$ ^' S
  45.     MODIFY_REG(hdma2d->Instance->BGPFCCR, regMask, regValue);: k( s* u9 D  p0 }1 n2 v
  46. : D* z3 `: m9 L$ a; D4 L% U
  47.     /* DMA2D BGOR 寄存器 */  
    6 C8 p, C; X0 j9 {: t1 d  O
  48.     WRITE_REG(hdma2d->Instance->BGOR, pLayerCfg->InputOffset);. S( M9 O7 C" e7 t7 N# F8 @

  49. # b4 o" n& f8 M- k$ v- D5 S8 T2 P! p
  50.     /* DMA2D BGCOLR 寄存器 */
    # X1 M( c; e& c
  51.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    0 i2 n4 q% x0 `# ]
  52.     {    ) {/ {$ u7 |$ e6 g
  53.       WRITE_REG(hdma2d->Instance->BGCOLR, pLayerCfg->InputAlpha &
    ( P# d8 c2 n- o, G
  54. (DMA2D_BGCOLR_BLUE|DMA2D_BGCOLR_GREEN|DMA2D_BGCOLR_RED));9 Z4 C6 f; T, H: |9 J$ P
  55.     }    * w+ c' h- N, o# }
  56.   }
    0 m8 I* P+ b: a' O6 |
  57.   /* 配置前景层 */, r% g3 u* v4 }' h  j
  58.   else. @% C0 C  D( q5 b! i$ U  L# M
  59.   {/ y0 k" l9 a3 x& H
  60.     if(pLayerCfg->InputColorMode == DMA2D_INPUT_YCBCR)
    & [+ J+ k+ o8 Y8 R8 h
  61.     {5 B# q- d5 q; {( F
  62.       regValue |= (pLayerCfg->ChromaSubSampling << DMA2D_POSITION_FGPFCCR_CSS);
    $ l  n3 W* Y% I/ t* g& M; P
  63.       regMask  |= DMA2D_FGPFCCR_CSS;# P  u, s  k5 L6 K) R+ v: E5 I
  64.     }
    3 l: b* I' w: B; \/ \# w8 w

  65. , j. v2 w, P5 H  r. z# ~. H
  66.      /* DMA2D FGPFCCR 寄存器 */
    " j2 w( q( i2 \# n7 e- {5 \# v' G
  67.     MODIFY_REG(hdma2d->Instance->FGPFCCR, regMask, regValue);3 H8 a* k+ @5 D8 Y% V! i; D

  68. 1 o; @% {2 F( l- t! e, y* @
  69.     /* DMA2D FGOR 寄存器 */
    " {9 L6 W% }6 E( ], T% f- V
  70.     WRITE_REG(hdma2d->Instance->FGOR, pLayerCfg->InputOffset);      
    # j' Q. @3 e4 a& {4 Z8 x
  71. ' \/ _, q" e* |/ W
  72.     /* DMA2D FGCOLR 寄存器 */   5 f9 c  X' b9 T! A
  73.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    % Q- o3 m' U' s2 M. P8 P
  74.     {
    7 W4 N3 _* y. d: y% d5 X3 U2 f/ w
  75.       WRITE_REG(hdma2d->Instance->FGCOLR, pLayerCfg->InputAlpha & 2 A! f( D5 |- R* s7 Q0 h( s5 I# a' t
  76. (DMA2D_FGCOLR_BLUE|DMA2D_FGCOLR_GREEN|DMA2D_FGCOLR_RED));      
    / B- r: f9 ^4 F* s" D2 l: {
  77.     }   
    5 a0 h) Z& u% Y/ S$ u1 v+ `
  78.   }   
    2 M  u/ g2 O4 G- z* _) G3 n. n
  79.   /* DMA2D就绪 */9 {6 R/ d0 B# j( V' h, V
  80.   hdma2d->State = HAL_DMA2D_STATE_READY;3 R/ C& U7 @  d

  81. 0 R+ a' u* K0 d* A
  82.   /* 解锁 */, b' s) Q7 ^! b6 @5 @
  83.   __HAL_UNLOCK(hdma2d);  ( a, h- L" W" p  _4 ]
  84. 5 F' j5 Y: `- P  h: H+ q- g
  85.   return HAL_OK;
    " B) }8 ]8 f5 Z* ]4 U
  86. }
复制代码

$ O, ]9 R  k0 M* l函数描述:# u- ^/ J: ^2 y+ e& s; C( P
6 s. |, y) D- Z7 x
此函数主要用于配置DMA2D要转换的前景层和背景层,即输入颜色配置。而前面的函数HAL_DMA2D_Init配置的输出颜色。: J% i/ L/ \$ U% F' |
1 y% C; J) y1 f- P' H0 K+ B) a: a
函数参数:# O+ t$ e# u3 _4 `  N
3 C! ~$ X8 z: @% h, A- R8 Q
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。
# W+ I- D/ g0 O0 h* x9 J* }  {& r  第2个参数用于配置前景层和背景层,0表示背景层,1表示前景层。8 i$ v  s8 C, b4 O9 L
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
+ m$ y+ D& Z7 T9 N; r6 K0 {' t) X使用举例:
! p6 V% |5 G% D! u, |
  1. : @- o- l* T! M. l) b1 i) L- z) P, c" Y! w
  2. DMA2D_HandleTypeDef Dma2dHandle;
    0 z$ |  @& U! U; y- V% b, O8 B

  3. 0 m, |! R- s, Z/ `: M; |! n
  4. ; P; H" S1 s) [4 Y6 t4 f* d; f* M
  5. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/8 [* H+ c9 }/ E  a" S1 b( `
  6. Dma2dHandle.Instance = DMA2D;
    1 H: y% P( v2 A+ h# Y, l

  7. 5 K" l' d7 u( {; U
  8. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */, h! L9 D3 k- I+ ]9 I2 k; V3 b
  9. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */
    3 ?4 [* o% O" `! X1 o
  10. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */
    % i' i' Y) C" t9 ~( a% ~
  11. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 *// }$ g2 m- q0 ?: s1 o0 M3 a
  12. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */
    . I1 n$ n3 X  Q; p( V* t
  13. + t7 Z$ e( y6 Y0 ^4 ~0 b$ Q5 q
  14. /*##-2- DMA2D 回调函数配置 ######################################*/9 A, Y) D7 F* Q+ ^% [2 a6 A( k
  15. Dma2dHandle.XferCpltCallback  = TransferComplete;
    1 t! g( ?- D- K, `% v* V) C9 _
  16. Dma2dHandle.XferErrorCallback = TransferError;
    8 S" t. W; E. E8 Y

  17. 3 h8 K+ T' }7 }" b- W% q
  18. /*##-3- 前景层配置 ###########################################*/
      C+ ?: Z7 x5 N1 u# \* w; P) j  m
  19. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */
      d* {* d1 T: Z3 Q
  20. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */+ Z* x  ?4 R7 ]! A8 E; ^3 ~8 A
  21. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */
    7 T1 F% \. ~$ ^* P+ u- h
  22. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */
    + S) [& N0 H0 D
  23. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/
    9 f: y; f6 d: t0 O8 k6 J
  24. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/
    % e' j" c0 L; g3 M& h9 g5 R3 |

  25. / G' y8 F9 d/ M/ W
  26. /*##-4- DMA2D 初始化 ###############################################*/
    9 r2 b0 H# [7 A# a7 g
  27. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
    + A/ p: u* K# o
  28. {+ X0 K0 X6 p; _' D
  29.     Error_Handler();1 H5 M2 t* \9 n/ j9 C- U
  30. }! r, _9 A0 ?$ {, s
  31. ! h. @1 Q+ U: F: B; M6 U0 A! d
  32. /* 配置前景层  */6 R4 a: e% P# r1 p; L
  33. if(HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1) != HAL_OK)" S" o: T0 i2 U4 M- d. s
  34. {
    ; ~" Q' s+ O# R- C. l- ^
  35.    Error_Handler();
    5 r" {6 P4 I0 y* @: d; x2 ~
  36. }
复制代码
; R0 H4 w- s; o6 ?7 }2 ]5 X5 h

$ h/ o' J1 T! \55.4.3 函数HAL_DMA2D_Start_IT! L. C) k3 r6 |4 W4 }" ~' H! r
函数原型:
9 L: }7 Q1 f. U, h# n8 N
( Y8 |3 o: _5 r) s
  1. HAL_StatusTypeDef HAL_DMA2D_Start_IT(DMA2D_HandleTypeDef *hdma2d, uint32_t pdata, uint32_t DstAddress, uint32_t Width,  uint32_t Height)1 q7 T' ^) _& F9 w  J9 A0 V, N" {/ ^
  2. {& n6 E8 l" n' E9 C2 t" }7 J3 q  M
  3.   /* 检测函数形参 */
    8 C7 v: A0 i' n
  4.   assert_param(IS_DMA2D_LINE(Height));
    8 p; }& K1 A4 z1 F
  5.   assert_param(IS_DMA2D_PIXEL(Width));
    ( x* K/ b+ [$ @" _. L: G4 I
  6. ! q/ H& I8 `( I  s
  7.   /* 上锁 */
    - d* a8 U* o5 o3 G
  8.   __HAL_LOCK(hdma2d);* w7 v  y/ e  k6 J  ~9 K6 |
  9. 6 a$ f. g% X* X& g- R8 c4 ^
  10.   /* 设置DMA2D外设状态 */
    0 o# Z' U$ p/ ^7 B) ?
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;% T8 D; M7 ^# j4 w/ R3 a

  12. 4 I) y2 M, `6 t8 b: J
  13.   /* 设置源地址,目的地址和数据大小 */+ e+ a2 W- ?2 a1 k& S
  14.   DMA2D_SetConfig(hdma2d, pdata, DstAddress, Width, Height);/ d0 A9 V; f" s- q- f

  15. ! Y: N  B" |1 H( ?( q. P. Y- }! C$ Y
  16.   /* 使能DMA2D的传输完成中断,传输错误中断和配置错误中断 */8 x9 j5 C# M; I  ~, x# a+ J
  17.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);% A; M( l+ V& {0 S
  18. ( ]2 w: R8 z1 x! d
  19.   /* 使能DMA2D */
    - l; k7 [. }* V! D8 o
  20.   __HAL_DMA2D_ENABLE(hdma2d);
    ' q9 k2 u  W/ J7 D
  21. $ [% B5 r- p  k4 e+ Z
  22.   return HAL_OK;
    4 l7 h, @  Y1 Q; g1 @
  23. }
复制代码
% [; h& H- u+ U  }3 D
函数描述:1 v  D; U) n3 E+ W8 X! u

; R- c0 `/ G7 N0 o此函数用于启动DMA2D数据传输。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。3 L0 ?9 ~8 C' Z1 n: ^: E$ s
1 i2 h: V/ |# ]- f
函数参数:' y/ t+ ]% B: f) _

' w: O7 a! J6 c$ X% n" C+ ^) m  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。; J- n/ ?$ T$ t/ C
  第2个参数是源数据地址。& E; _9 Z& g0 o' z8 x1 L4 E
  第3个参数是目的数据地址。
( v" v3 I* r. ]0 H  第4个参数是源数据的长度,即每行的像素个数。3 R2 w( R, b) p0 ~( ~1 e
  第5个参数是源数据的高度,即行数。
) s) Z) i$ e9 A7 [: d* G4 y  f  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
0 x/ J2 u9 b& i4 R使用举例:8 ~( B$ q* _6 q
# v  ~7 m. n# j2 r
  1. DMA2D_HandleTypeDef Dma2dHandle;
    6 F5 D  |; n$ f0 K; l1 ~
  2. $ f3 G! O7 Z8 v0 v
  3. if(HAL_DMA2D_Start_IT(&Dma2dHandle,            /* DMA2D句柄 */
    3 G; `6 c6 C5 f/ L
  4.                       (uint32_t)&BufferInput,  /* 源地址 */
    6 O, H) n/ L( n( w" O9 j' |
  5.                       (uint32_t)&BufferResult, /* 目的地址 */' U( ]: v! `( p3 l
  6.                       SIZE_X,                  /* 源数据长度,单位像素个数*/# M4 M, |) x: B/ p. G3 E/ i1 a
  7.                       SIZE_Y)                  /* 源数据行数 */
    2 _( C, J. r9 S- G/ i2 j& {2 \0 e. @
  8.    != HAL_OK)
    ) j0 ]+ b; p! R, w
  9. {
    2 u  y( ]' S2 N2 l3 {9 t6 t
  10.    Error_Handler();: u) l# M$ Y5 o  z) a3 P1 Y
  11. }
复制代码
9 c5 _% r  o# e7 s& ?0 }; H2 J7 p
55.4.4 函数HAL_DMA2D_BlendingStart_IT
0 }& N1 P$ [( q函数原型:% w) O' f8 X( E

# w3 L! n) m% Z. i  }8 s6 L
  1. HAL_StatusTypeDef HAL_DMA2D_BlendingStart_IT(DMA2D_HandleTypeDef *hdma2d, uint32_t SrcAddress1, uint32_t  SrcAddress2, uint32_t DstAddress, uint32_t Width,  uint32_t Height)
    7 q5 Q" I5 }7 i8 L" e& f  j
  2. {  f  k  q+ f& P1 f+ Z9 A) q
  3.   /* 检测参数 */
    ) p6 m6 W  j* J: y' V0 B# |
  4.   assert_param(IS_DMA2D_LINE(Height));
    " k( I9 M4 I  m/ O1 s- U" I/ s; Y
  5.   assert_param(IS_DMA2D_PIXEL(Width));
    8 O( r) ]* y/ ~% U
  6. 0 `# S' H2 U- \8 f# N3 d' @3 ^
  7.   /* 上锁 */
    ; K1 i! j) L1 {) Q: y
  8.   __HAL_LOCK(hdma2d);" U  F% L$ S. T! s0 f& X8 K- G! u

  9. 0 Y9 I, `5 c3 M8 H  @5 ~. _6 Z: u, E
  10.   /* 设置DMA2D外设状态 */
    8 [3 j! h- D0 p! L% q
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;* z! L  }# m+ [/ B5 E

  12. - L# o( I* R2 d9 S9 N) u/ C$ F0 i
  13.   /* 配置DMA2D源地址2 */
    $ I; \4 \3 L, m0 }4 o
  14.   WRITE_REG(hdma2d->Instance->BGMAR, SrcAddress2);
    8 F" w0 p7 |1 g4 |2 @
  15. ; _6 @6 r$ W1 r  s$ ]
  16.   /* 配置源地址1,目的地址和数据大小 */
    ! F+ |, J$ k' D; E' t" d  j* N6 o
  17.   DMA2D_SetConfig(hdma2d, SrcAddress1, DstAddress, Width, Height);, U% v2 [% V3 B8 \7 Z

  18. 8 }- w9 s9 f, j
  19.   /* 使能DMA2D传输完成中断,传输错误中断和配置错误中断 */# d7 \' \/ i4 v% l; l
  20.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);: M1 n5 U" H; ~$ Y7 C
  21. # G: v6 a4 D% w8 P
  22.   /* 使能DMA2D */% o( g  h5 q, `' x
  23.   __HAL_DMA2D_ENABLE(hdma2d);
    $ v3 @" r7 ^7 I" j6 }2 A4 L

  24. " O1 G1 A" K" N1 t+ X
  25.   return HAL_OK;" D( s/ o' {7 x7 U" i+ V
  26. }
复制代码

5 M6 p% I+ I# ^& u函数描述:; Y, v0 }7 e, S0 D9 l. r2 F

- y, Q/ d5 f2 G3 F3 Z; D$ ~6 W& A此函数用于启动DMA2D传输,除了数据传输以外,还支持颜色格式转换和颜色混合。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。
% m& K2 X! G3 a! Y0 I  e* K- S7 j7 R% e
函数参数:8 l4 `9 d6 ?5 q" a+ B: C6 \

! [) q+ O7 ?! F8 z0 z! I  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。1 l! ]( S  i$ s1 B4 l
  第2个参数是源数据地址1。+ P  ~7 l' L1 O/ p6 S  c
  第3个参数是源数据地址2。
. J/ d& o8 r( s' }* w. U  第4个参数是目的数据地址。) b6 V" C" J) g- W, ]
  第5个参数是源数据的长度,即每行的像素个数。
; I+ _; ]# d/ H2 e  第6个参数是源数据的高度,即行数。7 U! M) b8 f; D! k7 N8 G/ t
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。# F& I  N- _& Z$ [
使用举例:
+ f7 k7 H# P+ {8 ~) }+ t9 y8 N; K5 C( t2 U" Y# H: O
  1. DMA2D_HandleTypeDef Dma2dHandle;/ q3 {* Z/ {  G. u1 u
  2. , h9 Q8 o0 \  t$ L8 b; |6 o+ I1 n
  3. if(HAL_DMA2D_BlendingStart_IT(&Dma2dHandle,           /* DMA2D句柄 */
    2 }8 E6 }0 i3 v: w6 B' E, s
  4.                              (uint32_t)&BufferInput1, /* 源地址1,前景色 */
    4 u. ~' `4 V% v
  5.                              (uint32_t)&BufferInput2, /* 源地址2,背景色 */
    5 u; E! \: C$ M5 G) z- @
  6.                              (uint32_t)&BufferResult, /* 目的地址 */  T, u# M4 e" W$ i) `
  7.                               SIZE_X,                 /* 源数据长度,单位像素个数*/
    3 L7 v; P! ?! g
  8.                               SIZE_Y)                 /* 源数据行数 */+ k! ~- |  x1 @8 \" b  \- h
  9.    != HAL_OK); k& [9 j+ p; g+ l7 A) D
  10. {
    / ^! U) E0 g* m/ K) R$ k
  11.    Error_Handler();
    . d, X  X( K5 N; W. S) X
  12. }
复制代码
1 v0 ^) c& U8 J8 p7 X

. n6 ]# f0 o' [2 i# c5 G  ~3 w, h9 r55.5 总结
$ w: g  f8 ]4 t, j3 U* x0 E本章节就为大家讲解这么多,DMA2D功能比较重要,一定要做到熟练使用。
' M) E; ^; v5 M* q" U8 a; S. B4 S9 @4 d8 P# g$ Q; ~

! Y% ^2 p, P' F8 y: C
# |& G' X1 c: k3 o4 \) y% l) X. v% ?7 ]
收藏 评论0 发布时间:2021-12-24 17:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版