你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32H7的图形加速器DMA2D的基础知识和HAL库API

[复制链接]
STMCU小助手 发布时间:2021-12-24 17:00
55.1 初学者重要提示6 [" \* r% m3 a  G7 n% W
  DMA2D是专门用于LCD加速的,特别是刷单色屏,刷图片,刷Alpah(透明)混合效果全靠它,而且可以大大降低CPU利用率。
3 G5 q4 R) S* F4 r9 V5 S  测评STM32H7的LTDC+DMA2D性能,100Hz以上无压力,刷800*480图片和色块仅需2.6ms一张6 A. Q  T; A5 \- p
  H7的DMA2D与F429的DMA2D最大区别是支持了ARGB和ABGR互转,而且支持H7的硬解JEPG输出格式YCbCr转RGB,方便LCD显示。
% o' t" Z( b" P+ z: R  V* |0 W0 H  特别注意,大家只需对HAL库提供的DMA2D操作API有个了解即可,实际工程中,并不使用这些API,我们需要使用更加高效的寄存器直接操作,在下一章节会为大家说明。7 e+ N0 r$ {$ N" J+ o
55.2 DMA2D基础知识3 s: y7 m2 x9 l: j7 X
DMA2D主要实现了两个功能,一个是DMA数据传输功能,另一个是2D图形加速功能。, x4 E+ `; B* {) r" o
( K  N' x4 P: ?0 @* N" D
  DMA数据传输2 ]5 H' a3 a8 `' M7 u4 @
主要是两种方式,一个是寄存器到存储器,另一个是存储器到存储器。通过DMA可以大大降低CPU的利用率。3 @% v6 X4 U7 o1 M, W7 |( {5 B
% [4 N$ P8 d; [* |% E) S3 z
  2D图形加速功能
1 U* w) `9 H: ]- g支持硬件的颜色格式转换和Alpha混合效果。$ {4 P1 n. e, w9 m5 Z* e0 }# ~4 P
5 o. h: P- m* k: T, D6 V; D
55.2.1 DMA2D硬件框图
  B3 T3 Q8 ^+ M5 i认识一个外设,最好的方式就是看它的框图,方便我们快速地了解DMA2D的基本功能,然后再看手册了解细节。框图如下所示:/ @0 x" x. r) r+ v+ X

. i9 C9 O, A" q4 f: v6 c) Z9 V  C
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
1 w" r  o9 s/ t( M

* p7 ~: M9 _. M, M! ?6 w通过这个框图,我们可以得到如下信息:. \  R$ @& d& H$ h- y4 d+ t6 P
$ K- O8 S( g9 E1 E
  dma2d_aclk
; b: G1 A$ b0 o# s! u) lAXI 总线时钟输入。
' d( I( j- Q. _5 F1 O- m" P+ v: D; _+ \2 m9 R- V
  dma2d_gbl_it9 @4 D  c9 M* o% l, d6 k8 N8 p
DMA2D全局中断输出。
8 F; v( h; C  c) `' y" g
5 f2 \, G! [2 R2 ^  dma2d_clut_trg
) ?5 o4 [, [4 k1 @+ F  }* n( mCLUT传输完成信号输出,可以触发MDMA。
) ]! W/ b+ v9 o- y# u2 Z- D; G
& O$ D/ w9 j7 T/ R5 X  dma2d_tc_trg$ O) f9 h( \8 S* n* _
传输完成信号输出,可以触发MDMA。
1 Q' ]4 A5 y5 f8 v0 X) C5 B1 X) N, X6 @6 }: u6 t' s
  dma2d_tw_trg
0 }9 i# u/ ?& L- P# E/ v5 s( Y传输watermark信号输出,可以触发MDMA。
0 A4 w8 j! A9 Q. v; s9 f6 {0 d; ?$ l) @! V& Z/ e9 h$ S0 ?- L8 y
将这个硬件框图简化一下,就是下面这样:  K6 }% P) B7 E: U' a

3 r) b! l+ ?& f1 |6 _
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

  Q/ }) G1 p+ A( J! g8 P# X
4 c4 Z/ p7 J4 F4 V9 T5 J; h5 V6 ^下面按照简化的硬件框图,对每个部分做个说明。
+ ^# X, T8 ]1 _
$ y0 n2 ?) `! G9 ^7 I% z55.2.2 DMA2D工作模式$ Q/ f* v+ e: i# w
DMA2D支持的工作模式如下:
  k* b. N% E; Y; b5 A  k4 ?9 \3 Z/ Q2 f5 K4 z  V/ Y' }; z
  模式1:寄存器到存储器模式8 C- W, s: Z( D+ h
这个模式主要用于清屏,也即是将显示屏清为单色效果。* ^" U. ~6 o, S" A

+ W) o" |8 `2 e2 C; [- J0 u  模式2:存储器到存储器模式
& j; x# W% a5 t1 e( ^* B这个模式用于从一个存储器复制一块数据到另一个存储器,比如将摄像头OV7670的输出图像复制到LCD显存就可以采用这种方式。9 [6 S1 p+ R' E- k+ E' v
! l+ H: n% q3 N& C. S3 X3 _1 L
  模式3:存储器到存储器模式,带颜色格式转换; [' p, B' z; Q3 t/ o6 r
这个模式比模式2多了一个颜色格式转换,比如我们要显示一幅RGB888颜色格式的位图到RGB565颜色格式的显示屏,就需要用到这个模式,只需输入端配置为RGB888,输出端配置RGB565即可。位图颜色格式转换后会显示到显示屏上。* s- J4 b9 X6 k! E# j

. g' \# k  [- [0 S  模式4:存储器到存储器模式,带颜色格式转换和混合4 y: `" y( l0 F/ B% `; N! k# Z
这个模式比模式3多了一个混合操作,通过混合,可以将两种效果进行混合显示。8 `1 b3 H4 T& j  Y. j- H* f

6 u! [7 [8 v$ ^8 v/ s; w: Z8 f  模式5:存储器到存储器模式,带颜色格式转换和混合,前景色是固定的$ n9 D4 u. d7 i! R7 ~
同模式4,只是前景色的颜色值是固定的。
4 u0 n! k! p. `3 a( P: P4 E
+ p! u0 a7 ~4 s. Y55.2.3 前景层和背景层的输入以及颜色格式转换
4 ]. E, p- x4 R/ h前景层和背景层是指的用户绘制图形时的前景色和背景色,比如我们显示汉字,字体会有一个颜色,也就是前景色,还有一个背景色。又比如我们绘制两幅图片,想将两幅图片混合,那就可以将一幅图片作为前景层,另一个幅图片作为背景层。8 M5 b$ b! \- P8 G  S
$ q, [" `  X4 S$ ?
DMA2D支持的输入颜色格式如下,前景层和背景层一样:% g- p& H" _0 ^, x8 Q( s
4 w( s/ [9 E* [9 z9 a
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
1 G5 G7 T+ J$ f$ i5 g* b

3 o, r, q" I% e$ c7 s% l, L7 C前8种颜色格式在第50章的第2小节开头有介绍,这里把后四种做个说明:8 p  ^' I6 B. `
/ C7 _( u. R1 g% f" R
  L4 (4-bit luminance or CLUT)3 |$ ^- v# a3 P5 d% j
4位颜色格式,实际上仅仅是4位索引值,范围0–15,而每个索引值的具体颜色值在查色表CLUT里面存储。7 M( Y6 G+ O1 k6 e

  w0 x# O! N) N! c: h$ a0 U  A4和A8
3 @$ I& T  v6 N" `- b4 jA4和A8用于特定的Alpha模式,既不存储颜色信息,也没有索引值。) |* r- X9 j# @" O
$ M  L$ n- F) K7 s6 f: O" b% V8 a( m
  YCbCr
$ J& B( S8 h) C; {7 X这个是H7的硬件JPEG输出的颜色格式,后面JPEG章节为大家专门做讲解。# y: [8 M) ]) B% f

2 P9 {; Y' c! [# G. g- \5 {6 u; Q这里特别注意一点,输入颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。0 I. k! f6 u9 B* g
- ^1 l: f) d; W3 b5 Z5 I
55.2.4 前景层和背景层混合
# |. I8 W; o, K* w. w4 IDMA2D混合器用于混合前景色和背景色,这个功能不需要任何配置,仅需要通过DMA2D_CR寄存器使能即可。混合公式如下:
, |' m! ~8 e5 I0 S1 j* `& i5 A, `9 l( R! ~8 ^% E/ }5 I
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
9 S# O' F4 I/ M

) D/ q! e/ D0 H( k) S55.2.5 DMA2D输出颜色格式
9 I$ e* d! D# o$ t: cDMA2D支持的输出颜色格式如下:
4 Q/ A2 O* D+ s) ^! ?6 ~: U# i1 u% _, P0 ~, a+ W8 Y
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

$ l* ~, x* H6 \, M
' `2 H2 R, X& l% Z这里特别注意一点,输出颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。# V7 d' o( Z' l8 X6 J

- d* q5 v; Y+ K/ I& `55.3 DMA2D的HAL库用法. r$ \& U, k3 \* Z# U& r5 J. J
DMA2D的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断。下面我们逐一展开为大家做个说明。
4 s" W: t* H0 S# t9 d2 Z: T) j! S2 j$ \$ O9 b8 f5 _
55.3.1 DMA2D寄存器结构体DMA2D_TypeDef
/ Z4 f" h, u3 A9 F: uDMA2D相关的寄存器是通过HAL库中的结构体DMA2D_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:- G2 f7 \. @' g2 `) p
! b& l/ F% F* ^, }
  1. typedef struct( P: X1 a# l7 r9 f3 s
  2. {
    ( F. L; Q4 o5 K; C
  3.   __IO uint32_t CR;            /*!< DMA2D Control Register,                         Address offset: 0x00 */7 R& X  e( h9 ]( I+ K4 g4 I- r# Q2 \
  4.   __IO uint32_t ISR;           /*!< DMA2D Interrupt Status Register,                Address offset: 0x04 */' W4 ?- `. R/ j) |
  5.   __IO uint32_t IFCR;          /*!< DMA2D Interrupt Flag Clear Register,            Address offset: 0x08 */! R/ N& M7 b6 k( h; h! A+ b
  6.   __IO uint32_t FGMAR;         /*!< DMA2D Foreground Memory Address Register,       Address offset: 0x0C */" r( R. m# c* p) g% w3 [( o, E, s
  7.   __IO uint32_t FGOR;          /*!< DMA2D Foreground Offset Register,               Address offset: 0x10 */
    ( J$ e) |* m/ ]4 O5 o
  8.   __IO uint32_t BGMAR;         /*!< DMA2D Background Memory Address Register,       Address offset: 0x14 */9 i  U2 s. Z; P; N
  9.   __IO uint32_t BGOR;          /*!< DMA2D Background Offset Register,               Address offset: 0x18 */
    $ G# z+ w5 Y9 k  K
  10.   __IO uint32_t FGPFCCR;       /*!< DMA2D Foreground PFC Control Register,          Address offset: 0x1C */
    8 A  i4 i" ^# l9 _1 D" l
  11.   __IO uint32_t FGCOLR;        /*!< DMA2D Foreground Color Register,                Address offset: 0x20 */5 ~  w$ X% y. K& l0 k+ r
  12.   __IO uint32_t BGPFCCR;       /*!< DMA2D Background PFC Control Register,          Address offset: 0x24 */
    & d: D$ R0 `2 `
  13.   __IO uint32_t BGCOLR;        /*!< DMA2D Background Color Register,                Address offset: 0x28 */
    . n7 G. a0 J# Z8 c5 C
  14.   __IO uint32_t FGCMAR;        /*!< DMA2D Foreground CLUT Memory Address Register,  Address offset: 0x2C */
    # ~$ l. I9 b' b
  15.   __IO uint32_t BGCMAR;        /*!< DMA2D Background CLUT Memory Address Register,  Address offset: 0x30 */: t" x! X1 P* I, u
  16.   __IO uint32_t OPFCCR;        /*!< DMA2D Output PFC Control Register,              Address offset: 0x34 */
    / _2 F4 a8 A5 n( Y8 `" ~. ~
  17.   __IO uint32_t OCOLR;         /*!< DMA2D Output Color Register,                    Address offset: 0x38 */
    9 z5 V0 R0 K6 V
  18.   __IO uint32_t OMAR;          /*!< DMA2D Output Memory Address Register,           Address offset: 0x3C */. ^* P* y$ J7 ]; |& r$ N% y0 T) [& [
  19.   __IO uint32_t OOR;           /*!< DMA2D Output Offset Register,                   Address offset: 0x40 */2 l5 P5 ~- T0 P- q- j
  20.   __IO uint32_t NLR;           /*!< DMA2D Number of Line Register,                  Address offset: 0x44 */
    # C; y" |1 ^6 T# P+ U' y" q! S; y
  21.   __IO uint32_t LWR;           /*!< DMA2D Line Watermark Register,                  Address offset: 0x48 */
    5 l( z  r. W( O. x8 E7 j
  22.   __IO uint32_t AMTCR;         /*!< DMA2D AHB Master Timer Configuration Register,  Address offset: 0x4C */
    & P' j' m4 {, r! I2 q
  23.   uint32_t      RESERVED[236]; /*!< Reserved, 0x50-0x3FF */( N( h. U% M; p, J
  24.   __IO uint32_t FGCLUT[256];   /*!< DMA2D Foreground CLUT,                          Address offset:400-7FF */
    ! _3 t3 |5 x! e3 v/ u! \* f# l0 a! i2 N# h
  25.   __IO uint32_t BGCLUT[256];   /*!< DMA2D Background CLUT,                          Address offset:800-BFF */
    ( d  F, `/ F0 D9 P
  26. } DMA2D_TypeDef;
复制代码

* |0 U6 g0 L" r% b  o+ K! \  p  t+ G6 u9 f% S) Y
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:9 v6 c: Y' ]6 @4 I5 T1 z
: D0 G: G' ]9 U. x' H
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */+ ^0 \8 |% n# A9 H2 k' b
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
$ p" K9 n* |% j* C4 o6 V) ~7 p
下面我们再看DMA2D的定义,在stm32h743xx.h文件。
  1. #define PERIPH_BASE              ((uint32_t)0x40000000) 9 G: U0 N) C" U7 B
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000). G, T% a7 \2 _4 y- m# _- ?! E
  3. #define DMA2D_BASE               (D1_AHB1PERIPH_BASE + 0x1000); |; K$ f' t+ q7 T7 D7 i- R4 [- D
  4. #define DMA2D                    ((DMA2D_TypeDef *) DMA2D_BASE) <----- 展开这个宏,(DMA2D_TypeDef *) 0x52001000
复制代码

9 L6 O* x1 r% ]! R, W$ K我们访问DMA2D的ISR寄存器可以采用这种形式:DMA2D->ISR = 0。
# E. p6 p- j$ |) m- n% W9 h- P4 g4 d6 a4 \% U# l
55.3.2 DMA2D参数初始化结构体DMA2D_InitTypeDef
8 d) b( I, z5 m) B此结构体用于配置DMA2D的基本参数,具体定义如下:
4 @9 i% R' N& S' J2 d- G
, H4 f' y, o" x+ @6 m- b$ \, z
  1. typedef struct
    ; h" k" ?4 Z  _+ E2 U$ l6 x
  2. {
    * M/ U  T, d, P+ W5 o! z8 W
  3.   uint32_t             Mode;              5 f) e8 J7 m9 X" T9 B" w2 m( S
  4.   uint32_t             ColorMode;        
    3 `) _& h9 w3 G& H' i2 p# a4 r
  5.   uint32_t             OutputOffset;       . X' O+ _& \0 _( p- O$ ^
  6.   uint32_t             AlphaInverted;    4 |" D  }/ U3 M. f* }
  7.   uint32_t             RedBlueSwap;      
    + A* V7 M: g' G0 |, j
  8. } DMA2D_InitTypeDef;
复制代码
$ q3 K1 p* ]( }% E% Y. U9 ?
下面将这几个参数逐一为大家做个说明:
! ]$ f" `/ A" t9 ^# K" i
+ Q& L& a" R' |# e1 F  uint32_t   Mode
. c3 |7 Y2 \$ @0 ^$ \& E/ [此参数用于设置DMA2D的传输模式,具体支持的参数如下:& z- {: f) o+ J5 l8 Q% i

0 t" w# n; S% o/ J: E! i
  1. #define DMA2D_M2M        ((uint32_t)0x00000000U)  /*存储器到存储传输模式 */
    ; K" |- V( @2 z; e0 o
  2. #define DMA2D_M2M_PFC     DMA2D_CR_MODE_0         /*存储器到存储器传输模式,并执行FPC像素格式转 */, j0 E$ P& s+ h/ b: g
  3. #define DMA2D_M2M_BLEND   DMA2D_CR_MODE_1         /* 存储器到存储器模式,并执行像素格式转换和混合 *// ~, R" {0 Q9 k
  4. #define DMA2D_R2M         DMA2D_CR_MODE           /* 寄存器到存储器传输模式 */  V4 T& }+ X: z2 U! K! C+ ]" C6 D' d
复制代码

3 Y( @3 ], Q/ N  S/ a% B' x; m7 w" K6 w4 b
  uint32_t   ColorMode: P$ u6 j' B, Y" y$ Y9 B/ p
此参数用于设置DMA2D的输出颜色格式,具体支持的参数如下:
0 \& z( _/ J# P! C! e7 q) V1 w( m
, f# X, Z8 A4 l; |# }1 v( F0 [
  1. #define DMA2D_OUTPUT_ARGB8888       ((uint32_t)0x00000000U)               /* ARGB8888 */' Q: A, {% @! s/ }# e
  2. #define DMA2D_OUTPUT_RGB888         DMA2D_OPFCCR_CM_0                     /* RGB888 */, x7 ]4 x3 Q" }# ?. G! r% ^
  3. #define DMA2D_OUTPUT_RGB565         DMA2D_OPFCCR_CM_1                     /* RGB565 */# Z; k7 X* i$ K& n/ {) L- _
  4. #define DMA2D_OUTPUT_ARGB1555       (DMA2D_OPFCCR_CM_0|DMA2D_OPFCCR_CM_1) /* ARGB1555 */
    2 h" E2 {/ ~4 ?0 H" Y  A
  5. #define DMA2D_OUTPUT_ARGB4444       DMA2D_OPFCCR_CM_2                     /* ARGB4444 */
    6 P2 l$ |1 m  V- l
复制代码
3 X- W4 i2 N- N1 B3 M. K
0 v' K$ j* t9 g/ e% P. R
  uint32_t   OutputOffset
. }9 E; {  D+ V0 D3 e* D9 m此参数用于设置输出位置的偏移值,参数范围0x0000到0x3FFF。
! B/ _  L  w5 h) W6 n( B6 P& }3 F# I$ T
  uint32_t   AlphaInverted' H* e2 R! Q, o5 d& W
此参数用于设置DMA2D的输出颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     
) H' n1 D8 k3 s
$ t/ i$ p+ L* m! D8 r9 f9 Y
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */
    , S! H4 B9 A3 V/ p
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */
复制代码
0 C* F" O7 w3 E! N: a
  uint32_t   RedBlueSwap
/ o7 n( J/ x! n+ W此参数用于设置DMA2D的输出颜色格式中R通道和B通道的交换,具体支持的参数如下:5 s; S( N3 ~. h  ]

# s" K0 x- h) ~5 q
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */
    8 P1 n# I- o+ k
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码
8 i6 V) p- X2 l
55.3.3 DMA2D的图层结构体DMA2D_LayerCfgTypeDef; l3 ]# N( b5 b; V5 A
此结构体用于配置前景色和背景色。
4 B% O+ k5 C$ V! t
6 U# @/ C3 _9 V- j7 x: m. [- _
  1. typedef struct
    # ^, P$ l) G) f3 U; K5 {7 r1 @! n! e
  2. {
    4 B: S* f3 m# x5 W+ o+ K
  3.   uint32_t             InputOffset;      
    0 I) ~/ K+ H, p) {0 M& D
  4.   uint32_t             InputColorMode;   
    ( b, b" I9 L; {9 _# x' R
  5.   uint32_t             AlphaMode;        
    ' _4 H7 _+ i# _7 A6 s) b$ ?
  6.   uint32_t             InputAlpha;        
    5 B3 x; u' [0 d( Y
  7.   uint32_t             AlphaInverted;   
    & }$ L. Y3 T, ?0 a7 ]3 S
  8.   uint32_t             RedBlueSwap;       & Q8 C8 S! U5 g# ]: F4 s( m, P/ K. U
  9.   uint32_t             ChromaSubSampling;! P, x% T+ R' d+ m6 T
  10. } DMA2D_LayerCfgTypeDef;
复制代码

2 x! H7 Q# C8 E8 x下面将这几个参数逐一为大家做个说明。. D0 [' d- |% D  W4 w5 n

, _6 O" m+ l: [- M5 W6 }8 T  uint32_t  InputOffset4 B' w- _2 a5 N5 t
设置前景色或者背景色的输入偏移,范围0x000到0x3FFF。
3 V# Q" ]% _/ W3 f5 k8 J- D8 |) D& B8 U& X( u% S) M1 I
  uint32_t  InputColorMode9 l+ U) w  O! i  z& ^8 a5 P5 E
设置前景色或者背景色的输入颜色格式,具体支持的参数如下:: [/ b8 U, N. h' @" D! c6 [
$ P: ^) G3 o; L3 D% }( _
  1. #define DMA2D_INPUT_ARGB8888        ((uint32_t)0x00000000U)  /* ARGB8888 */- z6 y( n" T0 ^3 L
  2. #define DMA2D_INPUT_RGB888          ((uint32_t)0x00000001U)  /* RGB888   */
    2 E2 [1 s( k$ \/ o) U
  3. #define DMA2D_INPUT_RGB565          ((uint32_t)0x00000002U)  /* RGB565   */( \2 h3 f% ~1 F' z7 u) }4 p! r
  4. #define DMA2D_INPUT_ARGB1555        ((uint32_t)0x00000003U)  /* ARGB1555 */  M; [3 d. f7 P8 a. ?' z' k
  5. #define DMA2D_INPUT_ARGB4444        ((uint32_t)0x00000004U)  /* ARGB4444 */. T% V9 c5 v( x; h0 e( ]
  6. #define DMA2D_INPUT_L8              ((uint32_t)0x00000005U)  /* L8       */' X) G6 G* P3 \/ \
  7. #define DMA2D_INPUT_AL44            ((uint32_t)0x00000006U)  /* AL44     */7 o" L. i# M; {! D; Y+ N5 n  e3 R7 {
  8. #define DMA2D_INPUT_AL88            ((uint32_t)0x00000007U)  /* AL88     */
    3 O! o3 Y: L8 ?5 r- H0 b7 ~
  9. #define DMA2D_INPUT_L4              ((uint32_t)0x00000008U)  /* L4       */4 g* M& Q' O, O3 K
  10. #define DMA2D_INPUT_A8              ((uint32_t)0x00000009U)  /* A8       */9 u) g3 i/ v9 }$ ~( U4 B; o
  11. #define DMA2D_INPUT_A4              ((uint32_t)0x0000000AU)  /* A4       */0 _  l6 ?; M. w0 s) S$ N
  12. #define DMA2D_INPUT_YCBCR           ((uint32_t)0x0000000BU)  /* YCbCr    */
复制代码
* b3 `7 c( g: I* D& ^; m
  uint32_t AlphaMode
6 k5 ~* j: }  G7 S/ L4 u7 F) w设置前景色或者背景色的Alpha模式,具体支持的参数如下:/ A: s+ o4 Q0 ~* d0 P$ G
! C; x! a3 N) o5 L+ }7 a$ C
  1. #define DMA2D_NO_MODIF_ALPHA   ((uint32_t)0x00000000U)  /* 不修改Alpha通道值 */6 A/ }! F: P! i8 ?, u- X
  2. #define DMA2D_REPLACE_ALPHA    ((uint32_t)0x00000001U)  /* 用新设置的Alpha值替换原始Alpha值 */
    : D2 z( m) j7 w
  3. #define DMA2D_COMBINE_ALPHA    ((uint32_t)0x00000002U)  /* 用新设置的Alpha值与原始Alpha值的乘积替换原始Alaha值*/
复制代码
/ W6 @6 e- C. |/ ?& ?
  uint32_t  InputAlpha
& P" E( Z6 V- Z2 q3 z7 y  ~6 Y设置前景色或者背景色的Alpha值,范围0x00到0xFF,如果颜色格式是A4或者A8,那么此参数的范围是0x00000000到0xFFFFFFFF,标准的ARGB8888格式。
. D; `8 _5 j3 S* X0 i9 C/ S
) x, p2 @" n3 F/ v% O  uint32_t AlphaInverted
6 H$ V% r1 B8 l0 C% F& o设置前景色或者背景色的输入颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     
- C+ s! J9 t+ O$ O2 j+ u7 X  b6 t; s! J+ v9 S8 v+ x8 v7 w
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */" L, d9 q# L. e; H- i! @
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */     
复制代码

0 G' S7 T4 k& t; D  uint32_t   RedBlueSwap
# K2 m. b* x3 n# F) P: h0 J: A8 O设置前景色或者背景色颜色格式中R通道和B通道的交换,具体支持的参数如下:8 N- G  u! m) v) _' z( ]

% M2 A! }% l. D: H  s
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */
    $ X5 @9 b* Z$ \; V/ w
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码
+ j/ \& G& C+ d2 Z0 W0 [: B" U
  uint32_t   ChromaSubSampling
  ?2 Z- R" B: C6 M设置前景色或者背景色中YCbCr 颜色模式的采样格式,具体支持的参数如下:
  1. #define DMA2D_NO_CSS               ((uint32_t)0x00000000)  /* 4:4:4 */5 Y/ Y: _, f5 K5 T5 f
  2. #define DMA2D_CSS_422              ((uint32_t)0x00000001)  /* 4:2:2 */9 D8 m% F+ B! g2 o2 e- z8 P% }+ g0 u
  3. #define DMA2D_CSS_420              ((uint32_t)0x00000002)  /* 4:2:0 */  
复制代码
. x- L* c% |% L" `. |  r3 `
55.3.4 DMA2D句柄结构体DMA2D_HandleTypeDef
: f2 @9 x8 Y; {: S0 H/ S
HAL库在DMA2D_TypeDef, DMA2D_InitTypeDef和DMA2D_LayerCfgTypeDef的基础上封装了一个结构体DMA2D_HandleTypeDef,定义如下:
- J& P! K. v+ `# i7 Q( B0 b9 n4 ?4 K/ |" L
  1. typedef struct __DMA2D_HandleTypeDef* Y: R- P5 ~( y- U7 k  l$ q
  2. {
    * _5 K8 [& U" D
  3.   DMA2D_TypeDef               *Instance;                                                                                                                                                                                          
    + Z; s- q7 w9 S! X5 K( q5 m
  4.   DMA2D_InitTypeDef           Init;                                                        
      B! k+ g: b9 c0 L/ o  t
  5.   void                        (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                                                                             
    2 w* A, W0 ]9 G. B7 K$ A
  6.   void                        (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                      - M# A8 f- ]3 Y; Y+ G
  7.   DMA2D_LayerCfgTypeDef       LayerCfg[MAX_DMA2D_LAYER];                                    
    0 `; D+ s; N$ K: M+ p& P
  8.   HAL_LockTypeDef             Lock;                                                                                                                                                                                                   
    ' O9 m" \, r) h
  9.   __IO HAL_DMA2D_StateTypeDef State;                                                                                                                                                                                                   
    " n- e. I3 a) Q$ b8 p+ U: h  t" K- ~
  10.   __IO uint32_t               ErrorCode;                                                   } DMA2D_HandleTypeDef;3 |6 ?& |0 o) [) u
复制代码

+ p7 @/ _3 q! _! E下面将这几个参数逐一做个说明。, Q* b1 ]; i9 e0 g! L& D; M+ V
/ s5 v: a' V6 W$ p
  DMA2D_TypeDef  *Instance
, z1 J8 c# z+ @8 X$ z$ Y这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。3 ~7 x! }3 g7 I0 F$ u) o) R
! K7 z: V7 _, c) m' v5 ~2 m
  DMA2D_InitTypeDef  Init;  ; U  ]2 y# b8 I! C$ D. i
这个参数是用户接触较多的,用于配置DMA2D的基本参数,详见本章3.2小节。  }% u1 ?9 \( J$ i

/ {8 k$ [$ D" n% n* O$ P* Z4 F  void     (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);
3 E! n+ H0 R% b  void     (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);* ^3 K0 s9 `7 n( t( r
DMA2D中断服务程序里面执行的回调函数,一个是传输完成回调,另一个是传输错误回调。0 T9 ?$ ^6 x1 S8 {, C& W6 M! l

4 `5 U) v$ `+ L4 `. J4 ~  DMA2D_LayerCfgTypeDef   LayerCfg[MAX_DMA2D_LAYER]- k7 ^$ ~3 r, A5 |# Q  H
这个参数用于前景色和背景色的设置,MAX_DMA2D_LAYER=2,详见本章3.3小节。! \+ j6 T! _2 u+ l0 h3 W; o

' b$ J* t: c7 s. }6 `" F  HAL_LockTypeDef   Lock- C  _% b  D) C$ s) ^
__IO uint32_t    State;
, f" `, A" k- J  }; e) f
: q' ^: m3 k8 B" h__IO uint32_t    ErrorCode
4 C1 W. q& k# |. }2 `( }) T" |2 c% U. v
这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置DMA2D通信状态,而ErrorCode用于配置代码错误。
1 P$ _! X; {. _+ P# B) W
) x6 E; ]- {! ]1 L55.3.5 DMA2D初始化流程总结
2 M0 K, j* I6 O* W0 m; \
对于DMA2D来说,其实不需要初始化流程,每个功能都可以直接封装出一个函数来,下个章节会为大家专门讲解,也是实际项目比较推荐的方式。% C* K: L! [7 G, e
' d/ h. Q3 S' g- O% S- {: a( I4 I
55.4 源文件stm32h7xx_hal_dma2d.c( C2 k; v  g7 O: [  f
这里把我们把如下几个常用到的函数做个说明:* v! t! k+ Q  d8 f+ \& I+ v% l, _
, ^  J. D6 Y! {7 m7 c6 U
  HAL_DMA2D_Init
8 T" }( g5 j1 t0 w  HAL_DMA2D_ConfigLayer# p7 V5 K1 h2 h7 l  p
  HAL_DMA2D_Start_IT7 z) t4 a% g% w6 q) a+ B
  HAL_DMA2D_BlendingStart_IT
9 j/ I2 e0 r' h4 f1 F9 E" c& i& M
9 v7 i5 }4 p* y( [' v55.4.1 函数HAL_DMA2D_Init! |- Y( }& u1 d2 X( p6 I: l/ L
函数原型:
0 c/ p6 k* X3 ^# D; h( a7 V: N. L7 A: c0 o
  1. HAL_StatusTypeDef HAL_DMA2D_Init(DMA2D_HandleTypeDef *hdma2d)
    , g7 _3 e7 C; P3 S+ b
  2. { + o5 {' g6 `1 N3 @+ h% w  O

  3. ! h6 p3 N8 g) W- N( t) Z# f, X6 d
  4. /*  检测参数是否有效 */
    1 m" \" Z& K6 z5 J' P
  5.   if(hdma2d == NULL)8 B; k0 C0 a% Y
  6.   {, r( U/ q. @( o4 L# S1 |
  7.      return HAL_ERROR;
    9 q# l% F" [5 f' ~& A5 g
  8.   }
    6 ?) r) D( v* V% r" x

  9. 8 y; y  ?) u7 x: H) D( u
  10.   /* 检测函数形参 */2 @4 X( `- q& X7 H" r' n
  11.   assert_param(IS_DMA2D_ALL_INSTANCE(hdma2d->Instance));1 Y* [0 S- F1 m; ?& {2 b
  12.   assert_param(IS_DMA2D_MODE(hdma2d->Init.Mode));
    6 p' V8 ~& G# b/ e5 A& C4 M3 R$ |
  13.   assert_param(IS_DMA2D_CMODE(hdma2d->Init.ColorMode));
    $ [' C4 M% n( C6 V' L' [
  14.   assert_param(IS_DMA2D_OFFSET(hdma2d->Init.OutputOffset));8 i$ K" N3 E9 V, c  U, ^1 I7 E
  15. # O8 V. |7 Z, \$ ~/ k3 @- T" R* W
  16.   if(hdma2d->State == HAL_DMA2D_STATE_RESET)1 g! f2 n$ J+ F" E# I) C
  17.   {
    1 O7 {/ N/ m6 A. R: Q9 G
  18.     hdma2d->Lock = HAL_UNLOCKED;0 w1 g/ _8 {0 E5 {1 }. U8 z! B- i
  19.     /* 初始化GPIO,NVIC等 */" `8 X8 M( h/ G2 }2 M  `
  20.     HAL_DMA2D_MspInit(hdma2d);9 M, s' _9 U! K2 T. e
  21.   }
    ; T: t' p- n. G
  22. 8 n6 F. H6 p( E6 E, ~2 `( Y
  23.   /* 设置DAM2D外设状态 */
    ' n0 b9 }  ]* k6 ?$ Y7 Z
  24.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  5 }9 s2 e2 ~7 f! Z
  25. : I* w) G9 [$ S) A0 i1 N* D
  26.   /* 设置DAM2D工作模式 -------------------------------------------*/$ K4 O6 {1 d& C
  27.   MODIFY_REG(hdma2d->Instance->CR, DMA2D_CR_MODE, hdma2d->Init.Mode);- g/ G' p+ @" `6 P2 f# X
  28.   w, X2 T5 H( R( i! z
  29.   /* 设置输出颜色格式 ---------------------------------------*/3 J5 C! U1 R; o
  30.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_CM, hdma2d->Init.ColorMode);
    5 `/ z; L( W6 D4 p# J! w; m+ {

  31. . B/ h& C# q' \- [* K$ K8 H, g
  32.   /* 设置输出偏移 ------------------------------------------*/  
    6 `, N$ g# _% b9 C
  33.   MODIFY_REG(hdma2d->Instance->OOR, DMA2D_OOR_LO, hdma2d->Init.OutputOffset);  
    ( X2 \( H! w8 p% o: E7 u0 }  A
  34. + s8 O6 T4 M% W0 E* r; U. e* W
  35.   /* 设置输出颜色格式中的Alpah值反转 */
    3 e0 j3 ^0 O- n' ^  f0 `2 [, t% Z( i- \
  36.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_AI, (hdma2d->Init.AlphaInverted << DMA2D_POSITION_OPFCCR_AI));
    , w' [0 D3 n' \2 w7 j4 D: j

  37. " e! h- k' f3 {1 ?# f
  38.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_RBS,(hdma2d->Init.RedBlueSwap << DMA2D_POSITION_OPFCCR_RBS));
    6 \1 C( J7 D8 ]$ M3 e% T3 p2 @

  39. 7 [6 L: c% s9 M; Z2 b8 @+ z' _+ C
  40. * @/ d3 n) W2 h) R+ U3 W6 A
  41.   /* 无错误 */2 P# V+ @+ M  p' l- Q* Q, c
  42.   hdma2d->ErrorCode = HAL_DMA2D_ERROR_NONE;
    # p1 _8 ], Q) [+ k

  43. ' L1 ~' v6 U8 i
  44.   /* DAM2D就绪 *// n* K; Q- h8 w
  45.   hdma2d->State  = HAL_DMA2D_STATE_READY;
    3 r( W2 H. @. w* W: b1 q4 m: Q

  46. 1 {/ `3 ]" f0 B+ M
  47.   return HAL_OK;" w' U3 B% v4 b. h- k7 |
  48. }
复制代码
) V2 p( a+ M$ `( e1 w; g  B0 e$ v
函数描述:
* s; a$ N$ R; n% R2 |: M9 H
: i, p/ u9 C6 A; n5 C( _" N9 ^此函数用于初始化DMA2D的工作模式和输出颜色格式。
- p4 d) j' E- C6 w, c8 l2 V. Z) ?1 ~
函数参数:- I- D' O4 Q& y! A" W% {% F

  E5 \1 `: K% o) @5 q* R- L, v  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。8 a1 ~; n% e: t, j
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。8 M4 p' k" V6 t8 [2 B5 j' x1 f# {
注意事项:
8 _# W2 Q# J' }5 h2 k( S+ ]0 F$ U
2 x/ {6 J8 f0 C6 ~# \" C4 k6 X2 b7 F函数HAL_DMA2D_MspInit用于初始化DMA2D的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。) [1 M7 |3 o4 @+ H
如果形参hdma2d的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量DMA2D_HandleTypeDef Dma2dHandle。- k- B% H- Z0 \8 L+ O
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_DMA2D_STATE_RESET  = 0x00U。
/ H; c7 h. A- f6 r: {5 E. i6 `1 q+ W
解决办法有三9 d* ]8 s$ q% r" C# O' S

9 p9 X' _5 R- d$ B方法1:用户自己初始DMA2D底层。4 S. x, I4 A  X

6 w! |+ r9 E9 w+ Q! `$ ?方法2:定义DMA2D_HandleTypeDef LtdcHandle为全局变量。- o# G8 {) V6 {1 I' U

5 Z' e1 T9 ]4 i方法3:下面的方法
  1. if(HAL_DMA2D_DeInit(&Dma2dHandle) != HAL_OK)
    # ~* ^- C& U5 w" W9 j
  2. {4 [/ |8 ^; L3 {$ X5 n7 l6 G& e6 Y" d
  3.     Error_Handler();1 w/ a# ^6 K0 e9 f, n5 ?4 _6 G
  4. }  ( U+ y8 ^$ w3 w
  5. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK): a7 E' [4 v# y; J( N1 e
  6. {; O' R8 J$ \2 \( Q" C: @
  7.     Error_Handler();
    4 T; l' S9 n( C9 G0 z& ]
  8. }
复制代码
7 Y. U3 A7 W8 `, U. ~! W# G

$ z! i# U' Z; J5 N8 u6 o" l1 M使用举例:
/ A+ q1 W2 O* @% {# t4 E1 B, A/ X& z" M( k1 H0 i
  1. DMA2D_HandleTypeDef Dma2dHandle;$ e8 X, `, S3 e9 ?; M

  2. * n- U! D& i/ S; g/ F1 m" H
  3. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/
    $ U+ @, t( k2 V5 k  S3 J
  4. Dma2dHandle.Instance = DMA2D;# [1 K/ I! E% g6 V" r
  5. ; t; R& s  L* m( Q  A& \1 a
  6. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */+ `- a6 y) p4 O8 N, D
  7. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */" ~: ]! ?3 R5 m
  8. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */4 J3 c# @" D6 q5 Y4 d
  9. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */
    ! t( _3 x; x4 Z
  10. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */
    1 C9 u' ?( Y7 N) Y7 S9 n

  11. : q) y" {+ D5 M2 v' y1 F
  12. /*##-2- DMA2D 回调函数配置 ######################################*/
    0 b( V2 l8 P/ l. |5 t5 {4 @
  13. Dma2dHandle.XferCpltCallback  = TransferComplete;: m, S+ j% L( `) M% f6 d
  14. Dma2dHandle.XferErrorCallback = TransferError;3 c+ u* p" K( j0 Q1 l. o

  15. - m2 f8 b0 L  O  A1 E7 p" J4 ~# |
  16. /*##-3- 前景层配置 ###########################################*/
    % a- w* X- ?" F" R
  17. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */9 O# ~4 V; @4 I$ @. R
  18. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */
    ( \" p  V% D  E' ]. P$ y$ l
  19. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */( G5 C9 m8 `. }3 _: T9 |; a9 [
  20. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */
    ' t4 Z9 w. F6 d2 P! y6 N
  21. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/
    ! w: c& Z! z  K! ~" l5 m$ Y: U
  22. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/
    5 b2 U- N9 l6 A* C  e

  23. 3 r3 W& i- u& w  W- A4 X/ [

  24. " X2 J# l( l# M0 x5 B$ B
  25. /*##-4- DMA2D 初始化 ###############################################*/
    - {3 r. |6 d+ t5 y3 R! ]
  26. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK): ^8 _; {. o& l! \8 p+ D
  27. {
    ! U4 d! G- W6 K
  28.     Error_Handler();
    : }* Z* Z( n) I* ]  u/ ]/ k
  29. }
复制代码
2 t* r( L1 x6 Y$ @5 A9 L+ p
55.4.2 函数HAL_DMA2D_ConfigLayer
! Y3 l4 U, u- x: K. K' J函数原型:6 L' K1 l+ t* O2 _1 A
/ C% N6 l0 J' s) U7 N1 [& J
  1. HAL_StatusTypeDef HAL_DMA2D_ConfigLayer(DMA2D_HandleTypeDef *hdma2d, uint32_t LayerIdx)
    + m2 _( o  \! h9 \, T4 C( J! e
  2. { ( H$ i3 R) j1 y1 j4 Y7 N
  3.   DMA2D_LayerCfgTypeDef *pLayerCfg = &hdma2d->LayerCfg[LayerIdx];
    8 b7 z4 |- j* Q$ _; @

  4. " V8 I3 R* i1 n4 w* E9 i" v& O: K
  5.   uint32_t regMask = 0, regValue = 0;
    4 O* H( a7 ~# Q6 t
  6. " r5 w. g3 J) X  L% l; E
  7.   /* 检查参数 */) i0 ?1 W* b: I1 T6 [
  8.   assert_param(IS_DMA2D_LAYER(LayerIdx));  
    ! L5 I0 W) B3 H) l% j  K
  9.   assert_param(IS_DMA2D_OFFSET(pLayerCfg->InputOffset));  # ~( U7 b0 }2 E% y
  10.   if(hdma2d->Init.Mode != DMA2D_R2M)
    " A+ _# j6 i) _+ _, p
  11.   {  
    % H/ Z) B: n" c) C5 x5 q
  12.     assert_param(IS_DMA2D_INPUT_COLOR_MODE(pLayerCfg->InputColorMode));
    ' L! R$ d* S+ k4 r" }
  13.     if(hdma2d->Init.Mode != DMA2D_M2M)
    + `% G8 Q  W) e8 r
  14.     {
    4 L" Q3 `: U8 H  v6 J( {- v
  15.       assert_param(IS_DMA2D_ALPHA_MODE(pLayerCfg->AlphaMode));* F8 ?" b9 b7 R$ }1 Q4 K
  16.     }
    0 e' m- G' V0 Y
  17.   }
    / ?' T  }6 D1 k8 k2 k" L" c; q$ z

  18. & c% Z* F  R2 ~1 h2 O2 k
  19.   /* 上锁 */
    * z) i! y: \: G3 H
  20.   __HAL_LOCK(hdma2d);
    - t, L8 W6 C  ]7 a( q- D0 T

  21. ) s+ U8 w% I' Q1 p8 G1 H
  22.   /* 设置DMA2D外设状态 */. M3 [- e2 T1 z/ F  Q& |
  23.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  ( l* M5 H: s$ @

  24. 6 m5 @- V( r  O8 V5 W8 [. e
  25.   /* 准备好背景层或者前景层FPC寄存器配置参数*/
    $ m. l" R- k  `( r' T0 ]7 ^. T
  26.   regValue = pLayerCfg->InputColorMode | (pLayerCfg->AlphaMode << DMA2D_POSITION_BGPFCCR_AM) | \" ^7 F4 r- j$ p, Q: B; Z
  27.             (pLayerCfg->AlphaInverted << DMA2D_POSITION_BGPFCCR_AI) | \
    5 Z4 D) n! ~9 ]' v# p+ r0 R
  28.             (pLayerCfg->RedBlueSwap << DMA2D_POSITION_BGPFCCR_RBS);9 C) F/ {! G( w* _

  29. % t8 f2 M6 @/ o2 b
  30.   regMask  = DMA2D_BGPFCCR_CM | DMA2D_BGPFCCR_AM | DMA2D_BGPFCCR_ALPHA | DMA2D_BGPFCCR_AI | DMA2D_BGPFCCR_RBS;6 z( ^( D& ?; g' X

  31. ' ?1 z  B! c% }  C3 `5 U
  32.   if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    , I& C1 T2 Z; }" e9 K
  33.   {6 G3 y8 j+ g& s" o
  34.     regValue |= (pLayerCfg->InputAlpha & DMA2D_BGPFCCR_ALPHA);
    ) O- k7 j) `: N4 S
  35.   }
    # J6 j0 ^1 k. y0 A* t. |. _
  36.   else
    + @- ?" C0 G) q! v  t! Q3 L
  37.   {+ x1 _3 Y) C# R$ L! K
  38.     regValue |=  (pLayerCfg->InputAlpha << DMA2D_POSITION_BGPFCCR_ALPHA);
    ( |: w% X. I  g, h" ^# O" }! Y
  39.   }5 x  V' U: @  h. |+ W3 y# A5 e) b7 p

  40. & ^1 [4 a1 @# R8 [( ^; ]' v$ K& A3 G
  41.   /* 配置背景层 */
    1 X9 K  B- H" M* U# B$ b! u
  42.   if(LayerIdx == 0)/ J7 k2 O5 [1 j7 V* q1 \& h
  43.   {
    ; \, O9 p  `2 V1 F& r6 H  l
  44.     /* DMA2D BGPFCCR 寄存器 */
    $ S- T+ j4 b# l2 ?  I
  45.     MODIFY_REG(hdma2d->Instance->BGPFCCR, regMask, regValue);6 D) U6 C5 L; ?! l% u# y
  46. 2 S$ K! N$ N1 Z7 D9 B+ W9 q
  47.     /* DMA2D BGOR 寄存器 */  
    / P& R: J* c- L* s2 o$ `- _
  48.     WRITE_REG(hdma2d->Instance->BGOR, pLayerCfg->InputOffset);
    " m! z8 @; a! H% R( W4 h) U1 Q  ~

  49. 4 f; K, I2 C, L; w9 e5 U2 ?
  50.     /* DMA2D BGCOLR 寄存器 */ # q0 o) P7 B; I- G& c7 u8 C5 L
  51.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    6 n* P/ L, U) r1 s5 R6 z6 B
  52.     {   
    " g* M  i# z' U9 S
  53.       WRITE_REG(hdma2d->Instance->BGCOLR, pLayerCfg->InputAlpha & + ~$ a! R+ v) I( w; J
  54. (DMA2D_BGCOLR_BLUE|DMA2D_BGCOLR_GREEN|DMA2D_BGCOLR_RED));) s1 j- i6 z2 l1 T4 q
  55.     }   
    1 ~* ]1 j- h6 x: c# {
  56.   }
    ; Q$ J0 W3 u" Q; N8 S  A, ]4 ~8 p
  57.   /* 配置前景层 */! [. h- H+ y2 R( F
  58.   else
    7 g/ e5 y5 Q8 J9 j
  59.   {
    ' |) z, F6 e( \7 a6 Q. A
  60.     if(pLayerCfg->InputColorMode == DMA2D_INPUT_YCBCR)
    ' {+ ~1 _+ l1 `6 E/ j% k
  61.     {
    9 o7 \$ U( C0 L" g
  62.       regValue |= (pLayerCfg->ChromaSubSampling << DMA2D_POSITION_FGPFCCR_CSS);9 s9 j6 o3 Z, Y) p! |
  63.       regMask  |= DMA2D_FGPFCCR_CSS;1 E+ }- o9 G8 |7 w
  64.     }& |- w+ H/ F) {! x
  65. $ l: S- R) R9 E+ ]
  66.      /* DMA2D FGPFCCR 寄存器 */, N4 J$ c. R  A3 F4 O4 @
  67.     MODIFY_REG(hdma2d->Instance->FGPFCCR, regMask, regValue);
    7 g& f* M4 r' V- @+ t8 q
  68. 7 A7 l+ ]7 f" A2 y* _
  69.     /* DMA2D FGOR 寄存器 */
    ( q. W7 p0 L& m4 h
  70.     WRITE_REG(hdma2d->Instance->FGOR, pLayerCfg->InputOffset);      
    & I. l. W6 T3 X5 r) R: W
  71. - C; H, K! h. l: E
  72.     /* DMA2D FGCOLR 寄存器 */   
    9 W& p9 i" W6 H8 i8 X
  73.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))$ t/ \7 {; `$ f2 h" n3 O: I: t
  74.     {) m4 E' l7 {' t% r. G7 D4 ^
  75.       WRITE_REG(hdma2d->Instance->FGCOLR, pLayerCfg->InputAlpha &
    $ H) D& n: q' Y! {' z; v
  76. (DMA2D_FGCOLR_BLUE|DMA2D_FGCOLR_GREEN|DMA2D_FGCOLR_RED));      2 D4 S3 |1 w: A
  77.     }   7 i8 e4 B: N3 g7 n0 U" p
  78.   }   0 o  j$ Z1 o$ }
  79.   /* DMA2D就绪 */. e: P7 x5 R+ S3 @9 T
  80.   hdma2d->State = HAL_DMA2D_STATE_READY;! s5 z) I) W- I- s

  81. ) Y: W7 D- K1 C! ?0 K
  82.   /* 解锁 */  P& q6 X) V  P; F2 ?8 k, O: ]
  83.   __HAL_UNLOCK(hdma2d);  ! J& t$ J5 C0 l9 t
  84. 5 {8 a, S3 r9 j" ~8 S
  85.   return HAL_OK;
    % @1 ^% w5 B* b
  86. }
复制代码

+ r5 t: E$ I. j1 p函数描述:. S4 q5 v6 f* f* L. f
9 D" \! x4 R, `4 K3 o
此函数主要用于配置DMA2D要转换的前景层和背景层,即输入颜色配置。而前面的函数HAL_DMA2D_Init配置的输出颜色。2 E5 I' U, ]) z/ f

8 a4 x5 N; ]- a8 G$ l* Y  E" c% O函数参数:' Y" c  \; ]2 t
5 f# z& w9 r- o7 K% ]
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。
0 Q# `0 p* f5 ~* B. _: F  第2个参数用于配置前景层和背景层,0表示背景层,1表示前景层。2 t) t; Q5 q) N, {, i& k
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。  Y& Y+ l/ U0 h5 n& M
使用举例:# |, s$ j4 y  a, U) E& J
  1. ' }* S% c, U+ M& |& z
  2. DMA2D_HandleTypeDef Dma2dHandle;
    / y! v! k  ^# M7 j; {( K9 C

  3. " z8 v8 C6 G2 y% a* t
  4. ; A& q# w3 ?8 o2 D/ K
  5. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/8 x) c* o- j) `3 H$ x3 U" T
  6. Dma2dHandle.Instance = DMA2D;
    ; O  }9 g/ ]5 A  l: b0 R- r! H$ K

  7. : t4 V: b: @2 F+ a; q3 I
  8. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */
    7 _  @: u4 ~6 c
  9. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */7 g2 n" z% e: }2 E1 d* q2 a
  10. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */
    2 P9 `4 ~1 N0 F- x9 R7 Z
  11. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */9 k. }3 {3 R' ^" S+ |( X* [
  12. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */
    3 _# f# o7 s( c/ u1 n

  13. ) d: b/ r9 s. s/ A  V
  14. /*##-2- DMA2D 回调函数配置 ######################################*/
    + t( b$ J6 e+ T% F
  15. Dma2dHandle.XferCpltCallback  = TransferComplete;
    " ^# H4 `1 p2 `6 q+ l
  16. Dma2dHandle.XferErrorCallback = TransferError;& I! Q* x! H% A' C$ K! k9 l2 _
  17. 1 G+ J) n  x2 s6 D5 h9 Q2 l8 O
  18. /*##-3- 前景层配置 ###########################################*/0 m8 Z+ z. d3 R! R
  19. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */
    4 s$ D# O/ R: {1 n/ v  U( x
  20. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 *// \6 L$ z/ N' ?/ q" ^6 _3 {
  21. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */
    3 S0 d, [, O3 g+ [! ~& F
  22. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */
    ( S4 p  Q3 ~7 h2 f
  23. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/
    + |  i: y; n$ M$ ^* X: B* j8 `
  24. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/. i8 I: y3 P+ w

  25. % D6 h5 H& ]+ d' ^9 s
  26. /*##-4- DMA2D 初始化 ###############################################*/- ?) A9 Z# E) u) _( X2 {- M
  27. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)9 U( E# [2 z4 C2 C
  28. {
    ( a3 i8 T) n- ~- U
  29.     Error_Handler();
    5 q4 s$ n) D: X. S/ A  k
  30. }3 z! b" C5 m8 g. V+ e5 X! d# S

  31. ( A( J6 m5 ?* i+ Y1 n5 X( z
  32. /* 配置前景层  */
    2 D5 F8 b/ X+ j$ f2 e: E
  33. if(HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1) != HAL_OK): N* u% e9 z- V
  34. {
    - F4 P& z7 x3 _( [0 @% Y
  35.    Error_Handler();
    % ^" E. e8 Z) `
  36. }
复制代码

1 a. N$ z+ m# n. h% W. l6 @* _! j0 V/ Z: j  V) H7 K
55.4.3 函数HAL_DMA2D_Start_IT$ ^) j2 f( b. O
函数原型:; c$ ?% M. I% {/ Q
' p5 ]; v7 Y8 t) K; }# C
  1. HAL_StatusTypeDef HAL_DMA2D_Start_IT(DMA2D_HandleTypeDef *hdma2d, uint32_t pdata, uint32_t DstAddress, uint32_t Width,  uint32_t Height)
    # a' {7 x- b5 G
  2. {% I7 p; E6 o' p
  3.   /* 检测函数形参 */
    ; T! X& c' m, n  ~
  4.   assert_param(IS_DMA2D_LINE(Height));
    + Y1 h! p% L3 k  b: P& s
  5.   assert_param(IS_DMA2D_PIXEL(Width));
    : U4 a7 D0 J; U4 v& _; K

  6. ( N: e, ~+ c- i- J: ~
  7.   /* 上锁 */
    8 d; q: G, R. p3 G& K+ x
  8.   __HAL_LOCK(hdma2d);: e; A. q. T; I9 y
  9. & h( X/ R6 d6 T- l# T* u7 q
  10.   /* 设置DMA2D外设状态 */! G0 C- [6 ]. Q7 ?& y+ D& q, H
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;
    # ~& D: u2 H7 l6 L- I

  12. 4 o; a5 {3 z5 j; \
  13.   /* 设置源地址,目的地址和数据大小 */2 F9 {% I6 L9 @7 E) |4 s8 S
  14.   DMA2D_SetConfig(hdma2d, pdata, DstAddress, Width, Height);& j/ C% y7 j' I( s( @* ~

  15. * v% `: w, s  l/ `1 ^
  16.   /* 使能DMA2D的传输完成中断,传输错误中断和配置错误中断 */6 F3 G8 C$ R1 e+ C$ p- r
  17.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);3 W/ g% p) N/ A9 f  O7 A. X

  18. ; q4 V" }! o1 k  r* v! K
  19.   /* 使能DMA2D *// R- A+ E! K- _4 s" b9 Q& ?
  20.   __HAL_DMA2D_ENABLE(hdma2d);' {) [, \. S1 H% j

  21. 8 |& O1 W& b& i+ g# |* a$ B
  22.   return HAL_OK;
      |, i" H& @* z  U. M( w
  23. }
复制代码

3 g( u( i0 e2 |, ?4 ^函数描述:* W/ h  V: g7 b: s& |3 V0 ]

2 M) T7 r' m- W% m) U. P  B此函数用于启动DMA2D数据传输。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。5 E+ d' O" G0 b3 c

8 B" t1 b+ C& U! z& n2 Q函数参数:
( X9 I% t0 k6 j- Q1 @  U8 ]4 I/ b  S! L3 `! k
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。
9 K) ?, q8 Q# ]1 {; ~  第2个参数是源数据地址。
6 S6 d0 A  J1 V2 {/ g) u  第3个参数是目的数据地址。
' N. K( B3 J& w: M$ C: X# U  第4个参数是源数据的长度,即每行的像素个数。
8 I- d: I5 E4 {# A  第5个参数是源数据的高度,即行数。
+ [  E; w3 e) @! F: S0 @* q) w5 c  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。* A$ q. M( P, l$ h2 W# h# G
使用举例:
. l+ u& {2 ?  p1 N4 [2 @; @1 _7 U, {' Z: E
  1. DMA2D_HandleTypeDef Dma2dHandle;
    * [) I5 g, _3 Y/ ^2 D

  2. 8 z' ~$ l# I" v0 [) N: t
  3. if(HAL_DMA2D_Start_IT(&Dma2dHandle,            /* DMA2D句柄 */
    6 w4 y9 U0 O4 G. I5 W
  4.                       (uint32_t)&BufferInput,  /* 源地址 */
    & ^' e+ H/ C! R* n7 }
  5.                       (uint32_t)&BufferResult, /* 目的地址 */
    6 X+ v# l3 L5 F3 s( q6 j
  6.                       SIZE_X,                  /* 源数据长度,单位像素个数*/, p0 _& v# B& a1 f1 k  _
  7.                       SIZE_Y)                  /* 源数据行数 */
    9 w: L/ T0 z& U2 h) S  s
  8.    != HAL_OK)
    8 ^& F" E; r- a6 H, P
  9. {
    " K; [5 w0 w2 V% m& f; _$ o  H
  10.    Error_Handler();
    , z* o; ]' W; Z+ K+ |  u1 h
  11. }
复制代码

9 |7 s& k; p/ E: D1 g) n5 O55.4.4 函数HAL_DMA2D_BlendingStart_IT5 T1 d2 D; s+ {- D6 P
函数原型:* B2 {4 j* m- _7 p! o3 W4 e+ }

3 z" x) A  H, w$ A
  1. HAL_StatusTypeDef HAL_DMA2D_BlendingStart_IT(DMA2D_HandleTypeDef *hdma2d, uint32_t SrcAddress1, uint32_t  SrcAddress2, uint32_t DstAddress, uint32_t Width,  uint32_t Height)
    % l/ w' h" p1 ^- m$ z# e
  2. {
    0 s: b* t, c1 [/ B1 |
  3.   /* 检测参数 */- b% }* }$ k* L# n& @
  4.   assert_param(IS_DMA2D_LINE(Height));
    . c' O3 V! J& j7 c! `1 N
  5.   assert_param(IS_DMA2D_PIXEL(Width));
    7 W/ F/ W- J1 Q

  6. # }  }6 `3 F9 z1 U
  7.   /* 上锁 */
    5 z  c1 T0 ?5 x5 O$ b; \2 h
  8.   __HAL_LOCK(hdma2d);1 L6 {/ x6 c$ i7 c; E. O& c& v( J

  9. ( V" G6 N% q; J3 U7 G* h
  10.   /* 设置DMA2D外设状态 */& J; N+ y+ k: l
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;# R. A! B" V( W# \- E

  12. ' V) d" M+ `# w% o
  13.   /* 配置DMA2D源地址2 */3 }3 G/ X9 M$ H) ^
  14.   WRITE_REG(hdma2d->Instance->BGMAR, SrcAddress2);. k' j' _0 g2 V# R) I2 r3 K$ H

  15. - W6 ]7 Z( ?2 z& T2 f% }
  16.   /* 配置源地址1,目的地址和数据大小 */
    / S( H1 W2 s; B
  17.   DMA2D_SetConfig(hdma2d, SrcAddress1, DstAddress, Width, Height);
    0 Z# r9 s( S/ s( \: l9 l

  18. & `% {, a; v$ ?4 \) t
  19.   /* 使能DMA2D传输完成中断,传输错误中断和配置错误中断 */! A! Y" a8 H! B5 _6 n
  20.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);# X1 |8 `/ g# D$ B! l: |2 `, \* n

  21. ' G* G/ n7 {6 Y* s" x! T& q0 z5 d
  22.   /* 使能DMA2D */! J/ ^3 ~: V8 H5 C$ {- F  z; p
  23.   __HAL_DMA2D_ENABLE(hdma2d);
    . E4 {7 O- W! h" T$ R4 W
  24. 4 O* {3 M7 u1 c* y
  25.   return HAL_OK;
    : _* \- H+ g; r1 J2 {/ u
  26. }
复制代码

- W; _9 V* j9 D; S! O( ]/ K  _函数描述:
' ^2 j4 ~- D1 `
! Z1 E6 u0 k5 n( c- Z此函数用于启动DMA2D传输,除了数据传输以外,还支持颜色格式转换和颜色混合。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。
7 g! Z$ k) S! ~
/ {6 C$ S( l9 _& ~8 K函数参数:
* {3 F+ c! X, P# v- U: {" M. r: f( y  n7 O2 v
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。
+ _4 m# ^; l7 Q3 v/ T  u/ r( R  第2个参数是源数据地址1。; |9 A. k& M* E! ^  P. x% O9 r# h
  第3个参数是源数据地址2。' B( z. N/ X3 C! g% S/ b
  第4个参数是目的数据地址。
  _- l4 V& |. O. p  G  第5个参数是源数据的长度,即每行的像素个数。+ P9 t) X% q% g+ ]
  第6个参数是源数据的高度,即行数。8 A7 E3 v, H  v6 y& }
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
1 a# \- k' T% ?3 A, M. s使用举例:
' r6 b; [. f8 M3 [8 B. q+ n- ?' K6 f/ r8 ~1 P
  1. DMA2D_HandleTypeDef Dma2dHandle;
    2 D* I* O- _4 `: V: d5 W8 ]" z' l* Y- z+ ^

  2. - u; V/ F* _8 R9 ^! Z3 ~" |, K
  3. if(HAL_DMA2D_BlendingStart_IT(&Dma2dHandle,           /* DMA2D句柄 */
    3 ~! r6 V+ ^) Q( |" ^. ]) K
  4.                              (uint32_t)&BufferInput1, /* 源地址1,前景色 */ 0 e6 Q' z$ k9 b# m8 H
  5.                              (uint32_t)&BufferInput2, /* 源地址2,背景色 */; H- k0 d, |& r; ?+ B
  6.                              (uint32_t)&BufferResult, /* 目的地址 */
    + r0 G' r8 T8 I( ^- h
  7.                               SIZE_X,                 /* 源数据长度,单位像素个数*/" W6 g( [+ y; ^
  8.                               SIZE_Y)                 /* 源数据行数 */2 p+ Q7 W6 [: Z- [2 P* ~4 s6 N2 N
  9.    != HAL_OK)
    1 E* B4 i4 l$ _7 C0 w0 g4 G% q
  10. {" Q" f# h* L; U) e* s; z
  11.    Error_Handler();
    ; S- |3 c1 H; N  n9 s+ r' v
  12. }
复制代码
1 m% T# F/ m1 [, e$ u/ Z) L7 ?
9 q8 a* o$ j, z* N3 Z
55.5 总结
3 B: Y+ a" p4 b4 k8 y; {% y& k本章节就为大家讲解这么多,DMA2D功能比较重要,一定要做到熟练使用。
$ p* s8 J" ]$ E; k) c+ Y6 m
5 h( c" I, g8 ~+ I
9 D& z! Z8 g0 l  T: N# v; U
! g" l1 _/ K% M. k
收藏 评论0 发布时间:2021-12-24 17:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版