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

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

[复制链接]
STMCU小助手 发布时间:2021-12-24 17:00
55.1 初学者重要提示
# [2 ?& _, F$ {, L8 i  DMA2D是专门用于LCD加速的,特别是刷单色屏,刷图片,刷Alpah(透明)混合效果全靠它,而且可以大大降低CPU利用率。
7 W% u/ N. R, _& b/ k; r  测评STM32H7的LTDC+DMA2D性能,100Hz以上无压力,刷800*480图片和色块仅需2.6ms一张
. Z$ S7 e# c4 x! X  H7的DMA2D与F429的DMA2D最大区别是支持了ARGB和ABGR互转,而且支持H7的硬解JEPG输出格式YCbCr转RGB,方便LCD显示。
* F2 t, B" s2 c+ s9 X0 Q  特别注意,大家只需对HAL库提供的DMA2D操作API有个了解即可,实际工程中,并不使用这些API,我们需要使用更加高效的寄存器直接操作,在下一章节会为大家说明。
- h& A- A2 M3 l5 t4 h55.2 DMA2D基础知识2 V4 W1 w) S( v6 t. P$ c& h. }
DMA2D主要实现了两个功能,一个是DMA数据传输功能,另一个是2D图形加速功能。
  C$ I' h! I- R5 _+ w' e% z: y8 F  Z4 m5 k1 U
  DMA数据传输
4 ~* t. w3 W8 ~, I. {6 M+ ~6 R主要是两种方式,一个是寄存器到存储器,另一个是存储器到存储器。通过DMA可以大大降低CPU的利用率。6 L- q0 s7 \5 t, C, h) H
8 R4 s& ~: h3 ^7 A- u+ V' h, g+ n
  2D图形加速功能# n3 x) @, {! m$ F8 w) p) W; o
支持硬件的颜色格式转换和Alpha混合效果。: _. U5 }# X) q, m) }! Y

2 `& E9 }' Z2 @8 C55.2.1 DMA2D硬件框图
: e' R% L0 Q' R  X, X认识一个外设,最好的方式就是看它的框图,方便我们快速地了解DMA2D的基本功能,然后再看手册了解细节。框图如下所示:
" C) ~6 q+ r1 z& o! G) f" \2 b* r' x' X6 Y9 L
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

% s$ m5 n) W: U+ b
- R5 F. a! l% _' }  i+ R; J( J通过这个框图,我们可以得到如下信息:4 r+ S0 w% g% d- J7 \4 K
4 C& {8 |. F: i3 S1 g
  dma2d_aclk
% ^' G1 M, i' y) w8 ^$ QAXI 总线时钟输入。
, J0 {# K5 i/ v5 }1 `8 K) I3 X9 g8 V2 u: j  ]/ E9 s
  dma2d_gbl_it& g9 \" \1 c7 }& X$ f0 d8 `
DMA2D全局中断输出。
9 y, k, t, P" y" g* W5 ~1 c( g' W! m3 @/ g7 }
  dma2d_clut_trg
4 P! [/ n% W+ Q; J6 ~6 Y2 h  eCLUT传输完成信号输出,可以触发MDMA。
: `" n8 X! j) r
6 a0 ^( n% g( z$ d+ l  dma2d_tc_trg
) N9 V' _; `* h& z; R传输完成信号输出,可以触发MDMA。+ Z* ^2 K# ^6 B5 ]! g4 d- f
4 x! E* c0 z" ]; a$ X1 q% v
  dma2d_tw_trg / q8 N( p1 B4 b: w8 ?! V
传输watermark信号输出,可以触发MDMA。' H/ C$ }: T9 ~7 M. K' K: ^9 }% o

$ m8 B4 Z1 e7 D% G  r将这个硬件框图简化一下,就是下面这样:; S& O2 S6 [0 X4 S5 @& z: X

* d' h" _5 z7 v* z, w
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
% C) G/ |$ A0 Z, s( B  s+ o
2 G0 r  \- Q* O" Q
下面按照简化的硬件框图,对每个部分做个说明。$ J: O$ |; c4 G' x' S
8 Q8 D) [$ `7 Y; ^. Y4 x0 y+ t9 F
55.2.2 DMA2D工作模式. k9 j" m9 H# C2 t  |# L- G% P+ @5 Q
DMA2D支持的工作模式如下:
. N+ i- s. I2 @8 d. q6 [+ h5 F  A# U+ V: R! G1 R) L" p5 _
  模式1:寄存器到存储器模式
% \3 W4 C4 J1 g4 I& X这个模式主要用于清屏,也即是将显示屏清为单色效果。
5 ~$ L; q% |1 j* u3 _2 F6 ~" y& m# u& Z. o" c; I
  模式2:存储器到存储器模式
9 ?% A$ \4 q, Y/ M' x- ?这个模式用于从一个存储器复制一块数据到另一个存储器,比如将摄像头OV7670的输出图像复制到LCD显存就可以采用这种方式。
# x/ f; f3 K: B' |  I
3 E. x1 }, g7 {  z% u1 [/ a: U  模式3:存储器到存储器模式,带颜色格式转换
) V* D: u9 F. z这个模式比模式2多了一个颜色格式转换,比如我们要显示一幅RGB888颜色格式的位图到RGB565颜色格式的显示屏,就需要用到这个模式,只需输入端配置为RGB888,输出端配置RGB565即可。位图颜色格式转换后会显示到显示屏上。
. h3 V2 K; |9 I# W$ U6 {# ]
& Y5 K, s9 n9 ]  模式4:存储器到存储器模式,带颜色格式转换和混合% m: z' U! v' J; ~) c( \
这个模式比模式3多了一个混合操作,通过混合,可以将两种效果进行混合显示。
  F/ Y  |. {$ G6 m# e- K4 d6 d( j4 d4 {5 V+ f* l7 k  B
  模式5:存储器到存储器模式,带颜色格式转换和混合,前景色是固定的
0 W. s) l: R. o同模式4,只是前景色的颜色值是固定的。' }! U& {$ i: z$ B( P+ _; U4 Q
3 R  o7 }9 i0 z' m- X1 J* f( v
55.2.3 前景层和背景层的输入以及颜色格式转换9 |0 g& \: O+ z: \/ {
前景层和背景层是指的用户绘制图形时的前景色和背景色,比如我们显示汉字,字体会有一个颜色,也就是前景色,还有一个背景色。又比如我们绘制两幅图片,想将两幅图片混合,那就可以将一幅图片作为前景层,另一个幅图片作为背景层。- {9 t" G+ B: I* O8 t
0 \, T/ ^/ W9 y9 Q
DMA2D支持的输入颜色格式如下,前景层和背景层一样:% s' a8 V+ z/ ~" Y

% _/ `9 V& z: [
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
7 G- @0 v  \; w) [* E$ R1 R+ J# p( L
0 [  x3 ^8 E' f3 r/ F0 D8 J4 e
前8种颜色格式在第50章的第2小节开头有介绍,这里把后四种做个说明:
* N9 e. S# W" z' a) r: ~. }* l" S' Q* w  H% q
  L4 (4-bit luminance or CLUT)$ X: [1 j0 k1 @: V2 j
4位颜色格式,实际上仅仅是4位索引值,范围0–15,而每个索引值的具体颜色值在查色表CLUT里面存储。# K% ]% ^! v$ o* C' A
& ^& p) Q0 z" K7 K% y9 w$ g
  A4和A88 |' g  o0 w, x8 f- B% c
A4和A8用于特定的Alpha模式,既不存储颜色信息,也没有索引值。
! m* ~; S0 n8 J( K; D% U+ L* \, q; j1 u! o# l9 d% M0 a4 `
  YCbCr+ I1 s" Y& ]+ z2 m4 V2 C
这个是H7的硬件JPEG输出的颜色格式,后面JPEG章节为大家专门做讲解。
; Y; a$ V: _4 ]% J- ~
9 z& N" t4 y; X; h2 K  {! [这里特别注意一点,输入颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。
: V/ n. p  ?* q* ]2 ]* l
# p" h" _6 f6 R7 }0 D0 j0 {55.2.4 前景层和背景层混合5 D% ]9 [4 N7 T0 s: R# L4 M
DMA2D混合器用于混合前景色和背景色,这个功能不需要任何配置,仅需要通过DMA2D_CR寄存器使能即可。混合公式如下:9 f7 ^  V! J0 v; ]+ F% p
/ ^( a* I6 ^5 q, [2 q. ?/ n
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

9 q5 I1 K$ A2 u( V  \0 H; ^+ I: g& O3 i2 F  G
55.2.5 DMA2D输出颜色格式3 S, w0 i, b2 c# j. p4 a6 o
DMA2D支持的输出颜色格式如下:
  t2 W) e+ G4 J+ I) T
- K5 P. K" ~0 V$ {
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

. r( x" B: |5 x0 S3 z* s; q# O& Z1 I( R
这里特别注意一点,输出颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。  \: d7 a; u& g
) p0 i+ w& c% j, @
55.3 DMA2D的HAL库用法/ Q! q5 s6 i5 X" \
DMA2D的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断。下面我们逐一展开为大家做个说明。/ p( f, E2 Y$ O+ P/ `1 P! A
1 y; q8 {8 Z! q* d% W0 b& \
55.3.1 DMA2D寄存器结构体DMA2D_TypeDef
7 i% [3 w# ^& I) y9 D# c( GDMA2D相关的寄存器是通过HAL库中的结构体DMA2D_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:3 T* D% k( L, {* j' D" y) C

# k$ X$ S, \3 U* U
  1. typedef struct
    - ~0 D3 Z7 J; P7 m/ ^; R5 m
  2. {
    9 ~7 x8 g: m. X" ]
  3.   __IO uint32_t CR;            /*!< DMA2D Control Register,                         Address offset: 0x00 */
    3 }5 v8 z) y6 j+ Q* z4 d
  4.   __IO uint32_t ISR;           /*!< DMA2D Interrupt Status Register,                Address offset: 0x04 */
    7 T) @7 D0 Q1 D8 Z3 _( I! Y
  5.   __IO uint32_t IFCR;          /*!< DMA2D Interrupt Flag Clear Register,            Address offset: 0x08 */
    " W) q* x$ R, _; d. [
  6.   __IO uint32_t FGMAR;         /*!< DMA2D Foreground Memory Address Register,       Address offset: 0x0C */
    , t4 Z1 Y+ X9 U. S4 p5 A4 k
  7.   __IO uint32_t FGOR;          /*!< DMA2D Foreground Offset Register,               Address offset: 0x10 */
    . }5 o; {% B% U+ x8 n
  8.   __IO uint32_t BGMAR;         /*!< DMA2D Background Memory Address Register,       Address offset: 0x14 */6 o* \+ h, u5 z# r9 R6 P; Q+ R
  9.   __IO uint32_t BGOR;          /*!< DMA2D Background Offset Register,               Address offset: 0x18 */+ K; @  t' M% b2 u' \2 K
  10.   __IO uint32_t FGPFCCR;       /*!< DMA2D Foreground PFC Control Register,          Address offset: 0x1C */
    - t6 e0 x4 F) K1 S' @
  11.   __IO uint32_t FGCOLR;        /*!< DMA2D Foreground Color Register,                Address offset: 0x20 */
    & e- I& a% h; v; s, g. |
  12.   __IO uint32_t BGPFCCR;       /*!< DMA2D Background PFC Control Register,          Address offset: 0x24 */
    $ g  u( E) ~2 ^$ b
  13.   __IO uint32_t BGCOLR;        /*!< DMA2D Background Color Register,                Address offset: 0x28 */
    0 c6 U1 W( r* N' q
  14.   __IO uint32_t FGCMAR;        /*!< DMA2D Foreground CLUT Memory Address Register,  Address offset: 0x2C *// |/ o6 ]2 d8 a$ Z
  15.   __IO uint32_t BGCMAR;        /*!< DMA2D Background CLUT Memory Address Register,  Address offset: 0x30 */
    ' {8 u% m2 N5 P# _2 E
  16.   __IO uint32_t OPFCCR;        /*!< DMA2D Output PFC Control Register,              Address offset: 0x34 */
    ) C% `  ^- f( q3 N5 w4 s2 p
  17.   __IO uint32_t OCOLR;         /*!< DMA2D Output Color Register,                    Address offset: 0x38 */+ T/ O3 B9 j  S6 x) w& t8 R
  18.   __IO uint32_t OMAR;          /*!< DMA2D Output Memory Address Register,           Address offset: 0x3C */% g) X1 M1 o- w1 @4 D# O- h! Z( c
  19.   __IO uint32_t OOR;           /*!< DMA2D Output Offset Register,                   Address offset: 0x40 */4 `% V; Y4 ~0 e' `
  20.   __IO uint32_t NLR;           /*!< DMA2D Number of Line Register,                  Address offset: 0x44 */' ~2 K+ L. e4 V0 u6 u' \! |
  21.   __IO uint32_t LWR;           /*!< DMA2D Line Watermark Register,                  Address offset: 0x48 */8 q% K: b. Q3 N) P" z
  22.   __IO uint32_t AMTCR;         /*!< DMA2D AHB Master Timer Configuration Register,  Address offset: 0x4C */
    / f& x! M5 q1 P
  23.   uint32_t      RESERVED[236]; /*!< Reserved, 0x50-0x3FF */
    # C, ~# c, X1 {* o( X, A* O
  24.   __IO uint32_t FGCLUT[256];   /*!< DMA2D Foreground CLUT,                          Address offset:400-7FF */
    6 X& P+ L6 u9 Q0 E) E9 k6 P
  25.   __IO uint32_t BGCLUT[256];   /*!< DMA2D Background CLUT,                          Address offset:800-BFF */
    2 f# C0 @' d1 I
  26. } DMA2D_TypeDef;
复制代码
6 R+ m9 U9 d4 H, K8 D

: }9 ]4 _5 U9 u3 B9 u$ j  V8 x__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
$ [4 n2 b; f  m. j3 X  ^0 U
7 i( l/ @% Q# x( h9 }; @8 r
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */& b6 ?( e$ q, I' A' t8 M" M6 N
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

( V$ U2 G; a4 ^% x下面我们再看DMA2D的定义,在stm32h743xx.h文件。
  1. #define PERIPH_BASE              ((uint32_t)0x40000000)
    & v: O/ {2 R/ [8 E( j
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000), w- ~! B3 _% u
  3. #define DMA2D_BASE               (D1_AHB1PERIPH_BASE + 0x1000)
    - E) ?7 a: @' Y4 t
  4. #define DMA2D                    ((DMA2D_TypeDef *) DMA2D_BASE) <----- 展开这个宏,(DMA2D_TypeDef *) 0x52001000
复制代码

5 z9 n8 \' |/ O我们访问DMA2D的ISR寄存器可以采用这种形式:DMA2D->ISR = 0。
6 d% {  W# {/ |" h9 I3 `8 ?
# e/ G+ O9 o1 S! C! o( q2 B' z55.3.2 DMA2D参数初始化结构体DMA2D_InitTypeDef, p8 H5 d+ `/ |& ~9 ?
此结构体用于配置DMA2D的基本参数,具体定义如下:/ K& u. y9 u9 L

( f9 h6 B$ n  p% N( H
  1. typedef struct
    * c' l! A; L9 Y$ X
  2. {9 j  J( E- G5 U
  3.   uint32_t             Mode;              * g5 D: c. w% H: J0 a: r9 R# R
  4.   uint32_t             ColorMode;        " @; |+ I6 r" `; f. s8 k
  5.   uint32_t             OutputOffset;      
    , e# B, q* V/ S* m) L' U
  6.   uint32_t             AlphaInverted;   
    3 q6 k7 U% I0 V! s  r5 _: y0 ^
  7.   uint32_t             RedBlueSwap;       % z( l( X8 g( \) {3 |' j
  8. } DMA2D_InitTypeDef;
复制代码

$ i3 E! S; t2 N( m8 Z. |8 D下面将这几个参数逐一为大家做个说明:& B0 I8 F8 i+ F" ^, C% r
! b! E1 I) v+ v& `
  uint32_t   Mode
  j. f/ g( A; ]9 o( _此参数用于设置DMA2D的传输模式,具体支持的参数如下:; A0 z! s9 W2 F8 ^0 ?, h( i3 w2 M
0 K4 `6 q, ~- m" W/ k! C$ _' F
  1. #define DMA2D_M2M        ((uint32_t)0x00000000U)  /*存储器到存储传输模式 */7 X: n" b6 ^9 g0 `
  2. #define DMA2D_M2M_PFC     DMA2D_CR_MODE_0         /*存储器到存储器传输模式,并执行FPC像素格式转 */
    & e1 E- J! y, T- _. |' o$ A
  3. #define DMA2D_M2M_BLEND   DMA2D_CR_MODE_1         /* 存储器到存储器模式,并执行像素格式转换和混合 */1 m* w1 P+ \* e8 z4 `; w+ U
  4. #define DMA2D_R2M         DMA2D_CR_MODE           /* 寄存器到存储器传输模式 */7 {* y7 K" s7 y
复制代码

8 C9 f, @% K+ B1 U: `1 }8 K# x. B
2 k6 D  r2 @! g- \& I& D  uint32_t   ColorMode
8 f! N3 Z( f1 c此参数用于设置DMA2D的输出颜色格式,具体支持的参数如下:; ~. D  p' \) E" ^2 X

  }2 F3 v9 F' M" X! }
  1. #define DMA2D_OUTPUT_ARGB8888       ((uint32_t)0x00000000U)               /* ARGB8888 */( O+ a: z1 I2 @: ~7 M0 v
  2. #define DMA2D_OUTPUT_RGB888         DMA2D_OPFCCR_CM_0                     /* RGB888 */: {: x. C# [5 g) ]
  3. #define DMA2D_OUTPUT_RGB565         DMA2D_OPFCCR_CM_1                     /* RGB565 */1 V2 Q/ n$ z# M0 P" X
  4. #define DMA2D_OUTPUT_ARGB1555       (DMA2D_OPFCCR_CM_0|DMA2D_OPFCCR_CM_1) /* ARGB1555 */% L% C. F  B" ?
  5. #define DMA2D_OUTPUT_ARGB4444       DMA2D_OPFCCR_CM_2                     /* ARGB4444 */& f! e& }8 J1 o4 s( P0 @
复制代码
5 @% h/ r6 n  {: }% t7 ^# y( C
! u1 G8 [" `  c1 w: E! G
  uint32_t   OutputOffset
$ ^9 @0 K9 l/ D9 ]  f, ^此参数用于设置输出位置的偏移值,参数范围0x0000到0x3FFF。
' {- ]$ E% w. t" b$ h* L
" |# I  o/ s2 F2 a4 t# V  uint32_t   AlphaInverted
) @! L' |7 ^8 T, r( R$ e# {此参数用于设置DMA2D的输出颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     9 `  n: `( \8 U" D6 z6 {9 M
9 j' E5 P! q" I! j1 d' Z6 V) m
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */" @0 K1 I* V2 ?- Y5 g+ F
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */
复制代码
7 ^0 P! @0 e: z3 Q: ~! U0 Z9 [
  uint32_t   RedBlueSwap
  m0 Z9 q, _5 M0 {7 `  l' h! y此参数用于设置DMA2D的输出颜色格式中R通道和B通道的交换,具体支持的参数如下:* E- W! w' I# I. M- c8 O
$ Y9 e" y, z0 h. q, ]6 V& r
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */( |% t) R' z) O) x
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码
7 ^$ O- \: i" I, {& b0 p5 ~
55.3.3 DMA2D的图层结构体DMA2D_LayerCfgTypeDef; P1 }; {; ?0 U- Q8 ]4 a
此结构体用于配置前景色和背景色。
) m* U. t/ u7 P* v, V+ A- p' z9 r9 z; q, [% \
  1. typedef struct" z1 ^$ M+ a8 A) |( S9 L9 R4 A: V
  2. {# q! A2 v, W& I/ y
  3.   uint32_t             InputOffset;      
    " {; s- b; g1 F( }* d+ W
  4.   uint32_t             InputColorMode;   
    . T+ i/ K) F* i5 Q
  5.   uint32_t             AlphaMode;        ' `+ w! Y9 j: q4 V
  6.   uint32_t             InputAlpha;        ; f8 C- r" ?) x# F' d* F+ }
  7.   uint32_t             AlphaInverted;   
    8 ^( \( o5 l$ c  E) I1 D
  8.   uint32_t             RedBlueSwap;      
    3 }/ o5 i. z5 D( l4 v, I; g" n; z
  9.   uint32_t             ChromaSubSampling;+ e1 a5 C3 K, F) Y5 Z# M$ q0 {
  10. } DMA2D_LayerCfgTypeDef;
复制代码

1 D( v, A. ~2 }, n下面将这几个参数逐一为大家做个说明。
9 |6 j& e. p& v% C" R/ `; H2 K$ I+ A
  uint32_t  InputOffset
% J# v: t* D( ]7 q) v  x( p设置前景色或者背景色的输入偏移,范围0x000到0x3FFF。
3 Q! Q- q5 L- {7 M$ ], D% F0 Z+ T6 G; l) @
  uint32_t  InputColorMode
( ^7 p& o) a) w' b: B+ F1 U% [7 G+ p设置前景色或者背景色的输入颜色格式,具体支持的参数如下:7 _/ S2 L3 I+ f. t# s  U

$ K1 G& D6 ^3 I5 Q& L
  1. #define DMA2D_INPUT_ARGB8888        ((uint32_t)0x00000000U)  /* ARGB8888 */
    7 p- i/ G; F, x
  2. #define DMA2D_INPUT_RGB888          ((uint32_t)0x00000001U)  /* RGB888   */
    - t5 {. m; |' N+ Y8 i1 o
  3. #define DMA2D_INPUT_RGB565          ((uint32_t)0x00000002U)  /* RGB565   */
    + N! h' O, y7 `, R# K7 e
  4. #define DMA2D_INPUT_ARGB1555        ((uint32_t)0x00000003U)  /* ARGB1555 */. f! a" _# ]" T' L4 |: M
  5. #define DMA2D_INPUT_ARGB4444        ((uint32_t)0x00000004U)  /* ARGB4444 */0 W) r9 L$ h2 `  V) o, s
  6. #define DMA2D_INPUT_L8              ((uint32_t)0x00000005U)  /* L8       */
    ( f! u5 `0 I* X  N/ j: Z8 S" W" x
  7. #define DMA2D_INPUT_AL44            ((uint32_t)0x00000006U)  /* AL44     */4 C: ~; G: ?* a1 n+ Z& T; \" w
  8. #define DMA2D_INPUT_AL88            ((uint32_t)0x00000007U)  /* AL88     */
    & M4 \, C- B) u2 ]  o& T
  9. #define DMA2D_INPUT_L4              ((uint32_t)0x00000008U)  /* L4       */3 n/ X8 f: [' U; h& `, Z8 q
  10. #define DMA2D_INPUT_A8              ((uint32_t)0x00000009U)  /* A8       */
    ) m8 V# i# K; h
  11. #define DMA2D_INPUT_A4              ((uint32_t)0x0000000AU)  /* A4       */* I' P0 }; V& a
  12. #define DMA2D_INPUT_YCBCR           ((uint32_t)0x0000000BU)  /* YCbCr    */
复制代码
  F, R) X+ e. C3 d( W
  uint32_t AlphaMode
) C, W7 I' w6 H设置前景色或者背景色的Alpha模式,具体支持的参数如下:
1 d/ b$ C8 P/ e' ~' V4 N7 |, {9 e8 S% k: U3 `
  1. #define DMA2D_NO_MODIF_ALPHA   ((uint32_t)0x00000000U)  /* 不修改Alpha通道值 */1 g: B& j; y. y' ~* O# E
  2. #define DMA2D_REPLACE_ALPHA    ((uint32_t)0x00000001U)  /* 用新设置的Alpha值替换原始Alpha值 */
    9 T, V! J& R% b3 I# u- q( ]
  3. #define DMA2D_COMBINE_ALPHA    ((uint32_t)0x00000002U)  /* 用新设置的Alpha值与原始Alpha值的乘积替换原始Alaha值*/
复制代码
- U+ |& c" y9 R7 f& ?0 E+ ?
  uint32_t  InputAlpha8 Z. {1 U/ Y5 {) `' n& W+ H  a
设置前景色或者背景色的Alpha值,范围0x00到0xFF,如果颜色格式是A4或者A8,那么此参数的范围是0x00000000到0xFFFFFFFF,标准的ARGB8888格式。& j4 [" o0 [& K' f
2 V6 o1 g' d/ d( {% k
  uint32_t AlphaInverted
8 x* m; T/ g" x* Q" z设置前景色或者背景色的输入颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     
5 Q- h* b# v2 t6 g, Y5 u
. D4 w, P0 K$ W5 ]/ W
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */
    5 }6 N7 J; d) M9 s5 N2 P2 j  [* j
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */     
复制代码

( |& l% S$ g- q9 x, |5 j; R+ J  uint32_t   RedBlueSwap
, G' C( `3 o6 S  a! ^设置前景色或者背景色颜色格式中R通道和B通道的交换,具体支持的参数如下:
- q" A* F* Q9 X( G+ v! F$ {7 o6 c* d6 ?! ]5 s2 e6 K; Y. y
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */
    ' L) j9 K& u0 v/ r
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码
5 J6 W8 j( J' ?
  uint32_t   ChromaSubSampling
2 Y) ~+ ^, i3 f7 X2 k设置前景色或者背景色中YCbCr 颜色模式的采样格式,具体支持的参数如下:
  1. #define DMA2D_NO_CSS               ((uint32_t)0x00000000)  /* 4:4:4 */
    - @: j9 f! [! N3 }' a
  2. #define DMA2D_CSS_422              ((uint32_t)0x00000001)  /* 4:2:2 */
    - \3 ^  N' M& {* o3 C( r4 w/ V* J
  3. #define DMA2D_CSS_420              ((uint32_t)0x00000002)  /* 4:2:0 */  
复制代码
4 b# u$ E$ r+ m. V3 A2 x' Q
55.3.4 DMA2D句柄结构体DMA2D_HandleTypeDef
5 K( ?$ O( `2 V. T& V
HAL库在DMA2D_TypeDef, DMA2D_InitTypeDef和DMA2D_LayerCfgTypeDef的基础上封装了一个结构体DMA2D_HandleTypeDef,定义如下:/ q( S' N! T" D% A
' r7 ], E$ [/ S8 L; n6 a6 D4 Q
  1. typedef struct __DMA2D_HandleTypeDef* J3 f: k  D4 Q4 m
  2. {
    ( b( @+ u2 h2 }0 Z% t
  3.   DMA2D_TypeDef               *Instance;                                                                                                                                                                                          # R' T: w" v1 q; o* y3 h' _. B
  4.   DMA2D_InitTypeDef           Init;                                                        
    / r- g4 h! E. @5 B' |
  5.   void                        (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                                                                             
    3 D! a& a- C( N% ?* }
  6.   void                        (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                      & x/ }( y" v- t
  7.   DMA2D_LayerCfgTypeDef       LayerCfg[MAX_DMA2D_LAYER];                                    7 M0 ~+ ~& ~! f1 Y) l7 y( ?
  8.   HAL_LockTypeDef             Lock;                                                                                                                                                                                                    : a! i; h, v% X# m! P
  9.   __IO HAL_DMA2D_StateTypeDef State;                                                                                                                                                                                                   
    , k- D1 I3 }7 i$ _8 F
  10.   __IO uint32_t               ErrorCode;                                                   } DMA2D_HandleTypeDef;  v5 v( x2 R7 z7 y/ f3 x: g
复制代码
1 I8 @( r/ F& q* u: \
下面将这几个参数逐一做个说明。
' ^! c7 O0 A- n! z5 s5 u- L# V" \0 a& X7 }1 V* K
  DMA2D_TypeDef  *Instance
4 D: I4 f# D  z这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。9 _/ v: F$ s& ^' ^

9 w6 g: a+ E$ r8 @& u% A  DMA2D_InitTypeDef  Init;  + k/ P5 z* ?/ q5 D4 ^, u
这个参数是用户接触较多的,用于配置DMA2D的基本参数,详见本章3.2小节。
* \7 T' O( j# m, T% @, d/ u. H
" o# N; F- l+ a4 }) K# `  void     (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);
5 L- }  d& w8 f7 }% b  void     (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);) S" O" S# C( L) `
DMA2D中断服务程序里面执行的回调函数,一个是传输完成回调,另一个是传输错误回调。7 p1 s* h" s4 T' c3 u6 l

+ O, W5 a, n2 Q) V" c  DMA2D_LayerCfgTypeDef   LayerCfg[MAX_DMA2D_LAYER]
; p" D0 J9 e7 K6 d" b5 G5 |- Y这个参数用于前景色和背景色的设置,MAX_DMA2D_LAYER=2,详见本章3.3小节。
7 B& a$ t% n8 J9 h# E8 U+ p  V4 q* X- h# G2 Y
  HAL_LockTypeDef   Lock% P7 j$ j+ M3 w* c. U6 l
__IO uint32_t    State;1 W/ u+ W& V* ^) ^0 R5 F" ~
: F0 r+ B6 E% o3 O
__IO uint32_t    ErrorCode
! O6 R  X/ @& b: c; c: G) [  y9 n( k$ t; y0 K& q: B7 J4 n
这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置DMA2D通信状态,而ErrorCode用于配置代码错误。
( A; ?( G2 U) c% i" g. A; _1 m& P7 p' q: I# ~- l; Z9 r
55.3.5 DMA2D初始化流程总结
6 G( B- W( O5 d. j* [
对于DMA2D来说,其实不需要初始化流程,每个功能都可以直接封装出一个函数来,下个章节会为大家专门讲解,也是实际项目比较推荐的方式。2 D: v: B! f* s. t0 K8 B; h
3 a( S* o( j* c* m# H
55.4 源文件stm32h7xx_hal_dma2d.c
, g: C3 J# w& N% i/ X! p4 P( s这里把我们把如下几个常用到的函数做个说明:
7 d% h* `, [$ @' i( s$ Z
# v8 D' E" Z& @; p5 ^, P; T" g; s, Y  HAL_DMA2D_Init; b6 o/ ~3 j- y+ g3 E  |+ y# H
  HAL_DMA2D_ConfigLayer# l8 ~! }7 G3 U0 o
  HAL_DMA2D_Start_IT6 p/ e. z# F4 k% V8 e7 R1 Z3 ]
  HAL_DMA2D_BlendingStart_IT
+ R& L; A2 y; K* }$ q$ S& Y7 q1 f5 B4 W: v2 N$ R' t3 K3 w) k* j
55.4.1 函数HAL_DMA2D_Init
; N% I) p6 N0 B( k函数原型:- M) H* C4 A8 h2 I; ^

9 t3 ~- Z, _3 K5 v' s5 ]+ p
  1. HAL_StatusTypeDef HAL_DMA2D_Init(DMA2D_HandleTypeDef *hdma2d)7 \6 l9 O2 `) d) R1 l1 V
  2. {
    $ F1 |8 Z4 [% z/ U9 O; G7 J
  3. $ J- n3 M0 r0 [, V5 ^5 c( o+ \, t) Z
  4. /*  检测参数是否有效 */  r) v4 B0 u5 ^: v& X
  5.   if(hdma2d == NULL): z1 N, E, J6 H; \* e% [/ H# O
  6.   {, l; \: U" [" i* K1 h* N
  7.      return HAL_ERROR;# o& q" h+ D$ b+ `
  8.   }8 M- d  m. j$ L. e

  9. $ S6 a8 k% }+ F$ t) f" Z( W
  10.   /* 检测函数形参 */
    : r8 Z4 L1 i7 r6 L7 }
  11.   assert_param(IS_DMA2D_ALL_INSTANCE(hdma2d->Instance));
    - z. V$ {5 x1 c
  12.   assert_param(IS_DMA2D_MODE(hdma2d->Init.Mode));7 {  U' `+ f' g1 a% Q" a7 P8 |
  13.   assert_param(IS_DMA2D_CMODE(hdma2d->Init.ColorMode));5 L1 a' _9 \2 [- Z, E4 Q
  14.   assert_param(IS_DMA2D_OFFSET(hdma2d->Init.OutputOffset));0 h& C: h' C8 R: y# \! r# g& G& J
  15. + }. `, [# K5 `' J6 @- B: R5 s
  16.   if(hdma2d->State == HAL_DMA2D_STATE_RESET)
    / r# \9 N: R  v9 w
  17.   {+ m& Y. j/ Z, T4 x# f
  18.     hdma2d->Lock = HAL_UNLOCKED;$ R6 G. R# {3 s' O! X! B8 T6 E
  19.     /* 初始化GPIO,NVIC等 */- t& ]; P! ]' M" x$ ?
  20.     HAL_DMA2D_MspInit(hdma2d);3 U6 f  X( }  z. m3 w- w1 N
  21.   }4 j* l0 {2 ?7 g3 s' K4 ~
  22. 8 f" s8 ~9 H2 L" l& ?
  23.   /* 设置DAM2D外设状态 */
    % d  n* e/ I# F. u. D9 x* E* r+ o
  24.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  
      X2 ]8 @' X" w# U7 r

  25. 8 C3 B4 i* F. A/ b( _7 J! y
  26.   /* 设置DAM2D工作模式 -------------------------------------------*/- E9 R3 W$ M" J, s, q, g3 l
  27.   MODIFY_REG(hdma2d->Instance->CR, DMA2D_CR_MODE, hdma2d->Init.Mode);- J) D7 }" d- F: m4 }6 t/ |

  28. 0 ]. n9 B2 e  v2 p  X4 P' c: e2 \
  29.   /* 设置输出颜色格式 ---------------------------------------*/9 |" Y9 b5 J: n/ m* ?1 |4 M7 k
  30.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_CM, hdma2d->Init.ColorMode);, g0 m5 P) H* m5 a& }

  31. + D- F" I& x0 y. K: t3 l! Z/ u
  32.   /* 设置输出偏移 ------------------------------------------*/  
    " [; x! p9 u1 z2 X
  33.   MODIFY_REG(hdma2d->Instance->OOR, DMA2D_OOR_LO, hdma2d->Init.OutputOffset);  9 H" u  h# O# k$ i
  34. 3 W, H1 n: d/ g+ @) e' F( r
  35.   /* 设置输出颜色格式中的Alpah值反转 */
    % E5 L/ Z6 b+ u
  36.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_AI, (hdma2d->Init.AlphaInverted << DMA2D_POSITION_OPFCCR_AI));, O% B  i6 X' v# A- G. B( d

  37. 4 J! p1 F2 t  x1 i; c+ d6 W: `4 B+ {
  38.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_RBS,(hdma2d->Init.RedBlueSwap << DMA2D_POSITION_OPFCCR_RBS));: ?: r$ q9 W. R3 h5 I; W: y3 M. @

  39. 4 P! k& O5 E% G4 T: X
  40. - ?& E1 b% B8 U: q9 T: [7 D3 u" t
  41.   /* 无错误 */5 ]9 J0 H- s3 V; d5 @( |
  42.   hdma2d->ErrorCode = HAL_DMA2D_ERROR_NONE;( t7 Y6 x7 ^: |

  43. 9 m% b3 ?' F2 C5 E- ]4 t
  44.   /* DAM2D就绪 */2 u: r. V  g0 R) _
  45.   hdma2d->State  = HAL_DMA2D_STATE_READY;" e! ~. G' r, ?# x/ r) K6 C
  46. , R) r/ V/ N) |, Z% }
  47.   return HAL_OK;; i6 U  v0 D8 x2 ?% }9 O# Q
  48. }
复制代码
; L" ]+ _7 W& J1 v' \9 L
函数描述:0 n$ j- N( e- P7 m
( h5 R0 `, u/ f! L9 p' B* ?
此函数用于初始化DMA2D的工作模式和输出颜色格式。
9 k' N& V) j- P" a+ B, ]: p! j& m0 s1 r
函数参数:
! ~  c( Q9 ]! Z! J4 r% t5 Z# k6 z
0 Y4 V0 N5 R; s9 e& \$ y$ F, F/ v% ]  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。. m7 r4 e1 j* n4 z0 z+ E5 M8 S
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
: d0 o) I1 i2 u5 U2 W  k: O( M! t注意事项:9 |* n( |- V7 D
! {3 \+ Q* W. a- ?$ W
函数HAL_DMA2D_MspInit用于初始化DMA2D的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
" v$ N# I& ?& s5 h. K, @' t& Z4 r如果形参hdma2d的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量DMA2D_HandleTypeDef Dma2dHandle。: \1 Y+ Q8 g/ E. h/ W8 O2 l/ s
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_DMA2D_STATE_RESET  = 0x00U。9 }$ _+ l2 P  g1 B7 V3 q3 V3 ~
0 S" K( y& F1 _! X
解决办法有三+ y9 N/ l. z+ X

2 c; M" p8 S) x) q/ M方法1:用户自己初始DMA2D底层。+ v% |; d2 h9 v" J  x) }% F
/ t& k0 g" I  ?2 ^+ j& Y  u
方法2:定义DMA2D_HandleTypeDef LtdcHandle为全局变量。/ P8 l+ a# T$ m( e1 J
' A5 c6 L2 Z9 L' D
方法3:下面的方法
  1. if(HAL_DMA2D_DeInit(&Dma2dHandle) != HAL_OK)6 b5 a* D2 B6 D! y  C
  2. {
    ) g7 B2 g6 ?( [* H- }$ \, b
  3.     Error_Handler();
      K+ [! }" u4 k& c6 N
  4. }  0 _6 ^" o5 K" J' L2 g) V9 l, y6 B- \2 e
  5. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
    6 G! Z1 r. L9 o1 f* L+ X. g
  6. {
    $ v# z! x& R/ u; M$ N+ G" a
  7.     Error_Handler();
    9 o- H6 a0 q' l! I+ Q, j8 u# d' [
  8. }
复制代码

# l& X, |" e+ m$ d, S6 ^5 ^$ c2 \/ ?; f! E) C
使用举例:2 w. a  A! w6 O; h- Z( w  d( }
9 `4 j1 V5 t/ o9 |# Y: Y! E  d1 q
  1. DMA2D_HandleTypeDef Dma2dHandle;
    # T3 w  e5 X/ t1 `) \5 F/ P0 R
  2. " [& o3 v2 I0 s
  3. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/) Q, F+ Z8 |. X% }
  4. Dma2dHandle.Instance = DMA2D;
    6 Q" b" W9 C' x) A

  5. + ]  p2 k& k1 k8 L! b4 C6 S
  6. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */# [" b, f9 ~6 d; N% g
  7. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */1 d4 N1 L/ k) L' m0 X4 h
  8. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */* d! T. _  L9 Y6 a( p' e& \% q& n+ J8 k: O
  9. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */6 ]' `+ ]/ j2 T0 q
  10. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */
    ' f8 L* c+ }  u2 T: C5 ^$ p3 s/ U  H

  11. - O% ]. E  G7 H+ B& b
  12. /*##-2- DMA2D 回调函数配置 ######################################*/
    ( K; `) l  `5 c- t5 v  t& D* ?5 g
  13. Dma2dHandle.XferCpltCallback  = TransferComplete;
    ! \* d! C' U+ _) M4 g; o# u
  14. Dma2dHandle.XferErrorCallback = TransferError;' Y# @% M/ U2 f) Y- e9 K- c6 d  g, ^
  15. - G5 d3 @! K9 O" o) k
  16. /*##-3- 前景层配置 ###########################################*/
    ; ?. c8 ]( {5 q, d& R' v0 K( D
  17. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 *// k: [1 D& _* [! ]7 v4 T- A1 N; U  Z
  18. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */4 ?3 k' D8 J/ A* T1 h
  19. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */
    8 \' m7 R' b  c% }4 C3 `5 B( a. C* l
  20. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */
    7 e- o. B4 O9 ~. Y/ `$ R
  21. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/6 _' E0 f6 x. [: ?! J4 e
  22. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/
    . I, v& Z7 {- }
  23. * w/ p; Q+ v& g8 V$ |

  24. $ G* j: [; W# V3 G: @( N
  25. /*##-4- DMA2D 初始化 ###############################################*/5 u+ p9 w3 N+ T- q
  26. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)3 j9 D8 [, S& k7 C& q0 Z0 b
  27. {
    5 Z7 s+ r1 J/ Q; [+ O
  28.     Error_Handler();
    ; s( n4 T3 t# T) x
  29. }
复制代码
6 m* x1 R. D3 ]+ M
55.4.2 函数HAL_DMA2D_ConfigLayer
( Q6 M* V5 ], s3 c6 o函数原型:
5 [: o/ F3 K6 ?! U9 N( V8 @4 s/ @$ g" l8 F; ?* P  n8 y
  1. HAL_StatusTypeDef HAL_DMA2D_ConfigLayer(DMA2D_HandleTypeDef *hdma2d, uint32_t LayerIdx)& S, t9 ~: N( h8 D& a* S
  2. {
    6 O6 v" s5 a2 R& `2 p6 U, n: ]! l
  3.   DMA2D_LayerCfgTypeDef *pLayerCfg = &hdma2d->LayerCfg[LayerIdx];
    ) c; U$ A/ _# X2 y2 z4 k
  4. ( d/ S* P/ H& P7 O% a
  5.   uint32_t regMask = 0, regValue = 0;8 p7 C( S, w* T6 m
  6.   r, s$ X7 Q. |6 f# m! L' U2 R
  7.   /* 检查参数 */' {" T( C2 G$ e/ K( t
  8.   assert_param(IS_DMA2D_LAYER(LayerIdx));  - w* X/ d  P: A1 ~" A
  9.   assert_param(IS_DMA2D_OFFSET(pLayerCfg->InputOffset));  
    4 E, x8 U# K% j6 l- t
  10.   if(hdma2d->Init.Mode != DMA2D_R2M)' ~8 n' ~% w( E3 C5 i
  11.   {  
    9 ]- a9 T1 {  U/ l" o) U
  12.     assert_param(IS_DMA2D_INPUT_COLOR_MODE(pLayerCfg->InputColorMode));5 f1 u5 S* S" L
  13.     if(hdma2d->Init.Mode != DMA2D_M2M)3 B- T. i0 C! Z8 p; e
  14.     {
    2 e* A& O2 h" `  Y6 {( o4 |" }- O
  15.       assert_param(IS_DMA2D_ALPHA_MODE(pLayerCfg->AlphaMode));
    2 B' R& s+ }% Z. M. `0 d; J
  16.     }0 K9 _0 k! U1 ^: B0 u' P3 z; }  X
  17.   }
    : J# m7 l: v+ m  S- I2 F

  18. , ^  \9 Y8 G0 u3 H6 _; Z+ v
  19.   /* 上锁 */2 \" h% \: ?2 S
  20.   __HAL_LOCK(hdma2d);
    8 X5 _( E( h9 T% u9 `  n8 `7 R

  21. ( |2 e2 o; {0 b$ h" Y; o
  22.   /* 设置DMA2D外设状态 */+ I3 n, l6 D$ x" v: R
  23.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  9 E% t* F# A0 A
  24. 4 c$ ?3 C' d0 c+ }, g
  25.   /* 准备好背景层或者前景层FPC寄存器配置参数*/6 L; U1 |7 Q- V+ O4 F
  26.   regValue = pLayerCfg->InputColorMode | (pLayerCfg->AlphaMode << DMA2D_POSITION_BGPFCCR_AM) | \9 ]0 S5 I: w# g  s, u' g2 l
  27.             (pLayerCfg->AlphaInverted << DMA2D_POSITION_BGPFCCR_AI) | \
      U5 v% d9 f& E+ v1 Q
  28.             (pLayerCfg->RedBlueSwap << DMA2D_POSITION_BGPFCCR_RBS);
    4 |3 n4 D5 v' D1 j' ?+ T: Q8 |7 Q8 Q
  29. : \1 l% \- j& r
  30.   regMask  = DMA2D_BGPFCCR_CM | DMA2D_BGPFCCR_AM | DMA2D_BGPFCCR_ALPHA | DMA2D_BGPFCCR_AI | DMA2D_BGPFCCR_RBS;* b+ a2 V# I5 l; b% {. z

  31. ) {0 _/ q" t% n. g) L% x
  32.   if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))7 `/ o- X) \4 |0 Q; L. c
  33.   {; I3 r* v3 e/ r- c9 Z
  34.     regValue |= (pLayerCfg->InputAlpha & DMA2D_BGPFCCR_ALPHA);
    ( q9 ~' p5 H+ T  J
  35.   }' @2 P- b, r* w3 e
  36.   else
    # Q% n/ d" i! i
  37.   {
    6 M' Z4 D# g) p' j: X2 Y& A
  38.     regValue |=  (pLayerCfg->InputAlpha << DMA2D_POSITION_BGPFCCR_ALPHA);
    ; c# n/ t) y5 W
  39.   }; p7 j7 H' h/ K6 K& m- o7 b  z8 R7 f

  40. 0 P6 Y( H" l% i6 A9 _. I; z4 `
  41.   /* 配置背景层 */$ g' |$ G6 @! p1 Y
  42.   if(LayerIdx == 0)
    ! c8 Q2 G3 d7 F9 u, N5 `4 x& r  l# h
  43.   {$ J& ?9 e8 ~4 Q! K7 Y; S
  44.     /* DMA2D BGPFCCR 寄存器 */
    $ U! I: a4 s7 Y
  45.     MODIFY_REG(hdma2d->Instance->BGPFCCR, regMask, regValue);
    6 G0 ]8 D. Z, E# H6 Q( E' X# r

  46. % Y: M6 N- m3 T4 w0 k6 O
  47.     /* DMA2D BGOR 寄存器 */  5 Y4 L  X' `' @+ u) d
  48.     WRITE_REG(hdma2d->Instance->BGOR, pLayerCfg->InputOffset);7 |; `1 i; P2 k  j9 e6 D6 M
  49. + A% F6 k4 Z( F; U
  50.     /* DMA2D BGCOLR 寄存器 */
    . p% J  }3 c3 {: x* O# R8 X# y  N
  51.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))/ B# K! g; a0 A: r  ~( b5 ^7 t
  52.     {   
    2 ~3 H# W( ?! a+ u) k4 A
  53.       WRITE_REG(hdma2d->Instance->BGCOLR, pLayerCfg->InputAlpha &
    ; g' l9 V7 m1 `7 x0 {4 u
  54. (DMA2D_BGCOLR_BLUE|DMA2D_BGCOLR_GREEN|DMA2D_BGCOLR_RED));, P7 V4 D7 ?4 s& l4 n. d+ L, y6 |
  55.     }    # E4 u$ z5 M) x
  56.   }- p& d" r6 l' b+ e
  57.   /* 配置前景层 */% {: O3 ~. }$ E; d/ v+ Z/ {
  58.   else
    $ _' p3 _8 r. s' o) B6 t
  59.   {
    - K8 x$ L7 }6 A- y- M( G. J
  60.     if(pLayerCfg->InputColorMode == DMA2D_INPUT_YCBCR)
    6 p+ U/ u: b" ]9 U
  61.     {8 \: {. `9 a" q4 u
  62.       regValue |= (pLayerCfg->ChromaSubSampling << DMA2D_POSITION_FGPFCCR_CSS);% ^% J9 P/ q1 \5 n) T6 b. ?  Y* w4 V
  63.       regMask  |= DMA2D_FGPFCCR_CSS;
    " B/ }4 d7 B8 n7 E' q
  64.     }& D( X- n! x3 @* Z) z
  65. ! S! O* s; u# ^* H5 C4 }+ n
  66.      /* DMA2D FGPFCCR 寄存器 */
    ' N  H: G1 c1 Y) ?8 s
  67.     MODIFY_REG(hdma2d->Instance->FGPFCCR, regMask, regValue);
    & u5 Y1 s$ [" V( r

  68.   }6 D7 j2 a8 I' [4 H
  69.     /* DMA2D FGOR 寄存器 */
    0 m! |5 f$ v- s, [3 Y2 O, B
  70.     WRITE_REG(hdma2d->Instance->FGOR, pLayerCfg->InputOffset);      , k; h( E$ c1 a! N3 u
  71. $ d- d0 ^$ p& w  ?4 P5 E
  72.     /* DMA2D FGCOLR 寄存器 */   3 [) f) Q; v$ P* N/ T( Q  Z
  73.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    ; ~) \' p) [1 _) A! n
  74.     {
    5 e  [$ h+ v+ C+ r
  75.       WRITE_REG(hdma2d->Instance->FGCOLR, pLayerCfg->InputAlpha & 6 N4 m6 p  T. I* T' A, R! S, S: K
  76. (DMA2D_FGCOLR_BLUE|DMA2D_FGCOLR_GREEN|DMA2D_FGCOLR_RED));      / l0 S" q4 y8 d6 C$ L& o
  77.     }   ! ?# S: N3 W/ {! j
  78.   }   
    0 _5 @3 K9 L+ R! k: X1 W
  79.   /* DMA2D就绪 */
    : W. m* q/ q/ ?7 @7 ]
  80.   hdma2d->State = HAL_DMA2D_STATE_READY;
    9 F* C$ Y/ j6 t( {( t1 @) n

  81. , M/ M, Y" G( T0 R* |7 [! n
  82.   /* 解锁 */, x  h% K. g$ u' O/ J7 f* s9 X
  83.   __HAL_UNLOCK(hdma2d);  
    2 z5 ]1 ~6 _% a/ q; k* \; c

  84. ; ^9 u2 b" P- X# v$ @6 I7 {
  85.   return HAL_OK;3 I; G6 g/ h' v) I8 a/ i
  86. }
复制代码
$ O" _3 I0 U% ]8 b1 ]/ i$ k# v, b
函数描述:
, Y, C! B7 S- E: W/ i4 n
9 a1 J% S. h  E0 J$ Y- G此函数主要用于配置DMA2D要转换的前景层和背景层,即输入颜色配置。而前面的函数HAL_DMA2D_Init配置的输出颜色。( E" |& A4 S2 @1 i: {
8 I( G( ]% e/ y7 I3 P  b% z
函数参数:  b' U# V' E1 X8 S  g2 S
' E, c1 q. W; Q* \; d
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。
5 O4 d  x! S1 k# M2 \  第2个参数用于配置前景层和背景层,0表示背景层,1表示前景层。# I  F0 d* R( ]* |" N, I9 B" y
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。# @. j7 m4 k9 C% v5 f5 o
使用举例:
3 q6 U; I6 w. U. Z% Y
  1. + P  ]! A, Y& D& R' P
  2. DMA2D_HandleTypeDef Dma2dHandle;7 [1 O3 p7 D1 b% j- {6 E
  3. , s. @4 _( j6 h; d0 ^
  4. 2 Z, K# J0 \1 |4 K- x
  5. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/( F( g8 P5 U3 }' |. L( K$ s- ?
  6. Dma2dHandle.Instance = DMA2D;
    9 S- k- \( X5 z8 i4 k0 ~; E5 o# W% v# w

  7. , h$ l! k+ N7 T, w3 `
  8. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */
    ' s) H5 F  @0 I- E7 _
  9. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */
    - k) N/ }, {3 j4 t; T/ x/ ~3 R
  10. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */% ~/ c6 M8 f8 E& I$ U
  11. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */5 j( F+ b1 K  C9 }
  12. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */8 V6 E% N7 o; q3 S* `

  13. * s' d* G+ W/ ?9 X* V: ]% K
  14. /*##-2- DMA2D 回调函数配置 ######################################*/& n. t6 V# U" k
  15. Dma2dHandle.XferCpltCallback  = TransferComplete;
    3 o$ g3 g/ |  w4 d7 X7 y
  16. Dma2dHandle.XferErrorCallback = TransferError;
    ! B1 }8 Q7 R! n$ e0 S/ m  e
  17. 9 W7 M- x/ d' ^' g% @
  18. /*##-3- 前景层配置 ###########################################*/
    8 a; C- w2 I/ {" ^  L
  19. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */3 Y2 P4 z% c$ h+ ~8 ?2 o
  20. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */
    ) b! g: c5 G+ d+ O6 G
  21. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */
    ! F" \  o5 r6 I5 R
  22. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */4 V7 p8 Y/ `- }' ~5 h, S5 k
  23. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/
    6 D. {6 O1 R6 X0 s, _5 W8 M
  24. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/! ?/ A+ P8 y% Z  U3 A
  25. 0 c3 @( E9 Y6 @" b( x
  26. /*##-4- DMA2D 初始化 ###############################################*/, ?- _: f( w3 _- }* Y3 M3 f1 s# n
  27. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)2 Q1 i3 a1 b4 O, I+ e
  28. {
    8 x( J' g8 f& K
  29.     Error_Handler();
    ; }6 q& [) w: e6 y
  30. }
    6 R) Y/ l+ X$ {9 Z

  31. " _* B7 ~0 i! b! [3 F
  32. /* 配置前景层  */% x6 a# D# g2 D3 y1 y
  33. if(HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1) != HAL_OK)0 _, x- C5 K3 ?$ s* Y
  34. {
    7 x4 |3 M5 X- _8 G" q1 M8 x. J
  35.    Error_Handler();3 n& o+ p$ C/ d# n6 ?% ?- W
  36. }
复制代码

2 x4 ]) [8 Y) d% N  U
2 @: O& M& S# f  B1 w8 p55.4.3 函数HAL_DMA2D_Start_IT( }0 @6 ~1 ]- F
函数原型:# O% N, s! O9 T$ _8 A- D

9 D! s6 o3 ~) H5 }  W( A
  1. HAL_StatusTypeDef HAL_DMA2D_Start_IT(DMA2D_HandleTypeDef *hdma2d, uint32_t pdata, uint32_t DstAddress, uint32_t Width,  uint32_t Height)
    7 E7 C  s, B6 j
  2. {
    ' f* Q8 A  ~2 p8 I
  3.   /* 检测函数形参 */
    % O- j$ {( L3 z  U
  4.   assert_param(IS_DMA2D_LINE(Height));5 x- P4 ~( ^# n
  5.   assert_param(IS_DMA2D_PIXEL(Width));. T% g+ o9 x- M! _7 N

  6. $ i$ p% G: `+ d1 x) f$ o# q1 F* W
  7.   /* 上锁 */" `' M$ S8 |7 K; `
  8.   __HAL_LOCK(hdma2d);% v: X) Y  }, P/ x

  9. " p" }4 Z8 K$ |) _
  10.   /* 设置DMA2D外设状态 */. S) _: {4 t$ _, ~
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;
    0 V. F) ]+ b% S1 M/ f, K- x

  12. * Z# }; E6 k# t( O
  13.   /* 设置源地址,目的地址和数据大小 */- L, `" b2 l. K: h4 ~" F9 h# J. ^
  14.   DMA2D_SetConfig(hdma2d, pdata, DstAddress, Width, Height);
    4 w6 j  Z/ c  M) f+ E. |- j8 s
  15. 7 V; U, y) H  w# Q% c: N. i
  16.   /* 使能DMA2D的传输完成中断,传输错误中断和配置错误中断 */
    4 `3 `' Z' D) r" l: Q2 k9 [
  17.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);
    - e& }( F9 J3 l: @+ u
  18. % Q/ k: ?" `4 ~* q, j; O/ \
  19.   /* 使能DMA2D */# H$ z1 v. j, A4 l  N
  20.   __HAL_DMA2D_ENABLE(hdma2d);* D& s' r3 V7 i  ^4 Z+ N
  21. 5 V/ \8 U3 v3 M  a
  22.   return HAL_OK;! I0 Q4 D4 R, o9 S# x* |$ l0 A
  23. }
复制代码
8 v8 b- l3 Z; x! b+ i/ R  l3 P
函数描述:
2 }# E* H7 x& `" X+ a
/ g6 \* s; g6 ?6 x2 ^, v2 ~此函数用于启动DMA2D数据传输。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。& u$ a# N9 {% _
1 F2 y1 f$ _4 ?1 S) K
函数参数:
6 J( S* I. a3 d$ ?& \
0 C: _* M( u0 F3 m+ N4 [, I# v  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。
7 N5 k' ~% o/ q) R$ H% c  第2个参数是源数据地址。
* e$ [1 e! g. Q0 P' I  第3个参数是目的数据地址。- R) J4 k+ z- d
  第4个参数是源数据的长度,即每行的像素个数。
# F2 c* M8 h; r" b7 r. u; W/ w5 e4 g. ?3 j  第5个参数是源数据的高度,即行数。
+ r0 @  U' `* C8 Y  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
9 b" s9 ^% c. |- Y& D使用举例:
8 x. ]) _- g: I- R9 j2 g3 [1 b3 A, ]3 A! I
  1. DMA2D_HandleTypeDef Dma2dHandle;
    ) _* o+ v6 i1 P# k9 s$ d! Z
  2. ) `$ C4 B3 I3 H7 m" J( y' v
  3. if(HAL_DMA2D_Start_IT(&Dma2dHandle,            /* DMA2D句柄 */& r6 p3 L4 L  b( e- V
  4.                       (uint32_t)&BufferInput,  /* 源地址 */
    0 ]6 c! E8 q* ^' n" N
  5.                       (uint32_t)&BufferResult, /* 目的地址 */7 _% r4 f; k' b0 ]& H: o* Z% u
  6.                       SIZE_X,                  /* 源数据长度,单位像素个数*/( B" s: K1 s: `; s. q: x+ P! I" O* Z8 g: R
  7.                       SIZE_Y)                  /* 源数据行数 */7 y& k$ R( v! t4 E5 m
  8.    != HAL_OK)
    6 W2 \3 ]! ~. @) {+ ^' x
  9. {
    ! g- e. @" f0 e
  10.    Error_Handler();7 |8 ^! s$ ]% t' [5 Y
  11. }
复制代码

  P5 X, K3 S" |0 |55.4.4 函数HAL_DMA2D_BlendingStart_IT! g' \" g/ ?9 n9 ^+ t" d
函数原型:
9 h' V- t( N6 ?/ M
. V5 i# @4 d3 Y
  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)
    0 x7 h. V2 `5 f: J- D4 ^/ P
  2. {0 E  I: D, `  M, e& n, F5 r
  3.   /* 检测参数 */
    3 R$ h7 f; u  e3 k
  4.   assert_param(IS_DMA2D_LINE(Height));
    3 T- e% t5 P& f
  5.   assert_param(IS_DMA2D_PIXEL(Width));+ s- ^: z% X! l8 a( ]
  6. 0 K; T8 T6 ^6 l4 W
  7.   /* 上锁 */" u4 S5 t, x- k3 x, |8 |9 U
  8.   __HAL_LOCK(hdma2d);
    . ~' p% r/ N* F3 i
  9. 8 V4 j; y; h: v! |
  10.   /* 设置DMA2D外设状态 */
    " ~6 f2 L, w6 Y" c3 x
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;" J1 w5 }: D1 y. |; U- o/ b' z0 u
  12. - d) X% o* }* H3 `/ l6 G' f
  13.   /* 配置DMA2D源地址2 */
    7 Y$ I! `' g  [/ ?
  14.   WRITE_REG(hdma2d->Instance->BGMAR, SrcAddress2);/ o2 X- W0 D8 C  @% n( Y
  15. / U% O4 o* ?) O4 b
  16.   /* 配置源地址1,目的地址和数据大小 */
    5 E  F( Y4 ?1 L; |
  17.   DMA2D_SetConfig(hdma2d, SrcAddress1, DstAddress, Width, Height);: l1 L( D1 \" @$ ^

  18. # G8 u  V0 X" h5 x7 Y
  19.   /* 使能DMA2D传输完成中断,传输错误中断和配置错误中断 */. `% t2 |2 b% l2 q& i- k) H
  20.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);$ f0 F0 n. g. n# l  z: _8 z. g! a

  21. + G! }; p4 I; W, x7 }) q
  22.   /* 使能DMA2D */. b$ O8 [+ X4 z$ n6 ?. \
  23.   __HAL_DMA2D_ENABLE(hdma2d);" {' F- S$ C7 W
  24. $ R" J0 P7 N$ Z6 `# p
  25.   return HAL_OK;% \6 Q4 n7 R! n5 Q# _7 C+ Y; Y
  26. }
复制代码

4 Q( I. S0 z9 g0 m5 w8 W2 G* P函数描述:
/ J$ M- i& D% K8 Y. b! I! v5 n. l" o' _# _  J$ Q, r) D2 ^- I
此函数用于启动DMA2D传输,除了数据传输以外,还支持颜色格式转换和颜色混合。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。
6 u5 b. \; V$ L
0 A/ Y" f! S/ r5 h" ^! P: B函数参数:3 O* C- ?2 W, R: j. ~

/ k! f, ~: N, `* G  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。1 O7 w$ l  n3 s4 d9 O1 `
  第2个参数是源数据地址1。/ Y2 k: m8 j" x3 ?; T0 I" z1 V
  第3个参数是源数据地址2。
& K. o$ M* ~/ g4 n! Y  第4个参数是目的数据地址。9 I3 I! G! u& b! E+ a( r
  第5个参数是源数据的长度,即每行的像素个数。
9 z, M0 x0 v& T- M9 ^2 d) z- U  第6个参数是源数据的高度,即行数。
# u( g, K/ y* G! x9 f4 W9 A  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
, k# _7 X: M! a3 H& o使用举例:# d8 b) F3 c" o( ~' t

0 W; ^, l% [3 W& z
  1. DMA2D_HandleTypeDef Dma2dHandle;; I1 P+ L4 f: I3 j  n$ y

  2. 2 ]0 v2 u8 d' o4 h( |3 Y. p# v
  3. if(HAL_DMA2D_BlendingStart_IT(&Dma2dHandle,           /* DMA2D句柄 */
    ; C$ [, x; b: {6 K7 y; s& G
  4.                              (uint32_t)&BufferInput1, /* 源地址1,前景色 */
    & T& i" N5 V; O& g
  5.                              (uint32_t)&BufferInput2, /* 源地址2,背景色 */
    $ M3 v5 B$ a# Z
  6.                              (uint32_t)&BufferResult, /* 目的地址 */: \( N# O1 j2 I" m. t# p8 h
  7.                               SIZE_X,                 /* 源数据长度,单位像素个数*/- R0 C( }, }5 E6 o
  8.                               SIZE_Y)                 /* 源数据行数 */
    0 d0 v3 j+ [; z' n  O
  9.    != HAL_OK)
    ) l' F. o. Y3 {# w
  10. {
    - W2 k  X! d6 L
  11.    Error_Handler();
    " O& u+ F4 B. g% _1 O
  12. }
复制代码

" {7 E0 M" M+ f' ?) |' U& V
! }) Y1 X. O! M9 [55.5 总结
# b9 H/ D7 i  G+ s2 y5 x本章节就为大家讲解这么多,DMA2D功能比较重要,一定要做到熟练使用。
% A0 E5 O$ K' g; F, Q: n; |0 Z! D/ |) u+ N4 [8 b) q

7 |3 p% p8 @  Q8 Q. Q
- ^8 T7 }% S8 B+ M
收藏 评论0 发布时间:2021-12-24 17:00

举报

0个回答

所属标签

相似分享

官网相关资源

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