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