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