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