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