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

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

[复制链接]
STMCU小助手 发布时间:2021-12-24 17:00
55.1 初学者重要提示0 t- h. r; Z6 V  P& B
  DMA2D是专门用于LCD加速的,特别是刷单色屏,刷图片,刷Alpah(透明)混合效果全靠它,而且可以大大降低CPU利用率。
/ Q1 @. T$ D2 w2 j3 k" F  测评STM32H7的LTDC+DMA2D性能,100Hz以上无压力,刷800*480图片和色块仅需2.6ms一张: D- h( g+ @/ t. A* i
  H7的DMA2D与F429的DMA2D最大区别是支持了ARGB和ABGR互转,而且支持H7的硬解JEPG输出格式YCbCr转RGB,方便LCD显示。' O1 W* R5 W4 ?8 O# m
  特别注意,大家只需对HAL库提供的DMA2D操作API有个了解即可,实际工程中,并不使用这些API,我们需要使用更加高效的寄存器直接操作,在下一章节会为大家说明。  v2 F. a5 ?! v- X- h5 C1 z
55.2 DMA2D基础知识
; D5 g7 n* W3 N/ u3 t, i% W) @DMA2D主要实现了两个功能,一个是DMA数据传输功能,另一个是2D图形加速功能。
7 `+ g% j0 k# c, T+ ^6 E$ D# r! i% s+ }
1 L( P# q+ J% h4 U  DMA数据传输
6 C! ?8 w2 v. I0 A主要是两种方式,一个是寄存器到存储器,另一个是存储器到存储器。通过DMA可以大大降低CPU的利用率。! U: X8 h% d+ ~
" Q+ T# ~7 Y3 T0 j+ J
  2D图形加速功能+ J! }0 G  w  ]3 |: R+ m
支持硬件的颜色格式转换和Alpha混合效果。- ?7 e0 ~4 l' H

7 N$ y( h# Y- t9 }2 w55.2.1 DMA2D硬件框图
& h5 i, m  S8 d  Y; I' D0 c认识一个外设,最好的方式就是看它的框图,方便我们快速地了解DMA2D的基本功能,然后再看手册了解细节。框图如下所示:
, N8 E/ o) s: r- x8 v! L* J) \% e6 G. k$ s% s1 e% d
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
( `5 `, F7 M% A& Q
7 W& M) B; E5 a: Z8 D
通过这个框图,我们可以得到如下信息:
8 k, j8 @/ V/ Y, |& I! _$ \' T% ?1 L
  dma2d_aclk9 f$ `% r' J" q7 S
AXI 总线时钟输入。7 Z9 ~7 O8 v0 R0 Q% ~
$ h. \: S# A5 R" r3 }7 F% b
  dma2d_gbl_it6 @0 X" P# W6 {5 f
DMA2D全局中断输出。( d6 r+ h! g( _
. z  z) M+ A: f) V' E
  dma2d_clut_trg2 F  ?) P% x2 H
CLUT传输完成信号输出,可以触发MDMA。
# f$ m+ l+ f8 f$ e0 R8 _
0 l- ?# l2 r# `. w: f0 Q  dma2d_tc_trg
/ f3 c! |( n$ o传输完成信号输出,可以触发MDMA。1 e5 U$ J. _2 ^9 P( A+ g) V
6 U6 a& q' }3 s* S" n; D
  dma2d_tw_trg
5 n1 I* G7 ~# ~' W2 n$ z; ~传输watermark信号输出,可以触发MDMA。
7 W- C" V/ f: \. ]
! V8 e, L& {5 j" i4 R将这个硬件框图简化一下,就是下面这样:
/ C+ Q$ y  D; O; h  M2 ~; F, ?
6 ?2 N8 d. C& c# e
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
+ U; n# v- i; o9 h# v' C+ i, j
; ~% A; I) }" w  U: L" J4 r
下面按照简化的硬件框图,对每个部分做个说明。
% A" ~2 p/ I, G. K: S" l7 @. b8 Q% [
55.2.2 DMA2D工作模式
6 e; b6 @6 t. x# @DMA2D支持的工作模式如下:
; t: b, V$ k$ _
4 K$ W" Z( s" ~( A6 L8 v  模式1:寄存器到存储器模式3 _9 `% b' ~5 Q- U: U
这个模式主要用于清屏,也即是将显示屏清为单色效果。
: S" F) i( h9 r+ E/ t+ g* `
+ h/ R( a2 ~* N$ t) `5 a  模式2:存储器到存储器模式
4 j& [0 K1 N7 W9 O; o- ~' Y这个模式用于从一个存储器复制一块数据到另一个存储器,比如将摄像头OV7670的输出图像复制到LCD显存就可以采用这种方式。0 v8 M, x; Z1 s- K4 R

! @' _3 q0 @  v$ x. g& |0 r2 J; Q4 G$ g  模式3:存储器到存储器模式,带颜色格式转换
1 W6 d, h. G5 x- [这个模式比模式2多了一个颜色格式转换,比如我们要显示一幅RGB888颜色格式的位图到RGB565颜色格式的显示屏,就需要用到这个模式,只需输入端配置为RGB888,输出端配置RGB565即可。位图颜色格式转换后会显示到显示屏上。5 k& C$ X) I( Y8 d7 z4 t4 J8 J

4 j2 |! @8 n8 D9 |( n1 S) O  模式4:存储器到存储器模式,带颜色格式转换和混合
! d2 x' u- a, u( V# n4 D这个模式比模式3多了一个混合操作,通过混合,可以将两种效果进行混合显示。
: I0 t- Y; o) k5 C$ s: U
2 h; j! Y8 J: X  模式5:存储器到存储器模式,带颜色格式转换和混合,前景色是固定的
7 L9 B6 }; K( ?' ^4 k( R+ `5 [同模式4,只是前景色的颜色值是固定的。
' e8 l" Y4 d! B; o& M! ]
/ Q6 g+ V) I7 ?: q, B2 `55.2.3 前景层和背景层的输入以及颜色格式转换
  ]- {, s& z5 R前景层和背景层是指的用户绘制图形时的前景色和背景色,比如我们显示汉字,字体会有一个颜色,也就是前景色,还有一个背景色。又比如我们绘制两幅图片,想将两幅图片混合,那就可以将一幅图片作为前景层,另一个幅图片作为背景层。# k+ p! @$ l% [) c4 a
0 Y4 Q% I) a/ M! ?, C
DMA2D支持的输入颜色格式如下,前景层和背景层一样:: ]. B+ N" j, P

! V6 M0 _7 X! z1 e9 @8 h* E
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

2 I, M) ?, F8 Y+ d% r
  }9 E# D8 n  `. R  _1 b前8种颜色格式在第50章的第2小节开头有介绍,这里把后四种做个说明:
% g, @  J/ h% v6 M1 @1 V6 Q1 j2 Q  [" b$ }
  L4 (4-bit luminance or CLUT)$ u& h( a2 J$ K. U4 Y0 P
4位颜色格式,实际上仅仅是4位索引值,范围0–15,而每个索引值的具体颜色值在查色表CLUT里面存储。
. Q, d; P0 Y, _6 r8 f# o% O5 @' {
- _! b3 ]. b: p* p$ s  b  A4和A8
7 P- W5 k* d( P- O1 K4 SA4和A8用于特定的Alpha模式,既不存储颜色信息,也没有索引值。5 z4 s$ E* f! w% s3 R% d  D
- Q- D6 l2 y2 ]; s3 o8 S; O5 S7 H
  YCbCr; U$ v$ p7 r$ z1 U6 c7 f
这个是H7的硬件JPEG输出的颜色格式,后面JPEG章节为大家专门做讲解。5 v, G8 Z5 [. }: g0 S. S* E

3 K4 k* F9 k9 T这里特别注意一点,输入颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。
) q9 |& u& Q( u. N- }! E' b
: {" I: r: l, v& Q! e$ C: p55.2.4 前景层和背景层混合
- f0 }* n1 {3 ODMA2D混合器用于混合前景色和背景色,这个功能不需要任何配置,仅需要通过DMA2D_CR寄存器使能即可。混合公式如下:2 u7 D6 R  B1 @; P# W. O4 J

; j- X+ U0 u) g9 y5 X3 Z
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

! Q  x1 R! v6 U& C# X8 e# k% z3 k& a( a2 I- q
55.2.5 DMA2D输出颜色格式
/ }5 ]6 [# k) y$ }9 ~DMA2D支持的输出颜色格式如下:' y5 o! }4 j* [% U9 l4 ?
. k. a/ _, b  Z7 ?7 p& m
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

. l# c; g; Z4 s0 s0 d- q
; }) x3 L% r! D2 g9 ^. \这里特别注意一点,输出颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。
$ R# m/ o" O+ y: @  i+ O* z- h( l
: L, `9 U' i% k5 y1 z# L55.3 DMA2D的HAL库用法; ]  ~' q- S5 u; p
DMA2D的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断。下面我们逐一展开为大家做个说明。4 B, h9 F' L- p
: f+ r& m! w( b) `. @
55.3.1 DMA2D寄存器结构体DMA2D_TypeDef
; }9 M$ ?0 s! s9 o" j; q/ J. m# j+ JDMA2D相关的寄存器是通过HAL库中的结构体DMA2D_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:
0 R9 o3 `* |7 N/ D5 K2 A& {6 S/ O) |$ \  s% ?1 b
  1. typedef struct$ H9 @) E# T. R
  2. {
    + i! Q* Z) J* v& b
  3.   __IO uint32_t CR;            /*!< DMA2D Control Register,                         Address offset: 0x00 */
    5 g+ |" [& l- R( L: G
  4.   __IO uint32_t ISR;           /*!< DMA2D Interrupt Status Register,                Address offset: 0x04 */
    & A6 V& o+ C7 Y$ F1 }( g2 z! e
  5.   __IO uint32_t IFCR;          /*!< DMA2D Interrupt Flag Clear Register,            Address offset: 0x08 */: k: z) a9 o* H$ ]
  6.   __IO uint32_t FGMAR;         /*!< DMA2D Foreground Memory Address Register,       Address offset: 0x0C */: O  Z0 H+ |* c
  7.   __IO uint32_t FGOR;          /*!< DMA2D Foreground Offset Register,               Address offset: 0x10 */3 C" M' X: v# `+ p+ |( U
  8.   __IO uint32_t BGMAR;         /*!< DMA2D Background Memory Address Register,       Address offset: 0x14 */' }( _+ U, \* Z1 M; B
  9.   __IO uint32_t BGOR;          /*!< DMA2D Background Offset Register,               Address offset: 0x18 */
    3 o( N7 u. T4 O7 F8 S+ y/ q
  10.   __IO uint32_t FGPFCCR;       /*!< DMA2D Foreground PFC Control Register,          Address offset: 0x1C */
    " |% O) j  P# s8 i7 t1 W
  11.   __IO uint32_t FGCOLR;        /*!< DMA2D Foreground Color Register,                Address offset: 0x20 */6 r% f0 z/ e  ?5 O( c1 ]) O( F
  12.   __IO uint32_t BGPFCCR;       /*!< DMA2D Background PFC Control Register,          Address offset: 0x24 */+ C( ~; G6 T' {/ G
  13.   __IO uint32_t BGCOLR;        /*!< DMA2D Background Color Register,                Address offset: 0x28 */6 j4 k3 m6 g3 n+ R8 {$ M
  14.   __IO uint32_t FGCMAR;        /*!< DMA2D Foreground CLUT Memory Address Register,  Address offset: 0x2C */# m& c  j: B; ~' T! z/ n6 P9 A
  15.   __IO uint32_t BGCMAR;        /*!< DMA2D Background CLUT Memory Address Register,  Address offset: 0x30 */
    & g5 R' D" z+ U
  16.   __IO uint32_t OPFCCR;        /*!< DMA2D Output PFC Control Register,              Address offset: 0x34 */
    7 ~- e) m( o* c8 M  _
  17.   __IO uint32_t OCOLR;         /*!< DMA2D Output Color Register,                    Address offset: 0x38 *// |- E) y& c3 A0 x5 C
  18.   __IO uint32_t OMAR;          /*!< DMA2D Output Memory Address Register,           Address offset: 0x3C */, A' d% Z4 }8 Z  _! N- {
  19.   __IO uint32_t OOR;           /*!< DMA2D Output Offset Register,                   Address offset: 0x40 */- V- M; y' K+ C5 \7 F
  20.   __IO uint32_t NLR;           /*!< DMA2D Number of Line Register,                  Address offset: 0x44 */" h1 m, R6 ]+ {; Z
  21.   __IO uint32_t LWR;           /*!< DMA2D Line Watermark Register,                  Address offset: 0x48 */
    % Y. W# `1 d# M1 j% D
  22.   __IO uint32_t AMTCR;         /*!< DMA2D AHB Master Timer Configuration Register,  Address offset: 0x4C */
    3 J4 n1 \9 Y! \# V2 c9 l
  23.   uint32_t      RESERVED[236]; /*!< Reserved, 0x50-0x3FF */* z1 I. P7 g/ {, [: D% K! P! B
  24.   __IO uint32_t FGCLUT[256];   /*!< DMA2D Foreground CLUT,                          Address offset:400-7FF */+ g2 a5 `7 |. t+ c3 |' w
  25.   __IO uint32_t BGCLUT[256];   /*!< DMA2D Background CLUT,                          Address offset:800-BFF */% j; v1 N" R5 n4 [$ d& z
  26. } DMA2D_TypeDef;
复制代码

2 S5 ?3 p1 m& ?. X. u$ X5 `" Y( {% N3 j5 [; q
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:& X, {% o) G% C, i
. f% ^9 W. I" p- k/ d( `" z
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
    6 n0 D) i5 ^4 ?! i
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
; d; y' v3 h* K/ I7 @
下面我们再看DMA2D的定义,在stm32h743xx.h文件。
  1. #define PERIPH_BASE              ((uint32_t)0x40000000)
    0 P2 s2 m' \2 @( d( Z/ h* L+ F& e& O" _
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000)
    2 g- e, {" A8 `" D/ s  b2 ?$ k" j9 ^
  3. #define DMA2D_BASE               (D1_AHB1PERIPH_BASE + 0x1000)
    $ V3 X& r0 v5 a( v+ h+ `8 X
  4. #define DMA2D                    ((DMA2D_TypeDef *) DMA2D_BASE) <----- 展开这个宏,(DMA2D_TypeDef *) 0x52001000
复制代码
4 T- l! D8 \( H( Y* P2 V  Z0 _2 Y
我们访问DMA2D的ISR寄存器可以采用这种形式:DMA2D->ISR = 0。
/ {/ \0 Q6 K$ Z: Z( C5 U" k( S' ^/ `+ s8 C/ u& r2 l9 y. f
55.3.2 DMA2D参数初始化结构体DMA2D_InitTypeDef
% I3 T1 z; O4 A$ R此结构体用于配置DMA2D的基本参数,具体定义如下:
6 Y! Y+ X8 X4 }
7 m4 Y! Y- w3 P; }
  1. typedef struct
    - B* X6 |! V( y+ T& A1 |6 {2 H
  2. {
    - N/ r/ S3 d) E
  3.   uint32_t             Mode;                W9 i+ r6 n* E0 l) ~1 M
  4.   uint32_t             ColorMode;        
    3 H! \: W$ N% ^( q7 \
  5.   uint32_t             OutputOffset;       ( D6 [, A* Y$ S) n% C! z5 e+ R' ^
  6.   uint32_t             AlphaInverted;    # i3 f3 b- k0 B0 `/ k1 U* p9 F7 H% A
  7.   uint32_t             RedBlueSwap;      
    3 p, o- X6 D& @) A: ~
  8. } DMA2D_InitTypeDef;
复制代码
+ a/ Z0 x2 s$ M& h& m9 E$ u4 g
下面将这几个参数逐一为大家做个说明:  o# ]5 `6 C; Q4 S8 K: a
8 f7 I  }/ M" x: U
  uint32_t   Mode
/ L6 w3 \4 y8 D8 b9 u. q此参数用于设置DMA2D的传输模式,具体支持的参数如下:
  T4 K% p7 Y/ g" [. f% v2 j# U4 z# Q/ i/ q
  1. #define DMA2D_M2M        ((uint32_t)0x00000000U)  /*存储器到存储传输模式 */* t' ^/ R. i6 f1 s9 `
  2. #define DMA2D_M2M_PFC     DMA2D_CR_MODE_0         /*存储器到存储器传输模式,并执行FPC像素格式转 */
    2 J' L" r- v4 w3 [( y& S8 l
  3. #define DMA2D_M2M_BLEND   DMA2D_CR_MODE_1         /* 存储器到存储器模式,并执行像素格式转换和混合 */
    0 w. @0 t- W. o0 \
  4. #define DMA2D_R2M         DMA2D_CR_MODE           /* 寄存器到存储器传输模式 */
    # f* X& O& g6 S! o
复制代码

$ X2 C& `; s% x( ]4 ~
5 d8 u8 J4 s, W) K) [; P$ j  uint32_t   ColorMode
# H% I3 J8 A' c* c, C此参数用于设置DMA2D的输出颜色格式,具体支持的参数如下:; u0 k+ T8 S8 r- x) u# v# T

, P9 q# v6 [  y6 B* J8 G
  1. #define DMA2D_OUTPUT_ARGB8888       ((uint32_t)0x00000000U)               /* ARGB8888 */
    # W: M1 K- c8 I7 O5 ~, r0 S8 c
  2. #define DMA2D_OUTPUT_RGB888         DMA2D_OPFCCR_CM_0                     /* RGB888 */
    * }1 E1 F. F) s/ ?  H1 c( k
  3. #define DMA2D_OUTPUT_RGB565         DMA2D_OPFCCR_CM_1                     /* RGB565 */; i5 j' H( v1 T% [1 @. }
  4. #define DMA2D_OUTPUT_ARGB1555       (DMA2D_OPFCCR_CM_0|DMA2D_OPFCCR_CM_1) /* ARGB1555 */4 @' S: z3 D5 d9 m- t
  5. #define DMA2D_OUTPUT_ARGB4444       DMA2D_OPFCCR_CM_2                     /* ARGB4444 */: M9 ]1 u0 L% t& Q
复制代码
0 ^+ {! ]" x8 T' K

( h1 @0 x. `1 G0 t' P3 b0 j# \4 F) U  uint32_t   OutputOffset" g' M! `$ O& T8 Q
此参数用于设置输出位置的偏移值,参数范围0x0000到0x3FFF。
# T3 I4 }3 Y! M' M# C* ]! e' h+ {9 @
  uint32_t   AlphaInverted
) E* E2 u4 }8 L0 O( A此参数用于设置DMA2D的输出颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     " x# y7 F5 c, N* ?% B0 W0 Z: @1 [5 T
1 b/ w% L) r$ V5 V, @
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */( q1 Q$ Z, W1 G, ^
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */
复制代码
( t! U) d) m8 P3 w+ R, I' s- d
  uint32_t   RedBlueSwap6 _0 [1 h" P6 g5 O
此参数用于设置DMA2D的输出颜色格式中R通道和B通道的交换,具体支持的参数如下:
8 x" T* V1 w' t+ T, q7 b! i* B
- g$ o; o1 l* }/ z$ D0 w( D" `
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */
    # o2 }' f. q* A' ?
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码

9 i4 P/ x, q2 G, M( _! X9 [55.3.3 DMA2D的图层结构体DMA2D_LayerCfgTypeDef
8 Y! |: G" G/ z9 ~/ x& Q! R此结构体用于配置前景色和背景色。
# M: \2 ?) V3 ?4 v$ t. F0 P6 C0 }+ ]$ g$ _
  1. typedef struct7 R7 e1 P2 v/ C9 A6 Q8 @
  2. {3 e7 }2 V- \& o6 G
  3.   uint32_t             InputOffset;       , `) E) U; U9 C% V" f) u- _
  4.   uint32_t             InputColorMode;   
    % M: o7 U6 ~" G4 R' `
  5.   uint32_t             AlphaMode;        - c, E3 z/ F0 P9 i
  6.   uint32_t             InputAlpha;        # R" ?! f( O! ~$ _
  7.   uint32_t             AlphaInverted;    9 h. C1 P1 H( `- e; b; v
  8.   uint32_t             RedBlueSwap;       ( e4 t5 w7 L8 F" m+ L2 i; l
  9.   uint32_t             ChromaSubSampling;! f; g4 P* y' L1 M, ^0 C
  10. } DMA2D_LayerCfgTypeDef;
复制代码
7 `, X: t0 O+ e  O" R
下面将这几个参数逐一为大家做个说明。
$ f8 ?' x2 N; l# V3 D! X+ S& u4 B+ ]) B  k  s5 A* H- |
  uint32_t  InputOffset
$ t# m4 t8 V4 s3 E$ w. I设置前景色或者背景色的输入偏移,范围0x000到0x3FFF。
3 Q6 J& i/ _/ o
; I# B. n  V1 R( [  uint32_t  InputColorMode' V" h( V+ T: u/ P9 T) D
设置前景色或者背景色的输入颜色格式,具体支持的参数如下:# X$ P7 `+ e. @2 I( U) I
3 s7 N$ h8 z4 ]* H+ t$ _
  1. #define DMA2D_INPUT_ARGB8888        ((uint32_t)0x00000000U)  /* ARGB8888 */
    $ y0 A+ d: V0 D
  2. #define DMA2D_INPUT_RGB888          ((uint32_t)0x00000001U)  /* RGB888   */
    " o% P0 v( [$ V- q) c' E2 G# z" \; H+ Y) Z
  3. #define DMA2D_INPUT_RGB565          ((uint32_t)0x00000002U)  /* RGB565   */% k/ g6 M5 t6 _+ E
  4. #define DMA2D_INPUT_ARGB1555        ((uint32_t)0x00000003U)  /* ARGB1555 */$ G/ j. s6 X  \9 B: g
  5. #define DMA2D_INPUT_ARGB4444        ((uint32_t)0x00000004U)  /* ARGB4444 */+ g( i# |4 U+ l8 x2 o# I& j* q  G
  6. #define DMA2D_INPUT_L8              ((uint32_t)0x00000005U)  /* L8       */, p/ \5 }5 N8 k: k
  7. #define DMA2D_INPUT_AL44            ((uint32_t)0x00000006U)  /* AL44     */
    # D; X2 o( F5 p+ U
  8. #define DMA2D_INPUT_AL88            ((uint32_t)0x00000007U)  /* AL88     */
    ! e; b: Y4 `/ t! C7 F+ z
  9. #define DMA2D_INPUT_L4              ((uint32_t)0x00000008U)  /* L4       */; ?, s0 G0 ~( d3 Z  z1 c0 ]
  10. #define DMA2D_INPUT_A8              ((uint32_t)0x00000009U)  /* A8       */5 j: i$ C* i) P) c1 M0 G
  11. #define DMA2D_INPUT_A4              ((uint32_t)0x0000000AU)  /* A4       */6 E: _7 x4 e' b
  12. #define DMA2D_INPUT_YCBCR           ((uint32_t)0x0000000BU)  /* YCbCr    */
复制代码

5 G5 X. T$ r& H6 F  uint32_t AlphaMode# M7 T5 N! I) E: I8 J! K7 Y
设置前景色或者背景色的Alpha模式,具体支持的参数如下:  `5 j0 T2 ^0 F2 _
' |4 S0 }& A9 i2 k* D% c; F
  1. #define DMA2D_NO_MODIF_ALPHA   ((uint32_t)0x00000000U)  /* 不修改Alpha通道值 */
    7 a* j3 R  S( {' A/ h0 f
  2. #define DMA2D_REPLACE_ALPHA    ((uint32_t)0x00000001U)  /* 用新设置的Alpha值替换原始Alpha值 */
    * a; i7 n+ F5 g. T9 g+ d
  3. #define DMA2D_COMBINE_ALPHA    ((uint32_t)0x00000002U)  /* 用新设置的Alpha值与原始Alpha值的乘积替换原始Alaha值*/
复制代码
9 s& G$ n- z: L1 C! D5 Y# b/ M. x7 E
  uint32_t  InputAlpha
  ~# y: x' U4 v( H7 a+ i9 {7 {设置前景色或者背景色的Alpha值,范围0x00到0xFF,如果颜色格式是A4或者A8,那么此参数的范围是0x00000000到0xFFFFFFFF,标准的ARGB8888格式。' c$ G3 P( u. X, G  _0 m) z% q

, k* u2 M; `' H  uint32_t AlphaInverted' s; p4 a/ D: x
设置前景色或者背景色的输入颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     
0 w- N6 ~1 H. `* x$ x( s% l
, X$ h0 W( T6 w! x  ?; s
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */# {$ K& T  o9 B, v# l+ h* a
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */     
复制代码

" m& N3 |* J* C4 }7 ]  uint32_t   RedBlueSwap
. w7 u* d* G% E: Z. I设置前景色或者背景色颜色格式中R通道和B通道的交换,具体支持的参数如下:! J. l/ d4 b' H0 K* {5 g- g

5 a' d& y1 s* I0 S; b" a
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */- x7 c# e* B% o: R- j
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码

2 e& @" n8 Y% y, i  ^  uint32_t   ChromaSubSampling2 R7 g% |: R# f. D3 c
设置前景色或者背景色中YCbCr 颜色模式的采样格式,具体支持的参数如下:
  1. #define DMA2D_NO_CSS               ((uint32_t)0x00000000)  /* 4:4:4 */( D9 O: W9 x5 L1 e) `
  2. #define DMA2D_CSS_422              ((uint32_t)0x00000001)  /* 4:2:2 */' l7 A5 F7 U3 b& V4 p  e& X9 N
  3. #define DMA2D_CSS_420              ((uint32_t)0x00000002)  /* 4:2:0 */  
复制代码
" q, z2 \" e2 Y6 G* H+ Q7 i4 ~- w
55.3.4 DMA2D句柄结构体DMA2D_HandleTypeDef
2 S2 E" N6 z3 e! I2 P7 h
HAL库在DMA2D_TypeDef, DMA2D_InitTypeDef和DMA2D_LayerCfgTypeDef的基础上封装了一个结构体DMA2D_HandleTypeDef,定义如下:
" r0 x) I8 S, e5 p& G; P: W0 ]
$ q9 ]( P9 L! K2 M( J% S3 I  s
  1. typedef struct __DMA2D_HandleTypeDef
    $ M, o" `$ H8 S5 H
  2. {
    ) t' p, n7 p2 |8 [# h' G1 {  N
  3.   DMA2D_TypeDef               *Instance;                                                                                                                                                                                          
    ) @% W9 k% N  `% h; Q
  4.   DMA2D_InitTypeDef           Init;                                                        
    1 R8 p' \4 V8 P9 k! _7 O& k
  5.   void                        (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                                                                             
    9 A1 s7 ~2 m# Y0 f7 Q
  6.   void                        (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                      3 q) o8 X: O* P) U5 @
  7.   DMA2D_LayerCfgTypeDef       LayerCfg[MAX_DMA2D_LAYER];                                    
    * i) `# R5 k' E6 Q5 b6 {
  8.   HAL_LockTypeDef             Lock;                                                                                                                                                                                                   
    % T- q. ]) Q* {$ N7 r7 u. R
  9.   __IO HAL_DMA2D_StateTypeDef State;                                                                                                                                                                                                   
    , e3 f1 H2 i% y. [. |% g( S
  10.   __IO uint32_t               ErrorCode;                                                   } DMA2D_HandleTypeDef;
    ; K9 `6 Z* N# {% S+ ~
复制代码
6 E/ Z3 K& L( i+ c. {7 u  h
下面将这几个参数逐一做个说明。
+ s7 \( m8 R! @9 o/ t  G/ [) q0 f- c2 I1 u- a, y
  DMA2D_TypeDef  *Instance
1 p" V6 y2 Y6 G: |: L这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。9 T& F, g' o" f8 n
1 L+ k9 M3 i% x1 i. ?
  DMA2D_InitTypeDef  Init;  
6 Z; k$ E! T$ K0 k这个参数是用户接触较多的,用于配置DMA2D的基本参数,详见本章3.2小节。8 C- b3 H& x* F" |) s

' l# ]$ Y9 ?/ c  c2 v  void     (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);
# ^5 n, P. `$ X- ?  void     (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);. o, k) B3 X4 ?5 z) X- u& X: h
DMA2D中断服务程序里面执行的回调函数,一个是传输完成回调,另一个是传输错误回调。7 ]7 D) W1 s/ x2 O- W8 b3 S, I
/ L! e8 D$ E1 L
  DMA2D_LayerCfgTypeDef   LayerCfg[MAX_DMA2D_LAYER]
: g# b+ S+ [5 d8 s这个参数用于前景色和背景色的设置,MAX_DMA2D_LAYER=2,详见本章3.3小节。
# w  A/ H- _5 r: F6 F+ H( g+ X
" Z7 b* C& F5 u8 Z  HAL_LockTypeDef   Lock: ~8 [) R/ U* V3 C$ b
__IO uint32_t    State;
! y: e! g3 ^$ ~  p4 y
/ G6 l9 n: _- N) j' Z3 ~__IO uint32_t    ErrorCode1 v% [  }& S* N! a; Y5 o" U; Z. }
. F$ p7 R$ ?! i. f
这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置DMA2D通信状态,而ErrorCode用于配置代码错误。- a! R6 q1 \& G- k+ G& J0 ?! R

. E# n: a/ y2 J- ^55.3.5 DMA2D初始化流程总结
! u+ j+ W5 F% x* I# m! K3 P3 _
对于DMA2D来说,其实不需要初始化流程,每个功能都可以直接封装出一个函数来,下个章节会为大家专门讲解,也是实际项目比较推荐的方式。
: Z$ n5 s" E* X4 q. p/ I3 i! M1 k% _- D: y2 }. G( a
55.4 源文件stm32h7xx_hal_dma2d.c0 r1 l7 x1 N2 \3 F) W
这里把我们把如下几个常用到的函数做个说明:
5 @" l( p1 Z8 ^# _1 v0 e  Y6 r/ Z1 H" {9 u
  HAL_DMA2D_Init) g' P+ y' A7 n9 E5 ^6 n
  HAL_DMA2D_ConfigLayer- H6 |/ [1 V/ S  u4 P4 {! O, Z5 A7 ?
  HAL_DMA2D_Start_IT
8 l! Z, _. C% H, Y4 E4 w  HAL_DMA2D_BlendingStart_IT( h2 \- a* x& o3 C7 P& [8 \) ]
1 [' T, d* Y  Z& z
55.4.1 函数HAL_DMA2D_Init+ p. @% f# h( V
函数原型:, n  w* y0 ^' @% D$ b0 C. i

3 M4 t) a4 p1 ?) `8 M7 Z3 q
  1. HAL_StatusTypeDef HAL_DMA2D_Init(DMA2D_HandleTypeDef *hdma2d)
    8 ~' j& b) Z5 |0 V! P7 g5 U1 }
  2. { 4 W! {8 h$ Z6 W3 d6 J2 F

  3.   U( n: d+ G9 D4 {% Y5 O$ C
  4. /*  检测参数是否有效 */
    ; N9 j( I5 m. ]0 X4 V5 E8 p, x) @1 w
  5.   if(hdma2d == NULL)
    9 r5 w" m* z, J: E
  6.   {
    # [% U( W) d% V, ~
  7.      return HAL_ERROR;5 x" ]0 [9 D  D
  8.   }+ ~% f/ j3 q( S) m2 }* T1 ~1 e
  9. 0 g0 g( q2 u  M( N! e- R( ^1 a
  10.   /* 检测函数形参 */
    4 a0 i/ n" m3 a- W9 ?0 L# J! ?
  11.   assert_param(IS_DMA2D_ALL_INSTANCE(hdma2d->Instance));; P  d9 ?+ Z- l$ T3 ]2 P
  12.   assert_param(IS_DMA2D_MODE(hdma2d->Init.Mode));' [" K! d: ?. A( |( P% J( v
  13.   assert_param(IS_DMA2D_CMODE(hdma2d->Init.ColorMode));
    $ z+ {! j2 H- q; |0 _
  14.   assert_param(IS_DMA2D_OFFSET(hdma2d->Init.OutputOffset));/ o0 o( v9 X" V6 C

  15. ) y" c: ?! `* V; `/ U
  16.   if(hdma2d->State == HAL_DMA2D_STATE_RESET), j4 D7 a5 w9 C4 y6 Z
  17.   {: L, E0 B; o4 _
  18.     hdma2d->Lock = HAL_UNLOCKED;
    3 W' {( h" |5 D& {$ q# x
  19.     /* 初始化GPIO,NVIC等 */
      L8 l( q" x0 F& e( T
  20.     HAL_DMA2D_MspInit(hdma2d);
    4 }6 |/ {" p+ K+ O" L! Y
  21.   }
    : `7 V0 I5 V+ R  {
  22. ) e5 P2 B+ N$ X+ u" P' N1 \' q- H
  23.   /* 设置DAM2D外设状态 */9 s5 J- J& g7 c  v9 y$ n
  24.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  
    " d: Q. _, n( w& F

  25. 0 k/ u: W. j4 M0 W
  26.   /* 设置DAM2D工作模式 -------------------------------------------*/
    9 R. T2 ~: I+ e% R5 |
  27.   MODIFY_REG(hdma2d->Instance->CR, DMA2D_CR_MODE, hdma2d->Init.Mode);
    . M) Q4 I4 h2 Q' |- u6 @; r7 u

  28. # z- @9 M$ }/ u$ U& G' q0 ~6 N
  29.   /* 设置输出颜色格式 ---------------------------------------*/( S' ?( S& n0 ^! v7 M% f# _
  30.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_CM, hdma2d->Init.ColorMode);
    / z# K: v$ {6 L0 A; P

  31. 5 W! V' }% W. t; e- O' ^7 L
  32.   /* 设置输出偏移 ------------------------------------------*/  # s0 t4 f  W' k8 v  N: B
  33.   MODIFY_REG(hdma2d->Instance->OOR, DMA2D_OOR_LO, hdma2d->Init.OutputOffset);  ; u6 o/ Q/ I. H, |) [
  34. % z( s  \7 n: K' O% E
  35.   /* 设置输出颜色格式中的Alpah值反转 */2 p) |- A: ]+ S2 \1 }
  36.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_AI, (hdma2d->Init.AlphaInverted << DMA2D_POSITION_OPFCCR_AI));
    # u" M0 t/ z: A; @+ V9 j' m

  37. ; M, [4 z5 P4 W( }2 s/ \8 x4 a
  38.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_RBS,(hdma2d->Init.RedBlueSwap << DMA2D_POSITION_OPFCCR_RBS));
    % j# L4 W; K* P6 T# @

  39. $ Q( n! J+ v0 z1 v
  40. # ?- G0 g* n+ G* ?; j* `2 s
  41.   /* 无错误 */8 {2 L2 b6 J, b; R; ?2 t3 |9 o
  42.   hdma2d->ErrorCode = HAL_DMA2D_ERROR_NONE;6 ?7 a+ k8 B7 ~3 n3 Z7 X
  43. 7 Y+ A7 `5 i6 f. H# l$ i
  44.   /* DAM2D就绪 */$ C7 }3 a1 H6 |# d1 Q) i4 l$ p
  45.   hdma2d->State  = HAL_DMA2D_STATE_READY;
    , t3 q( I, b& A+ i8 c

  46. * i( S- a) i, _7 g
  47.   return HAL_OK;( d! @/ d( H1 |% v8 Y5 E/ T" h
  48. }
复制代码

/ B: [+ v0 B# c7 r& O9 h函数描述:
5 ^  n! ?. [3 D3 Z: s
4 L, N0 R7 ~8 {7 q8 K( R此函数用于初始化DMA2D的工作模式和输出颜色格式。. p2 x. l8 W! z! f
$ A, ^$ r# l7 a. j1 W# N6 t/ i9 W
函数参数:+ P$ u9 O9 o* d# |% b, x

8 `3 J0 N9 p1 G% t7 |1 z  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。: S' Q) K! y9 K' R& V
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。* J' L  P, ?9 |+ V, @2 q% M. i' ^
注意事项:
5 l$ \9 d" `" m% e* G! P  p1 P( M  \* x/ w
函数HAL_DMA2D_MspInit用于初始化DMA2D的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。* d6 T* F) S& m2 c, O' t
如果形参hdma2d的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量DMA2D_HandleTypeDef Dma2dHandle。
7 l6 W3 O7 ]0 `% \% p对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_DMA2D_STATE_RESET  = 0x00U。
; M& p9 F. ~- B- {! l7 ~1 o7 H+ `! y8 b- J9 a' ]4 V5 v$ E
解决办法有三& q- @! z' Q, R

4 {' e: c) _+ R/ J5 @1 ]9 q方法1:用户自己初始DMA2D底层。
9 X% _! E6 a1 c: ^' _
, a/ ?8 _4 l9 B方法2:定义DMA2D_HandleTypeDef LtdcHandle为全局变量。8 S$ }( o, L% s% Y& j
: s% W4 F8 t  k. n5 ~9 N
方法3:下面的方法
  1. if(HAL_DMA2D_DeInit(&Dma2dHandle) != HAL_OK)% Z: ^/ M' a* n7 |- k+ j' ^
  2. {; f7 R" q1 X: J" P) o  D1 ~
  3.     Error_Handler();
    : e' X  M7 ~6 B# [! i' y/ }
  4. }  ; ~* ?# l1 m! ^' o
  5. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)* C8 V* P; u/ ], I- T( U
  6. {4 t9 w$ D5 }1 t" S& S
  7.     Error_Handler();2 Z$ ^) f. G! D& ?& R  v
  8. }
复制代码
; [% X$ u: _/ R" p/ r4 ?# r( N; H. f
/ X6 m) w: a) z3 B9 f" \
使用举例:
$ ~  a$ S( X! y  j( p7 C0 z
; }9 q( R. c7 ~
  1. DMA2D_HandleTypeDef Dma2dHandle;$ D" C( [, c5 m. s- J4 }
  2. % e6 {+ \4 y, e1 i
  3. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/- R/ G" V3 w  p* {) Z
  4. Dma2dHandle.Instance = DMA2D;6 Z& i% K2 Y3 u
  5. 6 I9 f5 I+ K" O0 H
  6. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */
    1 _: K0 n7 O* `- d
  7. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */% I8 q# g# F+ L$ s2 U
  8. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */
    $ K; w, w& e4 p
  9. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */
    / b2 T& _) _' U, j: r, n
  10. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */5 Q4 Q1 ?: k& ]6 J( |

  11. / P* Y( A4 Y0 o2 k& O
  12. /*##-2- DMA2D 回调函数配置 ######################################*/$ x9 M6 N" {# |7 V
  13. Dma2dHandle.XferCpltCallback  = TransferComplete;
    ) b( K( a; p# p" A2 N0 e
  14. Dma2dHandle.XferErrorCallback = TransferError;9 R- E5 L4 i4 a$ F- |2 C; [- ^; R
  15. 7 G% @8 W0 y4 |- ?! x, }
  16. /*##-3- 前景层配置 ###########################################*// [9 B$ f( J, w$ x. h8 P6 Z" ~/ [
  17. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */4 A1 P* g9 ?3 i! c7 }
  18. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */
    * b& ?; }: I) J, T+ l
  19. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */. f$ L8 t7 `- P
  20. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */
    8 A4 h  B; F  S! a
  21. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/4 M6 {; D) ^4 q+ j# ?
  22. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/4 m. v5 R5 i  l* ^( b! _0 ^1 m" Q! d' {
  23. ' n' Y$ u2 n8 n, R
  24. ( J: Q. }& d" ]  c+ s3 C
  25. /*##-4- DMA2D 初始化 ###############################################*/
    3 r, L  q2 d. y9 d3 V, h. s4 a
  26. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
    $ `7 d4 ^9 l3 Z$ w* Q4 g
  27. {
    ) d! W& G' u. G0 K
  28.     Error_Handler();7 A  m3 w) S# @6 {  N/ W
  29. }
复制代码

- f* N2 ^  _. }8 D6 l: ~  q  p55.4.2 函数HAL_DMA2D_ConfigLayer. H$ w6 X+ y! |7 k
函数原型:
9 L( l# G0 U# a% v( \3 r. l) Z' y. Z. T' h& F3 ?
  1. HAL_StatusTypeDef HAL_DMA2D_ConfigLayer(DMA2D_HandleTypeDef *hdma2d, uint32_t LayerIdx)
    ( n! m/ x9 z( Q5 h3 j3 h" e5 U4 u  H3 j
  2. { * k  j! P; }# l( `
  3.   DMA2D_LayerCfgTypeDef *pLayerCfg = &hdma2d->LayerCfg[LayerIdx];
    5 s6 C# n& c+ a! q9 c2 V; b* T
  4. . k* G/ o$ x1 M1 `  a0 ]  f
  5.   uint32_t regMask = 0, regValue = 0;
    ; u  m& n+ N4 ^* O  V& e
  6.   M, e- A. m/ D& s6 C" r' J+ X
  7.   /* 检查参数 */' c" l6 o3 r: z
  8.   assert_param(IS_DMA2D_LAYER(LayerIdx));  % B" h  y& X/ J9 e+ X
  9.   assert_param(IS_DMA2D_OFFSET(pLayerCfg->InputOffset));  
    " s1 `! [% B4 a* M/ _
  10.   if(hdma2d->Init.Mode != DMA2D_R2M)" K! [$ k  k' L
  11.   {  
      N+ T% e: M% w
  12.     assert_param(IS_DMA2D_INPUT_COLOR_MODE(pLayerCfg->InputColorMode));7 E! Y7 l% j9 s2 m8 g+ n8 Y
  13.     if(hdma2d->Init.Mode != DMA2D_M2M)8 F' h9 T# _$ Y/ D- W" q
  14.     {
    - Q5 S6 S2 m3 m1 d1 ]+ r
  15.       assert_param(IS_DMA2D_ALPHA_MODE(pLayerCfg->AlphaMode));. e3 c+ n' e* F+ f  e$ B1 i2 \: g
  16.     }
    * D3 |/ y* D0 O" C# d+ M) h! ?
  17.   }3 |2 Y) x: h7 U, s" D0 V& b! h
  18. ; T" e/ f9 Z6 J5 Y+ s: r9 S) Y
  19.   /* 上锁 */# T9 `" t* a, M% r, [" m
  20.   __HAL_LOCK(hdma2d);" b( O- f" Y2 v% l5 r' z1 M
  21. 8 e! L, o, I4 @  ^3 C' R
  22.   /* 设置DMA2D外设状态 */. [3 }$ f% m+ V2 k3 r7 h
  23.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  
    & l3 {4 U! A! e5 }' E0 ^

  24. 8 n3 ~+ Y) m' |+ ?" v' i
  25.   /* 准备好背景层或者前景层FPC寄存器配置参数*/
      q, @, j: a; m
  26.   regValue = pLayerCfg->InputColorMode | (pLayerCfg->AlphaMode << DMA2D_POSITION_BGPFCCR_AM) | \
    9 z5 G0 }9 J3 N, t
  27.             (pLayerCfg->AlphaInverted << DMA2D_POSITION_BGPFCCR_AI) | \
    1 }$ p+ [9 d4 P* o
  28.             (pLayerCfg->RedBlueSwap << DMA2D_POSITION_BGPFCCR_RBS);8 L) k# {: y: [" _6 h4 a

  29. : n6 \( C% Z7 l
  30.   regMask  = DMA2D_BGPFCCR_CM | DMA2D_BGPFCCR_AM | DMA2D_BGPFCCR_ALPHA | DMA2D_BGPFCCR_AI | DMA2D_BGPFCCR_RBS;
    # C, ^8 e+ [: }, K( e
  31. 1 I2 B' H7 Z& Q
  32.   if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))0 ]; u$ U# W- e! n
  33.   {
    & e! N) e/ L( H$ w# Z0 O
  34.     regValue |= (pLayerCfg->InputAlpha & DMA2D_BGPFCCR_ALPHA);
    * u7 o! A4 J! }8 N# N) ]# B
  35.   }
    6 d) G! r% B+ ?. [( H' T* {' E
  36.   else
    : M5 U0 k" x- w( c' C+ ]3 h$ k
  37.   {5 A9 l1 M. \+ U+ l
  38.     regValue |=  (pLayerCfg->InputAlpha << DMA2D_POSITION_BGPFCCR_ALPHA);
    / E. G) b6 f. V: e
  39.   }
    3 @4 l9 s: ^) u% V
  40. 4 o8 @+ P1 X& b) t
  41.   /* 配置背景层 */6 y/ k) k5 L. O/ C; K. i  j
  42.   if(LayerIdx == 0)
    0 Q7 `  O/ w3 h/ i; J
  43.   {
    - v% p. y1 X1 v8 [4 @
  44.     /* DMA2D BGPFCCR 寄存器 */
    6 B2 |3 p; q" }6 l" U! l
  45.     MODIFY_REG(hdma2d->Instance->BGPFCCR, regMask, regValue);
    5 y4 K# D$ H) D6 p# A# Z

  46. " ~& d* _# t# L" g$ ]
  47.     /* DMA2D BGOR 寄存器 */  
    ) U" t  y( {3 i- P0 f1 f& u6 ~! \
  48.     WRITE_REG(hdma2d->Instance->BGOR, pLayerCfg->InputOffset);% }% J5 g4 L; |/ g8 V

  49. 1 n% C; w/ s& F$ z; h0 @5 `# w# Q4 ~
  50.     /* DMA2D BGCOLR 寄存器 */
    % s& T. R4 L; g8 h8 t4 L
  51.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))5 O' h4 c. u. V6 p
  52.     {    " U1 b" z: f. z! A
  53.       WRITE_REG(hdma2d->Instance->BGCOLR, pLayerCfg->InputAlpha & 4 _. q' \2 m8 k: |! o0 @+ j* {' t
  54. (DMA2D_BGCOLR_BLUE|DMA2D_BGCOLR_GREEN|DMA2D_BGCOLR_RED));- y$ g/ c3 a' ?( [" ~
  55.     }   
    / |( ~, p- d, l2 Y
  56.   }
    / Z6 ?# c* n4 m3 |3 A
  57.   /* 配置前景层 */7 \) {/ `# N  p0 m
  58.   else
    4 y+ R' C; h* L5 V
  59.   {. g8 Z1 s  D2 d  v# y
  60.     if(pLayerCfg->InputColorMode == DMA2D_INPUT_YCBCR)
    . w4 a2 ~" H6 _
  61.     {
    , a' K- K' C+ L: K% @
  62.       regValue |= (pLayerCfg->ChromaSubSampling << DMA2D_POSITION_FGPFCCR_CSS);. e- W, Q& y/ z9 j( g: X
  63.       regMask  |= DMA2D_FGPFCCR_CSS;
    ) C3 A: [* \+ W
  64.     }, j  \5 {% z) C" Q3 |0 K% R
  65. 7 W3 Q; [6 \; Z% c' I  l
  66.      /* DMA2D FGPFCCR 寄存器 */
    7 n6 h! m* L$ l, {" \  J! L
  67.     MODIFY_REG(hdma2d->Instance->FGPFCCR, regMask, regValue);7 J" q8 T: z9 p+ \) G

  68. 7 t+ \. y" W6 H& d* C" n% l2 b
  69.     /* DMA2D FGOR 寄存器 */
      J! G" U/ W6 G! l+ H# r4 u+ A
  70.     WRITE_REG(hdma2d->Instance->FGOR, pLayerCfg->InputOffset);      9 w' v% O# \1 R9 h; p2 x; p

  71. ! M, r1 ~2 v3 t' H9 T* Z
  72.     /* DMA2D FGCOLR 寄存器 */   
    0 d4 K: K$ S9 Z9 F1 }3 h2 Q
  73.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))& X7 ~- A- F, v* v; |' Y. R* C
  74.     {% G( o( g) r5 ^5 x( F9 p  Z) j
  75.       WRITE_REG(hdma2d->Instance->FGCOLR, pLayerCfg->InputAlpha &
    6 p" [/ n4 O) d
  76. (DMA2D_FGCOLR_BLUE|DMA2D_FGCOLR_GREEN|DMA2D_FGCOLR_RED));      
    + w1 u4 Y0 l+ W+ \% a- [
  77.     }   6 M* q" v8 T/ l' i$ A& V
  78.   }   1 ?$ K' Z* V& y; V% O
  79.   /* DMA2D就绪 */- _! o- q  G# D* Z% S
  80.   hdma2d->State = HAL_DMA2D_STATE_READY;
    & |. N7 t. X! _5 Z- Y8 G' P
  81. % `9 u6 A5 K+ s6 \
  82.   /* 解锁 */( l& {8 E1 w1 t0 f$ X1 I0 m
  83.   __HAL_UNLOCK(hdma2d);  , `7 _: J- @& B2 X& g

  84. 5 e. I0 ]! j1 w# j7 X
  85.   return HAL_OK;
    ! W8 A5 |3 H, Y. V
  86. }
复制代码

$ U+ e% L6 w4 S  k; Z/ S) k$ X, B函数描述:
9 f) H8 E  `; x5 e- |) l8 h" h6 o* b% B, _4 E" P
此函数主要用于配置DMA2D要转换的前景层和背景层,即输入颜色配置。而前面的函数HAL_DMA2D_Init配置的输出颜色。
3 s  h3 J4 W2 w9 g7 G6 K- j  j4 N8 J: K1 T+ c% O
函数参数:4 b$ l1 z; g; {5 B. n9 _* ~6 n
; C6 U9 }$ A0 H( Y( j; t% D0 I
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。
3 e8 R- G! o7 t  第2个参数用于配置前景层和背景层,0表示背景层,1表示前景层。
6 U2 W; @& l4 i0 V% b: g  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
" ?, c5 Q# ^3 V; x使用举例:3 p- i6 K2 ?2 Y& U) l
  1. 8 n7 c+ K  r6 T* a  A. T0 H. x
  2. DMA2D_HandleTypeDef Dma2dHandle;& P. v. W% T) E+ c; \( \& R
  3. 2 q3 i3 N, ^2 Z9 D. y/ s
  4. 1 y5 p- |. O3 @! [& X( ?
  5. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/
      `/ p& o9 T7 r; \! U% I
  6. Dma2dHandle.Instance = DMA2D;
    & H! Y( d; n& w4 u$ Z

  7.   V$ X) q  ]; _" h" |
  8. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */
    ; g5 n( R5 ~& F
  9. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */, m. V8 p# p* C2 }
  10. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */
    9 U; w0 a/ d. W: l0 M0 `
  11. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */
    # s& O" a# F, _1 z% n' A3 J( {& _1 F
  12. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */
    3 V" ]! M2 y9 C( h2 K+ N
  13. " w$ b. b% U# R* ~# |( F
  14. /*##-2- DMA2D 回调函数配置 ######################################*/! i: ]- d5 j; j+ L$ {
  15. Dma2dHandle.XferCpltCallback  = TransferComplete;, C, G( |5 Y! |% Y' i
  16. Dma2dHandle.XferErrorCallback = TransferError;; [. [+ v" N8 o) n) B

  17. ) U4 d8 k; g% O' `  J
  18. /*##-3- 前景层配置 ###########################################*/
    + r% e" ?' ]( l" O$ o8 h
  19. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */. H" I. n: S7 H
  20. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */6 i' D1 u/ E3 f+ P0 e1 Q
  21. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */9 F3 V8 M2 x& H+ O) h$ f+ S/ n; z
  22. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */- d) l6 z& c. x5 q+ p
  23. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/
    : Y7 f% d; U/ v: C. o/ E$ v0 ]9 y
  24. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/
    ( M$ Q( N$ M) c) w" \

  25. , G! x& ^( D  D
  26. /*##-4- DMA2D 初始化 ###############################################*/
    8 c$ y( L% V' n, M9 d% |
  27. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
    " l" n! M4 y/ c6 d9 H$ v6 c
  28. {" R5 G, o2 Q" Y
  29.     Error_Handler();/ I$ J3 Y, H8 Y' g
  30. }2 P2 b8 R  F: r% S
  31. 4 V  Z0 i7 f. i! e8 n
  32. /* 配置前景层  */3 X' W8 x9 A3 n* g  V$ Q, O( C7 M7 Q
  33. if(HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1) != HAL_OK)
    6 q* T; u) B+ N& \3 U5 w
  34. {' g0 B- z! O6 @) Z8 k# t" ~) `
  35.    Error_Handler();
    & i8 Y( j* _+ b
  36. }
复制代码

( }2 C+ U: |3 w2 k4 u+ ^/ {
2 X. i7 `( t7 ?% B8 L. Z& T% {! W55.4.3 函数HAL_DMA2D_Start_IT
" V& R$ M6 \' b& U- [) p: b' M' c9 l函数原型:
- r* B% N5 I0 c& H( V. I, e
% _5 i0 v0 L, f2 j4 I0 n
  1. HAL_StatusTypeDef HAL_DMA2D_Start_IT(DMA2D_HandleTypeDef *hdma2d, uint32_t pdata, uint32_t DstAddress, uint32_t Width,  uint32_t Height)+ i" p7 i0 [7 [0 J# U# q3 k2 \
  2. {+ A( ~# F5 Y( y% B1 [3 O
  3.   /* 检测函数形参 */8 Z( a% C9 t1 c+ _& ~
  4.   assert_param(IS_DMA2D_LINE(Height));
    * l( T  c, Q5 Q
  5.   assert_param(IS_DMA2D_PIXEL(Width));
    9 r# V2 X/ J3 x7 g; ~

  6. ) N2 A+ g; z; N/ w* V2 D
  7.   /* 上锁 */2 j) C/ b, S, w4 S9 O" y
  8.   __HAL_LOCK(hdma2d);2 L- y( O! A2 x6 B" G' f2 t; [

  9. ' T2 [& b+ J  S6 p* t+ k
  10.   /* 设置DMA2D外设状态 */
    $ A/ u4 \7 v- w2 R- n( A
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;
    9 m* v6 d8 U# v; ?' Z* T) m
  12. 0 p+ c7 {7 K5 T8 U- ~+ R
  13.   /* 设置源地址,目的地址和数据大小 */0 a9 E; m/ c( j8 A" q* G. A
  14.   DMA2D_SetConfig(hdma2d, pdata, DstAddress, Width, Height);* j/ t. Q. z* a8 O9 b0 C$ W

  15. 7 b, |2 g% o  x4 L
  16.   /* 使能DMA2D的传输完成中断,传输错误中断和配置错误中断 */( n' ?# O0 C7 ]% s% \$ P
  17.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);  _2 G0 b8 r, A% X) X" G+ [
  18. 9 ]5 g8 P* I( }3 U6 B& F
  19.   /* 使能DMA2D */
    ! K6 K6 b( p. [# Z: C
  20.   __HAL_DMA2D_ENABLE(hdma2d);
    , e: N! S6 M' A1 n' o3 I# M+ u

  21. * [% X, F5 \# Q
  22.   return HAL_OK;6 @3 ^) l5 b! o6 P! ~1 Y8 X: m
  23. }
复制代码

% b- ]3 f' ~4 x! K8 ]( q: f函数描述:. J5 m( E( }/ F* N, U0 E
4 t9 ?/ R7 \3 O! H8 \$ |; \
此函数用于启动DMA2D数据传输。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。3 m7 a' B9 r2 T0 V& `8 Q

9 S$ }! |9 _) N: N1 X函数参数:
* _; |% o9 l; ^* p  u" j& V# D" B, k8 s7 R
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。
- A/ c  Q% O* e; T+ u7 m* b  第2个参数是源数据地址。
1 M! j7 c( n3 U+ Y$ q  第3个参数是目的数据地址。
+ x3 q+ z4 p6 _" d* U) z: N* ~  第4个参数是源数据的长度,即每行的像素个数。1 ?5 X* C& z6 Y+ X, {
  第5个参数是源数据的高度,即行数。
* n) R7 T1 c  ^  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。5 }4 z+ O1 G0 d0 V' E
使用举例:/ [/ D) T. a; p9 ~  Q  G

' W. v5 l* `  ^7 i5 K
  1. DMA2D_HandleTypeDef Dma2dHandle;) R6 j8 \" [0 j! r
  2. " D. y! f( k, r8 G
  3. if(HAL_DMA2D_Start_IT(&Dma2dHandle,            /* DMA2D句柄 */
    ( Z" b4 Q1 \* R& K+ u7 G: S2 [
  4.                       (uint32_t)&BufferInput,  /* 源地址 */ , _0 s$ r4 f% P1 H4 Z( C/ w* c
  5.                       (uint32_t)&BufferResult, /* 目的地址 */% \- Q& |9 z6 D5 _  r
  6.                       SIZE_X,                  /* 源数据长度,单位像素个数*/( f" Q4 f+ h; [! o$ ]: j) F
  7.                       SIZE_Y)                  /* 源数据行数 */
    1 n) f5 L& G5 n8 Y/ V
  8.    != HAL_OK)9 X) }4 ?/ r+ T, `! c1 [
  9. {2 j( t( r, G7 P
  10.    Error_Handler();+ [2 z  W- z9 w; D) |( f1 v! s5 k) `+ X( l. B
  11. }
复制代码

& n9 H: J0 Y9 u55.4.4 函数HAL_DMA2D_BlendingStart_IT" x+ J7 A/ p0 p' C1 C& {' d
函数原型:
" c# m. x3 G. C! Z8 q
* Q6 }* D0 F  ~3 ]% `( s
  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)
    8 n$ }# t# L0 `1 r
  2. {, D2 t/ Z5 {6 R  L* J" h0 a) V
  3.   /* 检测参数 */
    1 f" d) ?0 r, g0 d$ l1 w
  4.   assert_param(IS_DMA2D_LINE(Height));
    0 ~+ ^5 r3 e) D+ |; O( Z8 u- q# H
  5.   assert_param(IS_DMA2D_PIXEL(Width));- h' s% ^( v. }3 S

  6. 0 f2 x' d" z: c; c; d
  7.   /* 上锁 */
    ' @- E) K0 |. l# m9 E9 R
  8.   __HAL_LOCK(hdma2d);6 S9 u) K3 R& y9 C# V% ~7 o5 l* z
  9. ( m# ?: C2 ~; Y1 m; T
  10.   /* 设置DMA2D外设状态 */
    9 C+ T8 w% V+ {& ~
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;
    ; T' T  _3 B9 J0 G$ E) A
  12. 0 @8 ~6 h4 {5 e6 e
  13.   /* 配置DMA2D源地址2 */
    , D$ d& N9 T/ g  Q4 D6 N! E5 _* u
  14.   WRITE_REG(hdma2d->Instance->BGMAR, SrcAddress2);3 [( B5 U/ z  G
  15. 4 G" t. Y- K: n1 `9 X3 U' t& z
  16.   /* 配置源地址1,目的地址和数据大小 */
    8 l; q6 P  G* b
  17.   DMA2D_SetConfig(hdma2d, SrcAddress1, DstAddress, Width, Height);  x/ c+ Z9 [7 J/ h

  18.   a4 ?* [% o9 H7 a
  19.   /* 使能DMA2D传输完成中断,传输错误中断和配置错误中断 */
    # J( p7 K* c, M5 w3 u
  20.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);
    1 e8 O/ y  S# P, {

  21. : s, N7 H) b1 J# s. ?
  22.   /* 使能DMA2D */
    8 F+ y% M8 A5 ?7 [
  23.   __HAL_DMA2D_ENABLE(hdma2d);
      ?. x  Y; e& |9 Z. {3 J

  24. - |+ c. Q8 b9 B% I, A* T' M
  25.   return HAL_OK;
    ( T! v$ }5 T) j* X
  26. }
复制代码
/ x6 C+ c1 w0 n9 g9 C/ z7 f9 m, n
函数描述:% [* a# I! _4 H# D! n

2 _- Z! h3 T- s1 {; }8 k+ V此函数用于启动DMA2D传输,除了数据传输以外,还支持颜色格式转换和颜色混合。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。
$ g- H+ R1 z- E6 w9 M& ~" m4 z6 u& L' f' h; u
函数参数:
" X0 X6 P8 p+ f, \4 e8 c0 E. J- w$ }
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。
5 h! [6 l' z- ?  第2个参数是源数据地址1。' M% z: k; v$ H
  第3个参数是源数据地址2。& O: }6 a5 f/ C
  第4个参数是目的数据地址。
2 Q8 }9 |* i' a; v: _% i4 p# u  第5个参数是源数据的长度,即每行的像素个数。
) {2 Z' m- i9 Z1 H2 M  第6个参数是源数据的高度,即行数。
1 Y+ s$ @* l& W+ w$ K  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
+ |' ]6 l* |6 S2 _/ t- L使用举例:8 ~7 }$ o4 R% G" a: I& C& S! \0 n# S! o
( f" @9 I  z, t- I
  1. DMA2D_HandleTypeDef Dma2dHandle;# D! q, G' |4 @, I/ Q% Z$ t

  2. 2 U  s; Z. @8 ?! d5 l# W
  3. if(HAL_DMA2D_BlendingStart_IT(&Dma2dHandle,           /* DMA2D句柄 */1 t. l4 [" B3 |
  4.                              (uint32_t)&BufferInput1, /* 源地址1,前景色 */
    ( z# \5 R2 E' f1 q. X* D5 u
  5.                              (uint32_t)&BufferInput2, /* 源地址2,背景色 */# I4 ?, H% A) `0 }, L0 K/ r8 a) D6 u
  6.                              (uint32_t)&BufferResult, /* 目的地址 */; V0 L; i+ K4 D5 ~$ Y8 z) Q9 i
  7.                               SIZE_X,                 /* 源数据长度,单位像素个数*/
    . b' p' }. E% Y/ q4 l4 ]
  8.                               SIZE_Y)                 /* 源数据行数 */
    ' r8 t# u1 A8 _" t1 c
  9.    != HAL_OK)" H2 B: b2 w, G
  10. {) K5 R7 Q" g2 x
  11.    Error_Handler();& x: Z* W1 T5 Z- D' C$ J
  12. }
复制代码

% N7 S; `- _( R  a( w
, ]1 S, s9 U# {5 e7 P) Z) l55.5 总结$ H0 U! L, s9 i
本章节就为大家讲解这么多,DMA2D功能比较重要,一定要做到熟练使用。3 S  b: t  G" K/ ~+ d2 }
: h6 V4 c6 N. x

& \8 @; F# l; ^* z1 `8 K" _
; d) d* f0 Q# m4 B: A# r
赞 收藏 评论0 发布时间:2021-12-24 17:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版