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