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