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

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

[复制链接]
STMCU小助手 发布时间:2021-12-24 17:00
55.1 初学者重要提示
8 J# q  Q: D# Q2 I( u: ~, ?  DMA2D是专门用于LCD加速的,特别是刷单色屏,刷图片,刷Alpah(透明)混合效果全靠它,而且可以大大降低CPU利用率。
1 W: |( \* J9 r  y* u5 P  测评STM32H7的LTDC+DMA2D性能,100Hz以上无压力,刷800*480图片和色块仅需2.6ms一张
8 o" Q: S2 i+ B/ k6 x2 l+ s  H7的DMA2D与F429的DMA2D最大区别是支持了ARGB和ABGR互转,而且支持H7的硬解JEPG输出格式YCbCr转RGB,方便LCD显示。' ?! H- I5 X' g
  特别注意,大家只需对HAL库提供的DMA2D操作API有个了解即可,实际工程中,并不使用这些API,我们需要使用更加高效的寄存器直接操作,在下一章节会为大家说明。
6 O# L. E7 Q7 P55.2 DMA2D基础知识" |8 g: _9 n+ P8 ]! M; D* L; Q! `
DMA2D主要实现了两个功能,一个是DMA数据传输功能,另一个是2D图形加速功能。
( D! S% N* m9 D* g/ _! \( e& j+ T+ ~
  DMA数据传输6 C8 P8 J! B# X" f
主要是两种方式,一个是寄存器到存储器,另一个是存储器到存储器。通过DMA可以大大降低CPU的利用率。
. t. h9 T7 T/ o6 z/ m* c9 I  \( l" a3 ^) k) d& L" W4 u
  2D图形加速功能; }( R* q, L# C4 [. c: O
支持硬件的颜色格式转换和Alpha混合效果。" T" o7 ^: b/ |- {! P, G9 m! p- Z% u

/ A8 c! ?% R9 E, X" T9 m55.2.1 DMA2D硬件框图
8 I$ R  \. H" |' l认识一个外设,最好的方式就是看它的框图,方便我们快速地了解DMA2D的基本功能,然后再看手册了解细节。框图如下所示:  Q2 w3 q+ y* R9 a/ I3 K
2 i7 ?5 q2 O, |5 d# D( ^/ _* Y
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
4 ]$ a4 `7 a8 J1 R

  t( [  q* I. W+ T- {! x通过这个框图,我们可以得到如下信息:- ?4 p7 t1 X- y4 P
  s* r( V( j) q3 f* v' l
  dma2d_aclk3 k+ h1 P1 c# N. x+ f0 V3 ?. v
AXI 总线时钟输入。; U5 l3 A! ]+ S0 @
. \1 B7 d# R- p( m+ C
  dma2d_gbl_it# ~1 G# |: }5 J6 y: J
DMA2D全局中断输出。; w2 @' k/ _" m: ~

$ m% r, R: U/ n3 p% @6 d0 j  dma2d_clut_trg4 }# J/ l  T. \, i/ ~$ U1 ?* F
CLUT传输完成信号输出,可以触发MDMA。
% z# g% \9 t% o$ o5 C, t$ P
. C' N+ P" I. X  dma2d_tc_trg$ w' a9 h/ P9 t; q* a; @  _
传输完成信号输出,可以触发MDMA。
% O7 f4 h- S! q5 n4 v6 |! M7 S+ d, M6 K0 T" _. A
  dma2d_tw_trg
, n  S) g# T9 I传输watermark信号输出,可以触发MDMA。& c, I1 u) B# |0 c. g

5 Y5 E8 a! L, z% m. d$ g将这个硬件框图简化一下,就是下面这样:
0 c) S2 {3 i& b7 x) \8 M6 s7 B
! G* h! L  }9 j8 `  R' U/ G3 H
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
) e+ V( J( h1 P! S0 \/ U

! s4 {* q8 \( ]0 |" J, L5 W下面按照简化的硬件框图,对每个部分做个说明。
% }* }7 T2 P/ R  U
2 Z0 j# ^; ?' @, l0 E) ~4 c55.2.2 DMA2D工作模式, q1 _2 X* l0 G2 L; z7 N
DMA2D支持的工作模式如下:
7 w& A/ w& O' |; x0 m
5 V1 q% E7 ^8 [* q( e2 p  模式1:寄存器到存储器模式
! W- J, X! c0 e1 R" w- M+ u' v1 S这个模式主要用于清屏,也即是将显示屏清为单色效果。1 X7 m  U- g$ F! `" B
* d7 x3 O; t) L( F# d; h
  模式2:存储器到存储器模式
- A, W: D+ i* a4 j# ~6 Q& c  h9 J这个模式用于从一个存储器复制一块数据到另一个存储器,比如将摄像头OV7670的输出图像复制到LCD显存就可以采用这种方式。
9 z1 U: W3 j0 n& G& u; N  z( Z
0 }& L- w/ K8 A& r- \  V) S9 v  模式3:存储器到存储器模式,带颜色格式转换
& t) e* f' E* P4 V/ ]  K这个模式比模式2多了一个颜色格式转换,比如我们要显示一幅RGB888颜色格式的位图到RGB565颜色格式的显示屏,就需要用到这个模式,只需输入端配置为RGB888,输出端配置RGB565即可。位图颜色格式转换后会显示到显示屏上。
  h; ~( b  v3 `  ?' O  \/ f( }: ]+ @& V" ]; z" v/ P4 k8 Y1 I
  模式4:存储器到存储器模式,带颜色格式转换和混合
9 H+ y/ ]( k4 u8 l2 b. Z这个模式比模式3多了一个混合操作,通过混合,可以将两种效果进行混合显示。( \1 C' R! i; w5 |  B

5 Z( j) T$ K* v- g+ r. I, S) y6 x  模式5:存储器到存储器模式,带颜色格式转换和混合,前景色是固定的
# j# T- t( ?# a; [$ s# N% e" Y5 ]同模式4,只是前景色的颜色值是固定的。: {( P8 G6 j! Q- ?
4 `5 A0 l: ~" V- ~3 ]! a# A
55.2.3 前景层和背景层的输入以及颜色格式转换
* r7 W0 k$ t% N$ q, c8 l前景层和背景层是指的用户绘制图形时的前景色和背景色,比如我们显示汉字,字体会有一个颜色,也就是前景色,还有一个背景色。又比如我们绘制两幅图片,想将两幅图片混合,那就可以将一幅图片作为前景层,另一个幅图片作为背景层。; M) i& V- B9 P! ~4 t8 X
/ H) p3 `) E* F  [: M2 [! x1 {
DMA2D支持的输入颜色格式如下,前景层和背景层一样:
* ~) r/ y8 S) S! z/ R$ K/ n8 ]: _0 c+ v2 N6 ?
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

5 J  ^. T5 I% D1 A
, k/ Q9 G9 X8 g1 \7 |' c前8种颜色格式在第50章的第2小节开头有介绍,这里把后四种做个说明:
- R: o- z: y# k& B7 e$ e0 Q0 e8 s0 i- e) K: }
  L4 (4-bit luminance or CLUT)
& ?+ r' ^( `9 Y& r+ j7 `* E8 V4位颜色格式,实际上仅仅是4位索引值,范围0–15,而每个索引值的具体颜色值在查色表CLUT里面存储。
, v* p) a4 i' n0 ?1 i6 s' x
% [9 u; T  p+ S4 w, {2 h# i* O" H  A4和A88 {9 F6 Z- T5 [: o0 T/ V
A4和A8用于特定的Alpha模式,既不存储颜色信息,也没有索引值。
* y- E  q. v& A) t4 P
! M% J0 u5 r4 ?/ f( H) [1 J2 B; B: C  YCbCr
0 E# C# `, @5 h3 m这个是H7的硬件JPEG输出的颜色格式,后面JPEG章节为大家专门做讲解。
% U3 G7 \+ b. u8 |& R! S8 y4 y6 x' }6 T
这里特别注意一点,输入颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。
( e8 m4 l! X% ]/ i: |6 k- f+ R8 |
8 a' e+ b' o8 q7 @55.2.4 前景层和背景层混合' r8 w: U- ]1 `9 Y8 `* X% h
DMA2D混合器用于混合前景色和背景色,这个功能不需要任何配置,仅需要通过DMA2D_CR寄存器使能即可。混合公式如下:2 }8 _) A# A* ^) C& T8 h6 M% O

( t+ U* y# c3 J# B
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

, U% q1 h* b$ y+ H- V. C2 b& P# Z1 l  D4 r+ E
55.2.5 DMA2D输出颜色格式( C3 s9 q% q% V* q% v& x9 R5 J
DMA2D支持的输出颜色格式如下:
' X# C& I* `* W! {7 v, Z) J
; G% T$ I3 b* I% _. J
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

* c0 o) v0 U- G6 t
% Q8 H& p; r0 g1 B' _这里特别注意一点,输出颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。
) V- K) K/ }) q1 Y( N% Y4 ^) @
+ z  [: _, k! E0 \- y55.3 DMA2D的HAL库用法
( s. d. ~& ~; Q( z, A* V6 }DMA2D的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断。下面我们逐一展开为大家做个说明。
) g7 q! o$ X1 I0 w/ {( k+ H9 j- x. i6 P
55.3.1 DMA2D寄存器结构体DMA2D_TypeDef3 d8 p4 S+ P5 _4 H
DMA2D相关的寄存器是通过HAL库中的结构体DMA2D_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:- b6 p  G/ Q$ k/ \' f1 @
0 u9 Q( Z& y4 R0 n6 z7 ?
  1. typedef struct6 u) \5 p9 v6 W, o  @  D- U
  2. {
    1 l  @8 J% |; }# E/ u0 `7 [) U
  3.   __IO uint32_t CR;            /*!< DMA2D Control Register,                         Address offset: 0x00 */
    # I  G" ~( E* c; U: J5 N  Q7 p3 M8 Q
  4.   __IO uint32_t ISR;           /*!< DMA2D Interrupt Status Register,                Address offset: 0x04 */
    8 }: F/ w$ ~* G, `" K
  5.   __IO uint32_t IFCR;          /*!< DMA2D Interrupt Flag Clear Register,            Address offset: 0x08 */
    . ^) N4 R8 K& y& K% D2 E* o
  6.   __IO uint32_t FGMAR;         /*!< DMA2D Foreground Memory Address Register,       Address offset: 0x0C */
    9 e2 T0 |# n" R
  7.   __IO uint32_t FGOR;          /*!< DMA2D Foreground Offset Register,               Address offset: 0x10 */! K' k, C: ~8 Z. ~
  8.   __IO uint32_t BGMAR;         /*!< DMA2D Background Memory Address Register,       Address offset: 0x14 */% R6 \4 K4 u2 m
  9.   __IO uint32_t BGOR;          /*!< DMA2D Background Offset Register,               Address offset: 0x18 */
    $ K0 j! r4 q3 J1 N% d" j
  10.   __IO uint32_t FGPFCCR;       /*!< DMA2D Foreground PFC Control Register,          Address offset: 0x1C */
    3 ]& N) c, M' ?: K
  11.   __IO uint32_t FGCOLR;        /*!< DMA2D Foreground Color Register,                Address offset: 0x20 */. t5 r: G; y6 ]
  12.   __IO uint32_t BGPFCCR;       /*!< DMA2D Background PFC Control Register,          Address offset: 0x24 */4 {0 M. M9 q5 K, ?
  13.   __IO uint32_t BGCOLR;        /*!< DMA2D Background Color Register,                Address offset: 0x28 */: t( a4 w( u/ i8 |: Y
  14.   __IO uint32_t FGCMAR;        /*!< DMA2D Foreground CLUT Memory Address Register,  Address offset: 0x2C */1 P) C7 I8 h7 \8 K. ?% W
  15.   __IO uint32_t BGCMAR;        /*!< DMA2D Background CLUT Memory Address Register,  Address offset: 0x30 */9 I; ?& s) M9 R5 |
  16.   __IO uint32_t OPFCCR;        /*!< DMA2D Output PFC Control Register,              Address offset: 0x34 */
    " }" N. s8 D# i5 y7 z
  17.   __IO uint32_t OCOLR;         /*!< DMA2D Output Color Register,                    Address offset: 0x38 */
    & F: D! ^  J; P' u
  18.   __IO uint32_t OMAR;          /*!< DMA2D Output Memory Address Register,           Address offset: 0x3C */5 q, h1 U7 K* W( O# a  y
  19.   __IO uint32_t OOR;           /*!< DMA2D Output Offset Register,                   Address offset: 0x40 */. s* @" Y5 {2 ~& e' F3 P( X! D
  20.   __IO uint32_t NLR;           /*!< DMA2D Number of Line Register,                  Address offset: 0x44 */* Q6 }' ~; Q# n, e- j  ]
  21.   __IO uint32_t LWR;           /*!< DMA2D Line Watermark Register,                  Address offset: 0x48 */  K+ ]: Q* T% o  q
  22.   __IO uint32_t AMTCR;         /*!< DMA2D AHB Master Timer Configuration Register,  Address offset: 0x4C */
    ! e4 B& I. X, V0 w( j* n
  23.   uint32_t      RESERVED[236]; /*!< Reserved, 0x50-0x3FF */
    8 H+ D9 K' Z0 H4 a; }3 S  ]
  24.   __IO uint32_t FGCLUT[256];   /*!< DMA2D Foreground CLUT,                          Address offset:400-7FF */
    + |$ W! n. [7 R4 y7 e! {
  25.   __IO uint32_t BGCLUT[256];   /*!< DMA2D Background CLUT,                          Address offset:800-BFF */
    # L; v1 ]' S, Q7 K5 @
  26. } DMA2D_TypeDef;
复制代码

. Z) c6 ?) J4 v, T# K. l
9 j: `" H$ E7 m! {# m__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:7 U6 j# @9 G& o) s4 ^) H

6 ^9 r( f1 Z! ?8 z
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */& n" @7 [6 n: N) n  I
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
) z5 N3 Y# J) x" `: G0 ^2 @7 n
下面我们再看DMA2D的定义,在stm32h743xx.h文件。
  1. #define PERIPH_BASE              ((uint32_t)0x40000000)
    / W& T* x/ r1 v- W- y, {) R
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000)
    , ^: p& F: @* [7 ]0 a5 t4 j
  3. #define DMA2D_BASE               (D1_AHB1PERIPH_BASE + 0x1000)9 H2 |" e) h0 _1 R5 s
  4. #define DMA2D                    ((DMA2D_TypeDef *) DMA2D_BASE) <----- 展开这个宏,(DMA2D_TypeDef *) 0x52001000
复制代码
0 C5 L% o5 |9 M5 a
我们访问DMA2D的ISR寄存器可以采用这种形式:DMA2D->ISR = 0。8 R3 o& n* y# e
' R4 n- I! \% q
55.3.2 DMA2D参数初始化结构体DMA2D_InitTypeDef; q/ c2 x3 p. T7 n
此结构体用于配置DMA2D的基本参数,具体定义如下:
# Z- j$ B2 i! {
1 ?8 D( n9 q8 U$ S3 R# p
  1. typedef struct$ I9 v. J% [: T1 e
  2. {
    / V, E% k4 I3 V* r9 ^8 \4 _
  3.   uint32_t             Mode;              
    ! k% b+ J  R5 t1 \/ @2 ?; k9 f
  4.   uint32_t             ColorMode;        8 g1 |0 g4 l* i# k4 ^3 [% w
  5.   uint32_t             OutputOffset;       * |0 ?/ ~0 {2 ~( j" K
  6.   uint32_t             AlphaInverted;   
    & y4 S$ l$ r: j$ [9 P3 ^
  7.   uint32_t             RedBlueSwap;      
    / C, z- _. q& o7 M" @9 D8 r" L
  8. } DMA2D_InitTypeDef;
复制代码

* w- p% Q  Z6 r9 g; n+ |" r下面将这几个参数逐一为大家做个说明:2 g+ j3 l8 \8 t
) [" A7 K- G: U! c% w; w$ a
  uint32_t   Mode) j) j& |$ a- s8 @5 G+ Q
此参数用于设置DMA2D的传输模式,具体支持的参数如下:) p, L- [) @& ]

! k1 {/ F7 Z' k7 M1 L3 o, i
  1. #define DMA2D_M2M        ((uint32_t)0x00000000U)  /*存储器到存储传输模式 */
    7 {. e6 b2 Q' M" O, i* P8 t
  2. #define DMA2D_M2M_PFC     DMA2D_CR_MODE_0         /*存储器到存储器传输模式,并执行FPC像素格式转 */  p5 i6 [' l* ^6 p$ ^9 x$ X/ f
  3. #define DMA2D_M2M_BLEND   DMA2D_CR_MODE_1         /* 存储器到存储器模式,并执行像素格式转换和混合 */; a, c8 {! Y2 X; n
  4. #define DMA2D_R2M         DMA2D_CR_MODE           /* 寄存器到存储器传输模式 */
    . F3 I! n8 n  k! X4 ~+ e
复制代码

4 L* ?- _, \1 B7 s& Q& o0 Z" m
" U5 U/ |: J5 p9 c: ^  uint32_t   ColorMode  U1 k( M7 @4 v! m5 k. C$ u1 J* S5 X8 q
此参数用于设置DMA2D的输出颜色格式,具体支持的参数如下:; ^  ]% e8 [4 k( t4 J- Y

3 _* D1 _: r6 e
  1. #define DMA2D_OUTPUT_ARGB8888       ((uint32_t)0x00000000U)               /* ARGB8888 */
    ; r0 n+ O! F) X8 U5 d% g
  2. #define DMA2D_OUTPUT_RGB888         DMA2D_OPFCCR_CM_0                     /* RGB888 */3 D; C- F0 ]* W: ~+ w
  3. #define DMA2D_OUTPUT_RGB565         DMA2D_OPFCCR_CM_1                     /* RGB565 */
    5 a  \5 x( f1 j5 T' U
  4. #define DMA2D_OUTPUT_ARGB1555       (DMA2D_OPFCCR_CM_0|DMA2D_OPFCCR_CM_1) /* ARGB1555 */. B. q& ^3 w+ Y, O* ?( D( X# K4 |
  5. #define DMA2D_OUTPUT_ARGB4444       DMA2D_OPFCCR_CM_2                     /* ARGB4444 *// N8 P2 q* N  S. g* }
复制代码
/ k( b* v7 z# f2 r( m
  h6 ]4 G1 x8 a" f$ k
  uint32_t   OutputOffset
4 i( k9 ]% t  j8 Y' f" ?% y' |此参数用于设置输出位置的偏移值,参数范围0x0000到0x3FFF。5 Y2 a% L4 G; I  H  A

8 a: X* w' k& H( R+ D  N  uint32_t   AlphaInverted
$ N& o$ N3 C9 b4 G; C此参数用于设置DMA2D的输出颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     4 X, @7 N: y. {+ N( l

: R: I  [- s9 z/ a" u- z
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */
    * I6 N: w  v' h' F' U
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */
复制代码

: Q( Y" `5 c1 b! V6 q( f7 y  uint32_t   RedBlueSwap
, I; l& |: m+ Z4 M# b此参数用于设置DMA2D的输出颜色格式中R通道和B通道的交换,具体支持的参数如下:
* O8 J; B: P+ q! _3 W. f; F6 u+ W+ ^
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */: ^$ B0 v: @8 _' d& s3 o
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码

' |, x- V- h( |% ^% a55.3.3 DMA2D的图层结构体DMA2D_LayerCfgTypeDef
' d, k) @0 Z: Q! I5 n& C! B; j此结构体用于配置前景色和背景色。
% A& T- Y# a! k8 G' i' J8 @/ |( e7 j0 U9 y6 w" |. y
  1. typedef struct- k) w7 u4 `  H& H7 K6 t2 e
  2. {
    % W% B, W" k# F' l6 ?' y' `
  3.   uint32_t             InputOffset;      
    5 \, G: o  z# u& H
  4.   uint32_t             InputColorMode;   
    7 g/ ^) j$ k, i& `+ F
  5.   uint32_t             AlphaMode;        
    1 t5 O: H7 i7 D, B, |, d1 T
  6.   uint32_t             InputAlpha;        
    2 ?) r9 n% a8 T5 T+ s
  7.   uint32_t             AlphaInverted;    ! Z2 V! Q/ |. L0 Q4 P
  8.   uint32_t             RedBlueSwap;       " y; H+ }1 U% A* p1 w( m: V5 |, I
  9.   uint32_t             ChromaSubSampling;: [1 y1 c* O7 ^+ d+ H
  10. } DMA2D_LayerCfgTypeDef;
复制代码
8 K0 t  z. o" C: u* D$ j$ T; y6 J5 y. p- m
下面将这几个参数逐一为大家做个说明。
0 J4 o' y8 `) X0 A& u$ Q: h, [& H+ m  ?" ^0 B( x; W0 O( B( m$ g
  uint32_t  InputOffset5 p1 I$ S- K8 f. e. z& i
设置前景色或者背景色的输入偏移,范围0x000到0x3FFF。
1 M$ R; X5 T) p  D# c+ j3 R  M
9 d& r5 m9 H8 m4 ]  uint32_t  InputColorMode( b! N1 n' n% W
设置前景色或者背景色的输入颜色格式,具体支持的参数如下:
, y2 K/ q8 I: J
4 a# A' o. J0 {3 ^
  1. #define DMA2D_INPUT_ARGB8888        ((uint32_t)0x00000000U)  /* ARGB8888 */8 ]7 C' m. A. i$ P2 ~6 Q0 v
  2. #define DMA2D_INPUT_RGB888          ((uint32_t)0x00000001U)  /* RGB888   */
    : s% V+ E5 x$ v/ F: n& `5 q
  3. #define DMA2D_INPUT_RGB565          ((uint32_t)0x00000002U)  /* RGB565   */
    3 i/ `/ P' n" i% u5 ]
  4. #define DMA2D_INPUT_ARGB1555        ((uint32_t)0x00000003U)  /* ARGB1555 */2 r  c, `+ X7 ], r' b
  5. #define DMA2D_INPUT_ARGB4444        ((uint32_t)0x00000004U)  /* ARGB4444 */1 ]3 i# L6 `% z, X( a4 H8 Z8 V
  6. #define DMA2D_INPUT_L8              ((uint32_t)0x00000005U)  /* L8       */$ x+ u0 _7 l  _. J0 D. o
  7. #define DMA2D_INPUT_AL44            ((uint32_t)0x00000006U)  /* AL44     */
    8 h: S4 X' U/ U. b8 S
  8. #define DMA2D_INPUT_AL88            ((uint32_t)0x00000007U)  /* AL88     */  v( U% _, l$ D5 N; D6 H, S1 n! ^9 m
  9. #define DMA2D_INPUT_L4              ((uint32_t)0x00000008U)  /* L4       */' z. U: p7 K" h) e4 m0 w# u. F
  10. #define DMA2D_INPUT_A8              ((uint32_t)0x00000009U)  /* A8       */- V$ j7 e4 p- u
  11. #define DMA2D_INPUT_A4              ((uint32_t)0x0000000AU)  /* A4       */1 t, u! h3 Q) E3 W
  12. #define DMA2D_INPUT_YCBCR           ((uint32_t)0x0000000BU)  /* YCbCr    */
复制代码

7 p3 n5 M5 P" q: M, F  \, o2 i  uint32_t AlphaMode
+ U* b: z" K& M# @$ ^设置前景色或者背景色的Alpha模式,具体支持的参数如下:
6 w/ R# P1 Q3 k3 e* [% I* H' Q; h+ }* b' I6 r
  1. #define DMA2D_NO_MODIF_ALPHA   ((uint32_t)0x00000000U)  /* 不修改Alpha通道值 */
    & n( E* [7 C8 A; p! p3 d
  2. #define DMA2D_REPLACE_ALPHA    ((uint32_t)0x00000001U)  /* 用新设置的Alpha值替换原始Alpha值 */( o4 b6 |( [% ^0 C0 }4 z2 Z
  3. #define DMA2D_COMBINE_ALPHA    ((uint32_t)0x00000002U)  /* 用新设置的Alpha值与原始Alpha值的乘积替换原始Alaha值*/
复制代码

5 Y2 `# _/ p7 c  uint32_t  InputAlpha
9 E3 y9 r) }6 c6 w设置前景色或者背景色的Alpha值,范围0x00到0xFF,如果颜色格式是A4或者A8,那么此参数的范围是0x00000000到0xFFFFFFFF,标准的ARGB8888格式。! r" c( y/ k$ l

( e9 _- B. p) D' n  w+ s, C. V  uint32_t AlphaInverted6 \: m7 G: r7 d. j% U: G4 M
设置前景色或者背景色的输入颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     
; {$ r+ z9 |: N4 a$ H- C& |1 J3 s' i& `9 X
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */
      r; C1 D9 r: _+ t  ]4 F8 g4 e. f
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */     
复制代码
2 d& k! m6 o  o" f! U
  uint32_t   RedBlueSwap/ B- A8 t. O; `  W0 E9 H6 K3 ]
设置前景色或者背景色颜色格式中R通道和B通道的交换,具体支持的参数如下:$ n- y: v/ Z7 v9 m& B* _: `
! w7 |" v4 k1 L
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */
    $ w0 ^, y) q2 r
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码

$ ], g$ W$ B6 z: t  uint32_t   ChromaSubSampling
' ~: L/ y, Z3 A& D* \) v设置前景色或者背景色中YCbCr 颜色模式的采样格式,具体支持的参数如下:
  1. #define DMA2D_NO_CSS               ((uint32_t)0x00000000)  /* 4:4:4 */6 r9 i1 F. F# u6 g# h7 t- c) Y
  2. #define DMA2D_CSS_422              ((uint32_t)0x00000001)  /* 4:2:2 *// ^0 |( L8 T( E
  3. #define DMA2D_CSS_420              ((uint32_t)0x00000002)  /* 4:2:0 */  
复制代码
; U9 S- w# L  p7 e* C9 X
55.3.4 DMA2D句柄结构体DMA2D_HandleTypeDef
4 {" M+ ?% A5 [/ [& j, m8 p" W2 g
HAL库在DMA2D_TypeDef, DMA2D_InitTypeDef和DMA2D_LayerCfgTypeDef的基础上封装了一个结构体DMA2D_HandleTypeDef,定义如下:/ \, c0 B* }9 F& H6 C7 u  c6 F
2 T" G/ l& c- H: s- h
  1. typedef struct __DMA2D_HandleTypeDef
    - a' E& M/ p# z: x/ n* `8 C
  2. {" n3 \- r' l- ~
  3.   DMA2D_TypeDef               *Instance;                                                                                                                                                                                          * f. M+ J4 Z3 p) K) Z- ?; Y
  4.   DMA2D_InitTypeDef           Init;                                                        2 Y  [/ g$ [" X" S
  5.   void                        (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                                                                             
    . P: r* G: `- `) ]) Q2 ]8 x( i5 i
  6.   void                        (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                      . H3 \3 c5 e, X
  7.   DMA2D_LayerCfgTypeDef       LayerCfg[MAX_DMA2D_LAYER];                                    : ^. _/ x3 p/ `3 B! A& Y
  8.   HAL_LockTypeDef             Lock;                                                                                                                                                                                                    ) d1 P0 ~  L/ T
  9.   __IO HAL_DMA2D_StateTypeDef State;                                                                                                                                                                                                   
    2 n% }; Q4 E8 {! M6 H- _
  10.   __IO uint32_t               ErrorCode;                                                   } DMA2D_HandleTypeDef;4 B4 b$ S% |% X0 x7 T% Z/ q8 y
复制代码

+ x# z5 t* B& L6 j下面将这几个参数逐一做个说明。
  {6 K" G6 s+ P8 |: E% H1 t
( F& {9 j9 b: T2 V$ w  DMA2D_TypeDef  *Instance! Z3 R- v* s; f+ K0 D# a
这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。
! }" @: S5 b  }$ o* P& v  w! N- h1 V
) Q: E6 N. x# \* ~" Y! f0 O  DMA2D_InitTypeDef  Init;  
+ A* Z7 [# H$ _这个参数是用户接触较多的,用于配置DMA2D的基本参数,详见本章3.2小节。
: x/ ~8 j. p; s0 P  |3 P- o5 U5 @* V# z+ q# y* x" Q+ i4 w- [/ J
  void     (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);: o! ?2 s3 X3 {4 i* _# o. t
  void     (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);
7 \9 i0 H1 ^; a7 i$ i; IDMA2D中断服务程序里面执行的回调函数,一个是传输完成回调,另一个是传输错误回调。' e" N5 W" F) q  E. l, s
1 p" I) Q. d' W& F5 t4 |- L( ~
  DMA2D_LayerCfgTypeDef   LayerCfg[MAX_DMA2D_LAYER]
' k# z- K- Q6 J. S% R这个参数用于前景色和背景色的设置,MAX_DMA2D_LAYER=2,详见本章3.3小节。% [. |( n& O) Q& w' L1 ]- O! t

$ U% @" m/ b8 k9 f. r7 W$ M' \5 f  HAL_LockTypeDef   Lock
2 X, V2 ~( S% z__IO uint32_t    State;
$ H+ E4 }: t+ p  \# k0 p( R
! r- S& [/ j  A__IO uint32_t    ErrorCode
* {0 I( K2 [9 e5 y% s/ c7 ^- N2 ]8 Z2 _- r
这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置DMA2D通信状态,而ErrorCode用于配置代码错误。
. z! y) I: w6 x* x
- P2 N4 V! ?, R55.3.5 DMA2D初始化流程总结

% ]0 X! Y- _) _% y1 N* \0 I: b4 S对于DMA2D来说,其实不需要初始化流程,每个功能都可以直接封装出一个函数来,下个章节会为大家专门讲解,也是实际项目比较推荐的方式。1 \& p4 x2 [- L; ?. u  l

& c% {8 m2 H8 x4 B  E5 o- [55.4 源文件stm32h7xx_hal_dma2d.c
9 h4 o. b0 F. e, p$ ~. O" j4 k% v这里把我们把如下几个常用到的函数做个说明:: H. T0 K. R1 Z4 Y. ]. Q5 z

! ^7 _/ q& H. }4 Q/ l) V9 u  HAL_DMA2D_Init
9 Y; S- z/ g$ A5 N: N/ w0 |  HAL_DMA2D_ConfigLayer5 ^; ]4 }! W- M7 T0 o  X- e
  HAL_DMA2D_Start_IT
; S& x0 W0 ~( n0 R4 `  HAL_DMA2D_BlendingStart_IT
4 {9 }2 ]5 c8 z: N  x
: _0 e" P8 A" |, ~55.4.1 函数HAL_DMA2D_Init/ A& P) v$ @# ?4 V
函数原型:
7 j/ k! u4 c4 h: x  M( D+ Y1 b; J
, o, G3 I3 ~5 x
  1. HAL_StatusTypeDef HAL_DMA2D_Init(DMA2D_HandleTypeDef *hdma2d); t) T  O: z% m+ x& }0 ?7 B6 v9 p
  2. { $ m0 l/ d2 j8 M6 \, ?

  3. : k* M" [) B+ H& C
  4. /*  检测参数是否有效 */! A3 N2 Z  A9 f! j1 U# q2 H2 s
  5.   if(hdma2d == NULL)6 R2 ^$ l7 y8 I; f) a
  6.   {
    / t& r7 O% w. t" j: F3 t
  7.      return HAL_ERROR;2 g- l, L9 ]: q3 \$ s; U* y8 q/ I
  8.   }
    : {, Z; p' u! y( m
  9. / l8 b0 @  |  _5 N% I
  10.   /* 检测函数形参 */
    . ^& E% v6 o8 [3 Y$ ^5 {$ Z
  11.   assert_param(IS_DMA2D_ALL_INSTANCE(hdma2d->Instance));1 O: X8 _$ T: c% l6 H% v
  12.   assert_param(IS_DMA2D_MODE(hdma2d->Init.Mode));
    $ d1 O6 a, z3 Y9 X# ~
  13.   assert_param(IS_DMA2D_CMODE(hdma2d->Init.ColorMode));! e6 v7 _3 J( s* }
  14.   assert_param(IS_DMA2D_OFFSET(hdma2d->Init.OutputOffset));
    2 i% M7 @; w: R1 c! U" D  k; `3 N
  15. 5 J# X1 o$ h1 G3 K! T, Y9 {; [0 Z
  16.   if(hdma2d->State == HAL_DMA2D_STATE_RESET)
    ; k3 M5 ^8 b7 _, y
  17.   {
    9 k* ]4 o5 Z  i0 r( R: ~
  18.     hdma2d->Lock = HAL_UNLOCKED;
    1 }9 L; P1 V; l
  19.     /* 初始化GPIO,NVIC等 */
    / ?" ]" Y1 v- ^
  20.     HAL_DMA2D_MspInit(hdma2d);
    4 D% ^# n7 U& X* ]! t$ q
  21.   }  r  u) [* x+ z& b* I# `
  22. 2 V1 Z% q/ S5 p6 {8 c
  23.   /* 设置DAM2D外设状态 */. i9 G6 z6 f+ J* r+ t0 o. B1 q
  24.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  7 ^4 }+ [: s/ @, M' x  ~

  25. 3 S9 C7 r" w& [& Q3 D" Z4 F5 X- S) O) q
  26.   /* 设置DAM2D工作模式 -------------------------------------------*/
    + R4 f7 a/ B0 Q4 t$ }0 u
  27.   MODIFY_REG(hdma2d->Instance->CR, DMA2D_CR_MODE, hdma2d->Init.Mode);, J; W% d; t6 d' D6 t7 r- g
  28. ( b  p/ n' K! \; R# J; b0 x! c$ |  \
  29.   /* 设置输出颜色格式 ---------------------------------------*/, n6 U3 c+ Y( b) J2 S
  30.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_CM, hdma2d->Init.ColorMode);7 F3 S  Q) h. K4 h; C

  31. % d; i0 S8 y, A$ u4 q
  32.   /* 设置输出偏移 ------------------------------------------*/  
      D/ x. N" {- D8 [* e
  33.   MODIFY_REG(hdma2d->Instance->OOR, DMA2D_OOR_LO, hdma2d->Init.OutputOffset);  
    / W2 i* H5 f0 A
  34. 5 u4 k8 @4 s8 s$ u+ g$ m; f
  35.   /* 设置输出颜色格式中的Alpah值反转 */
    8 @3 h( q% w9 W# k! Q4 E
  36.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_AI, (hdma2d->Init.AlphaInverted << DMA2D_POSITION_OPFCCR_AI));
    . O8 N" j0 n9 G& z1 P) [

  37. ' l5 o% Z- X( P8 O8 v& b
  38.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_RBS,(hdma2d->Init.RedBlueSwap << DMA2D_POSITION_OPFCCR_RBS));
    + q  Y: U  B9 J! \
  39. 3 p6 q) w4 w, D9 r
  40. 3 v" q& b  F5 I, L, O# k  T
  41.   /* 无错误 */
    / |* ^0 _7 C; a9 z8 |: b; I
  42.   hdma2d->ErrorCode = HAL_DMA2D_ERROR_NONE;
    : \7 V$ h0 c. N4 e# {  R
  43. 2 `3 d( T: u* h, Q
  44.   /* DAM2D就绪 */
    0 l3 i) r7 p* K' ]7 W* J
  45.   hdma2d->State  = HAL_DMA2D_STATE_READY;- r- n0 J$ H3 q8 |  T' }

  46. * ~( M# }) D5 b
  47.   return HAL_OK;# M9 G! g. s$ r1 z
  48. }
复制代码
0 Z0 |$ g6 a' R" V
函数描述:9 I' t9 G# m& u1 v, N8 Q/ {
7 P: @' H( |9 H: M8 Z" g1 R
此函数用于初始化DMA2D的工作模式和输出颜色格式。- k) @& ^1 \5 F( `. e& r- H
  W5 B1 [3 J9 M& f7 {7 W, K) M$ }$ L
函数参数:
4 G  A7 g1 c9 E$ u
; L% m, O1 U7 p# J. v8 y4 h  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。3 i  [. L' h6 d+ ?1 T& h2 a
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。  _: v/ [" i8 h9 {& `+ q1 u
注意事项:
6 [. k; ^" `9 ^5 [0 h. Q: n; J6 z! c% x, \
函数HAL_DMA2D_MspInit用于初始化DMA2D的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。* \, J8 {3 Q7 q5 x' x
如果形参hdma2d的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量DMA2D_HandleTypeDef Dma2dHandle。
+ k$ s. C3 j* l5 F& N对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_DMA2D_STATE_RESET  = 0x00U。
$ R4 d+ J- s% B3 p) m
: O" U% d8 h1 H: b; R解决办法有三
- q: m; o& `' `* i7 }3 c) E
" L! `. U- F' L6 B. e9 s3 k- K/ n方法1:用户自己初始DMA2D底层。$ o: T3 j: S$ G( \/ ^7 P

; n8 t  g) g6 U+ C  C% d, s6 X方法2:定义DMA2D_HandleTypeDef LtdcHandle为全局变量。
5 ?! [9 \0 f. A
( w8 f" H1 Y+ s5 j( t方法3:下面的方法
  1. if(HAL_DMA2D_DeInit(&Dma2dHandle) != HAL_OK)/ T2 }  t- G5 a6 D: R
  2. {
    6 a1 \7 p: z5 R/ v3 I0 H2 ]8 X
  3.     Error_Handler();
    + S2 ^' h0 Q+ \) _6 M) p
  4. }  
    7 `: C; Y# B1 s* o& t7 X4 w1 h
  5. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
    2 `' \' j. f7 b8 \+ e; H& M
  6. {0 [3 ?# _* }  Q
  7.     Error_Handler();
    9 F, m; |0 i& M$ R9 i
  8. }
复制代码

! S( p$ k  u- o$ Q" X
5 ?$ S" q% J3 q3 l: d使用举例:8 w) j% `8 Q& O/ s& f
: ]/ C$ Y& j! z  W9 j- i. u' W
  1. DMA2D_HandleTypeDef Dma2dHandle;9 V  a6 c5 g! I: }; G7 o

  2. : Y0 L% F5 j; D( W9 f; R
  3. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/
    ( R5 E3 V* N3 ?! |9 a2 u
  4. Dma2dHandle.Instance = DMA2D;0 K  E. ?( I0 d) V
  5. . F* v+ P; _4 C+ Q7 W
  6. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */% r, b( D5 \+ h6 m' L/ l; H6 n7 h
  7. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */; s# P9 M4 N( @& n; `+ N
  8. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */
    ; P. j$ P4 ~. R0 C6 B
  9. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */' y( A6 s+ `) S8 [$ |
  10. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */
    4 j4 Y* y  ?! o# J8 q
  11.   C. d. L7 j4 F6 o4 h5 u$ a
  12. /*##-2- DMA2D 回调函数配置 ######################################*/
    % R' V6 p8 K; u" D# d$ U
  13. Dma2dHandle.XferCpltCallback  = TransferComplete;
    " ^6 u. e1 k6 f) b! U9 ], E
  14. Dma2dHandle.XferErrorCallback = TransferError;. x+ T% V+ t6 b

  15. 0 \2 }" f, s- d# f3 T, u: _
  16. /*##-3- 前景层配置 ###########################################*/
    1 B! C9 }; q! ~/ }2 A' B0 S
  17. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */
    - Q  n. ?. O1 K  U% V: h
  18. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */' B2 B2 i7 Q% K+ h
  19. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */. o1 h  W7 |3 Z4 K1 C
  20. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */0 `! g' \7 y3 h5 G" y/ x+ Z- H0 X. x
  21. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/
    * u( ~! l8 \% T. Z% o. F
  22. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/8 {/ E6 }( s# ]6 L& b

  23.   ~. P( Z7 `8 v  K% v1 [7 _

  24. ) w6 y; P! T" v& Z
  25. /*##-4- DMA2D 初始化 ###############################################*/
    * r& b5 m+ x7 k4 ]5 e
  26. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)- c! T9 a& _* F3 J9 T, [
  27. {) W& U* Y( |7 a6 c/ v) \( d" ~* i
  28.     Error_Handler();
    ' a1 P1 C9 N  ^0 M2 D, L
  29. }
复制代码

& d7 ^1 x9 I+ k. s/ G7 x& E! \55.4.2 函数HAL_DMA2D_ConfigLayer
/ r( c: N! y1 R函数原型:6 o: M# Z. z8 o" T% u; o7 l  }% b
  N4 S) l+ P+ z  o' a: d5 `
  1. HAL_StatusTypeDef HAL_DMA2D_ConfigLayer(DMA2D_HandleTypeDef *hdma2d, uint32_t LayerIdx)
    3 e6 t- B& E( f& i2 d
  2. { * S& s+ R6 n2 K( J5 U2 I& v
  3.   DMA2D_LayerCfgTypeDef *pLayerCfg = &hdma2d->LayerCfg[LayerIdx];
    5 K3 t: V$ A7 ^$ f
  4. ( J0 m! F: `- |; ^: d
  5.   uint32_t regMask = 0, regValue = 0;  G2 [& Z& V9 \9 U
  6. " H& C% `1 _8 f/ `# S- O. m# U
  7.   /* 检查参数 */
    , I* k* n7 q' }9 v
  8.   assert_param(IS_DMA2D_LAYER(LayerIdx));  " O- R6 x- [, J+ u& T3 I  P8 g  W
  9.   assert_param(IS_DMA2D_OFFSET(pLayerCfg->InputOffset));  - N9 @& C( i  K$ w) F; x
  10.   if(hdma2d->Init.Mode != DMA2D_R2M)
    * b2 a& j0 @) g# _0 ~% q
  11.   {  $ Q8 {2 x/ G: R4 T
  12.     assert_param(IS_DMA2D_INPUT_COLOR_MODE(pLayerCfg->InputColorMode));
    0 `+ l* Y) b4 k' W
  13.     if(hdma2d->Init.Mode != DMA2D_M2M)1 r% A/ h6 \3 f; m0 X
  14.     {
    3 ~5 z' Z5 ?8 Q+ N* M
  15.       assert_param(IS_DMA2D_ALPHA_MODE(pLayerCfg->AlphaMode));
    / l% u: Z! Z9 l  X# v
  16.     }
    ) \$ f! z0 I% @& L
  17.   }! V( I0 j: i& a

  18. 1 s  U4 y; E* R, V: w4 \
  19.   /* 上锁 */
    3 |' K) W, e$ [0 s- p/ A; p& x
  20.   __HAL_LOCK(hdma2d);: D: r  E5 o6 ^7 n7 Y6 B
  21. , M4 ?# h8 w  ]- I3 o/ x
  22.   /* 设置DMA2D外设状态 */& }3 r. L; I, o
  23.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  - S& V  N9 {/ ?

  24. . G) {0 o1 \2 ~# n0 w
  25.   /* 准备好背景层或者前景层FPC寄存器配置参数*/6 ^, i; k6 v! E5 }$ C  Y3 t
  26.   regValue = pLayerCfg->InputColorMode | (pLayerCfg->AlphaMode << DMA2D_POSITION_BGPFCCR_AM) | \
    ( i* u& B! y; x3 t8 x
  27.             (pLayerCfg->AlphaInverted << DMA2D_POSITION_BGPFCCR_AI) | \4 K# Y  J$ B' O, T& ]; [: b
  28.             (pLayerCfg->RedBlueSwap << DMA2D_POSITION_BGPFCCR_RBS);' M+ u4 M  x1 v2 [- k6 N

  29. 4 _/ I0 f; k) W. ~7 k* Z& ]
  30.   regMask  = DMA2D_BGPFCCR_CM | DMA2D_BGPFCCR_AM | DMA2D_BGPFCCR_ALPHA | DMA2D_BGPFCCR_AI | DMA2D_BGPFCCR_RBS;, P; C* ^; }( x

  31. 4 {8 `5 W+ x7 G$ J* H  s
  32.   if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    - `; Y* n) l- s' a
  33.   {$ g- C6 E& |# H
  34.     regValue |= (pLayerCfg->InputAlpha & DMA2D_BGPFCCR_ALPHA);
    4 C: l6 [# }9 A1 m
  35.   }
    6 }4 G1 x( s: l/ X) N. `% }
  36.   else
    2 l1 S: H+ T$ n# l- q8 t
  37.   {
    / Y0 A/ [7 K; z7 u/ o& k. j8 a6 V
  38.     regValue |=  (pLayerCfg->InputAlpha << DMA2D_POSITION_BGPFCCR_ALPHA);' S) i1 H4 w9 _. J5 Z% V. d$ d
  39.   }
    - X: A5 [5 X" [) W( }) k

  40. , u4 ^2 o7 J2 I
  41.   /* 配置背景层 */
    / T8 y/ \  \0 ]; a
  42.   if(LayerIdx == 0)
    ) C2 P' }- W0 b9 J
  43.   {
    1 C, |# [8 e5 L% x% x6 o
  44.     /* DMA2D BGPFCCR 寄存器 */! n$ c% o; H+ A7 d; W6 [
  45.     MODIFY_REG(hdma2d->Instance->BGPFCCR, regMask, regValue);* {0 }9 O$ o: N/ d

  46. . Z2 b: v0 j1 s! C# r; b. k
  47.     /* DMA2D BGOR 寄存器 */  
    ; y! q! k0 h0 Z9 @* A
  48.     WRITE_REG(hdma2d->Instance->BGOR, pLayerCfg->InputOffset);% n' l- R' H& t6 C: |% d

  49. . W4 q/ {& U' s1 j
  50.     /* DMA2D BGCOLR 寄存器 */ / I' F- C+ p" }; B. X5 @
  51.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    - T7 B% ^+ t/ K  x9 z: w
  52.     {    & _5 x5 f+ v) B5 q
  53.       WRITE_REG(hdma2d->Instance->BGCOLR, pLayerCfg->InputAlpha &
    : Z# j% c- z' N  `& m3 D
  54. (DMA2D_BGCOLR_BLUE|DMA2D_BGCOLR_GREEN|DMA2D_BGCOLR_RED));
    : ^1 C: M2 c4 x* @
  55.     }   
    ) i; k- z* U+ X* Y8 b- m3 z8 y* A7 ]
  56.   }- n% C  _9 t4 [# O, r' b, G. Y; i2 H
  57.   /* 配置前景层 */
    ! @" _% ]; g& i4 u6 O
  58.   else
    2 R5 u. Q3 N0 I
  59.   {
    " ^! Q1 ^. j7 b; Q: D
  60.     if(pLayerCfg->InputColorMode == DMA2D_INPUT_YCBCR)
      Q. G  {$ X( s
  61.     {( r0 P8 S' F1 O
  62.       regValue |= (pLayerCfg->ChromaSubSampling << DMA2D_POSITION_FGPFCCR_CSS);
    9 b. h6 }& `( n  |6 G
  63.       regMask  |= DMA2D_FGPFCCR_CSS;( w. g% z8 ~  S4 w' k* f
  64.     }
    7 {% j4 C6 m- {9 t
  65. * s$ T- o% Z" j+ W0 e
  66.      /* DMA2D FGPFCCR 寄存器 */
    $ J' K  ^" s7 ]5 p
  67.     MODIFY_REG(hdma2d->Instance->FGPFCCR, regMask, regValue);0 ?1 u. z0 ]9 C' n

  68. 5 r4 @5 j2 `& {; h
  69.     /* DMA2D FGOR 寄存器 */5 u5 X4 c$ _" c$ L; a6 [! f
  70.     WRITE_REG(hdma2d->Instance->FGOR, pLayerCfg->InputOffset);      
    8 K6 o( _$ \: k
  71. # Q/ l9 C( n2 G7 @- Y9 f2 S* {
  72.     /* DMA2D FGCOLR 寄存器 */   & p. n9 Z; y% A6 d; G
  73.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    . _0 C* g$ i' s6 o; e/ T
  74.     {! p9 k6 [5 i9 G* o
  75.       WRITE_REG(hdma2d->Instance->FGCOLR, pLayerCfg->InputAlpha & * u9 L# j0 \& s* N( J
  76. (DMA2D_FGCOLR_BLUE|DMA2D_FGCOLR_GREEN|DMA2D_FGCOLR_RED));      
    + P6 s% C7 q8 ]4 V- `% |+ `
  77.     }   2 H( g/ G/ N, m0 y" P' P3 v
  78.   }   
    ( X5 T, w8 i$ z" ]
  79.   /* DMA2D就绪 */
    / C8 W1 H: Z# g# G" _' s
  80.   hdma2d->State = HAL_DMA2D_STATE_READY;7 g$ V' \/ E0 q: i2 }2 X8 P8 ^. t

  81. % |* f6 S" V3 `% W% o
  82.   /* 解锁 */
    8 I/ K* D& f" J+ G
  83.   __HAL_UNLOCK(hdma2d);  " J: [- }, c& h; d

  84. 6 @2 e' Q$ E/ H0 l# L' i) A5 t
  85.   return HAL_OK;
    + Y/ |2 @) W4 W+ Y0 r5 W) U' e
  86. }
复制代码
" ~$ Q3 }8 N1 \* F! _) P
函数描述:4 n8 W: F) g- x
" U) S4 f9 R: p: s* x+ b
此函数主要用于配置DMA2D要转换的前景层和背景层,即输入颜色配置。而前面的函数HAL_DMA2D_Init配置的输出颜色。
; Z1 O9 q/ h+ l: X! l  ~. c4 n8 X! V- `2 w, S. Y" J. \
函数参数:# Z' K, Y! u- r

/ x6 S8 F$ S8 Z/ W3 J3 s) ?" Z+ W6 D  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。
- A" d. G* [: e1 B8 X, d6 G$ c  第2个参数用于配置前景层和背景层,0表示背景层,1表示前景层。" W- D$ [. s3 ^  H* g% C
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
# I  A2 `# D" c) F1 _使用举例:3 S5 [* g# p' B3 k
  1.   ^. z2 }; {; J! T. y7 {
  2. DMA2D_HandleTypeDef Dma2dHandle;% k. A8 N  m; ?% k1 c

  3. " D1 H# F  C5 j: e2 d2 z

  4. 7 b; x9 a  V4 R7 [5 e% O  k2 C
  5. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/
    $ G) t1 _4 U% u, F# Q$ u
  6. Dma2dHandle.Instance = DMA2D;2 g8 F5 d; Y7 @# n9 R; }8 y
  7. * O, Y- y' l( f
  8. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */
    5 @7 }7 Z, \5 v5 R+ X
  9. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */% t0 {" n* f/ C& u: ]# u$ q8 t
  10. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */
    * s( Y) J1 V/ U2 |) @
  11. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */
    1 A" j; L9 r  P. T" I' Q- |/ b3 P
  12. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */& h- X8 p3 j2 q# [. q
  13. 9 W6 f# e- A# w/ N4 S, c& N$ |
  14. /*##-2- DMA2D 回调函数配置 ######################################*/
    + k0 q1 s8 ]1 {% {1 D/ x( d. g) P9 R( p
  15. Dma2dHandle.XferCpltCallback  = TransferComplete;
    ) m+ H$ q$ O- N/ l6 u$ j) `/ k1 [' S+ Z
  16. Dma2dHandle.XferErrorCallback = TransferError;' z1 r: U# q, a

  17. $ B2 E2 i! u, k, q" c5 M6 r7 d
  18. /*##-3- 前景层配置 ###########################################*/
    : x3 s, J) s2 `* y; i/ D1 P" s
  19. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */
    4 p9 `: X: u1 b  S+ G
  20. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */+ q( F1 O; _# F4 g
  21. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */+ @7 Y; Y9 }+ W! P
  22. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */
    . ?7 u, [% @) u2 q
  23. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/; X- {# x' _+ K) `
  24. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/
    * q' j! s0 w0 L+ h7 g% y

  25. ( g  B* ]& I6 y; m
  26. /*##-4- DMA2D 初始化 ###############################################*/) ~: h: f3 p+ c8 p6 s
  27. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
    + }; U6 H/ e/ h% D$ j( q3 G5 q
  28. {
    ; Q. L( v% M5 C
  29.     Error_Handler();7 D2 ?6 |9 v* Q. i, e2 v
  30. }3 f! @7 q( s; ^2 ^7 F1 H! c' p

  31. 3 T4 X- R7 p2 j. s5 y2 k
  32. /* 配置前景层  */
    9 I5 Z; v3 C" _! V
  33. if(HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1) != HAL_OK)
      S* S* f  C. M3 J
  34. {
    & t8 t/ T8 {) }0 N5 L
  35.    Error_Handler();
    & t2 d, L* ]4 |) i& `. [9 M
  36. }
复制代码

* w9 k3 C: O2 a4 y3 h% z
# Q9 R% |6 C) t5 x- z* {55.4.3 函数HAL_DMA2D_Start_IT/ H) `3 Y; X% U
函数原型:% T) J3 s$ G" M" E0 {

! F3 e) E2 u: s9 c' O/ B: z
  1. HAL_StatusTypeDef HAL_DMA2D_Start_IT(DMA2D_HandleTypeDef *hdma2d, uint32_t pdata, uint32_t DstAddress, uint32_t Width,  uint32_t Height)) t3 H/ B) N( Y8 K9 v) H. A
  2. {( x6 ?, n; a4 T- i# p$ e
  3.   /* 检测函数形参 */
    8 F( M' D: J7 a0 K
  4.   assert_param(IS_DMA2D_LINE(Height));
    # N( k7 e% f' W/ @$ R
  5.   assert_param(IS_DMA2D_PIXEL(Width));
    5 b5 u3 `* R' D& t0 ], J  q

  6. & s% k/ Z/ Z; ~# l5 X# b
  7.   /* 上锁 */
    7 u! s$ J; n8 w( s; W  {/ \
  8.   __HAL_LOCK(hdma2d);
    ; W9 k" s# `+ F4 G; z
  9. # O" }2 D* G* j- O' Y; g
  10.   /* 设置DMA2D外设状态 */
    1 r0 I2 `! A  E
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;( F/ f1 E) i- r1 D# |
  12. / V0 W1 P; `+ u0 ?* h
  13.   /* 设置源地址,目的地址和数据大小 */: h3 ?% a# G8 W
  14.   DMA2D_SetConfig(hdma2d, pdata, DstAddress, Width, Height);- @6 `3 b& \& t6 o$ H8 P

  15. / X2 _' R. N7 B2 r- B  i2 h
  16.   /* 使能DMA2D的传输完成中断,传输错误中断和配置错误中断 */
    6 o; I  y% C2 W+ [+ F7 M2 F
  17.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);' X$ a# O. f6 ?$ H% P5 D, Q
  18. ( v+ b" I5 t( w2 Q. ~' `
  19.   /* 使能DMA2D */% p! L. {$ y% q0 h2 k; g' b
  20.   __HAL_DMA2D_ENABLE(hdma2d);) E  a5 a+ ~9 q8 d$ ?, D" b

  21. 4 W' N, _; ~* \
  22.   return HAL_OK;
    ! \5 ~& i, J* ~& Q7 L+ G; Q2 l  f$ p
  23. }
复制代码

: A7 _( G) D7 }4 w函数描述:
/ h4 X' H# i) x& h9 }" Y5 V
6 x& C  L8 d) T- b此函数用于启动DMA2D数据传输。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。6 d0 T+ _$ l# o
7 Q. u) k- {" Z. {0 F: l5 G" @
函数参数:
) O  e; G' U( Y( P; x+ I  r1 R) c/ M$ c
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。; l! f5 B' a* h4 H. W0 F" x
  第2个参数是源数据地址。
7 V) E) L4 m" X+ [: L3 Q8 E2 U0 Y0 k3 A+ `  第3个参数是目的数据地址。3 c/ k( i9 K: ~/ Q+ s
  第4个参数是源数据的长度,即每行的像素个数。
- R* W% A9 y- D  第5个参数是源数据的高度,即行数。
* ?1 r; C  k0 _" ?$ l3 P0 ~' m; [  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。( `+ l+ i  a: p9 C% j& B
使用举例:0 m4 n' B: Y' ?9 R5 A( |* g0 ?

" O9 M0 \2 Y' d
  1. DMA2D_HandleTypeDef Dma2dHandle;
    ( @' L' b% T$ K2 r+ K

  2.   E6 A: x# H6 C! L
  3. if(HAL_DMA2D_Start_IT(&Dma2dHandle,            /* DMA2D句柄 */0 A8 {/ g1 @: ?4 s& C: e
  4.                       (uint32_t)&BufferInput,  /* 源地址 */
    3 Y5 Y9 b) s7 v0 O
  5.                       (uint32_t)&BufferResult, /* 目的地址 */
    . q  i4 m2 Q2 P. M$ K- N" {( _
  6.                       SIZE_X,                  /* 源数据长度,单位像素个数*/
    . r2 d5 R( |: }) E0 R
  7.                       SIZE_Y)                  /* 源数据行数 */
    " `1 ]; e5 m; t6 _- C+ K; U
  8.    != HAL_OK)
    5 G$ I# ], s$ T7 B* a% J
  9. {
    - n& w  j+ e" w) `, @
  10.    Error_Handler();7 B. ?* X1 V# Q6 j( R0 U) y
  11. }
复制代码
, }  k  |# I+ f; R4 c
55.4.4 函数HAL_DMA2D_BlendingStart_IT2 T# V$ w7 ?, M7 K) M/ d
函数原型:
( k+ \' ], \, Z3 c
6 a) M/ h6 `& q; F( |. p' V
  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)
    # T  R. b7 d- @; Z, {4 H* E8 b
  2. {0 L4 D8 P/ [9 ^  O
  3.   /* 检测参数 */( l4 l% h/ a4 I1 ^4 m, @3 M3 \
  4.   assert_param(IS_DMA2D_LINE(Height));
    1 T9 l$ ?9 V# `
  5.   assert_param(IS_DMA2D_PIXEL(Width));
    2 ?/ k: y; v- }+ E" S& E( g
  6. 0 z0 A- J8 Y5 q2 b$ v* n
  7.   /* 上锁 */8 F& p- b" @! B, T
  8.   __HAL_LOCK(hdma2d);6 u: L4 G! D  p& B3 g- A! w3 S
  9. ( o" R- d( o* Z& f& B3 G
  10.   /* 设置DMA2D外设状态 */
    6 @& \/ N+ a" l; E3 E# _0 r
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;3 w/ i0 D, u- E

  12. 0 e# o* t3 L4 f
  13.   /* 配置DMA2D源地址2 */
    ( H5 B! e, N! |! Q5 [  A# I- U2 U* h
  14.   WRITE_REG(hdma2d->Instance->BGMAR, SrcAddress2);8 }) \' N* W4 t, r8 G+ X
  15.   c. [+ c3 C. R! N9 r6 ^
  16.   /* 配置源地址1,目的地址和数据大小 */
    4 Y8 f* z$ x% b: d
  17.   DMA2D_SetConfig(hdma2d, SrcAddress1, DstAddress, Width, Height);; I+ g2 i7 X! F$ S
  18. - o* `) A  a5 G$ p+ S1 o: }
  19.   /* 使能DMA2D传输完成中断,传输错误中断和配置错误中断 */
    9 A; ^4 f% |3 [* Y# p3 t& M
  20.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);
    7 \2 }/ K& @8 B, p7 {& r1 u  s

  21. $ Q, W) `% j$ y7 m- w0 z8 [
  22.   /* 使能DMA2D */
    5 r6 u3 E1 k; k. c) h
  23.   __HAL_DMA2D_ENABLE(hdma2d);6 M7 p9 k& z& L! [8 a

  24. 4 ^1 q, b1 t# N" s. n- j
  25.   return HAL_OK;. w% I" d+ z2 k. X
  26. }
复制代码
2 r, E" W6 p% m
函数描述:
) m% x* F0 |. ~. _
0 A, S$ F7 q; h5 @$ ]" D此函数用于启动DMA2D传输,除了数据传输以外,还支持颜色格式转换和颜色混合。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。
# r+ T. M  J& D- ^: ]7 r- m! U% b; P. s$ P- g$ |
函数参数:& }  O5 ^, K- |! B  W
2 b3 T4 y0 w$ i1 K
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。& T: ]0 \  n) F  w! R* ~5 \" M/ G
  第2个参数是源数据地址1。
  ?' i$ v4 E) r3 i* `, K0 h  第3个参数是源数据地址2。
. b& H1 q: `' m3 D$ Q& N  第4个参数是目的数据地址。) `7 z4 A& O' B' A! R! C
  第5个参数是源数据的长度,即每行的像素个数。
4 H% V; F' E7 e8 m, y  第6个参数是源数据的高度,即行数。  [9 Z2 R7 c" k5 h+ m2 V% f
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。5 C# X% d& g2 a1 T7 r
使用举例:& G  w% v2 C9 r. Y5 }. R0 ]& t

6 l- _5 G* o4 A4 p& [) f
  1. DMA2D_HandleTypeDef Dma2dHandle;  \/ F; o. F% T3 ]7 H4 G' D
  2. & v  o5 F6 f8 A# K& _2 Z' z1 w( V
  3. if(HAL_DMA2D_BlendingStart_IT(&Dma2dHandle,           /* DMA2D句柄 */
    ) H& x/ X2 {' u: \7 b9 U) A  V6 D: a
  4.                              (uint32_t)&BufferInput1, /* 源地址1,前景色 */ & S( x4 a6 ~- [  v- W+ \7 [% u
  5.                              (uint32_t)&BufferInput2, /* 源地址2,背景色 */
    , E# Q# G2 L3 d4 I5 ?+ Y& z
  6.                              (uint32_t)&BufferResult, /* 目的地址 */$ }! k* Y4 D" s8 Z. U* H  v: w
  7.                               SIZE_X,                 /* 源数据长度,单位像素个数*/
    0 L, P8 }" V& M# }8 F6 O
  8.                               SIZE_Y)                 /* 源数据行数 */0 G* e8 Y" F" V/ l/ t- L2 a
  9.    != HAL_OK)
    , Q/ q9 M) Y* X6 `9 d9 F2 B
  10. {
    , |- P" i7 J0 A
  11.    Error_Handler();) }1 x  b- d- X! L9 o, G
  12. }
复制代码

. p2 P) o/ j, }8 @& R2 P' S. [5 B8 W; z
55.5 总结
3 z0 x: m, g+ z' ~$ d  O本章节就为大家讲解这么多,DMA2D功能比较重要,一定要做到熟练使用。1 r+ C( y" ~+ e8 Q" e! I/ g

; T+ v8 m1 x# M& _
3 w/ i: s& p1 a* R
" f" E% M7 X) S( y
收藏 评论0 发布时间:2021-12-24 17:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版