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