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