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

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

[复制链接]
STMCU小助手 发布时间:2021-12-24 17:00
55.1 初学者重要提示
* K& E$ f0 ?! v* D* a* Q  DMA2D是专门用于LCD加速的,特别是刷单色屏,刷图片,刷Alpah(透明)混合效果全靠它,而且可以大大降低CPU利用率。
3 e# F5 u7 r2 O/ z4 H  测评STM32H7的LTDC+DMA2D性能,100Hz以上无压力,刷800*480图片和色块仅需2.6ms一张
: l# F6 `* a! p0 ]( J, X  H7的DMA2D与F429的DMA2D最大区别是支持了ARGB和ABGR互转,而且支持H7的硬解JEPG输出格式YCbCr转RGB,方便LCD显示。1 ]2 `# }$ a8 b) ~5 {& X' h7 e
  特别注意,大家只需对HAL库提供的DMA2D操作API有个了解即可,实际工程中,并不使用这些API,我们需要使用更加高效的寄存器直接操作,在下一章节会为大家说明。9 X3 z5 f# J, I& h: J
55.2 DMA2D基础知识
% J) d9 I* Z* s% t3 B* R( x- fDMA2D主要实现了两个功能,一个是DMA数据传输功能,另一个是2D图形加速功能。& }2 K( S3 j1 q* T& A- P
' H5 D' q, l: u0 m
  DMA数据传输
6 b; c( q# U. a1 h. ?主要是两种方式,一个是寄存器到存储器,另一个是存储器到存储器。通过DMA可以大大降低CPU的利用率。+ k7 [8 b7 d' {0 G. J4 G
8 |: [7 m$ w6 F  E
  2D图形加速功能
; e% S$ V  E3 k: J  a5 z$ @支持硬件的颜色格式转换和Alpha混合效果。
$ V4 B; L9 r& n3 n# h
8 k" ^% T  u, C( ?9 z55.2.1 DMA2D硬件框图
/ [2 q9 P0 |" K( X2 v* M认识一个外设,最好的方式就是看它的框图,方便我们快速地了解DMA2D的基本功能,然后再看手册了解细节。框图如下所示:
& F7 X( P$ f4 Q4 w4 e( ]& I
8 @: ]' N- q5 S* X! J" t
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
) u7 c4 ~. c0 R& `9 _

% d' @/ a9 y2 m( z2 y通过这个框图,我们可以得到如下信息:+ B  m9 i2 o: j, V! E6 p* _

& q$ Z8 d# R' p. a  dma2d_aclk
  S8 i7 v' G3 S5 B) s' r6 Z* N% KAXI 总线时钟输入。
. l+ ]9 h, _$ C3 q6 O8 ~. ~' h( U! [1 Y3 b' O( z
  dma2d_gbl_it; B$ z) ~0 S. Y9 Q3 J
DMA2D全局中断输出。& b$ m3 c4 E: \  f

7 M+ F5 R. P. @- O* j  dma2d_clut_trg
) J- Z3 N, f% j, [; eCLUT传输完成信号输出,可以触发MDMA。8 [5 B: u% R6 ~7 a1 u* w7 G% w

: g% u: L* x) H  dma2d_tc_trg1 V) {/ t) ^0 L  j
传输完成信号输出,可以触发MDMA。( _; z+ F8 C/ g$ r

8 J) M6 `3 K, Z8 N: d7 R+ \. b  dma2d_tw_trg
  j0 m, ]) V8 m& T3 x2 B. d0 F传输watermark信号输出,可以触发MDMA。/ C0 o5 s3 U$ {* \4 s. n% a
$ ~; T; h9 }) q$ B1 l
将这个硬件框图简化一下,就是下面这样:, |6 E5 z' @+ Q* K1 `
6 T- e  ^" S+ u' S& q
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
6 M* o9 Z* U, a! w) @! @1 I) L

+ F+ l* \1 L# ?3 k3 T7 V( V6 J下面按照简化的硬件框图,对每个部分做个说明。: u+ Q% ?9 X( A

  M( ^. ]2 R: E# y, c* h55.2.2 DMA2D工作模式1 S: O6 s  X" @" J3 w! F% O
DMA2D支持的工作模式如下:
( I9 X3 ?/ }2 {5 X
) i2 Y" I7 _' S5 x9 B! ~3 R# g$ ^  模式1:寄存器到存储器模式  G% R6 h( `- h' S; o# _
这个模式主要用于清屏,也即是将显示屏清为单色效果。
$ f3 c5 n. w6 _, K
8 D8 {; w! ?5 `, R  模式2:存储器到存储器模式4 U% b5 j3 L3 X" s  o1 f
这个模式用于从一个存储器复制一块数据到另一个存储器,比如将摄像头OV7670的输出图像复制到LCD显存就可以采用这种方式。1 \/ g6 n0 {. y) O1 W' [
  E) Q+ |* Q7 @# Y; Y! T1 X/ X
  模式3:存储器到存储器模式,带颜色格式转换
- H5 G7 ~! Z$ S4 a. x/ m. U8 f这个模式比模式2多了一个颜色格式转换,比如我们要显示一幅RGB888颜色格式的位图到RGB565颜色格式的显示屏,就需要用到这个模式,只需输入端配置为RGB888,输出端配置RGB565即可。位图颜色格式转换后会显示到显示屏上。$ v# l- @/ L0 T0 ]
8 K* o% M; {8 u+ p9 v# {# }* v
  模式4:存储器到存储器模式,带颜色格式转换和混合2 G0 ~* p2 u4 w/ f
这个模式比模式3多了一个混合操作,通过混合,可以将两种效果进行混合显示。
* P1 ]. O5 U- w( Q+ \4 z% D9 {) K4 z2 K7 n
  模式5:存储器到存储器模式,带颜色格式转换和混合,前景色是固定的/ v9 R' z5 H' G* @8 z
同模式4,只是前景色的颜色值是固定的。
0 x& ?* m. z4 W% \0 `" \  Z
. [/ G% v9 s: {6 ]55.2.3 前景层和背景层的输入以及颜色格式转换, O: z. Z+ K& b! s* a5 B0 M* G
前景层和背景层是指的用户绘制图形时的前景色和背景色,比如我们显示汉字,字体会有一个颜色,也就是前景色,还有一个背景色。又比如我们绘制两幅图片,想将两幅图片混合,那就可以将一幅图片作为前景层,另一个幅图片作为背景层。) e8 X/ X- }, g2 }, {- h/ `6 y
: t2 ~: S, q0 l" O; W
DMA2D支持的输入颜色格式如下,前景层和背景层一样:% {9 d. x- g( }: P

: q1 e1 q2 z9 \5 r* t9 C% x5 ^5 \
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

/ W; m0 {) h8 y+ V4 ~6 q! y1 K/ K; k5 P
前8种颜色格式在第50章的第2小节开头有介绍,这里把后四种做个说明:
, `3 H, k% ^; r% g) C* c
: j% r8 k3 E) ~1 R! P: S+ Z; N  L4 (4-bit luminance or CLUT)6 k$ N; m( A' ^/ j& I% w
4位颜色格式,实际上仅仅是4位索引值,范围0–15,而每个索引值的具体颜色值在查色表CLUT里面存储。4 e7 ^- h) y: w7 f! B( n

' P, S0 c! v. S! }( G  A4和A8$ a2 _4 e  }' p6 u( M
A4和A8用于特定的Alpha模式,既不存储颜色信息,也没有索引值。$ B/ O% n3 l# c. c
0 o9 Y. Z' ]- R1 d. s
  YCbCr
+ x$ U) W) g: O0 p& G! n- @; |这个是H7的硬件JPEG输出的颜色格式,后面JPEG章节为大家专门做讲解。
/ l) e) ]3 j9 [+ {" f! w! x
, N; ~3 J, W0 R! f  x, T: o这里特别注意一点,输入颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。. Y. m& a; S" Y3 z( o9 h& {% u; ~

1 R! [; A# C! z4 E+ n/ r55.2.4 前景层和背景层混合9 Z7 {" Y2 n' z
DMA2D混合器用于混合前景色和背景色,这个功能不需要任何配置,仅需要通过DMA2D_CR寄存器使能即可。混合公式如下:3 {0 N; e  M! }: r( t7 j9 U, D: H
: T! R  T0 t; {& ^8 s% u
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
- j) l  V! D1 P
: C1 w6 L# |: P/ v7 a
55.2.5 DMA2D输出颜色格式
$ E# @' Z# B4 N' JDMA2D支持的输出颜色格式如下:* Q- L5 Q2 x' @* q: x4 }6 f0 u

3 k3 k9 z+ R3 H0 ~9 z
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
/ M; \, `& N, ^  q; }. @+ B
+ Q7 ]& N) u# ~6 C
这里特别注意一点,输出颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。
/ e8 E) y* F; b( w* K# [2 \+ ]. r2 e% R9 s% `# R( z
55.3 DMA2D的HAL库用法1 C& E' d9 f+ g- N4 r7 o: r
DMA2D的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断。下面我们逐一展开为大家做个说明。6 n5 O& s+ U2 S6 J. u1 d7 v3 `5 P
& f' P2 U& M8 h* _5 r1 F
55.3.1 DMA2D寄存器结构体DMA2D_TypeDef6 ~; p& P4 U7 M0 m
DMA2D相关的寄存器是通过HAL库中的结构体DMA2D_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:
7 S" @: J5 w. p+ H( N8 K6 J" Y- }* Y
6 z2 E& ]5 L  c" Q3 l% }% X
  1. typedef struct" d- b+ K$ @6 k& h1 \2 Y* C& f9 L2 Q4 W
  2. {
    3 o* B4 r0 Z, j
  3.   __IO uint32_t CR;            /*!< DMA2D Control Register,                         Address offset: 0x00 */
    3 J7 x' T3 C! Y8 z8 [
  4.   __IO uint32_t ISR;           /*!< DMA2D Interrupt Status Register,                Address offset: 0x04 */' N1 U; K, Y" M2 Q, N; F
  5.   __IO uint32_t IFCR;          /*!< DMA2D Interrupt Flag Clear Register,            Address offset: 0x08 */
    7 r4 m+ N) ^9 X8 |
  6.   __IO uint32_t FGMAR;         /*!< DMA2D Foreground Memory Address Register,       Address offset: 0x0C */
    ; a* X7 o" f& r" C) F0 i- s9 i: A1 N
  7.   __IO uint32_t FGOR;          /*!< DMA2D Foreground Offset Register,               Address offset: 0x10 */
    - m+ O  k% Q" r- F( x
  8.   __IO uint32_t BGMAR;         /*!< DMA2D Background Memory Address Register,       Address offset: 0x14 */) G, f& P+ K% c, k8 U( n4 d7 G' V
  9.   __IO uint32_t BGOR;          /*!< DMA2D Background Offset Register,               Address offset: 0x18 */
    % c" i9 P2 F; L4 z  D: @( s
  10.   __IO uint32_t FGPFCCR;       /*!< DMA2D Foreground PFC Control Register,          Address offset: 0x1C */1 ~: f- z$ L4 Y7 T  ]
  11.   __IO uint32_t FGCOLR;        /*!< DMA2D Foreground Color Register,                Address offset: 0x20 */
    8 A; q% T. A6 J. Q7 h
  12.   __IO uint32_t BGPFCCR;       /*!< DMA2D Background PFC Control Register,          Address offset: 0x24 */
    5 e. Y5 y9 w: i' z
  13.   __IO uint32_t BGCOLR;        /*!< DMA2D Background Color Register,                Address offset: 0x28 */
    ; ?5 L7 B9 u/ M* V0 A' d/ B$ x
  14.   __IO uint32_t FGCMAR;        /*!< DMA2D Foreground CLUT Memory Address Register,  Address offset: 0x2C */
    + w3 i' Q; s  n
  15.   __IO uint32_t BGCMAR;        /*!< DMA2D Background CLUT Memory Address Register,  Address offset: 0x30 */
    # @; i' t, M1 I# p8 E
  16.   __IO uint32_t OPFCCR;        /*!< DMA2D Output PFC Control Register,              Address offset: 0x34 */' t- i- L7 o' M( v  f7 _5 C. ^
  17.   __IO uint32_t OCOLR;         /*!< DMA2D Output Color Register,                    Address offset: 0x38 */: Z" Y) h; y5 {3 T5 Z4 f+ a6 q3 ]
  18.   __IO uint32_t OMAR;          /*!< DMA2D Output Memory Address Register,           Address offset: 0x3C */1 k7 q! J; d7 ?  E% w; m+ H/ X- E
  19.   __IO uint32_t OOR;           /*!< DMA2D Output Offset Register,                   Address offset: 0x40 */4 o% x2 }: ?  a# v$ o$ [8 }5 X
  20.   __IO uint32_t NLR;           /*!< DMA2D Number of Line Register,                  Address offset: 0x44 */7 j1 }# V5 s/ ?2 S) M; \: [0 S$ \( Y
  21.   __IO uint32_t LWR;           /*!< DMA2D Line Watermark Register,                  Address offset: 0x48 */
    * Q# k6 f" o- {: H
  22.   __IO uint32_t AMTCR;         /*!< DMA2D AHB Master Timer Configuration Register,  Address offset: 0x4C */
    / Z9 @5 }! v& E6 C0 O0 E
  23.   uint32_t      RESERVED[236]; /*!< Reserved, 0x50-0x3FF */
    7 C$ A3 B1 J5 g; b' E# X
  24.   __IO uint32_t FGCLUT[256];   /*!< DMA2D Foreground CLUT,                          Address offset:400-7FF */
    # ~7 H' |- g: L  Z) z3 ?! k: N/ m, K0 s9 x
  25.   __IO uint32_t BGCLUT[256];   /*!< DMA2D Background CLUT,                          Address offset:800-BFF */
    $ g$ h" y) Z* W+ v) R$ z4 |
  26. } DMA2D_TypeDef;
复制代码
; V/ M% d9 m4 ^; z+ c2 A# q

5 B+ G1 q% J' v* w__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
% `1 u1 `& v) N9 Y' M7 A
  o, u9 i* X3 @; J; u( O0 h
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */5 ^2 V$ H. q3 P6 u  n# r
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

3 @2 b8 Y2 Q9 {' g" C. n% e- f下面我们再看DMA2D的定义,在stm32h743xx.h文件。
  1. #define PERIPH_BASE              ((uint32_t)0x40000000) , C! ^& O$ l$ J1 A( C% K
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000)9 z0 B% z; W( q5 J
  3. #define DMA2D_BASE               (D1_AHB1PERIPH_BASE + 0x1000)
    6 d, u6 C1 e% ]. m+ h( ?
  4. #define DMA2D                    ((DMA2D_TypeDef *) DMA2D_BASE) <----- 展开这个宏,(DMA2D_TypeDef *) 0x52001000
复制代码

; x2 W; ?0 F4 O0 C8 C我们访问DMA2D的ISR寄存器可以采用这种形式:DMA2D->ISR = 0。* y- I6 T) X6 R8 q. f' s2 g
& s) K) j- F- ?, D
55.3.2 DMA2D参数初始化结构体DMA2D_InitTypeDef
- q) H6 _: L0 Q3 x% H. s此结构体用于配置DMA2D的基本参数,具体定义如下:
1 N& D% ^6 D4 Z/ X% U
! R# X* J$ t0 ]: j9 p& a9 N- b, w
  1. typedef struct, m" R+ D9 U/ w* R- s# F
  2. {
    0 F) W2 G, c( }3 H0 Y& K" z
  3.   uint32_t             Mode;              
    $ w! l' F3 ?/ c9 Q. o# M
  4.   uint32_t             ColorMode;        7 X/ n$ l! G, s  c: ?
  5.   uint32_t             OutputOffset;       / Z, i5 o- D9 `; y/ y, O
  6.   uint32_t             AlphaInverted;   
    - i$ P  \! U* Q
  7.   uint32_t             RedBlueSwap;       1 @6 v( V$ i+ n# t: a" y
  8. } DMA2D_InitTypeDef;
复制代码

. B3 k5 O2 o% |4 P7 `7 K0 F下面将这几个参数逐一为大家做个说明:# G$ _/ d* e# y# p. z' a# t+ c
3 w$ }1 J! c2 h6 ~# d
  uint32_t   Mode
8 v5 Z+ f8 N% @- x, j* u9 M此参数用于设置DMA2D的传输模式,具体支持的参数如下:
  l$ c- `; f% h' C  m5 n; P% K" I" |( b0 t3 n4 g
  1. #define DMA2D_M2M        ((uint32_t)0x00000000U)  /*存储器到存储传输模式 */
    - z" L$ [/ J+ ]7 ]8 o6 s( R
  2. #define DMA2D_M2M_PFC     DMA2D_CR_MODE_0         /*存储器到存储器传输模式,并执行FPC像素格式转 */
    - p; s9 e% ~' b1 w- g9 X/ |
  3. #define DMA2D_M2M_BLEND   DMA2D_CR_MODE_1         /* 存储器到存储器模式,并执行像素格式转换和混合 */7 A0 A2 X2 y+ o
  4. #define DMA2D_R2M         DMA2D_CR_MODE           /* 寄存器到存储器传输模式 */! j* ^8 f6 M. `( J8 T; U0 E& _
复制代码
+ c  i! G  O/ K! @8 a- l

, H) B$ {' d% o  uint32_t   ColorMode! M, Z9 Q7 ~* C  _8 S& f
此参数用于设置DMA2D的输出颜色格式,具体支持的参数如下:
$ F/ q7 F% j; \9 m+ J2 b% k" {+ t2 @# I2 L  ~" c, ^% T  G
  1. #define DMA2D_OUTPUT_ARGB8888       ((uint32_t)0x00000000U)               /* ARGB8888 */+ r- p7 W$ |3 |8 \2 q
  2. #define DMA2D_OUTPUT_RGB888         DMA2D_OPFCCR_CM_0                     /* RGB888 */5 s/ y# L' H0 T
  3. #define DMA2D_OUTPUT_RGB565         DMA2D_OPFCCR_CM_1                     /* RGB565 *// d: Z" M; C$ n
  4. #define DMA2D_OUTPUT_ARGB1555       (DMA2D_OPFCCR_CM_0|DMA2D_OPFCCR_CM_1) /* ARGB1555 */
    & n. k& O6 D! U' e- ]' A1 i
  5. #define DMA2D_OUTPUT_ARGB4444       DMA2D_OPFCCR_CM_2                     /* ARGB4444 */1 Z( r; a0 m) `$ J6 i+ y& J
复制代码

' V7 z1 Q+ `+ c. `  c5 j
( h9 V! v% L  e) q* S9 z) S  uint32_t   OutputOffset/ N3 y0 O" U# M
此参数用于设置输出位置的偏移值,参数范围0x0000到0x3FFF。
& Y3 T0 D1 Z! j5 D" H8 y) D
3 U0 C4 {8 x/ N- Y5 s  uint32_t   AlphaInverted
% d7 S1 ], t5 q此参数用于设置DMA2D的输出颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     ( I* `( _1 @7 U

; v6 ~3 k, M2 {: ]" k. a! [
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */
    - D4 ^3 P6 s6 ?( D
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */
复制代码

! j% y3 s+ A$ O7 @( N% x' c  uint32_t   RedBlueSwap
/ {7 I8 ^( b6 X1 ~' q此参数用于设置DMA2D的输出颜色格式中R通道和B通道的交换,具体支持的参数如下:
, n1 c* L, x: u! K$ H2 b6 J. M6 ~3 r: f  X" y
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */
    * T' W! F9 J; e0 T
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码

9 o9 D$ y! S- Y+ \- \1 M# i55.3.3 DMA2D的图层结构体DMA2D_LayerCfgTypeDef0 P7 j3 b& x3 M5 M" s  l! a
此结构体用于配置前景色和背景色。
/ P/ i, ?( p* r8 @8 D, F" A/ Z0 g. }4 t7 Z! g
  1. typedef struct3 W  ?& J* y3 s% c, t
  2. {1 S$ ?7 `8 [. m6 J4 F
  3.   uint32_t             InputOffset;       2 R5 k3 x8 F1 s) a. c" f
  4.   uint32_t             InputColorMode;   
    ; d# k# p6 T- q. z- N9 c3 q
  5.   uint32_t             AlphaMode;        2 d0 \+ y! _, v: p
  6.   uint32_t             InputAlpha;        ; i/ j3 u8 P1 Q$ q! O0 s
  7.   uint32_t             AlphaInverted;    % E' v' G8 l/ S
  8.   uint32_t             RedBlueSwap;      
    1 e* p( {: V- P, }, d! ~: r
  9.   uint32_t             ChromaSubSampling;8 F. k3 Q( _1 }; j1 g: q
  10. } DMA2D_LayerCfgTypeDef;
复制代码

; S* O  E+ C7 A: S1 r8 ^: [下面将这几个参数逐一为大家做个说明。
1 ^! S3 M% `4 X* R8 ^4 d- C4 G
' U1 e, k2 Y0 ^' {. T5 C  uint32_t  InputOffset/ u# n/ O% R+ T$ Q3 I
设置前景色或者背景色的输入偏移,范围0x000到0x3FFF。
% Y( K0 c% f' L' V& I  r, K  Y( _8 E0 ]& M- ~
  uint32_t  InputColorMode; h) m& E8 w- Z
设置前景色或者背景色的输入颜色格式,具体支持的参数如下:
  q* U1 U) s2 M2 D* r4 H9 `1 K8 M) `+ v. w" Y+ W& r  Z4 k6 ?% o+ ^
  1. #define DMA2D_INPUT_ARGB8888        ((uint32_t)0x00000000U)  /* ARGB8888 */
    8 L3 V- L5 I& ]# B+ E& ^$ j" l+ h; S
  2. #define DMA2D_INPUT_RGB888          ((uint32_t)0x00000001U)  /* RGB888   */+ V: ]: Y( r) U4 o; V" s
  3. #define DMA2D_INPUT_RGB565          ((uint32_t)0x00000002U)  /* RGB565   */
    * \# \5 E$ Y% z. u
  4. #define DMA2D_INPUT_ARGB1555        ((uint32_t)0x00000003U)  /* ARGB1555 */" z$ F& i$ E; Q. b! t' H  q
  5. #define DMA2D_INPUT_ARGB4444        ((uint32_t)0x00000004U)  /* ARGB4444 */+ m) z7 s6 ]' L6 s1 a5 X( l
  6. #define DMA2D_INPUT_L8              ((uint32_t)0x00000005U)  /* L8       */2 K# c2 W/ U$ `8 F& b1 i
  7. #define DMA2D_INPUT_AL44            ((uint32_t)0x00000006U)  /* AL44     */
    ( m3 N- B4 n5 x1 `" f/ E
  8. #define DMA2D_INPUT_AL88            ((uint32_t)0x00000007U)  /* AL88     */7 ~& G! q" Y( d) c1 {/ ^
  9. #define DMA2D_INPUT_L4              ((uint32_t)0x00000008U)  /* L4       */# m- g% ^4 ^3 D
  10. #define DMA2D_INPUT_A8              ((uint32_t)0x00000009U)  /* A8       */
    # |3 F' w7 W+ I( f% C, v+ \
  11. #define DMA2D_INPUT_A4              ((uint32_t)0x0000000AU)  /* A4       */
    0 w! [! s! `% ?; L( _& C
  12. #define DMA2D_INPUT_YCBCR           ((uint32_t)0x0000000BU)  /* YCbCr    */
复制代码

1 G; K6 t( @1 K0 \& K' }  uint32_t AlphaMode
* y8 [  l9 s& [3 R8 `3 c设置前景色或者背景色的Alpha模式,具体支持的参数如下:" `. J& J; G' j* W5 y! i
8 g5 y" Q4 q- [$ \6 {; s
  1. #define DMA2D_NO_MODIF_ALPHA   ((uint32_t)0x00000000U)  /* 不修改Alpha通道值 */
    5 o- N# Y. U: J  D; `
  2. #define DMA2D_REPLACE_ALPHA    ((uint32_t)0x00000001U)  /* 用新设置的Alpha值替换原始Alpha值 */' D3 ]8 z( l2 i9 Y% n
  3. #define DMA2D_COMBINE_ALPHA    ((uint32_t)0x00000002U)  /* 用新设置的Alpha值与原始Alpha值的乘积替换原始Alaha值*/
复制代码
" Z/ F- w0 o- _( o1 [! {
  uint32_t  InputAlpha( B8 ~7 W4 a: w- l) s& |( }
设置前景色或者背景色的Alpha值,范围0x00到0xFF,如果颜色格式是A4或者A8,那么此参数的范围是0x00000000到0xFFFFFFFF,标准的ARGB8888格式。
/ [, P! {8 g  b
) s8 s9 c! W8 u0 W2 j  uint32_t AlphaInverted- s; d  l. O+ h) e4 o+ Y
设置前景色或者背景色的输入颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     
, Q2 W! z  a  c8 R. W- r# c5 x1 u% y4 s( e' X1 U& a- E7 Y2 S/ f0 S
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */
    & T9 l5 ^, q: U" ?' ?9 ]
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */     
复制代码
; i+ k2 Y" }# X% k0 E
  uint32_t   RedBlueSwap
  R% V' Q* Z* h7 }设置前景色或者背景色颜色格式中R通道和B通道的交换,具体支持的参数如下:
6 p  U$ h& I4 T6 a% [1 X, z9 c( O2 G6 i
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */
    9 ^; o& @  Q* C) v; C5 S) f8 |
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码
- L& ^! S( u+ Q) O8 ^0 H3 t
  uint32_t   ChromaSubSampling
3 F. t% @/ z" Q设置前景色或者背景色中YCbCr 颜色模式的采样格式,具体支持的参数如下:
  1. #define DMA2D_NO_CSS               ((uint32_t)0x00000000)  /* 4:4:4 */3 S* F8 O+ L$ g
  2. #define DMA2D_CSS_422              ((uint32_t)0x00000001)  /* 4:2:2 */5 ~% z5 g7 E  A4 L
  3. #define DMA2D_CSS_420              ((uint32_t)0x00000002)  /* 4:2:0 */  
复制代码
/ X# I+ h' i8 e; U2 b) s; _
55.3.4 DMA2D句柄结构体DMA2D_HandleTypeDef

2 |- {  ]8 i. ^3 PHAL库在DMA2D_TypeDef, DMA2D_InitTypeDef和DMA2D_LayerCfgTypeDef的基础上封装了一个结构体DMA2D_HandleTypeDef,定义如下:
# L- n7 f% R# T5 E8 v% R' u( _. I' b, [8 B6 L$ n+ z
  1. typedef struct __DMA2D_HandleTypeDef' ^3 a$ x! v5 t: j3 A: {3 c( x
  2. {
    ) h9 k' F# ?* ?7 v0 v: T$ r
  3.   DMA2D_TypeDef               *Instance;                                                                                                                                                                                          
    + u# m  \4 }8 z8 w
  4.   DMA2D_InitTypeDef           Init;                                                        
    ( Q6 H7 Q5 G& N3 S* \! q0 V- F
  5.   void                        (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                                                                             
    / M& S1 `' B. `2 P$ m4 q
  6.   void                        (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                      
    $ k$ s; h$ ?# L6 Z% ~1 _
  7.   DMA2D_LayerCfgTypeDef       LayerCfg[MAX_DMA2D_LAYER];                                    
    : ^# @% e  ]0 M2 D! _  X+ ]
  8.   HAL_LockTypeDef             Lock;                                                                                                                                                                                                    , w8 v, o% D: [* N
  9.   __IO HAL_DMA2D_StateTypeDef State;                                                                                                                                                                                                   & Z1 v( ~( Y% I, G# e
  10.   __IO uint32_t               ErrorCode;                                                   } DMA2D_HandleTypeDef;
    * v* \/ k, K/ V
复制代码

" ^' m9 N( O& A+ X下面将这几个参数逐一做个说明。
* f, o+ Q1 O  Q) ?3 p" {
, G  r$ |" o) r& _' v$ n  DMA2D_TypeDef  *Instance* q6 h# k2 o3 D3 N  B! J( T  z
这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。. p+ |2 E7 ?& E3 l5 v8 i

1 h2 r5 d: H8 ~1 i. T  DMA2D_InitTypeDef  Init;  . P/ T6 H/ C/ ^( A% h7 h% j
这个参数是用户接触较多的,用于配置DMA2D的基本参数,详见本章3.2小节。( |- G! C! x+ Y# t$ ?3 |4 h
" N: y( M2 a2 ]$ `% S' E
  void     (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);
$ R, U; @4 {$ C0 b6 D  void     (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);
8 E( Q0 l$ v% K; g8 ODMA2D中断服务程序里面执行的回调函数,一个是传输完成回调,另一个是传输错误回调。9 [3 d' U" C+ z# q; K' f7 \
* F: e5 o/ k: v7 y" h
  DMA2D_LayerCfgTypeDef   LayerCfg[MAX_DMA2D_LAYER]2 l1 v5 Q/ h& O1 X/ S* t; F, l
这个参数用于前景色和背景色的设置,MAX_DMA2D_LAYER=2,详见本章3.3小节。
9 {4 [2 b( K. A2 P! B% K0 l) n, A
/ p9 Q' o, s( p4 y' q2 `  HAL_LockTypeDef   Lock
4 l* {# h' W2 ]: \9 S" j__IO uint32_t    State;. b' U3 Z  g  b

: b- d/ k) V7 }) n__IO uint32_t    ErrorCode
$ h9 j# J# t1 X* B, B' }* @! o
, r' _- ^  d4 j6 L2 w2 b# Q这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置DMA2D通信状态,而ErrorCode用于配置代码错误。  h6 t: T7 q0 ^9 a; R( w9 w

: i+ w5 v( ~( c! ?0 ?55.3.5 DMA2D初始化流程总结

2 ~6 I2 M3 x  J5 q0 k2 A对于DMA2D来说,其实不需要初始化流程,每个功能都可以直接封装出一个函数来,下个章节会为大家专门讲解,也是实际项目比较推荐的方式。
- l4 v) i$ ], q: Z  x8 T# @& I2 V6 q& W. C
55.4 源文件stm32h7xx_hal_dma2d.c
& w$ \. _4 M4 I6 G+ X; W这里把我们把如下几个常用到的函数做个说明:
! u- r) n8 \9 J8 X" h% i. K; M# Z; d9 t4 n
  HAL_DMA2D_Init
6 C6 e6 |+ ~  D6 _' Z  HAL_DMA2D_ConfigLayer
% a8 m5 E0 p! G* N  HAL_DMA2D_Start_IT
8 C! a, t( t+ v* d2 x9 x  HAL_DMA2D_BlendingStart_IT  N! w4 _/ H& S1 G4 T  Y" Z

7 ~' w9 T: |2 I) f* E55.4.1 函数HAL_DMA2D_Init' i6 J" f; e5 ~5 ~" L( M' Q. a
函数原型:# S2 ?4 {+ I+ z9 j1 J2 [

# R, S3 N% O! u6 s3 I
  1. HAL_StatusTypeDef HAL_DMA2D_Init(DMA2D_HandleTypeDef *hdma2d)
    7 s- L/ {9 @' P* z
  2. { : B: D' @$ q6 P+ Q0 _& q

  3. 7 c+ n3 d4 t5 d+ T  n5 M
  4. /*  检测参数是否有效 */% }! Y+ g) g4 X; @8 {( L  ?4 E4 p6 Y
  5.   if(hdma2d == NULL)7 J1 h4 O. ^# ~1 E5 s
  6.   {8 N! L) d& K/ [0 G+ L8 H
  7.      return HAL_ERROR;
    9 w6 r8 Y9 E4 ?6 o( a# {
  8.   }( u# M' \/ m) U" V* A
  9. 9 {- c# l7 }% l, e, b+ c; R
  10.   /* 检测函数形参 */* h/ T' ~& A) n0 m9 {/ x/ ^. M
  11.   assert_param(IS_DMA2D_ALL_INSTANCE(hdma2d->Instance));5 V3 E' E4 x" L4 c: E" m
  12.   assert_param(IS_DMA2D_MODE(hdma2d->Init.Mode));
    8 G1 ], y7 P/ l6 C* S5 A7 f+ t. T
  13.   assert_param(IS_DMA2D_CMODE(hdma2d->Init.ColorMode));
    2 a' y8 [+ [+ ]  W, J
  14.   assert_param(IS_DMA2D_OFFSET(hdma2d->Init.OutputOffset));
    * X4 i$ E: I* Y( z/ U- b. R6 O

  15. 7 K% [5 W1 }5 `6 M+ [0 R, v
  16.   if(hdma2d->State == HAL_DMA2D_STATE_RESET)3 m8 m7 d% \) ~$ J( y1 u+ h
  17.   {$ @* `5 T& A9 O0 I; N2 k. U' ~9 e- }
  18.     hdma2d->Lock = HAL_UNLOCKED;9 c* a1 R; t' V, B+ C; Z# F
  19.     /* 初始化GPIO,NVIC等 */
    / _5 x# A* @; T* i8 L' K3 {
  20.     HAL_DMA2D_MspInit(hdma2d);
    " z* ?  @6 g3 |5 W( n8 U% Q
  21.   }: {9 `7 w& [) o0 P) t1 @
  22. ! c1 J: m. D- W( a( d; I
  23.   /* 设置DAM2D外设状态 */# m4 [! E) f: s( Q
  24.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  
    + A) a5 Z& t. {: S/ x
  25. ( t  o+ D' Q+ T
  26.   /* 设置DAM2D工作模式 -------------------------------------------*/
    $ {  n& {0 v9 x  @
  27.   MODIFY_REG(hdma2d->Instance->CR, DMA2D_CR_MODE, hdma2d->Init.Mode);
    4 k! H5 X: O! h
  28. % y6 J1 c2 T0 _6 H* A9 Y  q6 ?
  29.   /* 设置输出颜色格式 ---------------------------------------*/
    $ g( }$ F" f/ z
  30.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_CM, hdma2d->Init.ColorMode);+ p+ T; V: b( Y; y3 {1 K

  31. + X$ D* e: a. U4 ?8 e
  32.   /* 设置输出偏移 ------------------------------------------*/  & y0 i; _5 }& c1 Z
  33.   MODIFY_REG(hdma2d->Instance->OOR, DMA2D_OOR_LO, hdma2d->Init.OutputOffset);  
    8 }. |$ x8 R( A' p

  34. ( ]6 E! H7 G1 P( |0 v  @5 k
  35.   /* 设置输出颜色格式中的Alpah值反转 */' S( A/ }2 b+ v
  36.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_AI, (hdma2d->Init.AlphaInverted << DMA2D_POSITION_OPFCCR_AI));
    * \2 n" N1 b, [1 n/ {

  37. , h- W% N( k  D4 m2 }+ V( Q
  38.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_RBS,(hdma2d->Init.RedBlueSwap << DMA2D_POSITION_OPFCCR_RBS));3 R0 m, z8 b# P) _
  39. 2 m' O  {7 L$ c( y3 w4 o
  40. ( c! N& |' G- r5 i$ j- c
  41.   /* 无错误 */! ]! m1 E7 H# Q; f* T9 ]" o
  42.   hdma2d->ErrorCode = HAL_DMA2D_ERROR_NONE;) B; e6 n- J0 f& v
  43. # X2 B" |$ g' l* U& J! K+ C
  44.   /* DAM2D就绪 */: i- ]. N6 ?1 z- m% i9 a
  45.   hdma2d->State  = HAL_DMA2D_STATE_READY;0 s! R% g2 p/ k7 b, Y, k
  46. 9 k7 G" a' i& X2 c4 m) }
  47.   return HAL_OK;
    . p1 L# A& H5 s+ j8 t( c
  48. }
复制代码

5 o9 s6 F6 O% S- `函数描述:) N* a/ L  |( W) {1 ^1 Y
* [; _, [! e# u, v; R( _9 j
此函数用于初始化DMA2D的工作模式和输出颜色格式。, D; f  T/ M/ P; @# E; ?6 L

7 |1 n6 W9 Z# S; b0 d4 l函数参数:
" y: ~" l  q4 y/ d8 w; O
1 n$ v! w5 z9 x% s. D8 s2 y: h  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。' ?6 q1 a3 h* M1 q
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。: @" c/ S, [( f& P0 x
注意事项:
9 L! ?' F1 }/ l+ h3 D5 J5 y
2 Q) A0 ]8 \; H; b7 G- \函数HAL_DMA2D_MspInit用于初始化DMA2D的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。: Q; p1 Q) d- `# _" T8 k. v
如果形参hdma2d的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量DMA2D_HandleTypeDef Dma2dHandle。
1 N5 q4 }( }& Z+ r7 r. i. \对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_DMA2D_STATE_RESET  = 0x00U。% y/ I. b( B0 }+ G# Z6 m
/ k* A5 m% w" c
解决办法有三# v7 `, x: h' m: t+ `) R$ F

6 G, @9 h) }% Z方法1:用户自己初始DMA2D底层。2 z0 r) O" C$ J* o! K

) Q  L* e5 _3 W方法2:定义DMA2D_HandleTypeDef LtdcHandle为全局变量。
( a; O  u0 [7 b! Q7 S
( m; t* o! j$ o! a1 b方法3:下面的方法
  1. if(HAL_DMA2D_DeInit(&Dma2dHandle) != HAL_OK)
    6 n( `; c& ]  G0 D- i
  2. {8 J8 D) B& E% l7 Y5 F$ L
  3.     Error_Handler();3 U7 g6 Y: X1 j9 M4 `
  4. }  
    . _5 y4 S1 O. x/ O* g3 p
  5. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
    - `( y% `" G9 S- H0 {1 x
  6. {
    ' J" Y' K2 {; ]. f, H$ {1 k9 }8 i
  7.     Error_Handler();
    8 ?  N: m1 T3 \% w+ t% g. c' T
  8. }
复制代码
/ }! M8 ~$ q$ L0 l

  W/ [, z' C8 K* h% \7 a+ y. Z9 a使用举例:
) Q7 L% I4 Z$ H7 J7 g  {( ]" S2 n' W' ]+ S8 a
  1. DMA2D_HandleTypeDef Dma2dHandle;% m; n" |; x2 s7 b( j  b3 Z

  2. 7 F, l0 T  O8 p) [' J! F* ^
  3. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/" X8 j& y- _) Q( t' N( G
  4. Dma2dHandle.Instance = DMA2D;
    9 }" k. z1 `3 l6 V4 v

  5. 0 L4 d6 Z/ }0 p# i5 o4 c6 A" N
  6. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */
    . T7 r+ E0 q8 {* u& u
  7. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */
    ; G! h% H, h: U4 U( k1 j# C
  8. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */& L' _: d" }9 |. p) c& L
  9. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */' l. v% N1 A" G1 E4 w; T0 o5 t+ V& h
  10. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */
    $ i+ }! u4 s3 i2 G

  11. : e7 s5 @0 k; r6 k- }4 b3 a
  12. /*##-2- DMA2D 回调函数配置 ######################################*/
    & q9 D0 r5 _) Q8 {4 V( K; Y4 F! e  n$ {
  13. Dma2dHandle.XferCpltCallback  = TransferComplete;
    & a# H, S3 u0 M$ b
  14. Dma2dHandle.XferErrorCallback = TransferError;$ j# g) ?" p" o8 A
  15. ) L; r/ E, @7 {+ F% D1 Z4 ]6 l
  16. /*##-3- 前景层配置 ###########################################*/# }; e" j5 V) q3 a3 T
  17. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */
    ( y- h0 e: H* I! n
  18. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */2 P( w0 ~6 j/ u$ }5 V( I, a! H5 p* D
  19. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */
    , K; b% g2 P: C- b8 L* z; {
  20. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */3 H  X. Z9 X7 \4 I- g5 F: Q
  21. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/5 a; B$ d- i4 S7 J1 E* H
  22. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/
    % S7 t# R# \" [  j# e

  23. " w7 P* _2 ?- N: ?! c& y3 }
  24. + V& E1 l  `9 i2 u' P
  25. /*##-4- DMA2D 初始化 ###############################################*/
    - H  }+ S; o  u( C5 h% F9 y4 q
  26. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
    7 e* {5 V& y& |+ H
  27. {! K8 B5 E, i" [* U  |& H; v
  28.     Error_Handler();( ~5 C# d/ y" ?; k) ?
  29. }
复制代码

- ]8 Z/ M  ]" ?5 I* D. S1 t55.4.2 函数HAL_DMA2D_ConfigLayer
2 E( d( o+ B1 K* {* Y8 k6 Q& ~9 n函数原型:
  M0 R* O: Q% ~" v' a2 G3 @4 z( E
$ m, W/ w! S! K  t" m' F7 r
  1. HAL_StatusTypeDef HAL_DMA2D_ConfigLayer(DMA2D_HandleTypeDef *hdma2d, uint32_t LayerIdx)& {( ?1 e) K: |: n, d/ y! G
  2. { ; |- z$ e! b4 q" @/ t
  3.   DMA2D_LayerCfgTypeDef *pLayerCfg = &hdma2d->LayerCfg[LayerIdx];0 X$ U& b8 G: k4 x3 n: c! S

  4. + ?2 }! b- u; H+ U. n1 E* ?
  5.   uint32_t regMask = 0, regValue = 0;
    ( z, R: V. C/ Y8 |. ?0 C8 |8 n

  6. 5 F  s0 n2 z1 s7 s  @1 I
  7.   /* 检查参数 */3 x" L* f! X' L9 b) N% J7 y$ A0 B
  8.   assert_param(IS_DMA2D_LAYER(LayerIdx));  4 S6 Q$ d2 s* S# D2 D: z) O
  9.   assert_param(IS_DMA2D_OFFSET(pLayerCfg->InputOffset));  
    9 v3 B1 A% x5 `5 G6 m  E0 v
  10.   if(hdma2d->Init.Mode != DMA2D_R2M)
    & y" f  s  T2 I# z
  11.   {  - P9 ~$ d9 G1 [) K
  12.     assert_param(IS_DMA2D_INPUT_COLOR_MODE(pLayerCfg->InputColorMode));1 H  m2 e0 ~. s7 D$ ?8 t+ F* D
  13.     if(hdma2d->Init.Mode != DMA2D_M2M)
    ; j3 m+ e4 H+ L* z& X/ L
  14.     {7 ^4 \. X, B, u2 B5 M+ s6 w9 @$ A
  15.       assert_param(IS_DMA2D_ALPHA_MODE(pLayerCfg->AlphaMode));
    2 T9 V; O, |  J4 a& z3 C- w
  16.     }
    * j  \6 r$ B) V# _0 `
  17.   }& F( r- x0 f, E3 ~

  18. 7 J3 O1 F: g' X: `. q
  19.   /* 上锁 */
    6 x+ @) p$ E! P0 O$ y
  20.   __HAL_LOCK(hdma2d);- m  x1 @: w$ L% P! U% I

  21. # W  g" j, @. k/ X% r3 [
  22.   /* 设置DMA2D外设状态 */
      H- F2 A3 Q* R7 U" q2 D5 x
  23.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  & t( E. E8 C: @/ t
  24. * q' A0 z) M" q9 B/ z- E
  25.   /* 准备好背景层或者前景层FPC寄存器配置参数*/
    2 X/ b6 o# H4 l# `3 @
  26.   regValue = pLayerCfg->InputColorMode | (pLayerCfg->AlphaMode << DMA2D_POSITION_BGPFCCR_AM) | \
    + L9 L$ [1 ?1 Y, ?4 ~+ R0 [
  27.             (pLayerCfg->AlphaInverted << DMA2D_POSITION_BGPFCCR_AI) | \
    ! S; |, F2 ]! L- \; x" p, _9 |5 _
  28.             (pLayerCfg->RedBlueSwap << DMA2D_POSITION_BGPFCCR_RBS);+ A% s- ]7 E' `; {6 B
  29. ( e+ @. G8 m: m  {. n& U# g
  30.   regMask  = DMA2D_BGPFCCR_CM | DMA2D_BGPFCCR_AM | DMA2D_BGPFCCR_ALPHA | DMA2D_BGPFCCR_AI | DMA2D_BGPFCCR_RBS;
    ! _, v3 t* p: e. |" J6 e/ [8 b5 l

  31. 2 I2 T& p8 ?2 m: y
  32.   if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    ' p1 ?2 Q9 J+ t# b
  33.   {& `- W9 b4 R# z/ i
  34.     regValue |= (pLayerCfg->InputAlpha & DMA2D_BGPFCCR_ALPHA);
    $ A- f1 l2 w4 r2 e
  35.   }
    2 @4 C+ Q3 }( G7 P) P3 q
  36.   else
    ! l5 ^6 Y% h% K6 U& q3 M; |
  37.   {5 z$ C, O( e, r+ j
  38.     regValue |=  (pLayerCfg->InputAlpha << DMA2D_POSITION_BGPFCCR_ALPHA);# g$ l# _/ h: c/ H, c0 a
  39.   }6 |& s; X+ m: M. ?. N( }

  40. 9 J* r, n" ?6 f( ~
  41.   /* 配置背景层 */
    & e9 _, U2 [- G6 c( q% l0 \" C# A
  42.   if(LayerIdx == 0)* _, i! {8 B% P1 e; Y
  43.   {/ U$ ]7 G; d  V  r7 U+ e, c0 h
  44.     /* DMA2D BGPFCCR 寄存器 */
      ^# D# v# n9 j8 k: V
  45.     MODIFY_REG(hdma2d->Instance->BGPFCCR, regMask, regValue);
    5 {# U' g1 s& W( Z  A$ K
  46. 5 X+ y$ z0 p1 ~/ V# _
  47.     /* DMA2D BGOR 寄存器 */  & }6 l5 Q7 \1 B( c0 `0 v
  48.     WRITE_REG(hdma2d->Instance->BGOR, pLayerCfg->InputOffset);
    0 `5 u8 y) ^: y& b0 a0 E

  49. 3 M7 V# R2 i* _8 b
  50.     /* DMA2D BGCOLR 寄存器 */
    3 h6 W  x: O7 k6 b! X" f
  51.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    ! r/ |! X' ?" J6 }5 x' ~, D
  52.     {    + t& ^% c- A) [  G! z
  53.       WRITE_REG(hdma2d->Instance->BGCOLR, pLayerCfg->InputAlpha &
    5 z# \7 h+ _2 d  D" M
  54. (DMA2D_BGCOLR_BLUE|DMA2D_BGCOLR_GREEN|DMA2D_BGCOLR_RED));
    4 U" C2 N$ @/ ?: Y# P2 X  j
  55.     }   
    + c9 b) `* Q3 Y
  56.   }0 i$ @' P& m* z6 T
  57.   /* 配置前景层 */
    * u4 L; f9 G0 w: `0 N
  58.   else
    7 `- a. k; x# V- B) `" d: e
  59.   {' R" A  \/ z+ L6 x
  60.     if(pLayerCfg->InputColorMode == DMA2D_INPUT_YCBCR)/ T  [% R+ H% h7 f( p
  61.     {( U" d9 M# J" U2 w
  62.       regValue |= (pLayerCfg->ChromaSubSampling << DMA2D_POSITION_FGPFCCR_CSS);
    $ u) [3 h7 T, H
  63.       regMask  |= DMA2D_FGPFCCR_CSS;
    7 t3 _. J$ t( C, M% T
  64.     }
    3 o7 c! n) W# D
  65. 8 c1 R4 B" V1 I! [9 q! @- f  _
  66.      /* DMA2D FGPFCCR 寄存器 */
      e4 ?. H7 L4 B" m9 l* V
  67.     MODIFY_REG(hdma2d->Instance->FGPFCCR, regMask, regValue);
    & q5 o( c2 `. A- [# v9 n; U. T
  68. 6 v) `' F7 Y& i& d  P
  69.     /* DMA2D FGOR 寄存器 */9 C; M. ^2 v+ O
  70.     WRITE_REG(hdma2d->Instance->FGOR, pLayerCfg->InputOffset);      
    1 `( c7 S0 t* q. b: ~5 W1 f7 Y; ?
  71. / T2 j) W/ Z& q  X1 v& m
  72.     /* DMA2D FGCOLR 寄存器 */   
    5 k4 W7 t5 E, W3 H' R5 F
  73.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    ) s: S& L. z2 Q$ u# O8 n; |
  74.     {$ Q8 S% c  r/ p
  75.       WRITE_REG(hdma2d->Instance->FGCOLR, pLayerCfg->InputAlpha &
    ; `: |( F1 s/ U1 I% O
  76. (DMA2D_FGCOLR_BLUE|DMA2D_FGCOLR_GREEN|DMA2D_FGCOLR_RED));      & M; Z+ A% G2 L" ?! q6 k3 O
  77.     }   
    ; r9 ^8 h/ @; E+ Z9 G
  78.   }   
    $ ?0 R: p! A" {7 e, p. b8 ?+ t
  79.   /* DMA2D就绪 */9 E4 N& c& Q% |: I! E. U1 _4 k
  80.   hdma2d->State = HAL_DMA2D_STATE_READY;$ n% H2 W( ]# b7 L! I7 I

  81. 7 ~$ k/ @/ b2 k' s: n- ?
  82.   /* 解锁 */
    6 t5 f5 l8 O, x! p. I
  83.   __HAL_UNLOCK(hdma2d);  4 P2 r! G( i* y; K! ^; ], B
  84. ) n# z. t' b1 c; Z# ^( ?' H
  85.   return HAL_OK;: i4 r3 V+ T. @
  86. }
复制代码

3 D7 S: B4 A/ O* `函数描述:& u4 x: q0 Z( q4 C# X% k  D1 {4 Y
" e3 f1 x' x3 Z. A  ~$ i$ h3 X
此函数主要用于配置DMA2D要转换的前景层和背景层,即输入颜色配置。而前面的函数HAL_DMA2D_Init配置的输出颜色。6 g' w. E5 }! F+ M
! u/ U( q  S6 S1 l% A" G
函数参数:
. t+ Z6 J, c7 }
% ~% H# H, d" W- \$ Z$ G  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。5 _/ f! v! E; w# P# _$ n2 R( r
  第2个参数用于配置前景层和背景层,0表示背景层,1表示前景层。, l9 o% A9 k7 m! F! x8 P
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。& F5 {- F9 n) j. U( W( z
使用举例:5 \& X5 C( s. h* T  X7 I! ~

  1. 0 D9 g8 g1 v0 A4 l
  2. DMA2D_HandleTypeDef Dma2dHandle;
    * Q( {/ n$ S' W
  3. ! p' K* H6 x6 K

  4. & H3 M! n! B: ^" t8 V- a
  5. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/# K7 y) L) m( @8 l9 ]/ n- M+ X) ]( F
  6. Dma2dHandle.Instance = DMA2D;1 F8 u( f5 y. k
  7. 4 Z3 D+ B) M5 R
  8. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */# @) |% n8 _' |2 e& C) i4 V1 ]8 R
  9. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 *// j% r2 n: ~' q6 N; p
  10. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */' P) J1 S4 `( n1 m6 F$ c2 T$ R
  11. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */
    3 A5 p$ D6 n* B* p: Q. W% G
  12. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */& H# r) Q) _/ F$ i" g# ~) J
  13. 6 W- a; E* M8 J# F
  14. /*##-2- DMA2D 回调函数配置 ######################################*/
    & H1 t' P0 U% m" G
  15. Dma2dHandle.XferCpltCallback  = TransferComplete;
    , l1 G6 Q& ?$ H5 S  x$ u! n1 ]" e
  16. Dma2dHandle.XferErrorCallback = TransferError;
    8 N4 U' g3 a3 n; i

  17. ! j3 V4 a* }# W7 ]
  18. /*##-3- 前景层配置 ###########################################*/
    0 @! ~7 r+ e7 S3 I: v* {
  19. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */
    ' N  \- P2 j. t, f1 F
  20. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */
    3 X2 v' E) k; B$ J6 H6 V. O
  21. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */6 D  c9 R6 v6 I: _; r' i
  22. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */* c: M- F  `- l  b; s4 d+ O/ q
  23. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/& J- I% ~  {! n+ T4 S3 _% J
  24. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/
    7 ^. N, S5 M% k; _' b0 j
  25. ' Y* Z9 |  C' m3 m$ u5 l
  26. /*##-4- DMA2D 初始化 ###############################################*/; u  _0 E- p0 Y: E3 K  z# F
  27. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)3 K( x+ }. r& s4 f4 _. d$ t- p9 t
  28. {
    / }- n- X6 L6 p# O
  29.     Error_Handler();1 W# m' |( `  u- }; B* O
  30. }: h9 `2 g6 _9 h$ l$ w6 `

  31. ! E# M' ~- R8 i1 P
  32. /* 配置前景层  */4 w2 b0 h/ q/ n! d6 z. U- j: ~( M
  33. if(HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1) != HAL_OK)( R- P2 h' X7 V0 b0 b  T
  34. {# T& H/ w4 D1 T" ~
  35.    Error_Handler();
    & B& Y5 g7 _% `: X9 @. s4 ~1 {
  36. }
复制代码

0 [+ a) V9 \( w( U+ c
$ p0 _2 v; A2 @1 Q' ~6 j, g55.4.3 函数HAL_DMA2D_Start_IT" u6 D/ \6 C( }% |
函数原型:
% n) Z( C: v5 F# F" E  ?+ N" K! h+ {" H
  1. HAL_StatusTypeDef HAL_DMA2D_Start_IT(DMA2D_HandleTypeDef *hdma2d, uint32_t pdata, uint32_t DstAddress, uint32_t Width,  uint32_t Height)
    , Z+ i3 N8 @. B
  2. {
    : }# s2 p! `# I* C/ H& s1 F) w. P
  3.   /* 检测函数形参 */# O$ C8 L" [: q
  4.   assert_param(IS_DMA2D_LINE(Height));& f4 R% w. p& [" O4 M
  5.   assert_param(IS_DMA2D_PIXEL(Width));
    * V* P% y' Y# n+ {  W: l4 X

  6. % r( U# J, Q* u0 G8 b8 N/ \4 Q
  7.   /* 上锁 */
    & F. k* a! l$ A/ E
  8.   __HAL_LOCK(hdma2d);) ^' \: R, q% r: {; w; ?9 O
  9. : u: h6 t* x; B) t% ~6 ~/ P1 R
  10.   /* 设置DMA2D外设状态 */; R& ?: H0 {. T7 ]
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;) U7 k8 v) e( C/ F4 Z
  12. % i, n7 ^5 k: E2 C
  13.   /* 设置源地址,目的地址和数据大小 */
    8 Y; R/ |1 h  s9 k
  14.   DMA2D_SetConfig(hdma2d, pdata, DstAddress, Width, Height);
    - l+ y6 n8 O9 |3 @' |) p2 a

  15. / m& ]* \, c" B* D0 w+ \- L
  16.   /* 使能DMA2D的传输完成中断,传输错误中断和配置错误中断 */+ K# ^) e, S' J" r! v  B! P
  17.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);
    . d/ _7 D4 J! f- ?0 i1 w! I
  18. . k, z' s& g+ _# C2 R4 K9 @* l
  19.   /* 使能DMA2D */3 E- k% w) L/ U* V6 n
  20.   __HAL_DMA2D_ENABLE(hdma2d);6 a6 k5 }( P: Y7 c0 M

  21. " j( L, c. r. f
  22.   return HAL_OK;
    7 \$ ]# R5 [7 L4 Q! R2 r
  23. }
复制代码

. `2 j5 X  a, g. `/ k% N4 N# S函数描述:
. e6 s/ B# I' \' F$ E# [
3 [1 q; v9 }+ o7 U2 ~' Q, G6 Z; K此函数用于启动DMA2D数据传输。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。, p6 q( n* D# H& x2 r! x' F" o9 j

! w9 C/ K5 ^; k7 `" B8 s1 M7 P函数参数:
; b5 l# I' x& K$ E+ J7 ]( K
1 w  t  i. y, V" y$ n  L  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。" I1 F& m* y# U) ]0 |
  第2个参数是源数据地址。
1 ?# o  w, b- z" B' g; e1 c3 I  第3个参数是目的数据地址。5 |4 A+ I) _) F# K( T4 ^
  第4个参数是源数据的长度,即每行的像素个数。) v* F+ B. @$ B6 R
  第5个参数是源数据的高度,即行数。" L4 j* ]; K. H6 U: {
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
: x6 C' J0 Y$ I# Z) j使用举例:
! M# v( k. N, O" S( Y1 h% ?% ?7 t8 @$ T4 A. F
  1. DMA2D_HandleTypeDef Dma2dHandle;
    , x- H; Y5 q  W; L4 H
  2. # [: f. T- C4 F+ q6 Y
  3. if(HAL_DMA2D_Start_IT(&Dma2dHandle,            /* DMA2D句柄 */" @! g; i4 |) l" z' P% J
  4.                       (uint32_t)&BufferInput,  /* 源地址 */ # O0 E; x3 f. T  Q" j, T8 F  s
  5.                       (uint32_t)&BufferResult, /* 目的地址 */: ~, a1 M' r. l& D1 t5 B
  6.                       SIZE_X,                  /* 源数据长度,单位像素个数*/
    / S& e& k/ N4 R$ g( Z
  7.                       SIZE_Y)                  /* 源数据行数 */% y! O# w  y" ^( c4 o
  8.    != HAL_OK)
    , C  g) i) M( @7 w
  9. {8 G, `3 c( E: B" R/ J! z$ s( S8 ]
  10.    Error_Handler();" [. t: `4 N. J% @
  11. }
复制代码
! H' P* I& X, V  a
55.4.4 函数HAL_DMA2D_BlendingStart_IT$ s& l- M4 h. H9 r# |- f
函数原型:
3 n& z4 C7 T% ^# @3 a& o
+ a( l" @  N6 z
  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)" F5 D, K* L3 g- Z3 m% T& W
  2. {
    : M0 q/ |$ B& h5 u, y6 ]
  3.   /* 检测参数 */6 c8 z) ^( C% S8 ]* {* e0 y
  4.   assert_param(IS_DMA2D_LINE(Height));; ]9 k. p3 {3 `% p' X. w( N
  5.   assert_param(IS_DMA2D_PIXEL(Width));! u3 Z5 p9 E7 @+ k; i

  6. $ _- y$ n$ k; p
  7.   /* 上锁 */
    - @  @6 m6 h7 p
  8.   __HAL_LOCK(hdma2d);: H1 d/ T8 P# ]# `, O- A! y6 ~

  9. 1 T1 t( f! x+ I1 [! l) ]& D0 M
  10.   /* 设置DMA2D外设状态 */4 c7 I" q7 W3 A0 j' P! y2 t. w3 X$ M
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;
    # G+ x* C9 Z8 M- z( |4 p

  12. ( F& A- `: \9 O/ ?& ~
  13.   /* 配置DMA2D源地址2 *// f7 T: y* {! x" v: Y' i
  14.   WRITE_REG(hdma2d->Instance->BGMAR, SrcAddress2);" p* [# Y) V: X) z9 K: }

  15. 9 o6 g$ o& H6 r$ p; i
  16.   /* 配置源地址1,目的地址和数据大小 */& X/ r) A8 o7 H) j) ?
  17.   DMA2D_SetConfig(hdma2d, SrcAddress1, DstAddress, Width, Height);9 L# \5 R* m7 w# u/ k4 J/ ^
  18. 6 S4 n' S- k& H, Y1 I" Z7 b/ |
  19.   /* 使能DMA2D传输完成中断,传输错误中断和配置错误中断 */& o8 w4 r; M% P4 T7 H: |( m: o2 j
  20.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);
    ! h+ e3 Y7 o/ @. E" x( A8 e: X- D; U
  21. # Z1 W7 N  J. u" J8 e
  22.   /* 使能DMA2D */
    ; f* d+ E* U( x! N+ A9 z* M
  23.   __HAL_DMA2D_ENABLE(hdma2d);" M( H2 v7 X# I' M
  24. 2 r8 R) W! C$ E; m* W
  25.   return HAL_OK;' U) o. j& r/ i0 q* n; U
  26. }
复制代码

/ m5 _: h" o* E! O函数描述:
7 F9 r+ q+ n$ g' O- E5 c! e& {9 k0 y. A% J
此函数用于启动DMA2D传输,除了数据传输以外,还支持颜色格式转换和颜色混合。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。! K4 N3 t& e, A% Z0 _( w/ h9 ?( ^9 Y
5 S. o# ~% U* A# j* A
函数参数:
4 E2 h5 Y, X4 g1 R: m( v& \7 D) ~, Z' T8 b8 n' x
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。' t' j1 K3 K& S8 q  {6 U8 d
  第2个参数是源数据地址1。% z" l! t! V0 A9 b$ A: _0 r
  第3个参数是源数据地址2。  V$ f3 ~5 w  ?1 c+ U. D
  第4个参数是目的数据地址。2 E: D% }4 _8 ?5 z6 N
  第5个参数是源数据的长度,即每行的像素个数。
6 K3 @3 g* R- a0 F$ p# U  第6个参数是源数据的高度,即行数。
, `- V+ w' H* I" |6 M$ f+ z  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。& Y2 c! O* s# G' \
使用举例:, p" x; q  Y  T$ W9 I1 r1 f
% {. [) w" q) b3 ?2 L
  1. DMA2D_HandleTypeDef Dma2dHandle;
    " a& ]- `6 ?/ [  `0 L
  2. - ~0 M* z* m' X- l5 m; }/ }# }
  3. if(HAL_DMA2D_BlendingStart_IT(&Dma2dHandle,           /* DMA2D句柄 */
    # x2 Z' w* _0 Q( ^9 `+ }2 H
  4.                              (uint32_t)&BufferInput1, /* 源地址1,前景色 */
    * r4 q8 \) c) }# L6 X0 T$ J
  5.                              (uint32_t)&BufferInput2, /* 源地址2,背景色 */% v! r4 V9 j* k: Q; x
  6.                              (uint32_t)&BufferResult, /* 目的地址 */
    1 A4 ]7 B3 O. Y( e0 i% ?4 O
  7.                               SIZE_X,                 /* 源数据长度,单位像素个数*/
    7 O* w. @* X6 \# r
  8.                               SIZE_Y)                 /* 源数据行数 */2 i! B5 J- E6 w7 _) F9 c* T
  9.    != HAL_OK)
    ! u0 Z: v9 N& O7 i9 O" n) k- y6 q
  10. {8 L/ d0 b3 _; f3 H& E3 W
  11.    Error_Handler();3 C$ f* r- y# D% j8 B6 b* Z, R
  12. }
复制代码
7 u9 h' q4 P  e( z# ~% ~

' H5 M2 b2 f( T7 w& a. X55.5 总结
; D' G% x$ r3 ?8 s9 O/ j- W) _本章节就为大家讲解这么多,DMA2D功能比较重要,一定要做到熟练使用。
% L. a/ z1 T! k. ^6 p  b6 f' a4 J/ H  F# u0 B5 D' ~3 A+ y) R
) [  Q) N% |2 a0 y8 J
& u1 R1 A+ L9 a% x
收藏 评论0 发布时间:2021-12-24 17:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版