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