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