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

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

[复制链接]
STMCU小助手 发布时间:2021-12-24 17:00
55.1 初学者重要提示" D* a; Z) g* o8 p( P
  DMA2D是专门用于LCD加速的,特别是刷单色屏,刷图片,刷Alpah(透明)混合效果全靠它,而且可以大大降低CPU利用率。. ?- }9 f2 {: T0 I) N7 A* I( N. u
  测评STM32H7的LTDC+DMA2D性能,100Hz以上无压力,刷800*480图片和色块仅需2.6ms一张
% ^; V. k- O& y- n  H7的DMA2D与F429的DMA2D最大区别是支持了ARGB和ABGR互转,而且支持H7的硬解JEPG输出格式YCbCr转RGB,方便LCD显示。/ B  q, C% n! q  {1 Z) o# q
  特别注意,大家只需对HAL库提供的DMA2D操作API有个了解即可,实际工程中,并不使用这些API,我们需要使用更加高效的寄存器直接操作,在下一章节会为大家说明。
* N8 W5 F% R8 S! q- s55.2 DMA2D基础知识# h  @, d( ~8 i' J5 }* h
DMA2D主要实现了两个功能,一个是DMA数据传输功能,另一个是2D图形加速功能。/ u% p+ z$ A* W' p9 G% P' R8 [

( z9 k& X  z# k* {0 u6 o  DMA数据传输
$ u/ x/ H0 s+ a主要是两种方式,一个是寄存器到存储器,另一个是存储器到存储器。通过DMA可以大大降低CPU的利用率。
1 V7 c, @# h. T
- x5 V3 T  F3 z+ _- A  2D图形加速功能
# p% b- R7 @' Z+ j# F# r6 M3 W' k支持硬件的颜色格式转换和Alpha混合效果。' ]3 B: Z8 B6 o0 X

- c; X/ Y0 g  B+ F$ l" a55.2.1 DMA2D硬件框图) o1 K2 }1 v( e5 C" k! V
认识一个外设,最好的方式就是看它的框图,方便我们快速地了解DMA2D的基本功能,然后再看手册了解细节。框图如下所示:, }2 _  {6 j5 c

+ K9 f4 B+ n4 {2 [  F, \
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
$ c1 e" U. U% `

1 [. F$ \, U, o, Z( ^# V% q通过这个框图,我们可以得到如下信息:; P3 z9 n- p/ S+ F9 F
8 j1 R5 z2 Y5 u9 ^' @
  dma2d_aclk* i# G" T( e% X+ u3 H- ?! y* S1 y
AXI 总线时钟输入。, t1 W/ @7 U6 Z1 a6 f. N+ q

' _% e# W) f, H( V$ e! g! z! ~0 `$ k# c  dma2d_gbl_it
2 O# M$ q! v6 P; W8 @DMA2D全局中断输出。& s! L2 H5 p- |: S2 V* \' f

3 I- J" ^2 O& d1 O# T: {' E  dma2d_clut_trg9 I  ?* R" t! C3 n
CLUT传输完成信号输出,可以触发MDMA。6 N7 V2 _$ ]2 a) C, w
" Z% V9 O$ A, U2 }1 ^# E
  dma2d_tc_trg
/ Z5 y. x' L- s4 D9 n4 j传输完成信号输出,可以触发MDMA。
( |" E2 G5 O+ x" ?- i, e/ |. U) o% y/ j5 S
  dma2d_tw_trg ; {7 x1 f7 D$ d" N9 {, A
传输watermark信号输出,可以触发MDMA。
3 G6 @( ~/ ^1 Y) S! ]0 P  D5 e
' a9 u" e  r! b8 ?1 J$ `将这个硬件框图简化一下,就是下面这样:0 S* F" R" l. k+ ^
1 k2 |* I! j* g' P9 Y0 z
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
7 X7 D# J, ?, ~9 [. o% Z; Q

/ h' h8 B/ }+ Q下面按照简化的硬件框图,对每个部分做个说明。
! j( [9 J7 Q' G! z0 H1 s
3 J$ w) l& h" F% w4 _55.2.2 DMA2D工作模式
2 E/ l7 t7 n- |$ v4 \. b$ hDMA2D支持的工作模式如下:
, i) c1 r- Q! Y/ P
3 O8 t$ \& r7 f0 z* N! E  模式1:寄存器到存储器模式; y( O5 N; H2 P7 s
这个模式主要用于清屏,也即是将显示屏清为单色效果。8 H" W+ @! v3 @- h3 J+ N$ }4 f' S) E
& i  h" G% N! U9 W. i. E6 z! p$ c% ]
  模式2:存储器到存储器模式6 e/ j& G0 s9 M0 m% x. k
这个模式用于从一个存储器复制一块数据到另一个存储器,比如将摄像头OV7670的输出图像复制到LCD显存就可以采用这种方式。
4 N# _2 T( e' A0 [2 u: w
0 Z3 q2 q# B7 U4 O" H. C  模式3:存储器到存储器模式,带颜色格式转换- K- @2 I& N! M
这个模式比模式2多了一个颜色格式转换,比如我们要显示一幅RGB888颜色格式的位图到RGB565颜色格式的显示屏,就需要用到这个模式,只需输入端配置为RGB888,输出端配置RGB565即可。位图颜色格式转换后会显示到显示屏上。" ]' z( B- Y. w4 J5 Q4 B) i  z1 z
  J4 V  s; z4 n: o$ R5 P4 v
  模式4:存储器到存储器模式,带颜色格式转换和混合
8 h& A' h3 y* o; L# O$ R# O2 j这个模式比模式3多了一个混合操作,通过混合,可以将两种效果进行混合显示。* v5 {2 ], Q/ _( y
; d2 |7 x0 S( [- D6 f$ u" I8 B
  模式5:存储器到存储器模式,带颜色格式转换和混合,前景色是固定的
8 j% W  `; w% V# W  x) h# c; l同模式4,只是前景色的颜色值是固定的。1 V: @5 q8 Y% q# X% o7 `+ c4 R

$ P7 T/ g6 a' X* m8 e55.2.3 前景层和背景层的输入以及颜色格式转换& i, ]6 T1 k9 q+ r7 @( Z% @4 A( t
前景层和背景层是指的用户绘制图形时的前景色和背景色,比如我们显示汉字,字体会有一个颜色,也就是前景色,还有一个背景色。又比如我们绘制两幅图片,想将两幅图片混合,那就可以将一幅图片作为前景层,另一个幅图片作为背景层。
* X( w. U1 G+ v/ c" M. s. e6 p
# f* q& V+ k' d8 p. ~' P2 r$ l- gDMA2D支持的输入颜色格式如下,前景层和背景层一样:
$ D9 v& a9 u1 S
1 r' t- n) }3 p2 ]( g9 {
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

+ a  @- c. b4 x- s
% o- \3 o: w( e  `前8种颜色格式在第50章的第2小节开头有介绍,这里把后四种做个说明:0 i" T, S/ Y2 Q( E7 n+ E

" |+ h$ V# R( I5 [* z* k( z  L4 (4-bit luminance or CLUT)
/ k& p0 u* K; ]; @1 X# @4位颜色格式,实际上仅仅是4位索引值,范围0–15,而每个索引值的具体颜色值在查色表CLUT里面存储。% n) T9 D( l) q/ {0 q% ~
: A; K! [6 N2 J7 j7 G
  A4和A8+ E1 w% C# I7 m, @% {
A4和A8用于特定的Alpha模式,既不存储颜色信息,也没有索引值。
$ o4 f) G% k  F% I  x; W! E
0 ~& f* V# ^' `2 g6 k2 e  YCbCr
) U1 k; _8 |- ?; C$ q- X这个是H7的硬件JPEG输出的颜色格式,后面JPEG章节为大家专门做讲解。3 C+ m1 G# |0 L& d. B; v0 w

- p; D' T6 I) g2 }+ I7 X7 s这里特别注意一点,输入颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。( Q" P5 B0 L5 {; c6 C) G

" ]! c3 x  a: j, s55.2.4 前景层和背景层混合
' v/ f9 c1 t4 ]2 ~DMA2D混合器用于混合前景色和背景色,这个功能不需要任何配置,仅需要通过DMA2D_CR寄存器使能即可。混合公式如下:
1 b" R' B- _* h2 H9 r8 i/ {) L* P4 v4 n1 r6 H3 ]% D
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
7 N& @3 a8 s: M! z% n! w
7 I" h1 ^: y5 v4 j: c( i
55.2.5 DMA2D输出颜色格式
5 S  d' Y: X' C5 D# ]1 MDMA2D支持的输出颜色格式如下:
( [. M: A2 M3 D' ?( O" j& i7 L( a  M$ C5 |& Q5 V" c2 S0 H/ A
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

$ x3 y0 w/ f1 c0 K9 g9 q% u$ x& R7 v+ n% y4 z* ?. j  m6 e- A
这里特别注意一点,输出颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。$ O% U  n4 l7 X) A/ T" a, u

( f! c3 V/ O& M55.3 DMA2D的HAL库用法
% |1 v3 }1 a# ], }DMA2D的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断。下面我们逐一展开为大家做个说明。# s* f1 e$ _  b5 c
( w8 F* i2 H  V8 y  I2 P2 @0 G
55.3.1 DMA2D寄存器结构体DMA2D_TypeDef* X/ M# I! K5 S2 ~
DMA2D相关的寄存器是通过HAL库中的结构体DMA2D_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:
$ h0 y, c2 |+ i# p8 b+ o, N; [* u3 a; ~7 [% d0 v+ r! O
  1. typedef struct6 G- \3 V2 p/ I6 W$ k' |
  2. {
    - I, i3 v- {3 ?! [5 Y
  3.   __IO uint32_t CR;            /*!< DMA2D Control Register,                         Address offset: 0x00 */
    + e6 X; K: m, a5 W* a
  4.   __IO uint32_t ISR;           /*!< DMA2D Interrupt Status Register,                Address offset: 0x04 */. |- M. r& V  F' _9 ?
  5.   __IO uint32_t IFCR;          /*!< DMA2D Interrupt Flag Clear Register,            Address offset: 0x08 */
    2 y9 Q& d5 T+ i, j0 b7 q1 U  K
  6.   __IO uint32_t FGMAR;         /*!< DMA2D Foreground Memory Address Register,       Address offset: 0x0C */  q; m& h. l7 \& f7 p; Y
  7.   __IO uint32_t FGOR;          /*!< DMA2D Foreground Offset Register,               Address offset: 0x10 */1 g" D( t4 h6 G5 _: _" Y
  8.   __IO uint32_t BGMAR;         /*!< DMA2D Background Memory Address Register,       Address offset: 0x14 */
    3 T4 j1 k! J1 p0 V5 h
  9.   __IO uint32_t BGOR;          /*!< DMA2D Background Offset Register,               Address offset: 0x18 */; j9 w' g5 c6 r: O! u, f
  10.   __IO uint32_t FGPFCCR;       /*!< DMA2D Foreground PFC Control Register,          Address offset: 0x1C */6 y5 ^5 C2 A7 K6 c& Y
  11.   __IO uint32_t FGCOLR;        /*!< DMA2D Foreground Color Register,                Address offset: 0x20 */
    2 |- p& R( @0 [3 @( a/ \* K
  12.   __IO uint32_t BGPFCCR;       /*!< DMA2D Background PFC Control Register,          Address offset: 0x24 */
    8 L$ h/ e, r$ M4 P2 b" v
  13.   __IO uint32_t BGCOLR;        /*!< DMA2D Background Color Register,                Address offset: 0x28 */7 o; ~# D( A8 n# G2 c/ p
  14.   __IO uint32_t FGCMAR;        /*!< DMA2D Foreground CLUT Memory Address Register,  Address offset: 0x2C */, H% t9 c' L" Q. ^8 J. r3 W% f$ n
  15.   __IO uint32_t BGCMAR;        /*!< DMA2D Background CLUT Memory Address Register,  Address offset: 0x30 */$ A6 y. p0 H( \; s% z* S
  16.   __IO uint32_t OPFCCR;        /*!< DMA2D Output PFC Control Register,              Address offset: 0x34 */
    6 S4 M% |# E/ E! p  D) V
  17.   __IO uint32_t OCOLR;         /*!< DMA2D Output Color Register,                    Address offset: 0x38 */" e3 V$ ]# _. f6 `2 n
  18.   __IO uint32_t OMAR;          /*!< DMA2D Output Memory Address Register,           Address offset: 0x3C */$ B4 V# n6 R, _8 d, B6 B: r3 R
  19.   __IO uint32_t OOR;           /*!< DMA2D Output Offset Register,                   Address offset: 0x40 */# C4 {: x. i+ h* {* ~
  20.   __IO uint32_t NLR;           /*!< DMA2D Number of Line Register,                  Address offset: 0x44 */, q( a/ n" C7 K: X+ F, X, B
  21.   __IO uint32_t LWR;           /*!< DMA2D Line Watermark Register,                  Address offset: 0x48 */, T& Z9 k$ k* D2 v
  22.   __IO uint32_t AMTCR;         /*!< DMA2D AHB Master Timer Configuration Register,  Address offset: 0x4C */; y8 E! s" c( Z& `
  23.   uint32_t      RESERVED[236]; /*!< Reserved, 0x50-0x3FF */
    8 J" m6 Z8 a0 N5 B$ g( [, Q7 {0 [3 K
  24.   __IO uint32_t FGCLUT[256];   /*!< DMA2D Foreground CLUT,                          Address offset:400-7FF */# A; R7 v; [% M) r/ y
  25.   __IO uint32_t BGCLUT[256];   /*!< DMA2D Background CLUT,                          Address offset:800-BFF */
    # T8 B/ I3 u9 M
  26. } DMA2D_TypeDef;
复制代码

7 U& [& b, }6 z# E. a6 I5 q6 h. ], K- Q; L8 I
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:* e6 z! `5 d# ?1 w' \
/ o" c; j' h: `; n4 A
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */: _. h; I( i+ s5 G/ L* C
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
7 p+ Y  _; w$ E2 O1 U+ g/ @
下面我们再看DMA2D的定义,在stm32h743xx.h文件。
  1. #define PERIPH_BASE              ((uint32_t)0x40000000) * f# H2 l& H  _2 ?7 b
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000)% ~( G: Z3 ]: ~; K0 F9 L
  3. #define DMA2D_BASE               (D1_AHB1PERIPH_BASE + 0x1000)8 a+ R9 s2 P1 V7 @3 L! |
  4. #define DMA2D                    ((DMA2D_TypeDef *) DMA2D_BASE) <----- 展开这个宏,(DMA2D_TypeDef *) 0x52001000
复制代码
. q- Q% `5 M& P2 O8 k* N) h
我们访问DMA2D的ISR寄存器可以采用这种形式:DMA2D->ISR = 0。
  F; {" _. O8 [4 O% M) c2 H" Q6 n% I& v; B2 u
55.3.2 DMA2D参数初始化结构体DMA2D_InitTypeDef; d0 S* X1 Y+ ]9 {8 H. Q- f
此结构体用于配置DMA2D的基本参数,具体定义如下:
( E8 d6 M' \5 _2 C
! R6 f0 r" T2 A
  1. typedef struct
    / B  s' B' m. l9 A, t5 h
  2. {
    9 e* s+ H- i/ {" O1 V
  3.   uint32_t             Mode;              
    5 C* Z) w0 f8 L, y6 O8 x# w# n
  4.   uint32_t             ColorMode;        ! t2 j; r' z7 v  B$ X4 @
  5.   uint32_t             OutputOffset;      
    ) D4 t! j- E  f% K6 ?1 U% L5 p
  6.   uint32_t             AlphaInverted;    6 E5 C8 }4 _# d  q' a, s, H
  7.   uint32_t             RedBlueSwap;       6 N! Z* K$ ?* Y/ b* _- ~# t
  8. } DMA2D_InitTypeDef;
复制代码

( \5 K7 `* M7 s* s' H9 ^下面将这几个参数逐一为大家做个说明:
1 @7 y9 Z7 {, P* v* x/ z/ G
) P" }) [5 x2 H' I5 M3 c  uint32_t   Mode  M: {8 S4 R, h# r
此参数用于设置DMA2D的传输模式,具体支持的参数如下:
% {; w7 [7 W0 @8 B, C( S- l
" `) Q$ k* F; @4 ^% @4 J. _
  1. #define DMA2D_M2M        ((uint32_t)0x00000000U)  /*存储器到存储传输模式 */
    $ d& w- q& G. c3 d; N
  2. #define DMA2D_M2M_PFC     DMA2D_CR_MODE_0         /*存储器到存储器传输模式,并执行FPC像素格式转 */
    ) {# U) t, V3 j
  3. #define DMA2D_M2M_BLEND   DMA2D_CR_MODE_1         /* 存储器到存储器模式,并执行像素格式转换和混合 */* u2 Q! [7 W9 S: x- g1 S
  4. #define DMA2D_R2M         DMA2D_CR_MODE           /* 寄存器到存储器传输模式 */6 W* R3 ?% _7 T' v5 A) u* d- w
复制代码
+ l2 x4 v5 m; f" W3 u% \2 H
- P: V% L$ W2 {: e. z$ x2 R# M
  uint32_t   ColorMode8 y2 t* S& F; D- M. z
此参数用于设置DMA2D的输出颜色格式,具体支持的参数如下:
2 u9 |0 W6 T. ]5 f0 l
3 _3 ?4 D  P5 X! [+ a+ D
  1. #define DMA2D_OUTPUT_ARGB8888       ((uint32_t)0x00000000U)               /* ARGB8888 */
    ; G% `4 p, z5 a* X2 Q9 f! B/ M
  2. #define DMA2D_OUTPUT_RGB888         DMA2D_OPFCCR_CM_0                     /* RGB888 */
    % V' S; l, I8 Y8 p9 C  H/ P
  3. #define DMA2D_OUTPUT_RGB565         DMA2D_OPFCCR_CM_1                     /* RGB565 */. ?% u: B9 T: y8 P, d) k
  4. #define DMA2D_OUTPUT_ARGB1555       (DMA2D_OPFCCR_CM_0|DMA2D_OPFCCR_CM_1) /* ARGB1555 */, X' L9 |) {6 M0 b
  5. #define DMA2D_OUTPUT_ARGB4444       DMA2D_OPFCCR_CM_2                     /* ARGB4444 */
    # n- B4 E* D* E8 V
复制代码
) W: T( W& t3 h
3 b4 d/ F. N7 x
  uint32_t   OutputOffset: A% e. D4 O3 C9 F6 I; [
此参数用于设置输出位置的偏移值,参数范围0x0000到0x3FFF。$ t, v4 p+ ~( k9 G1 {

! k  k% k) |0 T2 g  uint32_t   AlphaInverted
" o1 |7 X. h$ L% }' V此参数用于设置DMA2D的输出颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     
. v8 Q! p; ]( ?2 K: ?, j4 O" ^2 k: t/ U2 b/ P, q- m, |
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */
    + y0 p5 m1 ]/ Y, Y: d
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */
复制代码

7 v7 ^$ Y' v3 v  uint32_t   RedBlueSwap
3 R* l. v! a5 M9 _, p+ k7 W此参数用于设置DMA2D的输出颜色格式中R通道和B通道的交换,具体支持的参数如下:! N5 k8 \3 \6 n6 r3 N9 L+ V* u

1 N2 h3 V1 y( Y  b; G( {" w
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */' a7 `  c# T, H4 e
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码
  A4 w$ y/ B+ a* ^. Y
55.3.3 DMA2D的图层结构体DMA2D_LayerCfgTypeDef# U& I1 W: i  J& x! X9 ~( Z& A0 }
此结构体用于配置前景色和背景色。
$ b) ^# l( t+ W( m" W4 k
: z+ Z+ u* v8 v, o
  1. typedef struct, a8 ]2 `" K1 X  N& Z' J4 {
  2. {
    1 @0 Q! {, M# u& H2 A6 }
  3.   uint32_t             InputOffset;      
      Q! g8 H3 ]% y- H4 n5 {
  4.   uint32_t             InputColorMode;   
      ~6 k& z. ]2 v" _: W
  5.   uint32_t             AlphaMode;        0 E+ b: L+ L' o: Y5 T+ {' Y
  6.   uint32_t             InputAlpha;        
    , r3 A+ j7 _1 e5 \# g
  7.   uint32_t             AlphaInverted;   
    & q- M! T% o$ T7 m
  8.   uint32_t             RedBlueSwap;       / q4 l0 g% v) X3 @
  9.   uint32_t             ChromaSubSampling;
    / C! o" w+ [: ?1 S/ I4 @! r
  10. } DMA2D_LayerCfgTypeDef;
复制代码
! I7 j% H9 z! }" Z- R
下面将这几个参数逐一为大家做个说明。
- o2 d. I4 I+ X- D, W# ^
+ P* {1 ]# D( E5 ]6 ]) E6 Z  uint32_t  InputOffset: K: G- {) I7 A* a8 H4 \
设置前景色或者背景色的输入偏移,范围0x000到0x3FFF。/ g/ T: e5 ?5 b
: K% B( I& K1 o+ d& c
  uint32_t  InputColorMode: r  ]; m0 M- Q2 ]* u; ~! s# `
设置前景色或者背景色的输入颜色格式,具体支持的参数如下:
( z( m; W8 R- T' s* g/ c# v' S, z$ G, G/ S% w& m
  1. #define DMA2D_INPUT_ARGB8888        ((uint32_t)0x00000000U)  /* ARGB8888 */( N5 Y$ Q* j5 \- |: W
  2. #define DMA2D_INPUT_RGB888          ((uint32_t)0x00000001U)  /* RGB888   */
    6 |7 A; d  @0 L
  3. #define DMA2D_INPUT_RGB565          ((uint32_t)0x00000002U)  /* RGB565   */: O$ }0 y) f% @( ?% g- q( j' [/ \# U
  4. #define DMA2D_INPUT_ARGB1555        ((uint32_t)0x00000003U)  /* ARGB1555 */
    0 h6 Q4 s# F" }
  5. #define DMA2D_INPUT_ARGB4444        ((uint32_t)0x00000004U)  /* ARGB4444 */+ Y, f, ]/ V# |( v1 s3 J- J8 }
  6. #define DMA2D_INPUT_L8              ((uint32_t)0x00000005U)  /* L8       */& T, o! k3 t% U( V
  7. #define DMA2D_INPUT_AL44            ((uint32_t)0x00000006U)  /* AL44     */; z& F3 P7 T- n# |6 ~
  8. #define DMA2D_INPUT_AL88            ((uint32_t)0x00000007U)  /* AL88     */
    7 ^2 r1 u% l$ p6 I( ~. z
  9. #define DMA2D_INPUT_L4              ((uint32_t)0x00000008U)  /* L4       */5 m7 X- {6 j. T+ e' u# P$ t
  10. #define DMA2D_INPUT_A8              ((uint32_t)0x00000009U)  /* A8       */# j) G/ R# n% s; D! m
  11. #define DMA2D_INPUT_A4              ((uint32_t)0x0000000AU)  /* A4       *// X6 k! z% ^+ m; S
  12. #define DMA2D_INPUT_YCBCR           ((uint32_t)0x0000000BU)  /* YCbCr    */
复制代码

0 s$ ^# j+ d* R  o  uint32_t AlphaMode
, M+ P# [; s9 }% o设置前景色或者背景色的Alpha模式,具体支持的参数如下:: U, g# c, C  W3 H0 B4 h' y% ~
" G# r" Q# g. M( T2 U6 X9 D7 e/ g
  1. #define DMA2D_NO_MODIF_ALPHA   ((uint32_t)0x00000000U)  /* 不修改Alpha通道值 */
    * a; ^  A6 R" x! k5 C8 p# h
  2. #define DMA2D_REPLACE_ALPHA    ((uint32_t)0x00000001U)  /* 用新设置的Alpha值替换原始Alpha值 */& w: Y  n2 z! M4 ^$ y& d
  3. #define DMA2D_COMBINE_ALPHA    ((uint32_t)0x00000002U)  /* 用新设置的Alpha值与原始Alpha值的乘积替换原始Alaha值*/
复制代码
' O2 A4 N. d( H
  uint32_t  InputAlpha" n- N- o4 C( e6 e8 w9 ^  D
设置前景色或者背景色的Alpha值,范围0x00到0xFF,如果颜色格式是A4或者A8,那么此参数的范围是0x00000000到0xFFFFFFFF,标准的ARGB8888格式。+ Y* {4 f1 L4 q* ?# `
, E3 E# N  F$ {( \4 L# T
  uint32_t AlphaInverted$ U1 k# C. ^5 D
设置前景色或者背景色的输入颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     
6 K, @/ ]* P2 X
3 R9 B; u# l$ [; j
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */
    6 d8 i2 a! o& B  x& G& M# z. Y" u
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */     
复制代码
  {* b! u9 {- n, b
  uint32_t   RedBlueSwap8 f) ^, l: b+ s8 @( w2 w
设置前景色或者背景色颜色格式中R通道和B通道的交换,具体支持的参数如下:
' m5 k- D1 X$ P6 ?% x
: s( w$ d& J* M
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */' G: l6 R* _5 i7 d. Z
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码
' ^, g1 _$ J! d6 r* _
  uint32_t   ChromaSubSampling. o8 r  x5 i  z1 x3 P
设置前景色或者背景色中YCbCr 颜色模式的采样格式,具体支持的参数如下:
  1. #define DMA2D_NO_CSS               ((uint32_t)0x00000000)  /* 4:4:4 */
    ! [' j9 N2 ]. l9 C8 C
  2. #define DMA2D_CSS_422              ((uint32_t)0x00000001)  /* 4:2:2 */
    0 B  O) P/ ]4 Q/ f# }' p+ j
  3. #define DMA2D_CSS_420              ((uint32_t)0x00000002)  /* 4:2:0 */  
复制代码
5 c4 ]* C; o' ~7 [2 z& g, c  A$ L8 E
55.3.4 DMA2D句柄结构体DMA2D_HandleTypeDef

0 I/ C9 y. N; \9 A' }HAL库在DMA2D_TypeDef, DMA2D_InitTypeDef和DMA2D_LayerCfgTypeDef的基础上封装了一个结构体DMA2D_HandleTypeDef,定义如下:
$ ~3 Q5 h( k# d8 j0 B3 T+ ~( t& _, z, n. Q- a
  1. typedef struct __DMA2D_HandleTypeDef5 M( T. G/ S+ S" I" r4 d( z
  2. {& H- U) o7 A* {0 q2 o, ~% q
  3.   DMA2D_TypeDef               *Instance;                                                                                                                                                                                          
    6 \6 Q# R/ ^4 n
  4.   DMA2D_InitTypeDef           Init;                                                        ! n! Z! W3 V1 Q
  5.   void                        (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                                                                             
      C1 B* ^4 n6 ~3 q+ v/ ^
  6.   void                        (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                      
    ) X8 G% `, R: @8 ]* y2 H7 N
  7.   DMA2D_LayerCfgTypeDef       LayerCfg[MAX_DMA2D_LAYER];                                    
    ( K, s. _! N4 C' T# I9 l
  8.   HAL_LockTypeDef             Lock;                                                                                                                                                                                                    ( F  k% X3 G6 Z) o  [) B
  9.   __IO HAL_DMA2D_StateTypeDef State;                                                                                                                                                                                                   
    1 q: y4 U) J- `# f9 W
  10.   __IO uint32_t               ErrorCode;                                                   } DMA2D_HandleTypeDef;
    ( f+ B9 s* @& U
复制代码

# W  C7 k5 x; q下面将这几个参数逐一做个说明。
0 N* t' [$ p: G0 w9 u" w0 y4 u1 q1 @
7 X/ K( ?) g* ?( p' z- }  V5 E# v1 W  DMA2D_TypeDef  *Instance
" C, K- M% o  `) J这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。, U$ l- I; s# Y/ }' u

* J- p, T$ C3 e  DMA2D_InitTypeDef  Init;  
0 c0 s! }( g1 h6 G8 G2 z+ ]这个参数是用户接触较多的,用于配置DMA2D的基本参数,详见本章3.2小节。
! K2 ]' H" \2 l. C9 }, Z7 c- N* j' }2 f+ G( _
  void     (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);5 U. `& A' D: f
  void     (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);% R3 M- b! \8 h+ F2 P
DMA2D中断服务程序里面执行的回调函数,一个是传输完成回调,另一个是传输错误回调。
0 m0 M- i6 ?% D6 T! l( O) b& N0 n5 r+ Y+ R0 h/ _# k
  DMA2D_LayerCfgTypeDef   LayerCfg[MAX_DMA2D_LAYER]
$ _9 M3 ^9 g% M" [这个参数用于前景色和背景色的设置,MAX_DMA2D_LAYER=2,详见本章3.3小节。
8 F" H! F, A4 U: n9 q: V, i
  K9 J. f& \! B. R7 v5 W; Q  HAL_LockTypeDef   Lock
9 r9 m# @6 t" l! V( b" ?5 \__IO uint32_t    State;& R. e1 c7 ]  w* D$ d( C3 W
1 k, H9 s3 |8 s; A3 ^5 b
__IO uint32_t    ErrorCode/ g: e/ @5 @' C7 t5 p$ K3 i; H: W" I
# m5 a4 ~7 C; [% H
这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置DMA2D通信状态,而ErrorCode用于配置代码错误。
: [. [* e/ r* I- Z0 H( x5 e3 M: s- E
55.3.5 DMA2D初始化流程总结

' `  _: z- N$ S' {对于DMA2D来说,其实不需要初始化流程,每个功能都可以直接封装出一个函数来,下个章节会为大家专门讲解,也是实际项目比较推荐的方式。/ J1 x% B7 t9 k: M. r3 `

7 p: M. D0 p$ u$ X8 W7 A4 {  q55.4 源文件stm32h7xx_hal_dma2d.c
' k& ]& t. c5 v- y  i( R这里把我们把如下几个常用到的函数做个说明:3 P; l2 _$ |7 P( [+ n% _

: e$ l: u, C* T, g' E( D  HAL_DMA2D_Init" C- {- N3 U3 c2 z/ l1 A) [
  HAL_DMA2D_ConfigLayer+ A7 I2 q$ N) z8 q( b2 q8 f
  HAL_DMA2D_Start_IT
# C/ b. t) v0 _. @7 [- K  HAL_DMA2D_BlendingStart_IT6 E- M. D' U1 y/ k% }2 z: F0 t! h. R

6 E+ I" o6 H1 ?+ C4 G. O. d55.4.1 函数HAL_DMA2D_Init
, Z- t. C3 x$ ?# O函数原型:
' Y* j0 y8 m: M* T. m2 H% Y8 W8 s
( A% F+ b# G. u
  1. HAL_StatusTypeDef HAL_DMA2D_Init(DMA2D_HandleTypeDef *hdma2d)( j8 x. r+ H6 l! w6 q2 t; B9 k) `8 I
  2. { - C9 [+ n0 C3 l' ^0 O+ _
  3. 7 z4 _4 u2 k: O
  4. /*  检测参数是否有效 */
    9 V! K0 A; D# j1 Q( {
  5.   if(hdma2d == NULL)2 l2 Z6 p0 l! `: m- \& Y- [- Z+ p
  6.   {
    9 h0 w+ d8 U, U( }
  7.      return HAL_ERROR;: h& [4 v/ V4 j6 Z9 f: o
  8.   }
    ! V% \9 V, m0 |2 J2 M5 X
  9. ( r* {" k& Q: A( ~; i! i" c' K+ \' k
  10.   /* 检测函数形参 */, M' w) h: }1 u3 X9 l; G" N
  11.   assert_param(IS_DMA2D_ALL_INSTANCE(hdma2d->Instance));
    % w7 u# D# N& a
  12.   assert_param(IS_DMA2D_MODE(hdma2d->Init.Mode));* v4 P* a6 T: N( ~5 w& `
  13.   assert_param(IS_DMA2D_CMODE(hdma2d->Init.ColorMode));. r' d3 t1 h# D; u: i
  14.   assert_param(IS_DMA2D_OFFSET(hdma2d->Init.OutputOffset));
    ; v, e3 R$ ?/ P+ K( A4 Y
  15. 9 ~; ]# C8 |* }4 H" Y' x6 d. ]
  16.   if(hdma2d->State == HAL_DMA2D_STATE_RESET)7 t% r$ V5 t; b% l- `
  17.   {+ U8 N# G0 C4 h1 S. X$ s
  18.     hdma2d->Lock = HAL_UNLOCKED;
    % R! U' v3 f7 [0 j6 D
  19.     /* 初始化GPIO,NVIC等 */
    ' ?8 `( X2 s2 u7 |9 }( Q
  20.     HAL_DMA2D_MspInit(hdma2d);
    ; V4 {- p. T6 |) l" c  E6 ?' S
  21.   }- p8 D! a6 `1 ], Z  {) T! m- _7 A

  22. ! w8 b+ k. b- v2 y1 k( x  K4 d
  23.   /* 设置DAM2D外设状态 */
    ! @' i* s/ i7 s1 t& h/ I+ |
  24.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  
    ( [2 r- O: ]# v* x
  25. : c. [' c& [1 i4 p# k8 ~0 @+ c, w
  26.   /* 设置DAM2D工作模式 -------------------------------------------*/
    % n4 K! Q' v. Z2 T+ E1 R* o  k
  27.   MODIFY_REG(hdma2d->Instance->CR, DMA2D_CR_MODE, hdma2d->Init.Mode);
      d7 n4 B' L9 b8 `5 z
  28. ! z9 N, L, W5 |5 i
  29.   /* 设置输出颜色格式 ---------------------------------------*/0 d0 A% p4 @. o' O' n
  30.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_CM, hdma2d->Init.ColorMode);
      x* h& X* S. f- G- r3 y
  31. , P. o* B* r: v: |& _
  32.   /* 设置输出偏移 ------------------------------------------*/  
    8 ?; C2 j5 n9 H0 o" w$ s: J
  33.   MODIFY_REG(hdma2d->Instance->OOR, DMA2D_OOR_LO, hdma2d->Init.OutputOffset);  
    5 @: V: V4 A9 j5 h
  34. ) g# b' q2 d5 v5 }$ V
  35.   /* 设置输出颜色格式中的Alpah值反转 */
      P, W) ^1 x  D
  36.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_AI, (hdma2d->Init.AlphaInverted << DMA2D_POSITION_OPFCCR_AI));$ k% h( j2 ^8 _0 A7 f, D

  37. . y* w2 q8 o/ `8 T
  38.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_RBS,(hdma2d->Init.RedBlueSwap << DMA2D_POSITION_OPFCCR_RBS));& V7 u5 F4 Q! e7 Q+ r

  39. 7 ^  b) i- \" S; Z9 k6 ^8 K8 D

  40. - W" n7 o  R5 ]. i( |7 C
  41.   /* 无错误 */
    4 b/ g& r0 B9 G& V& X3 ?! M$ X
  42.   hdma2d->ErrorCode = HAL_DMA2D_ERROR_NONE;
      t3 s, `  G6 }3 r" Q  [4 _

  43. 1 l. a- c: v$ j
  44.   /* DAM2D就绪 */& \% r; H' j0 I0 ~1 q
  45.   hdma2d->State  = HAL_DMA2D_STATE_READY;
    - u$ ~: h% F. }; \
  46. ) j: n, f- P9 m; F
  47.   return HAL_OK;+ f! o& q1 Q' E( c
  48. }
复制代码

' M$ j9 F% f- ~8 @3 ]函数描述:
& X# K; A% P) Z( W  u! B
& g, Y3 D. J$ `6 c3 F此函数用于初始化DMA2D的工作模式和输出颜色格式。' a, K, D0 f6 A7 L, X0 S: O! P$ _$ |

: }" Q& O6 s" J7 ^! Z/ ~7 y: |* \函数参数:# x' b  [5 X6 W! D, P
0 J3 K9 o0 L: W/ i
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。. W2 s! t% R) u- k! n" u
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。) S6 L* R! {$ @) s* h& U# s6 e
注意事项:
% ], z+ c. I4 x  y6 x1 ?) R" H; w6 J7 |4 I- }
函数HAL_DMA2D_MspInit用于初始化DMA2D的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。$ A; a" m9 x- w, s  k7 A( i& {3 J8 K: {
如果形参hdma2d的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量DMA2D_HandleTypeDef Dma2dHandle。
& X: k0 A7 `# b' Z/ z9 \/ r) [8 b! {对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_DMA2D_STATE_RESET  = 0x00U。
. k7 C( [8 O$ {+ ]% D3 j3 x: w( B9 V8 Z
解决办法有三
$ e4 H' |: Z0 I
2 Z4 T4 O2 h# }' s5 H% |方法1:用户自己初始DMA2D底层。# V+ c3 `0 N1 c: _5 G: Y& v

# ?7 d  v/ l; r( ]$ U方法2:定义DMA2D_HandleTypeDef LtdcHandle为全局变量。
4 w# g# ]: ^2 x9 q
4 D  o4 o  c& d1 H& ]方法3:下面的方法
  1. if(HAL_DMA2D_DeInit(&Dma2dHandle) != HAL_OK)
    $ k2 K5 q3 e7 B6 q; R: I+ ?
  2. {
    . z  d: u+ j) c
  3.     Error_Handler();
    0 O& b% `4 s, t; E+ Q, g; b
  4. }  
    : R$ o+ G  ~9 u% N! \2 V
  5. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
    2 c* W) S9 H% B. E
  6. {
    9 |3 M' j5 z' x& f2 a
  7.     Error_Handler();: w: s( q0 k" H2 V# j5 J
  8. }
复制代码

7 n- T3 i) w  E2 P! u1 \! [' I6 ]! u, P* C
使用举例:
- F& N% N+ B. m; o0 t0 c" _
0 T7 `& u( X4 a, R9 A3 o' \- M
  1. DMA2D_HandleTypeDef Dma2dHandle;1 v: I& P1 h7 v( V! P3 j- K6 G% q

  2. & Q$ _7 e- O8 z  B6 z) H# N
  3. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/
    8 A# f: @3 _7 L; M6 m  p2 g4 U8 Z
  4. Dma2dHandle.Instance = DMA2D;
    : @; L+ a7 M7 K+ J
  5. 9 u' }/ D# Z0 `+ |, W
  6. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */
    9 i  l. Y; I  T5 @
  7. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */* u7 S- z) a' r. X8 k2 S+ p* n' Q) a
  8. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */
    . u  S9 C: F! u+ [4 l9 g% g) b3 [
  9. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */: y1 z! h% R# Q) z+ K7 p
  10. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */1 q# V3 q. C" v# ?) e7 s2 @
  11. 9 H( x+ |; T6 U$ O& Q# n, f
  12. /*##-2- DMA2D 回调函数配置 ######################################*/
    5 x) h+ n* d7 x/ L* ~
  13. Dma2dHandle.XferCpltCallback  = TransferComplete;
    2 k) [4 m4 Z2 d5 Q" @
  14. Dma2dHandle.XferErrorCallback = TransferError;9 I2 K1 Q6 {5 I( C$ S; @) K
  15. 9 \3 R3 S; S6 R) ?3 o& T
  16. /*##-3- 前景层配置 ###########################################*/0 V# |5 y9 Y8 Y4 M
  17. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */
    0 {. L$ f& d2 x! _& @0 E+ g  p
  18. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */
    ' _9 a, Q, {$ V% o
  19. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */! X+ M- O$ E. E' ]( |
  20. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */
    , l" f* p7 D1 f
  21. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/
    8 S3 h! P: \, s& q: Z
  22. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/
    , [1 A+ L1 l& \0 [
  23. 9 [! L5 E4 g  X- T3 A3 m
  24. 7 m+ O4 S- B+ D2 M8 X( v. r" L
  25. /*##-4- DMA2D 初始化 ###############################################*/
    / T& O! S7 S: b% E
  26. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)' T  c6 F, f1 C# r, q
  27. {
    7 A& o3 S6 d5 c# ?+ S
  28.     Error_Handler();' D3 J6 D, U. Q; D, Z, _4 i9 D
  29. }
复制代码
. X" n! \3 j* ?7 U" a0 F5 ^
55.4.2 函数HAL_DMA2D_ConfigLayer% E. S8 a: F/ i# x
函数原型:6 o; V0 [& O5 k* D, i
) m% ]' @: S% x. a8 A) V2 T. c8 B- Q
  1. HAL_StatusTypeDef HAL_DMA2D_ConfigLayer(DMA2D_HandleTypeDef *hdma2d, uint32_t LayerIdx)
    5 ^- V6 b# J( n2 \+ v
  2. { ; O5 }+ ?+ p- q5 E* _* `
  3.   DMA2D_LayerCfgTypeDef *pLayerCfg = &hdma2d->LayerCfg[LayerIdx];: Y! n$ W7 w7 i

  4. : n% @2 R" x8 d2 d7 j( j
  5.   uint32_t regMask = 0, regValue = 0;
    6 t5 Z5 N2 h) l* N+ {# r/ }5 I7 B  V
  6. ! @: w  ~1 B5 q8 U- H7 T
  7.   /* 检查参数 */, w- n$ l" ~7 G% B8 E/ ^( H% `
  8.   assert_param(IS_DMA2D_LAYER(LayerIdx));  8 E6 |7 b7 M; C% d0 j& _# X
  9.   assert_param(IS_DMA2D_OFFSET(pLayerCfg->InputOffset));  
    ' `/ j2 i4 j. Y; H, S! N" j
  10.   if(hdma2d->Init.Mode != DMA2D_R2M)0 i. n: W! @. b" _  {5 @
  11.   {  7 N# h6 [$ F3 u, z$ f
  12.     assert_param(IS_DMA2D_INPUT_COLOR_MODE(pLayerCfg->InputColorMode));
    / u* E- y  z7 Y6 `
  13.     if(hdma2d->Init.Mode != DMA2D_M2M)
    3 Z0 @9 i* m' F
  14.     {6 u6 ?6 F9 `+ `: d1 f. ]
  15.       assert_param(IS_DMA2D_ALPHA_MODE(pLayerCfg->AlphaMode));7 U' [: c* u8 x4 z( L
  16.     }
    + R& a: w% s3 H5 u6 A
  17.   }
    / v3 G* i' r+ a, m: P3 ?9 x

  18. # U+ T& I3 ?2 _0 A% w& a7 U. E
  19.   /* 上锁 */
    ) t7 w# F, K& D& f, _# \% E
  20.   __HAL_LOCK(hdma2d);0 _4 V) d, |; p* }! x& E* y
  21. 7 l/ F$ J* V6 M5 o$ J+ a  @/ ^9 M
  22.   /* 设置DMA2D外设状态 */5 l7 a2 \5 {( k( G3 |
  23.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  
      ]4 D7 R* |7 v9 |

  24. 0 b) i1 l4 G- p) I  c) R
  25.   /* 准备好背景层或者前景层FPC寄存器配置参数*/6 \, O$ @* p+ l+ R0 L' W+ e: M0 e% ]
  26.   regValue = pLayerCfg->InputColorMode | (pLayerCfg->AlphaMode << DMA2D_POSITION_BGPFCCR_AM) | \. `. ~/ A- E* h7 k" S  H* f
  27.             (pLayerCfg->AlphaInverted << DMA2D_POSITION_BGPFCCR_AI) | \- D( U) U6 _" Y7 E- D3 ~4 ^+ O
  28.             (pLayerCfg->RedBlueSwap << DMA2D_POSITION_BGPFCCR_RBS);
    ! J/ e3 P, f$ ~: A
  29. ' T" D% C6 s5 g3 T- P
  30.   regMask  = DMA2D_BGPFCCR_CM | DMA2D_BGPFCCR_AM | DMA2D_BGPFCCR_ALPHA | DMA2D_BGPFCCR_AI | DMA2D_BGPFCCR_RBS;7 @, I. O" i% Q* V
  31.   }/ `( I3 I, i6 I. R* h  K
  32.   if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    + {- j  U6 D  [
  33.   {
    ! s. }( S; p' p# T7 A
  34.     regValue |= (pLayerCfg->InputAlpha & DMA2D_BGPFCCR_ALPHA);
      s- U; [& b3 m4 A
  35.   }: k5 D1 Y! E1 w/ ?1 P
  36.   else* D* E: ~+ A, F6 U
  37.   {/ v6 E, k' Q1 ]8 o/ U
  38.     regValue |=  (pLayerCfg->InputAlpha << DMA2D_POSITION_BGPFCCR_ALPHA);
    " ~7 A3 R) v# g& U* R5 r
  39.   }2 d2 Y  i% v" B1 y
  40. , R/ d4 @: i9 t; f2 ~
  41.   /* 配置背景层 */
    % S% Y# I6 X' s! {
  42.   if(LayerIdx == 0)" }1 \% x. a2 m: n) j# i
  43.   {
    " m8 \- }5 ]2 C/ Q# L; H/ B2 R) p
  44.     /* DMA2D BGPFCCR 寄存器 */( m, l9 }( u. L" u7 q9 t( _
  45.     MODIFY_REG(hdma2d->Instance->BGPFCCR, regMask, regValue);) ?! z; w, F! U) K, t" j2 u( L: k

  46. , }: }# T; M) \& \* m3 }
  47.     /* DMA2D BGOR 寄存器 */  / b% x6 c/ ~% s3 h8 E
  48.     WRITE_REG(hdma2d->Instance->BGOR, pLayerCfg->InputOffset);
    8 A/ Q$ I" L% i0 x/ V; n
  49. 3 Z( s( Z, n5 s2 X
  50.     /* DMA2D BGCOLR 寄存器 */ & S6 x! H) G1 q7 f7 `
  51.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))0 ?4 J) U$ }1 r& E; d
  52.     {    9 j0 j) e" ]6 i: M0 N6 t0 N. X
  53.       WRITE_REG(hdma2d->Instance->BGCOLR, pLayerCfg->InputAlpha & & `* q- V, B. M% L- d/ ?
  54. (DMA2D_BGCOLR_BLUE|DMA2D_BGCOLR_GREEN|DMA2D_BGCOLR_RED));
      j1 J2 u- {4 \
  55.     }   
    2 z6 x! o2 U/ \
  56.   }  v$ A  A. T% z
  57.   /* 配置前景层 */
    # ?" C; A$ j; H+ f
  58.   else6 j: c$ {* y0 c
  59.   {
    1 V7 B: a% h2 r: _1 R
  60.     if(pLayerCfg->InputColorMode == DMA2D_INPUT_YCBCR)
    4 a. B- c* `4 E8 Z9 W8 H
  61.     {, b- n3 B3 J. U" ]7 w" C7 r) l
  62.       regValue |= (pLayerCfg->ChromaSubSampling << DMA2D_POSITION_FGPFCCR_CSS);
    ( c/ t" u. B" C0 M2 G( G3 f0 h
  63.       regMask  |= DMA2D_FGPFCCR_CSS;' b6 ]8 p7 p8 N* u3 ^. V( L4 ^
  64.     }, Z) s/ `$ V2 g) i; ~
  65. - h2 D+ p6 w8 W; X) Z& Q
  66.      /* DMA2D FGPFCCR 寄存器 *// [, K; M/ N  d6 D
  67.     MODIFY_REG(hdma2d->Instance->FGPFCCR, regMask, regValue);  q* g8 H& \) ?6 d/ n
  68. ; s) ^% w2 o! x$ u
  69.     /* DMA2D FGOR 寄存器 */8 V  Y% Q: b4 Q5 `; P
  70.     WRITE_REG(hdma2d->Instance->FGOR, pLayerCfg->InputOffset);      
    2 [0 K" T: \9 d- w, {/ R  o7 b$ v
  71. ) ~  Z9 D/ v: G4 X- [
  72.     /* DMA2D FGCOLR 寄存器 */     F9 u- z' ^1 t# r* a5 Y
  73.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    7 n" n8 R0 E% P
  74.     {6 Z0 `- t5 q6 D
  75.       WRITE_REG(hdma2d->Instance->FGCOLR, pLayerCfg->InputAlpha &
    6 f( o5 [+ K. F# j& l
  76. (DMA2D_FGCOLR_BLUE|DMA2D_FGCOLR_GREEN|DMA2D_FGCOLR_RED));      & ^6 M2 f; q' a# A9 t9 b5 f( f6 p
  77.     }   
    $ v8 |  L8 p2 s! d
  78.   }   
    ; q8 T/ O( ]# [& l
  79.   /* DMA2D就绪 */
    ; ~; p& t- M; ~* T
  80.   hdma2d->State = HAL_DMA2D_STATE_READY;& y5 [  P! Q; U
  81. ) y* s6 Z4 T) b2 ?* q2 m0 v
  82.   /* 解锁 */
    ! F$ P, i, K1 @6 P. w1 [( c9 U# N
  83.   __HAL_UNLOCK(hdma2d);  9 p) k* P( T: u; n. x& U: r  |9 [
  84. 8 t6 Z: }! A3 a' H1 c; N
  85.   return HAL_OK;8 C; u, [  b9 R( _6 k. m" c
  86. }
复制代码
# K: @6 o2 r: `/ l9 k+ b- D
函数描述:; ]  c) p' ]" h0 h

, h# O/ a$ F1 y6 b. o此函数主要用于配置DMA2D要转换的前景层和背景层,即输入颜色配置。而前面的函数HAL_DMA2D_Init配置的输出颜色。( _4 P. a  ]3 s" u/ {+ A, \
4 i, F$ q+ h$ N
函数参数:+ K  b. l; P9 H" @9 }  Z

0 o# i5 s7 Y2 E; a& N4 e8 ?  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。& d6 c* j$ ~: w% H9 U9 a$ F1 E
  第2个参数用于配置前景层和背景层,0表示背景层,1表示前景层。
' W8 u0 y  \7 @' b  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
6 a% r' y) d; X4 {1 ?, R3 j  n/ \使用举例:
6 c2 w2 ]8 R6 K+ o! x
  1. % i; a9 e7 a! ^& \' M
  2. DMA2D_HandleTypeDef Dma2dHandle;. k/ ^8 R  T. ^5 s- O
  3. 6 m" }8 D! j, u% W2 }

  4. 7 L' u. M! J% C, x% J5 K
  5. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/
    3 r& T4 j% S  K5 l& l. ]3 o
  6. Dma2dHandle.Instance = DMA2D;
    + v7 h- _: k: O6 f
  7. 4 _; T, i- i4 ^' g
  8. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 *// \& u3 Y6 R* q; a5 @
  9. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */& h: M, ^% F, [% Y7 S' H) l% @0 K& u; v" _
  10. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */+ {2 X: P% A* k1 V: R/ u
  11. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */3 n: D# }" [5 w& r' f/ _3 b
  12. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */+ w$ f  ^6 |% [9 r7 |9 `' h) i( Z
  13. $ j5 {1 [  e  B! j; {; I# j8 ?
  14. /*##-2- DMA2D 回调函数配置 ######################################*/" |! X* s# C9 G  u" q
  15. Dma2dHandle.XferCpltCallback  = TransferComplete;% q# R, w5 C4 f: ?# M, I
  16. Dma2dHandle.XferErrorCallback = TransferError;
    * ?0 w! n, T9 Q; s: |; `  |2 O
  17. ( m4 p! z8 |% {8 b# }
  18. /*##-3- 前景层配置 ###########################################*/' |- b! {, k9 e: u. X
  19. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */
    7 z, i& \  j# ]* C, @; f- \
  20. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */% P  R) A' l6 H8 c
  21. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */
    4 g3 `2 a2 v1 ?# P3 X/ a" l% ]+ z
  22. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */, C$ t1 _# d; j( m: R
  23. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/
    ) W8 N: J! F: @/ `3 e/ X+ j
  24. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/
    $ B$ W7 R  I* N
  25. & C  r  |3 g6 l2 Y2 a4 S2 I
  26. /*##-4- DMA2D 初始化 ###############################################*/
    , ~2 U3 E- E/ _9 k# |
  27. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
    2 p! z  x( D8 d; \. c3 t  ~
  28. {5 x6 T/ J1 U; A+ t: w( u9 Q
  29.     Error_Handler();, I. |6 p* k" S& T; R8 a
  30. }
    3 F/ U# i  ~1 Q( y% h
  31. * I! n2 _; @# u- n
  32. /* 配置前景层  */" {* |2 E( p" A9 H& M1 u) v6 s2 f
  33. if(HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1) != HAL_OK)
      h! X' O: z, b( V9 E2 f, I
  34. {
    ( f0 _  k- w; Y) J$ b" v. _6 \
  35.    Error_Handler();
    $ e# H  Y# W6 ^4 N/ g1 C
  36. }
复制代码
1 k* |% R9 [4 v

$ F" ^& F4 `  ^/ R: d% h55.4.3 函数HAL_DMA2D_Start_IT  Q; \6 Q& {* G& q: {
函数原型:
0 J" m$ p4 V! }7 z! x" @
; G. l  ^" x' B+ {
  1. HAL_StatusTypeDef HAL_DMA2D_Start_IT(DMA2D_HandleTypeDef *hdma2d, uint32_t pdata, uint32_t DstAddress, uint32_t Width,  uint32_t Height)" W4 F6 H& b+ I
  2. {$ A, ]8 {5 e' S: w2 S
  3.   /* 检测函数形参 */: i7 X! k( u2 C$ W& y
  4.   assert_param(IS_DMA2D_LINE(Height));
    - p2 }& r$ l$ ]7 R. G
  5.   assert_param(IS_DMA2D_PIXEL(Width));- \* ]" T% I. c
  6. # L3 z) c1 [* l, W2 U
  7.   /* 上锁 */1 k$ W1 Q) e. l! [6 N. ?
  8.   __HAL_LOCK(hdma2d);& h7 c/ ^% X: H8 Q8 ?" o7 l4 p
  9. ( f. z/ Z. M4 n3 C! D
  10.   /* 设置DMA2D外设状态 */
    ( w% J; e( A4 V5 ?! E+ U
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;- K) e6 \- A) w
  12. 5 e- ]8 V' l, _1 u$ i
  13.   /* 设置源地址,目的地址和数据大小 */" Z& n) ^5 K( M9 Z
  14.   DMA2D_SetConfig(hdma2d, pdata, DstAddress, Width, Height);* S% c9 S- d& A( f

  15. ' J6 s9 W6 q' O
  16.   /* 使能DMA2D的传输完成中断,传输错误中断和配置错误中断 */
    . K7 b: Z  f& k5 @0 D& M
  17.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);8 z1 J/ c; a+ ?7 Z8 E
  18. . x# K0 Z: C& U- I! O% S
  19.   /* 使能DMA2D */
    ) z: U+ m5 `/ O; U% s2 }
  20.   __HAL_DMA2D_ENABLE(hdma2d);+ K$ r" Q' s* h5 o2 W
  21. 3 X$ f; A+ Z) O; ?/ t5 ?$ k- c
  22.   return HAL_OK;
    ) H+ P: A0 |5 m$ ~, u
  23. }
复制代码

, h! ]% v2 M; g6 u  G0 q3 `1 p函数描述:
1 S# B6 y, n4 D( G0 V+ J) l- v9 L. q- H6 K- r0 ^5 L$ `. r6 K
此函数用于启动DMA2D数据传输。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。
( Q% x' v$ x4 k) A8 o
- R. P* |  e8 c, {3 r函数参数:! Z# i' {; {& N" A, s  f* v
2 R* X" G5 }8 ^! N4 ?- Q% t
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。
# Y* W, M7 n8 E3 P" G1 k  第2个参数是源数据地址。
6 d3 S9 r0 X7 _, K6 P3 K; x3 V, X  第3个参数是目的数据地址。
, e7 r/ d5 }3 O  L& u  第4个参数是源数据的长度,即每行的像素个数。2 @( G* `! E, s2 V) g. K
  第5个参数是源数据的高度,即行数。
7 C' m# Q1 L9 t2 d6 d% f  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。9 r& C! T' M# J, }$ G
使用举例:
+ ^; }% b' C$ P0 w+ O& C1 p
) S) w0 [; i3 q3 S( d/ ]' `& v
  1. DMA2D_HandleTypeDef Dma2dHandle;/ P% b3 q  B" c

  2. 9 J* Z2 i* y; T! B$ b- r0 Y. L7 C
  3. if(HAL_DMA2D_Start_IT(&Dma2dHandle,            /* DMA2D句柄 */1 n( d8 \: `8 H! z& B8 X, |
  4.                       (uint32_t)&BufferInput,  /* 源地址 */
    : \5 t8 `/ d. ]3 _
  5.                       (uint32_t)&BufferResult, /* 目的地址 */3 ?" A+ q! W3 O- v! `4 v% I' e; N
  6.                       SIZE_X,                  /* 源数据长度,单位像素个数*/
    , z0 Q& R6 \9 J* d) ~
  7.                       SIZE_Y)                  /* 源数据行数 */$ y* x+ S- E* v- b7 u+ p1 L
  8.    != HAL_OK): I- C# T$ Q) X0 q* S& ^
  9. {
    , w0 y$ d. h/ [, }$ j! _
  10.    Error_Handler();5 z: k+ c' k  W$ v% K, @9 c6 }6 I
  11. }
复制代码

  z, L, H# z0 m$ h' Q55.4.4 函数HAL_DMA2D_BlendingStart_IT
, x/ c4 Y) b6 o; E& e0 X$ e函数原型:
1 v! v- e; R3 A0 M" d4 M* U6 ^3 K" s$ C7 U6 y6 ~
  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)" E, f& M- m: N  c5 P
  2. {) D. s- ^; H. r) i/ |
  3.   /* 检测参数 */! p/ z5 i7 f% j) S, U7 ^' _: a
  4.   assert_param(IS_DMA2D_LINE(Height));
    & w. Q0 @1 l; M* ]2 r3 o+ O3 H8 s6 ?
  5.   assert_param(IS_DMA2D_PIXEL(Width));7 Z& y; U/ p5 A* [! z7 Y2 ]: N; O, D
  6. 6 m1 }: t! X5 v/ n  A
  7.   /* 上锁 */: |6 _8 b4 M4 W+ I5 S6 m
  8.   __HAL_LOCK(hdma2d);3 b7 ~' b$ g; d2 G! L% D/ D! M; O$ e
  9. 8 ^  T7 q2 X' V3 _
  10.   /* 设置DMA2D外设状态 */+ f9 O0 r1 r3 c6 @
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;+ p( ]% ?5 |4 }! D; v" N* w% N- X
  12. - L) H$ [' U* R) x  H
  13.   /* 配置DMA2D源地址2 */
    ! b  i3 V! \" G3 ^9 y
  14.   WRITE_REG(hdma2d->Instance->BGMAR, SrcAddress2);  x; p) J$ Y& T
  15. 7 t! D& M2 f9 V' ]' Z0 X( E
  16.   /* 配置源地址1,目的地址和数据大小 */
    0 p6 ^, m: R7 N0 l( w" a
  17.   DMA2D_SetConfig(hdma2d, SrcAddress1, DstAddress, Width, Height);) a' i# u; F$ `
  18. ' k4 V9 {7 H- {+ v% Q4 y3 G2 N
  19.   /* 使能DMA2D传输完成中断,传输错误中断和配置错误中断 */2 z. X4 H5 l+ S  Q
  20.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);
      V4 K& P/ p$ `+ u' Z
  21. 6 H& W) v6 G2 ]- e/ A
  22.   /* 使能DMA2D */
    9 K3 x4 L8 w7 u, \7 Z
  23.   __HAL_DMA2D_ENABLE(hdma2d);, b& o6 O% u4 X% h# Q* ^1 v
  24. 0 _. m) N  |5 f7 N, o2 Y' H
  25.   return HAL_OK;6 a" i! _3 m3 ?; k/ x/ p' \- j
  26. }
复制代码
1 G& r/ v# U0 m0 e5 ?. v+ q
函数描述:$ }. f: w0 ]( r6 s" I
# w! n+ h9 N, w& z
此函数用于启动DMA2D传输,除了数据传输以外,还支持颜色格式转换和颜色混合。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。' N  O4 ^- f, p4 f: u

6 o5 _; a4 }: Y函数参数:
) u! T/ X" G" j3 V9 P4 z
5 f3 d9 j, b- `) P5 ~% S  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。! H$ T" A  V; k' R: g" W
  第2个参数是源数据地址1。9 ~! `' F$ J% Q
  第3个参数是源数据地址2。
, W" O( f4 ~9 c, Z, m  第4个参数是目的数据地址。
. `; Y, y& s( T: d7 N' Z  第5个参数是源数据的长度,即每行的像素个数。
2 h% c. q) f. f! K* X" S  第6个参数是源数据的高度,即行数。1 x: r  t. o  m/ u( R2 ]* H
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
" T! _: b0 T1 Y( k* J使用举例:
2 p; d1 q  m6 r, H! u6 Q+ j) s+ s( Z  n% Y" r3 ?  q" j
  1. DMA2D_HandleTypeDef Dma2dHandle;6 J# V8 V0 X& K

  2. / z, P. |/ G5 U: I  Z9 e
  3. if(HAL_DMA2D_BlendingStart_IT(&Dma2dHandle,           /* DMA2D句柄 */( \& f1 O  x5 T% {8 P- y
  4.                              (uint32_t)&BufferInput1, /* 源地址1,前景色 */ 2 b8 m+ O( e+ n4 V
  5.                              (uint32_t)&BufferInput2, /* 源地址2,背景色 */
    / I6 L& V! Z* u9 f0 m  {+ x; [
  6.                              (uint32_t)&BufferResult, /* 目的地址 */2 }# u; q  ]" F5 X! s
  7.                               SIZE_X,                 /* 源数据长度,单位像素个数*/
    5 V& d8 Y) ?/ ~+ Z" N6 U
  8.                               SIZE_Y)                 /* 源数据行数 */
    $ p% `1 [' V) x, r% s
  9.    != HAL_OK)6 E: D/ `/ v2 A  h- ^
  10. {
    1 I6 ?- l! E1 O- A5 y
  11.    Error_Handler();
    # T1 ?/ i, j% l. Q
  12. }
复制代码

" p9 n0 d7 k# ^  o8 e% C2 _# X. Q: ~' i6 e4 S& x( s7 s
55.5 总结( I, C1 w: ?7 a9 b# I4 @
本章节就为大家讲解这么多,DMA2D功能比较重要,一定要做到熟练使用。
; V: A4 z; f: r# L, c, L3 q8 o6 z5 i5 u' a
3 ~$ y6 Q7 i- t6 H
0 c3 T5 ~3 F; ^1 I9 u. p3 k- \+ W
赞 收藏 评论0 发布时间:2021-12-24 17:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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