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