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