55.1 初学者重要提示4 S# [% r' M$ R1 [4 {. e5 N
DMA2D是专门用于LCD加速的,特别是刷单色屏,刷图片,刷Alpah(透明)混合效果全靠它,而且可以大大降低CPU利用率。8 M- S* j6 d/ V. _; ]! Y! V5 g- o7 N
测评STM32H7的LTDC+DMA2D性能,100Hz以上无压力,刷800*480图片和色块仅需2.6ms一张。* B' R" R: I/ e
H7的DMA2D与F429的DMA2D最大区别是支持了ARGB和ABGR互转,而且支持H7的硬解JEPG输出格式YCbCr转RGB,方便LCD显示。: {$ R! [* P% F' {* j( L: p) ^
特别注意,大家只需对HAL库提供的DMA2D操作API有个了解即可,实际工程中,并不使用这些API,我们需要使用更加高效的寄存器直接操作,在下一章节会为大家说明。
0 j! h. u D2 z55.2 DMA2D基础知识
k% S! Z+ f6 M" {DMA2D主要实现了两个功能,一个是DMA数据传输功能,另一个是2D图形加速功能。6 j5 Q5 J$ J! W8 t
& u( g0 \% A- N. b
DMA数据传输- i: z- q( H0 G2 T
主要是两种方式,一个是寄存器到存储器,另一个是存储器到存储器。通过DMA可以大大降低CPU的利用率。3 G/ A2 w& d# u1 T# _
/ @$ \( M6 [* {9 A6 M6 q 2D图形加速功能( z @! o- H. W
支持硬件的颜色格式转换和Alpha混合效果。3 M% p5 N! k v7 A* f9 o
9 T! ^2 X }! B55.2.1 DMA2D硬件框图+ x* Y' g9 C4 \+ r
认识一个外设,最好的方式就是看它的框图,方便我们快速地了解DMA2D的基本功能,然后再看手册了解细节。框图如下所示:3 @' I- ]9 M! T7 n* n, f
8 K3 {. k* }3 ^* A8 O; I9 u$ | v' E/ k v
. k8 I9 C3 j0 K2 b4 I
通过这个框图,我们可以得到如下信息:
3 M% m% F+ ]/ ]# i
7 C5 h" Q1 ]: f dma2d_aclk: z& T4 k; z6 z$ j* w' I9 U# ?' W- k
AXI 总线时钟输入。1 }% V6 v% G- t* a9 ]6 I/ y
3 y. o5 q3 ?3 {, y& j
dma2d_gbl_it6 n7 o z9 w$ F4 ?5 s- e
DMA2D全局中断输出。- ^5 R+ L# X8 }8 f( K
1 V0 Y- Z2 B' J2 N8 S
dma2d_clut_trg9 T4 d% ?, x: n$ ]7 R T0 q
CLUT传输完成信号输出,可以触发MDMA。* f4 s0 F7 W9 T' w
" _! k& m/ k4 d dma2d_tc_trg2 A) N$ T& i. x- C* U) i4 B
传输完成信号输出,可以触发MDMA。
0 i* S4 }6 s& h& q6 i( B
3 h* x( L5 s2 D, k4 ?; G1 \ dma2d_tw_trg
3 `% S' g9 p8 e5 f. \6 w$ h, _传输watermark信号输出,可以触发MDMA。$ }) U% u# m9 G) E8 B7 E2 o
8 o8 `1 i5 Y8 o/ g, M* U9 Y将这个硬件框图简化一下,就是下面这样:1 f, S8 i5 ?7 D6 a
, U; N( j3 H6 C' |$ h
; h/ J$ b/ y; h {, M
) H! h5 [# X( X
下面按照简化的硬件框图,对每个部分做个说明。0 c$ B/ N8 z' t+ }4 m8 l) Z* Z/ }' e
) c9 Y2 C, N- ^* J1 h
55.2.2 DMA2D工作模式
8 W: ?2 | l. N) f! b2 j1 aDMA2D支持的工作模式如下:
: C. b b$ m7 O- h- R4 t/ F( i3 e
0 k: D0 u9 s ^7 `. T' t6 `" y 模式1:寄存器到存储器模式
" D- q0 B) o. ]2 R# T: G! h- Q; d+ W这个模式主要用于清屏,也即是将显示屏清为单色效果。
3 f" r: j0 ^! \: Q. \7 e% Z+ Q7 o: R6 l+ S4 `
模式2:存储器到存储器模式
8 P, n! t7 {8 K这个模式用于从一个存储器复制一块数据到另一个存储器,比如将摄像头OV7670的输出图像复制到LCD显存就可以采用这种方式。 e* J/ j7 m& z, q, m$ w9 V
1 c. u+ f' f0 `
模式3:存储器到存储器模式,带颜色格式转换
, F% M& |+ H# q! _: N$ B: M; k1 B这个模式比模式2多了一个颜色格式转换,比如我们要显示一幅RGB888颜色格式的位图到RGB565颜色格式的显示屏,就需要用到这个模式,只需输入端配置为RGB888,输出端配置RGB565即可。位图颜色格式转换后会显示到显示屏上。
' n7 F e( ?0 w: n
( v u9 \$ v2 H; C& h 模式4:存储器到存储器模式,带颜色格式转换和混合
1 B9 t1 a: ]* N; g1 E/ j8 H这个模式比模式3多了一个混合操作,通过混合,可以将两种效果进行混合显示。. g8 v0 ^% ]8 {& y3 f- o* F3 }
; w) n) A8 ?7 O9 _
模式5:存储器到存储器模式,带颜色格式转换和混合,前景色是固定的# _, E A+ X6 S5 H( E1 l" Z6 M
同模式4,只是前景色的颜色值是固定的。& {4 [* f, x; h! q1 Z v! D8 ]. n4 z8 |
6 a' h& u0 }; @$ v6 m' ^
55.2.3 前景层和背景层的输入以及颜色格式转换
* G" z* c: h) b; J( X# k前景层和背景层是指的用户绘制图形时的前景色和背景色,比如我们显示汉字,字体会有一个颜色,也就是前景色,还有一个背景色。又比如我们绘制两幅图片,想将两幅图片混合,那就可以将一幅图片作为前景层,另一个幅图片作为背景层。
. A0 q' J- h( I& t2 ]9 }
$ G3 f9 w& Q2 u8 XDMA2D支持的输入颜色格式如下,前景层和背景层一样:6 ]5 y; d, e5 z4 ^6 M. f# ]
% s9 B) D Y5 U. G
, p. S! |" x# l* u
# k: W( a* g X2 m& G, M2 t$ h前8种颜色格式在第50章的第2小节开头有介绍,这里把后四种做个说明:
9 P2 X7 c0 @& t1 E9 n# C. c
" K5 X6 @- I! @- j3 d- E2 s( Z L4 (4-bit luminance or CLUT): I& ^1 H! B. i' S; K# i9 I* Q
4位颜色格式,实际上仅仅是4位索引值,范围0–15,而每个索引值的具体颜色值在查色表CLUT里面存储。, z" k/ Q# u2 T* g+ R8 d# s
+ A! N2 T* b" E
A4和A8
, u4 o7 p2 Y! ~1 hA4和A8用于特定的Alpha模式,既不存储颜色信息,也没有索引值。
( m# B/ A* m7 _8 y' K; M3 S9 E" Y. g9 B( X7 J) F" ?7 E( n& U0 y0 u a
YCbCr
- S& y/ ^# f" {8 s& g; a6 a这个是H7的硬件JPEG输出的颜色格式,后面JPEG章节为大家专门做讲解。" f0 l1 v0 k- Y" P' ~ t9 N
9 j, Y" V9 v6 \3 I6 \ a
这里特别注意一点,输入颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。
: A2 E& F( I8 x* a$ I: P) S" q7 Q' R8 O& ]. e
55.2.4 前景层和背景层混合
& c6 X1 N) W8 |' }DMA2D混合器用于混合前景色和背景色,这个功能不需要任何配置,仅需要通过DMA2D_CR寄存器使能即可。混合公式如下:
4 N0 L+ |* V6 ?1 U
. Z/ J. ]! Y6 o, c; T. g+ Y5 M* e; ^6 M" ]" k; w
0 j8 ]- j$ [* n) a55.2.5 DMA2D输出颜色格式
5 r/ [0 p2 U5 o# B) H. {$ bDMA2D支持的输出颜色格式如下:
! P$ X* g2 y. |' l2 d6 n1 i' B- s+ t" H: Q
2 S: b8 {1 y% @" T0 K2 ^' t8 I6 T% W6 L5 F7 Z7 r& s
这里特别注意一点,输出颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。
" ]8 ^" z) J. L, j/ z
$ Y/ s+ [) [* q7 m; ~# \55.3 DMA2D的HAL库用法- u \2 v( P+ ~# N3 D# o- w
DMA2D的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断。下面我们逐一展开为大家做个说明。. ]% G" R: p: f6 C
: W, E, v# K( \& ^& M' d
55.3.1 DMA2D寄存器结构体DMA2D_TypeDef1 w/ h7 p0 `+ W1 f% u' c& I' B
DMA2D相关的寄存器是通过HAL库中的结构体DMA2D_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:
9 L6 M& P1 Z8 X7 O6 }$ E) S3 M6 }; s. p! L. Z5 |
- typedef struct: a* {' m b, w Y7 J* C2 V
- {
6 p5 Q, j! O: g0 |: _9 D. I$ m; U - __IO uint32_t CR; /*!< DMA2D Control Register, Address offset: 0x00 */
* A" T; {8 ^! G1 X9 i - __IO uint32_t ISR; /*!< DMA2D Interrupt Status Register, Address offset: 0x04 */
6 \3 I" ]- B1 o$ [4 O3 {: i - __IO uint32_t IFCR; /*!< DMA2D Interrupt Flag Clear Register, Address offset: 0x08 */ u* W A: I, ^- o6 D
- __IO uint32_t FGMAR; /*!< DMA2D Foreground Memory Address Register, Address offset: 0x0C */
7 D2 y B2 D, m0 u A/ K - __IO uint32_t FGOR; /*!< DMA2D Foreground Offset Register, Address offset: 0x10 */' ? w: p) p* k9 @$ N* w% T
- __IO uint32_t BGMAR; /*!< DMA2D Background Memory Address Register, Address offset: 0x14 */
& z4 u% ^- a. O1 t4 t - __IO uint32_t BGOR; /*!< DMA2D Background Offset Register, Address offset: 0x18 */2 D; G7 ^- N' P7 C4 D# Q
- __IO uint32_t FGPFCCR; /*!< DMA2D Foreground PFC Control Register, Address offset: 0x1C */. [% t3 \2 O5 Z$ A
- __IO uint32_t FGCOLR; /*!< DMA2D Foreground Color Register, Address offset: 0x20 */
9 G% E4 N* p0 E( @ J7 Y6 h1 ? - __IO uint32_t BGPFCCR; /*!< DMA2D Background PFC Control Register, Address offset: 0x24 *// w- x, B5 V2 o
- __IO uint32_t BGCOLR; /*!< DMA2D Background Color Register, Address offset: 0x28 */% D; D" | f2 M! Q3 g6 _9 T
- __IO uint32_t FGCMAR; /*!< DMA2D Foreground CLUT Memory Address Register, Address offset: 0x2C */
8 P( L& h, C2 W! s: D& ^( x - __IO uint32_t BGCMAR; /*!< DMA2D Background CLUT Memory Address Register, Address offset: 0x30 */
J* z' m! @; k5 s6 }/ X: b - __IO uint32_t OPFCCR; /*!< DMA2D Output PFC Control Register, Address offset: 0x34 */& A. F5 g& t$ a7 z. f) K' X3 j
- __IO uint32_t OCOLR; /*!< DMA2D Output Color Register, Address offset: 0x38 */9 o/ H6 S* C9 M+ t, V3 s1 E
- __IO uint32_t OMAR; /*!< DMA2D Output Memory Address Register, Address offset: 0x3C */7 S9 W* ^6 q# K1 e5 |
- __IO uint32_t OOR; /*!< DMA2D Output Offset Register, Address offset: 0x40 */$ S w$ i/ }& P
- __IO uint32_t NLR; /*!< DMA2D Number of Line Register, Address offset: 0x44 */
8 \# W% c/ }+ F W7 [ - __IO uint32_t LWR; /*!< DMA2D Line Watermark Register, Address offset: 0x48 */6 K, S+ T3 H6 `1 D: d7 W
- __IO uint32_t AMTCR; /*!< DMA2D AHB Master Timer Configuration Register, Address offset: 0x4C */
( n0 G3 R1 n0 p8 N$ Z, I - uint32_t RESERVED[236]; /*!< Reserved, 0x50-0x3FF */
& X# T+ }; d F9 R, P8 _8 U7 q j - __IO uint32_t FGCLUT[256]; /*!< DMA2D Foreground CLUT, Address offset:400-7FF */
4 A, P! K% N: }( J2 O - __IO uint32_t BGCLUT[256]; /*!< DMA2D Background CLUT, Address offset:800-BFF */0 v8 J5 K5 V0 p( [5 {+ \6 ~
- } DMA2D_TypeDef;
- r& T3 c @5 Y' e- m- N4 b
复制代码
) O: ` Z& N6 \% _8 X
8 I7 E/ L3 J) v) g__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏: C; d* s, {6 O6 b9 K3 S; @ T
, N! M. [2 c* e Y- #define __O volatile /*!< Defines 'write only' permissions */
) c, I) }8 P L) z2 H - #define __IO volatile /*!< Defines 'read / write' permissions */
复制代码 5 c4 V! E* a) g% ^0 ? R( g
/ f7 V! [5 A: f; m
' x! z+ C1 c# K) Q2 O; [
下面我们再看DMA2D的定义,在stm32h743xx.h文件。5 x. ^3 j7 s# m+ r/ p3 E
s7 M4 e- d+ M' v
- #define PERIPH_BASE ((uint32_t)0x40000000)
; ?- H0 N$ s& K3 l/ ? - #define D1_AHB1PERIPH_BASE (PERIPH_BASE + 0x12000000)
( Z) n8 Q' y, P- y" i3 o& V - #define DMA2D_BASE (D1_AHB1PERIPH_BASE + 0x1000)
" L: t7 e0 b8 \6 l - #define DMA2D ((DMA2D_TypeDef *) DMA2D_BASE) <----- 展开这个宏,(DMA2D_TypeDef *) 0x52001000
* R; Y9 J+ b1 ?) N) ^
复制代码 7 x+ H# D# c4 @/ p; J8 p9 E2 Z4 g4 L: ~
% X7 k# Q% c6 i3 I我们访问DMA2D的ISR寄存器可以采用这种形式:DMA2D->ISR = 0。 B% ~; @/ T" e. I% P. D' \
1 U. {3 `8 _, ~55.3.2 DMA2D参数初始化结构体DMA2D_InitTypeDef
6 r( J2 ]" v$ S. m! x+ R此结构体用于配置DMA2D的基本参数,具体定义如下:, e% ]& k/ a' b+ I" j$ B
0 ]. z( r/ P5 e5 }4 b) L! [! _
- typedef struct
; r' |& E+ Z% S! g* X5 r3 K0 M - {% i; A$ d, A2 a, M. B. Z
- uint32_t Mode;
8 @- d% @. j6 e/ A - uint32_t ColorMode; ( E8 t. a. D8 R0 o; e
- uint32_t OutputOffset; # u: f8 b) z: X# ~
- uint32_t AlphaInverted; 0 N4 w- H2 j4 s+ c" m+ s
- uint32_t RedBlueSwap; / p z( f( o9 c+ ~
- } DMA2D_InitTypeDef;
复制代码
6 G9 X0 [$ g3 F4 n4 r! C; o下面将这几个参数逐一为大家做个说明:
/ {% R$ m5 p1 [$ Q# Y$ e+ `+ d( F0 A3 x) O) @ O% X! Q
uint32_t Mode# U9 ^# C" S$ ^
此参数用于设置DMA2D的传输模式,具体支持的参数如下:
: ^7 \: U$ O* k
& l1 i" G. s" }- #define DMA2D_M2M ((uint32_t)0x00000000U) /*存储器到存储传输模式 */
" } Y9 r2 O- o4 Y5 u* y: n - #define DMA2D_M2M_PFC DMA2D_CR_MODE_0 /*存储器到存储器传输模式,并执行FPC像素格式转 */
! `8 a& M8 i! q+ R$ A/ h* E( Z) } - #define DMA2D_M2M_BLEND DMA2D_CR_MODE_1 /* 存储器到存储器模式,并执行像素格式转换和混合 */& K2 d) h* U* v' o
- #define DMA2D_R2M DMA2D_CR_MODE /* 寄存器到存储器传输模式 */
复制代码
+ n& ~( @* B. n" ?/ q, j9 g/ O) J* @# F) |) ]2 W
( @, }1 Y! f* N
uint32_t ColorMode
* \0 G4 D; w1 G3 S# T* N$ a0 k9 ?+ f' L% i此参数用于设置DMA2D的输出颜色格式,具体支持的参数如下:
6 Y4 @4 S2 r6 ?1 `! V- 2 \' Y9 R" `/ _7 O. X$ I7 E W! U
- #define DMA2D_OUTPUT_ARGB8888 ((uint32_t)0x00000000U) /* ARGB8888 */0 T7 ~3 E! ^; Y4 V( t% t
- #define DMA2D_OUTPUT_RGB888 DMA2D_OPFCCR_CM_0 /* RGB888 */
1 E3 _+ q9 r: S, a& l - #define DMA2D_OUTPUT_RGB565 DMA2D_OPFCCR_CM_1 /* RGB565 */
8 ^8 J9 X& _$ V8 H - #define DMA2D_OUTPUT_ARGB1555 (DMA2D_OPFCCR_CM_0|DMA2D_OPFCCR_CM_1) /* ARGB1555 */
6 M( q! @+ P- I+ ? - #define DMA2D_OUTPUT_ARGB4444 DMA2D_OPFCCR_CM_2 /* ARGB4444 */
复制代码 4 y3 r7 [) A" B5 Z
uint32_t OutputOffset* {/ c, Q6 N! u( u" ]
此参数用于设置输出位置的偏移值,参数范围0x0000到0x3FFF。
5 [) j( w W! K" _' s; t
3 N6 W0 l) @5 v L uint32_t AlphaInverted: n# d" `, q' Q3 d5 p3 J' p6 k
此参数用于设置DMA2D的输出颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下: 7 @+ M. i/ L2 f& \7 {
3 |3 Z2 N' \0 G- J
- #define DMA2D_REGULAR_ALPHA ((uint32_t)0x00000000U) /* 正常输出 */
4 W& j" ^5 B! X6 ]% Q& v, y - #define DMA2D_INVERTED_ALPHA ((uint32_t)0x00000001U) /* 反转输出 */
复制代码
6 s7 {6 s ], }$ w# m uint32_t RedBlueSwap% F4 h2 p# u% p5 M: n$ d/ W; E: f/ V
此参数用于设置DMA2D的输出颜色格式中R通道和B通道的交换,具体支持的参数如下:0 w8 h. ^$ I) A+ c) Q* p
- #define DMA2D_RB_REGULAR ((uint32_t)0x00000000U) /* 不交换(RGB or ARGB) */5 B ?" @" K$ J3 [2 v, Z0 H
- #define DMA2D_RB_SWAP ((uint32_t)0x00000001U) /* 交换(BGR or ABGR) */
5 Z+ r* z7 c% |, m
复制代码 3 ?' `7 u5 P J0 h
55.3.3 DMA2D的图层结构体DMA2D_LayerCfgTypeDef- I1 v3 C! ^- r; Q
此结构体用于配置前景色和背景色。 c r' l0 Q9 f( Z- y) o
9 O& e( J( y+ q! h+ C) d/ t
- typedef struct
. A, ?6 ~% u& m; ? - {
& Y8 j. ]* Q! M/ a5 J - uint32_t InputOffset; ; e: c1 Z; o9 k6 M; d# j; }
- uint32_t InputColorMode;
& H! Z- X! f7 \" E3 h# L6 n4 _ - uint32_t AlphaMode;
8 r2 A% u% p4 s' }; ~7 t - uint32_t InputAlpha; & Q0 l) _7 @ ^% a5 f
- uint32_t AlphaInverted;
' b- c$ g. x) v) n# Q" h% a( \4 ` - uint32_t RedBlueSwap; ' J3 t' y; A5 F8 k5 O0 l' b4 W
- uint32_t ChromaSubSampling;: X& l) J; z( |+ }
- } DMA2D_LayerCfgTypeDef;
复制代码
- B6 B; P7 |' h( d
) d/ A) _2 e& ^$ u1 P, g% Y
7 ?9 ?' W0 {: a5 j7 K( x, ]/ I- o下面将这几个参数逐一为大家做个说明。
7 A$ `( c* W. v% O( Y ~3 j9 ~9 q7 C
uint32_t InputOffset
& ?6 ^" K- |* q" }6 T设置前景色或者背景色的输入偏移,范围0x000到0x3FFF。
+ F0 W, X$ y% {0 d$ Q6 _3 E" |; H: @$ W" K1 N0 k% S5 Q
uint32_t InputColorMode
) G( M) v# b. X( |2 A5 x设置前景色或者背景色的输入颜色格式,具体支持的参数如下:
+ T8 [ i; m! y; m* s
H9 v2 I4 A& g- #define DMA2D_INPUT_ARGB8888 ((uint32_t)0x00000000U) /* ARGB8888 */" V$ }! G y' j
- #define DMA2D_INPUT_RGB888 ((uint32_t)0x00000001U) /* RGB888 */8 I0 [6 i) m. _* Y) N% M
- #define DMA2D_INPUT_RGB565 ((uint32_t)0x00000002U) /* RGB565 */3 H! q7 i2 @: P5 ^6 B7 t
- #define DMA2D_INPUT_ARGB1555 ((uint32_t)0x00000003U) /* ARGB1555 */
3 P: n- M8 @2 z; r" P2 k' e/ r - #define DMA2D_INPUT_ARGB4444 ((uint32_t)0x00000004U) /* ARGB4444 */( B: h5 [3 j; ^1 q* Q% P
- #define DMA2D_INPUT_L8 ((uint32_t)0x00000005U) /* L8 */
/ p& P" c! X" C( k v - #define DMA2D_INPUT_AL44 ((uint32_t)0x00000006U) /* AL44 */
" W+ h+ j/ |: R/ |& j! I - #define DMA2D_INPUT_AL88 ((uint32_t)0x00000007U) /* AL88 */
5 r( c" N$ j% M+ v3 z# _7 F" K; u) D - #define DMA2D_INPUT_L4 ((uint32_t)0x00000008U) /* L4 */$ B- S6 n1 W" _2 Q. J/ {
- #define DMA2D_INPUT_A8 ((uint32_t)0x00000009U) /* A8 */
, j# ^! Z7 v; c. G: w. H - #define DMA2D_INPUT_A4 ((uint32_t)0x0000000AU) /* A4 */* H8 c# w, z0 w6 k+ g
- #define DMA2D_INPUT_YCBCR ((uint32_t)0x0000000BU) /* YCbCr */
! @$ P; }- t# C( r7 @
复制代码 - G# e( ?) P2 D+ G5 w# x
' b( P5 p: T U5 R. O; g! I( V uint32_t AlphaMode6 m# z B- ], G! F+ [$ d
设置前景色或者背景色的Alpha模式,具体支持的参数如下:6 x, |+ K, s+ F$ y: s+ T
# p! Q8 A! L8 `+ s9 X1 s5 o1 A
- #define DMA2D_NO_MODIF_ALPHA ((uint32_t)0x00000000U) /* 不修改Alpha通道值 */9 w' u1 @1 W( X# U3 i
- #define DMA2D_REPLACE_ALPHA ((uint32_t)0x00000001U) /* 用新设置的Alpha值替换原始Alpha值 */( N! ?2 M& J+ J- ~7 l# _
- #define DMA2D_COMBINE_ALPHA ((uint32_t)0x00000002U) /* 用新设置的Alpha值与原始Alpha值的乘积替换原始Alaha值*/
复制代码
' c& p2 e# w! ]. R4 |9 ^ U$ Y, W$ \) N; \7 l. K
7 E4 F4 S- p5 I& K" x
uint32_t InputAlpha
/ C2 y, l7 U: ^5 \# e设置前景色或者背景色的Alpha值,范围0x00到0xFF,如果颜色格式是A4或者A8,那么此参数的范围是0x00000000到0xFFFFFFFF,标准的ARGB8888格式。3 _5 Y+ B" _9 G8 b
: n, _! N& g6 p6 @. }7 w
uint32_t AlphaInverted; B8 |: i y w9 Q* x
设置前景色或者背景色的输入颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下: 1 K4 k. R/ j$ I2 w7 h; N& h
- #define DMA2D_REGULAR_ALPHA ((uint32_t)0x00000000U) /* 正常输出 */
* X2 k2 a3 p6 g' c0 r+ K4 ? - #define DMA2D_INVERTED_ALPHA ((uint32_t)0x00000001U) /* 反转输出 */
复制代码 H! v" p. C4 C' {& A3 D
7 h. o" {# g3 F. X: l6 a: Q
" C) `2 f8 Y: a& k; @$ L0 f* o uint32_t RedBlueSwap- J1 z6 F1 q% B: q+ N: N |
设置前景色或者背景色颜色格式中R通道和B通道的交换,具体支持的参数如下:; P+ D9 D' Z9 b
# \2 Q! x1 n3 n0 d- #define DMA2D_RB_REGULAR ((uint32_t)0x00000000U) /* 不交换(RGB or ARGB) */3 c5 ^( G; \! n" ]
- #define DMA2D_RB_SWAP ((uint32_t)0x00000001U) /* 交换(BGR or ABGR) */1 T8 y4 H" P2 K/ g" e$ T/ D5 R& L
复制代码
! L" S) a/ d% Q+ X, H& P
0 Z/ B/ a5 B; r% p8 n0 K& a uint32_t ChromaSubSampling4 |. f3 G4 L4 P* H" S
设置前景色或者背景色中YCbCr 颜色模式的采样格式,具体支持的参数如下:: C! a* k# x% U# D: Y& i3 W
" J8 w: E$ J6 S: F- #define DMA2D_NO_CSS ((uint32_t)0x00000000) /* 4:4:4 */8 J- N7 H2 u, F0 _) c* a4 t
- #define DMA2D_CSS_422 ((uint32_t)0x00000001) /* 4:2:2 */
4 D- ]( S1 A/ ~ - #define DMA2D_CSS_420 ((uint32_t)0x00000002) /* 4:2:0 */
$ c5 r: {, \( z# i
复制代码 + W$ Z) G4 b$ S' e5 e' I0 m' |+ v
, R4 t# W+ `; v; c# h3 K55.3.4 DMA2D句柄结构体DMA2D_HandleTypeDef
7 u1 F& a2 t( c( QHAL库在DMA2D_TypeDef, DMA2D_InitTypeDef和DMA2D_LayerCfgTypeDef的基础上封装了一个结构体DMA2D_HandleTypeDef,定义如下:
5 }& \# n2 l9 T/ B: s
3 [/ \) h# f1 B' r, J7 D7 e- typedef struct __DMA2D_HandleTypeDef" X7 B8 r- y* A4 L5 Z
- {
& z! P: r: z: `7 W - DMA2D_TypeDef *Instance; & q' O. L9 p+ z: {8 s3 P
- DMA2D_InitTypeDef Init; 4 p- S( [0 ]# ^7 \
- void (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d); $ I$ U: H& t7 R( m' U( L
- void (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d); 7 C' n# j$ R2 @1 C2 e8 w6 D4 X3 n
- DMA2D_LayerCfgTypeDef LayerCfg[MAX_DMA2D_LAYER];
1 x+ w& I7 M6 v$ E6 ]/ ^ - HAL_LockTypeDef Lock;
. Q- z4 Q4 {- q2 i; ]! K- S o8 F - __IO HAL_DMA2D_StateTypeDef State;
% D4 x; u1 Z. f/ x! E+ [/ Y - __IO uint32_t ErrorCode; } DMA2D_HandleTypeDef;
复制代码
5 n8 F |9 w* n. k8 u3 M/ }
$ u3 ?5 U4 r# `9 Y; |' R" X' o7 ]
* w6 e* H. {: X下面将这几个参数逐一做个说明。# X1 O, @8 {& m, g! {
! f4 i8 b' ]6 j+ Y$ k
DMA2D_TypeDef *Instance
) U) D& b4 e$ M3 l* M这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。 R9 M6 f6 w: u' r
! M" b: E/ H: s0 P" e3 @ DMA2D_InitTypeDef Init; 4 H; S. R7 s7 s8 |: U, G' {) v& e
这个参数是用户接触较多的,用于配置DMA2D的基本参数,详见本章3.2小节。
$ a2 B: v& S4 ]+ u$ r1 l+ F! G/ O' J1 w8 ]% l, }, V
void (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);
1 {6 W& U+ e* B1 r# z f" v void (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);
) x3 L( L2 f) b mDMA2D中断服务程序里面执行的回调函数,一个是传输完成回调,另一个是传输错误回调。$ Z+ C8 c- F# I5 J9 ]
: q' E& j/ u" S' f, ^# y8 n
DMA2D_LayerCfgTypeDef LayerCfg[MAX_DMA2D_LAYER]
- M. ~5 |' x$ j/ ^ w这个参数用于前景色和背景色的设置,MAX_DMA2D_LAYER=2,详见本章3.3小节。/ q' G5 g* @, L* `
. f7 ]5 G: z+ V1 g1 r, E
HAL_LockTypeDef Lock
5 \, L2 w* K& R__IO uint32_t State;6 [+ U7 D$ i( Z' k' i+ {% J
! ~' J+ r0 j2 Y+ G
__IO uint32_t ErrorCode" g+ o: P- {8 K0 o
7 r, Q) J0 V& m/ `- a这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置DMA2D通信状态,而ErrorCode用于配置代码错误。
. T, ~. ]4 M& O- m+ n& g* o1 [3 @+ M
55.3.5 DMA2D初始化流程总结
2 C/ |; w# W; Z8 z0 X F对于DMA2D来说,其实不需要初始化流程,每个功能都可以直接封装出一个函数来,下个章节会为大家专门讲解,也是实际项目比较推荐的方式。3 E1 R# E2 A! n
/ X) N# h% R" A1 r55.4 源文件stm32h7xx_hal_dma2d.c
& ~* F+ l% [1 \' v/ H5 t这里把我们把如下几个常用到的函数做个说明:
5 W. L' h Q& P0 E- @
( O' E; T# u$ ]: N, B3 g HAL_DMA2D_Init
. t n+ v$ ~: N8 c0 s6 ` HAL_DMA2D_ConfigLayer
5 O0 l. k& \& J/ ~: F HAL_DMA2D_Start_IT8 V9 y5 j; V8 n
HAL_DMA2D_BlendingStart_IT2 q3 a4 @5 n: e9 P% F
55.4.1 函数HAL_DMA2D_Init
) v5 X. b8 ?6 E/ p$ \1 D6 v7 l函数原型:
, ^7 {. p. [: U0 g# I- Q( W. g" L) ]3 t0 J& O
- HAL_StatusTypeDef HAL_DMA2D_Init(DMA2D_HandleTypeDef *hdma2d); b6 Q' M5 K3 }) e: V
- { # K, C: O5 L# P/ ~
w9 N$ X1 R4 F2 G# Q- /* 检测参数是否有效 */, X$ I) v0 k5 [2 D- {# r
- if(hdma2d == NULL)4 X+ p( _. A8 H" [9 j6 r
- {
: v- A/ s! J% Y0 Q) u - return HAL_ERROR;
' ~" O, F/ ~! c) A1 F% @; R - }
1 O7 a/ h! i3 c. j- K
$ C- D6 n; Z! ]( S2 g- /* 检测函数形参 */6 x# M# E, ^1 C1 ~
- assert_param(IS_DMA2D_ALL_INSTANCE(hdma2d->Instance));' o. o7 M' n7 p1 T# T1 \
- assert_param(IS_DMA2D_MODE(hdma2d->Init.Mode));: H5 }& H7 b4 a* ^5 y
- assert_param(IS_DMA2D_CMODE(hdma2d->Init.ColorMode));: c5 u- ^1 _, x$ V/ \) j
- assert_param(IS_DMA2D_OFFSET(hdma2d->Init.OutputOffset));; B* }2 R: J. s2 U
# @$ h" c1 J9 c# l- if(hdma2d->State == HAL_DMA2D_STATE_RESET)/ m0 l7 s1 K! X* D6 ], I
- {( R: e+ t. ~& p: r2 \
- hdma2d->Lock = HAL_UNLOCKED;
4 Q' q3 Q4 t. t# u2 e# J - /* 初始化GPIO,NVIC等 */
' N: F: Y9 u/ ^- D9 f6 t - HAL_DMA2D_MspInit(hdma2d);; b. `. o7 n/ z' f+ Q, Z
- }
0 [+ L& T) \2 \1 v$ b y2 F
# X5 ]& x ~( D% V& A# y- /* 设置DAM2D外设状态 */; d$ b s3 [7 a( t. j/ ~
- hdma2d->State = HAL_DMA2D_STATE_BUSY;
8 D6 s) V1 _8 P, Z% K% S& X, g
' y5 z/ }6 A5 @7 X" S9 _+ n* }) Y- /* 设置DAM2D工作模式 -------------------------------------------*/" B1 D% Z9 j. b1 C( x% r# N% X9 j# O
- MODIFY_REG(hdma2d->Instance->CR, DMA2D_CR_MODE, hdma2d->Init.Mode);' p8 Y, i5 u+ A6 w1 z- _
1 J0 [* e, ?5 \- G$ ~, g h: I- /* 设置输出颜色格式 ---------------------------------------*/
8 l, ^# g' i- W0 r% o% h - MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_CM, hdma2d->Init.ColorMode);
: T8 ^. ?* `- v8 R% l- K) v5 A - 7 b0 a% W9 M2 ], r5 R: ^
- /* 设置输出偏移 ------------------------------------------*/ 3 }$ K& p0 ]( `) Z. A1 w
- MODIFY_REG(hdma2d->Instance->OOR, DMA2D_OOR_LO, hdma2d->Init.OutputOffset);
8 A) K9 Y2 D0 `3 U! {7 Z - 0 Z8 q- h2 @; R; K
- /* 设置输出颜色格式中的Alpah值反转 */5 o4 ?5 o0 b9 D! h* p
- MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_AI, (hdma2d->Init.AlphaInverted << DMA2D_POSITION_OPFCCR_AI));
% O) e' o( U/ S3 \+ C3 g - % v3 s/ w J0 R3 k% ~
- MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_RBS,(hdma2d->Init.RedBlueSwap << DMA2D_POSITION_OPFCCR_RBS));
) M3 _5 c7 G: D# \* x0 K4 ]& ~
# V3 s' V s/ c# {- * C2 |1 {7 l) a r/ U+ |) d
- /* 无错误 */
' j4 S9 f1 s k) B - hdma2d->ErrorCode = HAL_DMA2D_ERROR_NONE;/ I3 Y: D8 E7 l, ?& v5 ?
) X4 v- K5 k Y$ {! \8 K- x5 c- /* DAM2D就绪 */" t5 U( v, c( C5 {" G0 N
- hdma2d->State = HAL_DMA2D_STATE_READY;5 u( e2 [: Y9 l
* m6 c4 r) i ^9 k* |; {; k- return HAL_OK;
# }) `/ j, N6 G6 f1 C* @ - }
复制代码
, k& ~ ]% y% s r! Z! w2 i% B# j; W6 Y3 t. _3 u: z0 I8 ^5 ]
函数描述: C& _( _9 w, j1 o
3 O# ^6 J) C/ u
此函数用于初始化DMA2D的工作模式和输出颜色格式。% x8 |7 p7 Q1 w _7 A
9 o0 J' ~4 K' _* D1 Q& p- Q) @7 I
函数参数:9 m" t0 m& B1 _) u2 A: u3 E
; K) h! L; h0 {1 p' l: V$ v$ m) [
第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。
+ ?) c$ v0 j3 V5 R2 O 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。7 c& z7 L* ^' M; n* W( f: I2 p( \3 N7 x, s
注意事项:
- J" N& }0 [& F0 |/ ^4 q( b
' v# r3 f4 P3 K函数HAL_DMA2D_MspInit用于初始化DMA2D的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
4 i; X" J6 U7 j/ q. C; S5 H如果形参hdma2d的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量DMA2D_HandleTypeDef Dma2dHandle。
% O/ N- c; N7 Q$ a& ~4 T对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_DMA2D_STATE_RESET = 0x00U。$ |' v: ~# ~5 Z4 b
- ^) O$ i6 n) x( A0 x8 [% _: G5 P- A解决办法有三, }: \* B( l! E6 o. i- y0 x, e+ N
' v' Z8 g" p6 X$ a; j- k方法1:用户自己初始DMA2D底层。
. R6 Y( u o. r' `' G( S# Z0 Y r
, C/ C* q# t9 E2 p- V方法2:定义DMA2D_HandleTypeDef LtdcHandle为全局变量。
5 X7 u5 G4 A5 q5 k; c
3 l+ N$ s) e) W* o, u3 A! m5 N方法3:下面的方法; l& q- f1 e# }0 `8 k* e
4 q' i" u8 G P/ B$ O6 z1 z( J
- if(HAL_DMA2D_DeInit(&Dma2dHandle) != HAL_OK)
; v; ~' ?" q* o: r - {! D" a, @) N, [8 n
- Error_Handler();
- y: L6 {- Z; W# Q - }
6 F! f* ` T% l! @ - if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK): o* j0 i$ k3 }- \4 x. l. D8 F
- {. B3 C& a2 B W: `) |1 h* y
- Error_Handler();' r& X6 R/ A5 \; Q8 x( ]
- }
复制代码
! r/ |8 M, {0 K9 [
$ r/ u; b- P7 O, N6 Y* q( _% T. u. A! m/ [0 g, O. S
使用举例:
+ k3 B; \: f9 f+ Q8 A4 P5 L: d* t {3 N0 i1 q, V& h+ B
- DMA2D_HandleTypeDef Dma2dHandle;
8 ^* @5 @2 Q! x
0 e3 h$ {; {+ g3 o5 @# P; I6 a' N- /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/# @) q7 R3 d% F9 n3 u
- Dma2dHandle.Instance = DMA2D;
' ~% v5 A; P+ m) L/ U7 K) d# U
) f; p$ s( S: r c- G, _- Dma2dHandle.Init.Mode = DMA2D_M2M; /* 存储器到存储器模式 */
# B3 S) H2 K5 o! X9 ]4 ?9 v) W - Dma2dHandle.Init.ColorMode = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */' K/ t; B8 o( w, @3 Y
- Dma2dHandle.Init.OutputOffset = 0x0; /* 无输出偏移 */2 s- n4 \2 f$ ?' s5 S7 ~: Q
- Dma2dHandle.Init.RedBlueSwap = DMA2D_RB_REGULAR; /* 输出颜色的R/B通过不切换 */
$ g2 X- H1 G. m0 V0 N' |1 W - Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA; /* 输出颜色的Alpha通道数值不翻转 */3 f# j2 }2 C) d) N
- 5 c& {- h7 d: C6 Q: u5 k! {
- /*##-2- DMA2D 回调函数配置 ######################################*/; `9 _2 n% ^" |3 K# V3 U; Y6 T
- Dma2dHandle.XferCpltCallback = TransferComplete;, _: U8 r/ w4 r; ]
- Dma2dHandle.XferErrorCallback = TransferError;# L: ]3 T2 s0 f6 x7 R. |; q, [
- , a' G: P6 @# b- ?- h8 y9 `2 i8 X. H
- /*##-3- 前景层配置 ###########################################*/$ m" t0 A) }8 V( N
- Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA; /* 保持输入颜色格式中的Alpha值 */
4 Y) ~3 j( e2 G9 A) y: h' p - Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF; /* 完全不透明 */ p7 v1 S$ N" l' q- s/ h7 R
- Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */, i' @7 Z" W- t4 _$ h- P; B& @7 E
- Dma2dHandle.LayerCfg[1].InputOffset = 0x0; /* 输入无偏移 */) T( t i6 D l' T
- Dma2dHandle.LayerCfg[1].RedBlueSwap = DMA2D_RB_REGULAR; /* 输入颜色的R/B通过不切换*/
/ G) }" E+ }6 q& r4 D - Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA; /* 输入颜色的Alpha通道数值不翻转*/
) d+ f }$ k! P5 V: n8 c8 r7 M
1 s, j3 r+ V( ~; i$ X3 M! a$ A
v" V- |+ K, T7 Q6 K0 g& G& F L" I- /*##-4- DMA2D 初始化 ###############################################*/
) {3 Q2 R& t4 Z) U' j' D$ p6 K - if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
1 |: O' Z5 M5 P7 i0 ]5 ]! o - {
) }5 a# _6 i8 [) {. W1 f - Error_Handler();- @8 K, t S& u. }9 e* P- s
- }
复制代码 1 a# F2 p; M( Z
2 ~( T4 I; D4 l) _
) n& C0 N; h& ^; `55.4.2 函数HAL_DMA2D_ConfigLayer- `. a+ A$ {; Y
函数原型:( x) Z# k. x; X4 j. m" Y+ R
0 R0 a! U6 S# G
- HAL_StatusTypeDef HAL_DMA2D_ConfigLayer(DMA2D_HandleTypeDef *hdma2d, uint32_t LayerIdx). F1 b ?( s7 F% v1 B6 Q' X
- { . D. y+ I" t9 S: ]) e
- DMA2D_LayerCfgTypeDef *pLayerCfg = &hdma2d->LayerCfg[LayerIdx];3 j) W. d9 p/ ^, B5 k
- 5 U R+ L5 o* x0 Z, l& q- \* k
- uint32_t regMask = 0, regValue = 0;& O6 q9 {5 l& U* ~
, I' {8 A. _+ q- ^0 g9 Y1 i- /* 检查参数 */3 i7 `4 U6 G2 p
- assert_param(IS_DMA2D_LAYER(LayerIdx)); 0 i! e, q6 w0 b* L" q
- assert_param(IS_DMA2D_OFFSET(pLayerCfg->InputOffset));
7 J/ K8 ?8 E+ E7 z - if(hdma2d->Init.Mode != DMA2D_R2M)
$ @6 k; G5 }; _+ I) e6 n0 [5 A! ~# j - { 4 O4 j7 N( v/ Y4 R# E/ K( O3 m
- assert_param(IS_DMA2D_INPUT_COLOR_MODE(pLayerCfg->InputColorMode));
4 R" h+ o$ {, |/ H - if(hdma2d->Init.Mode != DMA2D_M2M)
1 M/ j# | j1 n - {
. U5 @0 s, z6 v0 p1 {7 Y - assert_param(IS_DMA2D_ALPHA_MODE(pLayerCfg->AlphaMode));; v* c/ @- t- O$ C; J3 S' w. q
- }
. c6 p4 a! ^; H4 v, o) h - }
! d) I3 I) N$ m - i% `# k0 O( B! |! j& d8 N' A9 i1 B
- /* 上锁 */. ~, X0 K8 n- w( N4 @9 i# `: M
- __HAL_LOCK(hdma2d);
. a' E) |6 N# \ - # C7 k* c* D! I* q
- /* 设置DMA2D外设状态 *// L+ g' P, @4 \+ Y0 K
- hdma2d->State = HAL_DMA2D_STATE_BUSY; . [- ]0 t8 g2 W
, ]/ d2 l |* X r" H2 \/ Z- /* 准备好背景层或者前景层FPC寄存器配置参数*/8 ^8 T( a: v& w
- regValue = pLayerCfg->InputColorMode | (pLayerCfg->AlphaMode << DMA2D_POSITION_BGPFCCR_AM) | \
8 p' V+ D# A8 Z- [ - (pLayerCfg->AlphaInverted << DMA2D_POSITION_BGPFCCR_AI) | \
7 F& f* r) J$ z - (pLayerCfg->RedBlueSwap << DMA2D_POSITION_BGPFCCR_RBS);
) y/ ^& P( E, n. C' `/ v7 y" v5 m
: n. C, O- i2 n4 H2 K- regMask = DMA2D_BGPFCCR_CM | DMA2D_BGPFCCR_AM | DMA2D_BGPFCCR_ALPHA | DMA2D_BGPFCCR_AI | DMA2D_BGPFCCR_RBS;, u. y& y2 [( S
- ! y- E9 N; _6 @3 |
- if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8)); h1 I5 t" n+ \0 u
- { l3 W' l/ o& P4 h7 k7 T v, ?
- regValue |= (pLayerCfg->InputAlpha & DMA2D_BGPFCCR_ALPHA);
, G9 \& \4 {) O4 q) e - }2 X5 |" v0 o8 j: x* H3 x3 ^
- else
0 v4 l' |" m, e0 t* M1 [5 G6 F - {+ Y0 t' A( B0 B. n
- regValue |= (pLayerCfg->InputAlpha << DMA2D_POSITION_BGPFCCR_ALPHA);% G" Y" r0 } T+ _9 f; u
- }
2 K8 P0 C0 k8 r7 ?2 N5 Z
$ y$ m" ?( t+ o, i$ Q- /* 配置背景层 */- `5 y, S( V/ L* Y9 T2 \! |
- if(LayerIdx == 0)/ |8 M: O; Q$ }) G: A+ ?
- {, x$ h" o$ N$ U2 }& O
- /* DMA2D BGPFCCR 寄存器 */
7 r8 X+ d/ B7 J- y4 u4 W - MODIFY_REG(hdma2d->Instance->BGPFCCR, regMask, regValue);* s& P* c: f6 q" O$ q. p0 y" L9 A, c
- 3 w' t8 W+ p, n3 Q: w Y# K( U3 s4 p
- /* DMA2D BGOR 寄存器 */ * b& w# F& ^" p
- WRITE_REG(hdma2d->Instance->BGOR, pLayerCfg->InputOffset);
0 @: r- S) P$ n: C. x/ [ - 6 I, s& k3 J' \# U4 r
- /* DMA2D BGCOLR 寄存器 */
; i- x f; v* f; r - if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))1 a' q7 W$ i0 f2 N u
- { 8 ?9 X7 C0 O4 `6 \/ p
- WRITE_REG(hdma2d->Instance->BGCOLR, pLayerCfg->InputAlpha & - P$ W2 s, `- x5 ]: p4 |3 p* v
- (DMA2D_BGCOLR_BLUE|DMA2D_BGCOLR_GREEN|DMA2D_BGCOLR_RED));1 x4 E# o( `" r6 N4 P# P
- }
0 L: P) S/ J, ]% g+ p - }* L1 [ J" f' _ E8 F" r) e
- /* 配置前景层 */
* U: t+ R" B( |. w: H - else, U. G) x& i0 m& q l) ^3 n
- {* R! A! F- P5 e+ o9 m, z, M
- if(pLayerCfg->InputColorMode == DMA2D_INPUT_YCBCR)( x, \% [9 N, @$ L2 ?5 }" Q x
- {+ k2 f1 @) w- I
- regValue |= (pLayerCfg->ChromaSubSampling << DMA2D_POSITION_FGPFCCR_CSS);; x' v5 H* \+ n! y
- regMask |= DMA2D_FGPFCCR_CSS;) R% R) ^: f, ], u$ b/ H
- }& M! j2 b* a- X {8 `/ o% |
$ J& `9 R8 ?0 v9 T, p- /* DMA2D FGPFCCR 寄存器 */
! ~ k: ]2 F0 g1 r' ^1 p - MODIFY_REG(hdma2d->Instance->FGPFCCR, regMask, regValue);& Y$ z+ L( u, Q
- ! m% \$ |4 X/ Z* p8 V+ |" z
- /* DMA2D FGOR 寄存器 */( n+ Z. C1 s: x$ K" N# i3 x
- WRITE_REG(hdma2d->Instance->FGOR, pLayerCfg->InputOffset);
6 J" E0 E- v4 E7 J0 l - & r. v/ T% H/ b+ k* B$ ^! k2 G7 O
- /* DMA2D FGCOLR 寄存器 */ $ t! g+ ~; H) p) x8 b
- if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))# k5 s# _* q; r& P0 A! D5 t% A
- {2 ], `/ ?. i! }$ f+ k0 U$ Q Q/ f
- WRITE_REG(hdma2d->Instance->FGCOLR, pLayerCfg->InputAlpha & + t- y5 G0 H7 ~! `# L
- (DMA2D_FGCOLR_BLUE|DMA2D_FGCOLR_GREEN|DMA2D_FGCOLR_RED));
8 H$ Z. ~2 D& A2 ]2 y - }
) f4 @1 N, s- b8 ^" j, k - } ' M% I' M* O' I, T. d
- /* DMA2D就绪 */
, F. n9 n! x* f% S5 I1 X z - hdma2d->State = HAL_DMA2D_STATE_READY;
1 s u2 B s x
/ b) B: T+ `% U: E$ f+ k6 i4 g4 g- /* 解锁 */
8 Y2 n- o! p' ?% z* G+ ?: H - __HAL_UNLOCK(hdma2d); ! w- {) q4 m# I7 ^
. W) c2 h. S( U. u( f% a- return HAL_OK;
4 N6 @/ Q7 r7 V& _ - }
复制代码
' A) r' h Q. _; r, p4 |
0 r; B' m7 t2 k( h9 y/ T8 K6 Y2 b7 A/ U
函数描述:
" V; `8 S1 X3 W5 t
: y2 K" t7 J" [ @2 x0 ]此函数主要用于配置DMA2D要转换的前景层和背景层,即输入颜色配置。而前面的函数HAL_DMA2D_Init配置的输出颜色。2 P* A. _ r0 o9 o
- z. C) ^0 K9 @5 c* t: G函数参数:! N$ Z2 `8 S1 M: D4 {' q; K
4 m" E- Q1 p' l8 C 第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。+ [2 ^2 A, y5 y+ W& o$ _( A" m( D6 R
第2个参数用于配置前景层和背景层,0表示背景层,1表示前景层。
0 `0 b( u0 L( c) Q( U/ |$ o 返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。8 k+ o/ O) ~" _ k, B, `
使用举例:; V Y {0 ~8 Z
0 [ b& v. h1 K' }( {4 S9 X- DMA2D_HandleTypeDef Dma2dHandle;
- z: O5 c- g2 Q7 o( u# U - " b( S' D: f7 E B
- 9 s/ }" a }/ ~" l! }% L
- /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/% ^" M5 J/ t9 b% j& Z/ I0 L
- Dma2dHandle.Instance = DMA2D;
! f" ^! o6 M( M1 i
! K/ \! E8 ~# y8 i; S- Dma2dHandle.Init.Mode = DMA2D_M2M; /* 存储器到存储器模式 */
, y8 t4 j0 \9 q' t - Dma2dHandle.Init.ColorMode = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */
4 \' M. w E. z9 s - Dma2dHandle.Init.OutputOffset = 0x0; /* 无输出偏移 */
% V4 N9 V- T* a& Z" z; X E - Dma2dHandle.Init.RedBlueSwap = DMA2D_RB_REGULAR; /* 输出颜色的R/B通过不切换 */) y0 \1 J* E/ R" Y$ I0 T5 s8 y) @. l
- Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA; /* 输出颜色的Alpha通道数值不翻转 */9 \5 l, X, z; s2 I( K0 {2 c m* F- b
- % k# T3 b6 q# R8 L
- /*##-2- DMA2D 回调函数配置 ######################################*/' E9 v4 Z, w7 c; P3 T) U- A6 y
- Dma2dHandle.XferCpltCallback = TransferComplete;) m! k8 M e* X) `' [! y+ ~
- Dma2dHandle.XferErrorCallback = TransferError;
5 K4 G/ [& R* }' s, ?8 d - ; [: |- b$ H g3 B4 B* P" s
- /*##-3- 前景层配置 ###########################################*/
9 x# s/ ]6 J! ^3 q* G4 { - Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA; /* 保持输入颜色格式中的Alpha值 */
; w; G% |* x( Z& }7 \; z - Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF; /* 完全不透明 */- Y. s: w: |( @8 D' I5 M* Q
- Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */
1 c' s. B v+ ` N( E! T; R - Dma2dHandle.LayerCfg[1].InputOffset = 0x0; /* 输入无偏移 */
+ V4 B) y+ m h. c3 x - Dma2dHandle.LayerCfg[1].RedBlueSwap = DMA2D_RB_REGULAR; /* 输入颜色的R/B通过不切换*/! a' q! m, E9 j: N- R. i
- Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA; /* 输入颜色的Alpha通道数值不翻转*/- L5 y6 G4 P; }+ Q8 s/ d1 E+ r+ @
- 1 q- R4 W" D# C+ n. u
- /*##-4- DMA2D 初始化 ###############################################*/
' i% _- @7 m! Y! [, f" m - if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK). X7 l+ s3 E8 h# K; Q t, F
- {
( s7 B+ {# z0 U3 @( h l - Error_Handler();
6 X$ l, E3 P. @. b - }
; x! G& l2 {$ @1 B7 H: }; D% W
8 {: I) r5 Z0 S- /* 配置前景层 */
/ K1 u7 G' \2 z0 t7 n: W( W9 @ - if(HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1) != HAL_OK)! ^! T! Y8 p e( [' [6 \
- {; I' z7 t2 w( W/ X0 P
- Error_Handler();) Q" R* A) W+ V
- }
复制代码
; U! b# ]+ A; f/ ^3 O8 R& B# O
# f/ P/ _' [' i4 ?4 K, `% Q
; g4 E3 z, h; M: l6 }& h' f, K; c" z9 m55.4.3 函数HAL_DMA2D_Start_IT! t; Y9 ]5 s# G* N
函数原型:- E0 l5 g1 v* q' v
5 J) C: m# Q+ [: a
- HAL_StatusTypeDef HAL_DMA2D_Start_IT(DMA2D_HandleTypeDef *hdma2d, uint32_t pdata, uint32_t DstAddress, uint32_t Width, uint32_t Height)
6 p( r* n$ B% O0 d$ a7 C' G; _3 {$ Z. t - {1 C P. }7 P- ]% ]
- /* 检测函数形参 */5 r* w9 ?/ O% z) i( N! r: R
- assert_param(IS_DMA2D_LINE(Height));
1 W$ n7 d2 A6 O E. s) B; r - assert_param(IS_DMA2D_PIXEL(Width));
" a- @+ w6 O/ W! S/ u+ @4 y - 2 n7 `7 @! {' S% Y
- /* 上锁 */
' n: u) \! }7 O7 I g - __HAL_LOCK(hdma2d);
( ^) a" j t3 u$ g0 Z5 ~ - # y* t" X% y1 \1 {$ [
- /* 设置DMA2D外设状态 */
, H$ \+ F$ z, x, x) C - hdma2d->State = HAL_DMA2D_STATE_BUSY;
# o' @: _ c. y6 j- ]* `
6 p( \$ \/ u& Z4 {- /* 设置源地址,目的地址和数据大小 */
" U( ?8 c+ w& Q& Q# L' d4 N - DMA2D_SetConfig(hdma2d, pdata, DstAddress, Width, Height);
4 Z4 h7 l$ D. y; ]' K- t; ~ - 7 b6 {, v, ?' u9 X
- /* 使能DMA2D的传输完成中断,传输错误中断和配置错误中断 */
5 U. K- H' n' g* g/ \ - __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);
/ q) Q' @1 @0 H: e! i+ h
. ?) J; f* |( [3 L+ ?/ c- /* 使能DMA2D */ C% E; Y% I, j6 B- p2 O4 H7 I
- __HAL_DMA2D_ENABLE(hdma2d);
0 \6 V+ f/ T; E - ' _6 C" y. I' [6 `
- return HAL_OK;6 Q6 V* F1 q) q0 F! O/ S4 G
- }
复制代码
3 C% Q/ n% m% p l# |
. |" w9 }7 `7 ?0 l/ H, z; F( y
$ Z# \* @! P* h* M% w函数描述:
( q* H$ h0 r, b" ?$ R+ @- O I
+ i; n% u6 q M8 f7 M& K此函数用于启动DMA2D数据传输。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。
; n( h1 e& {: G& y% q4 @. n* @& v$ Z" A
函数参数:+ D. I; i0 N+ `$ F- V
: N( N( U3 I+ D4 p
第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。% I, U* a! S9 ~9 R$ e' p: p
第2个参数是源数据地址。7 }* e4 w! ^: _ ]" ~1 | j) s
第3个参数是目的数据地址。2 o9 P1 k( S' b# m
第4个参数是源数据的长度,即每行的像素个数。
4 S8 e" J4 G' s i U* k- g 第5个参数是源数据的高度,即行数。% u: b; p8 g1 Q$ J1 x
返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。' Z3 h5 `" E. d9 r* b! ~, g* H$ D& n
使用举例:
. m8 B" w8 r8 `6 {+ w( \& b& w; e6 {, W
- DMA2D_HandleTypeDef Dma2dHandle;
: d) j, z" B$ N; v2 a v+ R3 I - 5 `9 e) V3 g1 k9 T r% {
- if(HAL_DMA2D_Start_IT(&Dma2dHandle, /* DMA2D句柄 */* ^+ B9 S5 P+ ~' D3 {8 H6 k( S
- (uint32_t)&BufferInput, /* 源地址 */ 2 P0 E- A% d. V8 I2 Q2 _
- (uint32_t)&BufferResult, /* 目的地址 */$ R4 A- U, c+ P1 v4 G6 {
- SIZE_X, /* 源数据长度,单位像素个数*/
/ i5 C( y, {2 U8 |% _4 o - SIZE_Y) /* 源数据行数 */& m% U0 A a" B
- != HAL_OK)4 [, S& c+ x( z1 Q6 T' J2 F
- {: \. L& ?7 E5 D. k
- Error_Handler();
9 q$ \& }. o- h. ?6 x" L - }( ?! P& g: X. Z S: {/ ?$ }. v
复制代码
- c& y6 I5 \# o6 _2 H; a) C! s; f0 n7 h+ G8 {0 i" n8 ?0 Y% g
55.4.4 函数HAL_DMA2D_BlendingStart_IT
9 {- I, k, V* o2 b函数原型:/ r/ u% M, d, j
% X" ?+ F6 ?: k0 t" y/ y- HAL_StatusTypeDef HAL_DMA2D_BlendingStart_IT(DMA2D_HandleTypeDef *hdma2d, uint32_t SrcAddress1, uint32_t SrcAddress2, uint32_t DstAddress, uint32_t Width, uint32_t Height)
% q. K' V5 h) {4 p - {* f) Y n# ~: @1 e2 l$ A
- /* 检测参数 */% v( A2 U7 Y1 S' B* a; T1 M
- assert_param(IS_DMA2D_LINE(Height));/ I9 p7 y Q. N! d! Z8 ^! H
- assert_param(IS_DMA2D_PIXEL(Width));6 H7 ?1 z. W% u1 i' |
- + v" ^) q1 l1 K
- /* 上锁 */+ v1 Y; b/ n- i& y# ^
- __HAL_LOCK(hdma2d);
% G; {+ Q; A+ c9 `* L - 0 ~+ g# \' K, y; b1 ~
- /* 设置DMA2D外设状态 */
0 o1 d+ C1 d7 Q. a* _: u0 [ - hdma2d->State = HAL_DMA2D_STATE_BUSY;
7 e5 d V- @ D
$ Q1 D2 l* F% L" ?- /* 配置DMA2D源地址2 */
R+ H3 P' {- L7 U+ T( e' w - WRITE_REG(hdma2d->Instance->BGMAR, SrcAddress2);* ~; V* O c q% Z) r, g( Z. M
- 3 L" t9 G& m3 V% v9 [3 [ ?, i
- /* 配置源地址1,目的地址和数据大小 */% U. Z- X$ G6 a" I5 W5 m/ J: S
- DMA2D_SetConfig(hdma2d, SrcAddress1, DstAddress, Width, Height);
1 d- n( O+ _; b: c v4 {- b - + I" I: M+ H& O5 |/ U) s
- /* 使能DMA2D传输完成中断,传输错误中断和配置错误中断 */7 O( V! B6 J. f, V3 {3 c0 }
- __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);# V3 N, @, V9 O
- ' J# {$ D2 n7 u0 G# m3 P
- /* 使能DMA2D */
/ K; f, Y/ }. Q5 S3 g0 O - __HAL_DMA2D_ENABLE(hdma2d); C `- _8 h( h2 z9 [1 C# C; A
- / ?- P0 D7 R( a* o, [% z, \& ~' }' ]
- return HAL_OK;, X I# N A/ m7 D7 z, x! }" x
- }
复制代码
1 |/ o: I7 W+ e" }, M* w
; r2 |! T1 {( c% k! _% L3 l$ N# Q5 r! L0 y
函数描述:# q x. a2 D: N7 f( t$ b2 w2 O9 L
% m5 @" _% N* O' J4 A* S. m+ Z3 U2 o
此函数用于启动DMA2D传输,除了数据传输以外,还支持颜色格式转换和颜色混合。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。
2 q+ k' Q, V0 T( A0 n1 d
5 c5 S7 z5 o: j# v5 W7 @. b函数参数:# g; f* L9 \+ \) w) C' Y! O
" X4 A$ `) X3 |9 Y2 S9 h; q7 ? 第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。& p+ N5 O: u; P% m+ G7 m! U
第2个参数是源数据地址1。
8 {" ^4 w* [/ X+ P7 k: } 第3个参数是源数据地址2。
: N6 ^' A4 W6 |7 b1 O 第4个参数是目的数据地址。1 g. ^- t* u. ~8 @- `- Y2 s9 j
第5个参数是源数据的长度,即每行的像素个数。
% c9 I4 E6 s$ p% U6 y; Z" i5 I! @8 R 第6个参数是源数据的高度,即行数。& g& y: G8 T6 {7 U
返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。; C4 Y8 ~1 \$ U' ~/ y
使用举例:, m& n7 p7 K3 T4 O, r
% C/ U+ _+ \9 q0 O5 V) b- R- S `
- DMA2D_HandleTypeDef Dma2dHandle;9 c( R# T$ V3 Q
4 L9 y1 E. b% y' X% }3 G, c% J- |- if(HAL_DMA2D_BlendingStart_IT(&Dma2dHandle, /* DMA2D句柄 */ r6 A9 o, B8 q& X5 D" }
- (uint32_t)&BufferInput1, /* 源地址1,前景色 */
- q" h @8 S4 _* E: F3 X L - (uint32_t)&BufferInput2, /* 源地址2,背景色 */$ T. _" V, E @1 q. A
- (uint32_t)&BufferResult, /* 目的地址 */
: J+ g# X5 k/ N! P - SIZE_X, /* 源数据长度,单位像素个数*/ C2 y2 @* ]0 @6 v. g2 I1 f
- SIZE_Y) /* 源数据行数 */
4 T) O. i. O: L6 R {, \4 y - != HAL_OK)( _! m6 l! p" p6 h! |& Z
- {
) H* ~% W$ @, L2 D& O- p - Error_Handler();& C' v5 e. C7 j6 W: `$ R8 Z
- }
复制代码
3 f* C. v6 I; [! i% T) _" |
! y' F4 t0 G; X Y, X4 n( |% d4 B. t- b# L0 @
55.5 总结& g1 ~" `& I {
本章节就为大家讲解这么多,DMA2D功能比较重要,一定要做到熟练使用。
0 E) C8 x6 x9 c1 l7 J$ ~% |% U! X$ K% {% x5 {
+ r6 M3 k* c3 c9 v7 A8 j: r w: @1 g' C
|