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

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

[复制链接]
STMCU小助手 发布时间:2021-12-24 17:00
55.1 初学者重要提示
; R" i- z2 g5 `  DMA2D是专门用于LCD加速的,特别是刷单色屏,刷图片,刷Alpah(透明)混合效果全靠它,而且可以大大降低CPU利用率。
- ~' L, z" Y# a  测评STM32H7的LTDC+DMA2D性能,100Hz以上无压力,刷800*480图片和色块仅需2.6ms一张4 {) Y$ v4 V3 v$ h4 z
  H7的DMA2D与F429的DMA2D最大区别是支持了ARGB和ABGR互转,而且支持H7的硬解JEPG输出格式YCbCr转RGB,方便LCD显示。+ [' U5 ?3 R; n6 @
  特别注意,大家只需对HAL库提供的DMA2D操作API有个了解即可,实际工程中,并不使用这些API,我们需要使用更加高效的寄存器直接操作,在下一章节会为大家说明。
1 H* S/ K. x9 q- r( L55.2 DMA2D基础知识
" l  K. v, Z+ k6 _DMA2D主要实现了两个功能,一个是DMA数据传输功能,另一个是2D图形加速功能。
0 j/ M0 i# `: [9 \" x7 E6 j  y- |
; B* _! K  x0 u, k& u; M+ `  DMA数据传输
8 g2 n9 P) ^% l# N  a2 }. s1 g5 k主要是两种方式,一个是寄存器到存储器,另一个是存储器到存储器。通过DMA可以大大降低CPU的利用率。" x+ S; p$ X. i  P! u+ [: F, `3 _5 b
/ |" Q2 e  F9 C' F" f' w
  2D图形加速功能/ g7 H0 \5 t+ z0 @7 N/ g
支持硬件的颜色格式转换和Alpha混合效果。
3 W: U2 u$ ^$ v5 P
$ N% o) V8 C2 ]1 Q* p55.2.1 DMA2D硬件框图) f2 t+ R, X; a, X
认识一个外设,最好的方式就是看它的框图,方便我们快速地了解DMA2D的基本功能,然后再看手册了解细节。框图如下所示:
5 m  h% {2 I; h: `* y! b5 ~* b
) M4 D# C/ U8 u
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
- ?& [# m. h. T! u! a
6 X( ^, Y; }/ x! v/ e$ Q  r
通过这个框图,我们可以得到如下信息:
: ^  c1 h# i7 v  z) Z! T3 M
# C" M5 z. g3 i) m, F, E& q7 q  dma2d_aclk: g8 M$ e2 J/ a7 Y& y/ X) B: U
AXI 总线时钟输入。
/ I1 q+ g: [3 h$ b. w' _/ I" Y  X% H$ D8 K* ^
  dma2d_gbl_it. a- n: P. z0 f! {# H
DMA2D全局中断输出。
7 X1 b/ q, h0 ~9 U; o; o) }2 b, b& m4 j# i
  dma2d_clut_trg
% f/ g9 U$ k8 m, h" {CLUT传输完成信号输出,可以触发MDMA。
7 |  C' L! H! D8 P
" v8 z9 h8 _# @+ L6 @' Q  dma2d_tc_trg6 Q4 F. J8 m2 e: N
传输完成信号输出,可以触发MDMA。) d! X% E. J7 `/ q* b- o2 _

( a* `9 Y9 k/ b( o  dma2d_tw_trg
5 m/ Q: Y" @. ~& v传输watermark信号输出,可以触发MDMA。( _0 a* u  E  y
: b, W! ~0 t/ }7 V
将这个硬件框图简化一下,就是下面这样:8 G4 I6 j1 H# L5 k9 r7 ~

; J  i, D0 u- N# J
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

- f3 [: E* f2 O# {* _0 i  z; e) b; h
$ p4 [+ `0 @+ A8 T0 o; l$ W下面按照简化的硬件框图,对每个部分做个说明。( W' e$ a5 T1 h+ [7 {9 I% @0 E
5 [1 Z/ p0 j! t9 `* ~/ f5 {
55.2.2 DMA2D工作模式7 \" a' c+ F: e2 U; u
DMA2D支持的工作模式如下:
6 {1 \; j' a* e$ |! ~3 ]8 J7 ]( k. g8 o. B4 e4 o* L
  模式1:寄存器到存储器模式
+ a& e0 s# T/ Y这个模式主要用于清屏,也即是将显示屏清为单色效果。* C& p( c3 U6 q( d* A: g0 e

/ u; w3 d  s9 U; |$ I  模式2:存储器到存储器模式
1 j, j$ ^& _. L这个模式用于从一个存储器复制一块数据到另一个存储器,比如将摄像头OV7670的输出图像复制到LCD显存就可以采用这种方式。( ~; O4 y" e, c
9 G) n8 B" |# x
  模式3:存储器到存储器模式,带颜色格式转换6 ^* e) O' W! P
这个模式比模式2多了一个颜色格式转换,比如我们要显示一幅RGB888颜色格式的位图到RGB565颜色格式的显示屏,就需要用到这个模式,只需输入端配置为RGB888,输出端配置RGB565即可。位图颜色格式转换后会显示到显示屏上。
- l% K: L, r& y9 `
7 ?$ n. i4 G5 W$ A* x  模式4:存储器到存储器模式,带颜色格式转换和混合
0 [% q* I) k& P8 R这个模式比模式3多了一个混合操作,通过混合,可以将两种效果进行混合显示。
1 i% H& P" Y8 G% b9 t( }0 l
2 Z! ?9 Y* L' P; J9 z  模式5:存储器到存储器模式,带颜色格式转换和混合,前景色是固定的
# l; @  ^/ l  v2 Q同模式4,只是前景色的颜色值是固定的。8 C, f9 E+ ?) Q

$ A$ s  s8 l3 _9 W- M3 |/ m1 ^( Y55.2.3 前景层和背景层的输入以及颜色格式转换
! B6 }$ t2 f2 T. F, k前景层和背景层是指的用户绘制图形时的前景色和背景色,比如我们显示汉字,字体会有一个颜色,也就是前景色,还有一个背景色。又比如我们绘制两幅图片,想将两幅图片混合,那就可以将一幅图片作为前景层,另一个幅图片作为背景层。
$ y: b3 T7 p! p$ W8 E
$ Z2 C- J5 K0 r( BDMA2D支持的输入颜色格式如下,前景层和背景层一样:
3 p2 \: Y( g) |  G
7 ]4 V5 T! y) p1 f% D- m
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
, i9 [7 @% q" u% p

, c  E' Z$ B. x3 z+ u前8种颜色格式在第50章的第2小节开头有介绍,这里把后四种做个说明:% ~/ M+ O# Q( o5 ^

. N. r3 M  s8 a: b# ~- X  L4 (4-bit luminance or CLUT)
8 x( K1 B9 @, Y3 v4位颜色格式,实际上仅仅是4位索引值,范围0–15,而每个索引值的具体颜色值在查色表CLUT里面存储。
* X4 D$ d+ z2 o$ E' `4 \9 e' t
* P  R& t0 b& `9 \: z* _4 h+ _2 v4 j  A4和A8
0 _! k7 W( a, F; ?2 G; |A4和A8用于特定的Alpha模式,既不存储颜色信息,也没有索引值。- r% i3 K! H5 D6 s' g7 J5 s* C% j
( b/ {6 @. t  s( M$ G4 g% E3 V
  YCbCr+ c2 v6 r4 I; F7 {
这个是H7的硬件JPEG输出的颜色格式,后面JPEG章节为大家专门做讲解。
: O5 r, m4 f; J; ~8 ]& ]) c4 x7 h; w9 ^5 |( n$ A
这里特别注意一点,输入颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。
! A" m. ?, E8 _1 F! i; V' \1 U& d" P6 q7 |# D: X! }. Y
55.2.4 前景层和背景层混合! E$ L' S( H! D& A* r
DMA2D混合器用于混合前景色和背景色,这个功能不需要任何配置,仅需要通过DMA2D_CR寄存器使能即可。混合公式如下:# o" @3 P: @( M) y. F$ B

; {( ^4 r* D' v7 Z& e  }$ c
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
  ]3 X" [4 g  A7 o: [0 j) ~$ x
) N: }6 H: O( Q1 G) R1 K  x+ w
55.2.5 DMA2D输出颜色格式
' t  y7 i8 O: _# P) B5 Y1 o- tDMA2D支持的输出颜色格式如下:
) K; i$ z$ _+ t" Q( y4 O' x6 E- r7 W
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
7 B; q1 p) B6 N5 Y. X! j
$ p: E0 Y2 M; \$ G
这里特别注意一点,输出颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。/ I6 w4 _+ {6 w9 `  j% d: y

7 p$ p. u( U. s- Z* Q# r55.3 DMA2D的HAL库用法
, |/ z0 I# {; O7 y1 G( I$ oDMA2D的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断。下面我们逐一展开为大家做个说明。
, ], m1 U/ H0 f: I: }+ A* U' f5 [! W
  o- U/ L  m, a% O2 }# x) O: m55.3.1 DMA2D寄存器结构体DMA2D_TypeDef
% G1 h' Q) W/ A( \1 S# K' WDMA2D相关的寄存器是通过HAL库中的结构体DMA2D_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:4 a9 V5 U' `8 p" ?1 W$ R( G0 Q

* F, s  I- |- N0 \
  1. typedef struct( y( D0 d+ b2 m- w  H0 q
  2. {
      r8 K1 X" G( k4 v3 P. P& U4 ~
  3.   __IO uint32_t CR;            /*!< DMA2D Control Register,                         Address offset: 0x00 */9 u/ d+ b7 a2 N
  4.   __IO uint32_t ISR;           /*!< DMA2D Interrupt Status Register,                Address offset: 0x04 *// c2 }( f% g6 r0 g7 X+ l9 d- _- O
  5.   __IO uint32_t IFCR;          /*!< DMA2D Interrupt Flag Clear Register,            Address offset: 0x08 */
    5 ?- m3 f1 z; E: h  T* p$ H, L
  6.   __IO uint32_t FGMAR;         /*!< DMA2D Foreground Memory Address Register,       Address offset: 0x0C */
    1 ~/ w4 S! y  B
  7.   __IO uint32_t FGOR;          /*!< DMA2D Foreground Offset Register,               Address offset: 0x10 */
    ; R. u: Q9 K! U2 A! V
  8.   __IO uint32_t BGMAR;         /*!< DMA2D Background Memory Address Register,       Address offset: 0x14 */
    " ]- h3 n, E5 s2 {8 B; h8 J  E
  9.   __IO uint32_t BGOR;          /*!< DMA2D Background Offset Register,               Address offset: 0x18 */
    " G* H- A5 `. r
  10.   __IO uint32_t FGPFCCR;       /*!< DMA2D Foreground PFC Control Register,          Address offset: 0x1C */
    ( [) F, x& O# C) P1 u; s7 P
  11.   __IO uint32_t FGCOLR;        /*!< DMA2D Foreground Color Register,                Address offset: 0x20 */7 N) Y# E2 N$ v, B. h* o
  12.   __IO uint32_t BGPFCCR;       /*!< DMA2D Background PFC Control Register,          Address offset: 0x24 */. E2 ^; |) p5 ~) X
  13.   __IO uint32_t BGCOLR;        /*!< DMA2D Background Color Register,                Address offset: 0x28 */6 B/ B+ f8 W* Y! b4 U7 ]4 ^! q& q
  14.   __IO uint32_t FGCMAR;        /*!< DMA2D Foreground CLUT Memory Address Register,  Address offset: 0x2C */& B. s  W3 x" L) n) u
  15.   __IO uint32_t BGCMAR;        /*!< DMA2D Background CLUT Memory Address Register,  Address offset: 0x30 */
    9 P- o; t6 {1 ^& M
  16.   __IO uint32_t OPFCCR;        /*!< DMA2D Output PFC Control Register,              Address offset: 0x34 */. Z9 l7 G1 [" T* ]; `- z+ ^, v. }
  17.   __IO uint32_t OCOLR;         /*!< DMA2D Output Color Register,                    Address offset: 0x38 */
    $ ^( e' t# O! w8 k0 _
  18.   __IO uint32_t OMAR;          /*!< DMA2D Output Memory Address Register,           Address offset: 0x3C */
    ' e4 H1 @: x  k0 h, |  U. l
  19.   __IO uint32_t OOR;           /*!< DMA2D Output Offset Register,                   Address offset: 0x40 */; \: q5 h8 ?4 r. Q9 G  M; a. ]6 v
  20.   __IO uint32_t NLR;           /*!< DMA2D Number of Line Register,                  Address offset: 0x44 */
    ! \! x1 r# J6 P. Y! r
  21.   __IO uint32_t LWR;           /*!< DMA2D Line Watermark Register,                  Address offset: 0x48 */
    4 A9 V! w4 P- i9 \
  22.   __IO uint32_t AMTCR;         /*!< DMA2D AHB Master Timer Configuration Register,  Address offset: 0x4C */
    . I% S4 j$ i/ K, T
  23.   uint32_t      RESERVED[236]; /*!< Reserved, 0x50-0x3FF */; T" B5 u% T- f8 @& k
  24.   __IO uint32_t FGCLUT[256];   /*!< DMA2D Foreground CLUT,                          Address offset:400-7FF */
    - X- Q. k2 O' c9 e0 H$ K, k# M+ y" }
  25.   __IO uint32_t BGCLUT[256];   /*!< DMA2D Background CLUT,                          Address offset:800-BFF */
    # R* Q- Q- }* @
  26. } DMA2D_TypeDef;
复制代码
* c5 f9 `/ Z: g. X; i+ N* D
) Q( w+ A- @- _' r- p8 v
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:1 L1 K; t' o, h' v4 Z) {

; e' b$ M/ \: U! T% m3 f- a
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */. q( G+ L; D' e4 \5 o. s3 {0 v& [1 }
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
- h& H( e" c2 z  i: p& T2 V$ c
下面我们再看DMA2D的定义,在stm32h743xx.h文件。
  1. #define PERIPH_BASE              ((uint32_t)0x40000000) 4 ~" y+ A, C9 \; a. g
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000)
    $ `9 \1 t/ [+ s& Q
  3. #define DMA2D_BASE               (D1_AHB1PERIPH_BASE + 0x1000)! l9 x8 e% @! j3 ]
  4. #define DMA2D                    ((DMA2D_TypeDef *) DMA2D_BASE) <----- 展开这个宏,(DMA2D_TypeDef *) 0x52001000
复制代码
3 Y' v5 P& x% l
我们访问DMA2D的ISR寄存器可以采用这种形式:DMA2D->ISR = 0。
* E) m! ~# f, H! e
% B+ ^% K5 u) J2 D" J55.3.2 DMA2D参数初始化结构体DMA2D_InitTypeDef" [+ h9 [. D9 t# O) A* W6 H5 T* p
此结构体用于配置DMA2D的基本参数,具体定义如下:( _# c1 o2 p% i3 S
8 q5 i% W" C: m# Z8 V/ _
  1. typedef struct
    ! q1 T& D) C% _& W
  2. {! D8 `2 w# c$ }" ^$ c. t5 x0 Q. d# I( m
  3.   uint32_t             Mode;              % e7 G! o  p9 K( ?9 q- S. a* O
  4.   uint32_t             ColorMode;        1 N& b) U% N4 }
  5.   uint32_t             OutputOffset;       $ E% ], x9 G  w9 E
  6.   uint32_t             AlphaInverted;   
    6 Y8 q! C* z0 h" i+ ^
  7.   uint32_t             RedBlueSwap;      
    * g  j6 g! v) V4 |" F  V+ C/ q- |0 W
  8. } DMA2D_InitTypeDef;
复制代码
0 Z( T& \, ~! v0 o4 `2 W
下面将这几个参数逐一为大家做个说明:  N% {( l! g! S# U0 C: D% X+ n

7 o5 W3 p' I& O8 k, ]+ p7 _" Z  uint32_t   Mode' J- Z  a( b! r
此参数用于设置DMA2D的传输模式,具体支持的参数如下:" g% [& E8 v3 }. H# `5 ?
* R2 R: z' Q- W( G' q$ T8 l& E% n
  1. #define DMA2D_M2M        ((uint32_t)0x00000000U)  /*存储器到存储传输模式 */
    2 J6 `: z0 F$ Z
  2. #define DMA2D_M2M_PFC     DMA2D_CR_MODE_0         /*存储器到存储器传输模式,并执行FPC像素格式转 */
    & i7 W& j; |! b  @2 u) b9 S/ c; T( x
  3. #define DMA2D_M2M_BLEND   DMA2D_CR_MODE_1         /* 存储器到存储器模式,并执行像素格式转换和混合 */: K; @9 ^: X9 Q% H! q3 n  b' ]
  4. #define DMA2D_R2M         DMA2D_CR_MODE           /* 寄存器到存储器传输模式 */3 t# ~* g# b+ E' M# O/ v' w( R2 b
复制代码
' g9 Z) \! v/ d0 V( U: v& M( n$ ]
" @( |# N* g" X1 g4 \
  uint32_t   ColorMode6 G' t4 r2 O" U/ C7 {. p& C
此参数用于设置DMA2D的输出颜色格式,具体支持的参数如下:
( ]1 _% ?' v9 B4 V; n7 f7 e3 k+ }! V2 A4 l% I8 `: i+ C
  1. #define DMA2D_OUTPUT_ARGB8888       ((uint32_t)0x00000000U)               /* ARGB8888 */
    / H" K! b% n" O* g
  2. #define DMA2D_OUTPUT_RGB888         DMA2D_OPFCCR_CM_0                     /* RGB888 */6 b) g0 H) M) t+ G
  3. #define DMA2D_OUTPUT_RGB565         DMA2D_OPFCCR_CM_1                     /* RGB565 */
    ) u5 H) `# [0 R9 s
  4. #define DMA2D_OUTPUT_ARGB1555       (DMA2D_OPFCCR_CM_0|DMA2D_OPFCCR_CM_1) /* ARGB1555 */
    0 _& p3 o/ r6 g( g% l% n, L
  5. #define DMA2D_OUTPUT_ARGB4444       DMA2D_OPFCCR_CM_2                     /* ARGB4444 */
    7 k. _; k6 x8 Y4 ~8 ?
复制代码
- _) P# y+ u: i& I
8 @/ f1 B" E1 |& a7 j+ y
  uint32_t   OutputOffset! _6 z( y) m) V& q- T
此参数用于设置输出位置的偏移值,参数范围0x0000到0x3FFF。
+ u2 `! A; u1 m' E% N
9 x1 L+ v; `; e) b7 Y1 H  uint32_t   AlphaInverted0 w9 b: L* W+ A# k$ I  s
此参数用于设置DMA2D的输出颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     
: L: T& v* k' {  v' J* ?$ E
( p1 ^7 Q( `( B3 F+ M3 ~
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */
    : F7 [! C: M; R% j/ M
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */
复制代码

0 h. T) ]" T8 R5 H; P- u: a. \  uint32_t   RedBlueSwap; t; s8 N$ g& f) u  V
此参数用于设置DMA2D的输出颜色格式中R通道和B通道的交换,具体支持的参数如下:
/ D( O" {  k$ b1 ~6 k) E2 P4 F6 N; M7 Y4 L6 k5 S( d4 j
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */
    " V+ d7 d- o3 A1 I' c
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码
$ ]  V  n' I  K( P
55.3.3 DMA2D的图层结构体DMA2D_LayerCfgTypeDef
, ~7 K+ v! _6 s此结构体用于配置前景色和背景色。( e; u* U7 @% g) M4 X

, x$ |# ^! U. `7 |0 r( _- Y# S
  1. typedef struct' g; v" F; {, I5 J2 K
  2. {0 {' N: |$ N' v, q3 d0 [" h1 ?/ p: C
  3.   uint32_t             InputOffset;      
    ) s* b3 T) _' ^! p+ ^. l- u
  4.   uint32_t             InputColorMode;    1 e. n" q" f! v1 u! C7 E
  5.   uint32_t             AlphaMode;        1 k' j5 [. O1 A0 v. x
  6.   uint32_t             InputAlpha;        
    / p) B; U1 F4 E! t* ^4 n
  7.   uint32_t             AlphaInverted;    : l* R! ?7 _4 M
  8.   uint32_t             RedBlueSwap;      
    $ ]; j! e1 J, F- v6 D! f
  9.   uint32_t             ChromaSubSampling;
    . d( Z* J, [3 [3 t
  10. } DMA2D_LayerCfgTypeDef;
复制代码

& Z* D" H% a! g$ o+ f7 f7 R下面将这几个参数逐一为大家做个说明。
/ ~4 q8 x& Q/ {$ I. s
- |0 q1 \/ A$ L# J7 [2 N  uint32_t  InputOffset
4 @+ Z/ B/ O  |' O6 J设置前景色或者背景色的输入偏移,范围0x000到0x3FFF。; {" e9 p* ?% k& \
) O/ x2 S, F' `2 e) b
  uint32_t  InputColorMode; t5 q9 R* B* s$ e
设置前景色或者背景色的输入颜色格式,具体支持的参数如下:# x" r- @0 L5 w: Q  B3 n' n

! F0 S( u( P3 f: l
  1. #define DMA2D_INPUT_ARGB8888        ((uint32_t)0x00000000U)  /* ARGB8888 */
    , S" h, A  r( a. C! u8 u
  2. #define DMA2D_INPUT_RGB888          ((uint32_t)0x00000001U)  /* RGB888   */
    # m" Z. _, B; ^5 }
  3. #define DMA2D_INPUT_RGB565          ((uint32_t)0x00000002U)  /* RGB565   */
    4 y1 b. Z3 |: e% F( Z+ E
  4. #define DMA2D_INPUT_ARGB1555        ((uint32_t)0x00000003U)  /* ARGB1555 */( G. i2 C" I. o. r
  5. #define DMA2D_INPUT_ARGB4444        ((uint32_t)0x00000004U)  /* ARGB4444 */) B+ J$ N9 g/ c8 M( A" d5 F
  6. #define DMA2D_INPUT_L8              ((uint32_t)0x00000005U)  /* L8       */
    2 q2 ~9 ]1 E$ h: P* u
  7. #define DMA2D_INPUT_AL44            ((uint32_t)0x00000006U)  /* AL44     */
    * v3 f/ S0 G0 ?
  8. #define DMA2D_INPUT_AL88            ((uint32_t)0x00000007U)  /* AL88     */' j( x5 Y( ]% ?# K& Q/ U5 M# t9 J
  9. #define DMA2D_INPUT_L4              ((uint32_t)0x00000008U)  /* L4       */1 }* ?) _2 h! v2 \7 S
  10. #define DMA2D_INPUT_A8              ((uint32_t)0x00000009U)  /* A8       */
    ) e, M; d# p- C+ v
  11. #define DMA2D_INPUT_A4              ((uint32_t)0x0000000AU)  /* A4       */' t6 s; v3 ?6 W6 S% `3 k5 A5 m
  12. #define DMA2D_INPUT_YCBCR           ((uint32_t)0x0000000BU)  /* YCbCr    */
复制代码

& k+ S& W7 O, J& ^* m  v' x  uint32_t AlphaMode& ]: z1 K. h0 h; E
设置前景色或者背景色的Alpha模式,具体支持的参数如下:
2 ^7 M3 C; W& A3 p' F) n+ c9 M
, V9 u4 |* Z/ j1 y1 j: Q8 w- N' Z
  1. #define DMA2D_NO_MODIF_ALPHA   ((uint32_t)0x00000000U)  /* 不修改Alpha通道值 */
    ; X, M  E/ L" ?6 h) U6 I
  2. #define DMA2D_REPLACE_ALPHA    ((uint32_t)0x00000001U)  /* 用新设置的Alpha值替换原始Alpha值 */
    / Q4 N* B' j) q8 n* U
  3. #define DMA2D_COMBINE_ALPHA    ((uint32_t)0x00000002U)  /* 用新设置的Alpha值与原始Alpha值的乘积替换原始Alaha值*/
复制代码
& ?7 o. i- e) `* t0 z; C
  uint32_t  InputAlpha
- `+ {) J1 E; l; z! K: W设置前景色或者背景色的Alpha值,范围0x00到0xFF,如果颜色格式是A4或者A8,那么此参数的范围是0x00000000到0xFFFFFFFF,标准的ARGB8888格式。7 u6 V- s4 ~# Z: u5 S# e. }2 Y, v

7 ?/ C4 D# i, B" _; [  uint32_t AlphaInverted
% F. F0 H0 n3 w1 p设置前景色或者背景色的输入颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     
8 B( N( }) A* C# B3 ~. d/ x+ ?
) T! g$ V% M0 [9 n  I
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */( k2 g* y. v4 u1 b5 k% G; I
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */     
复制代码
: h8 ~5 e' F4 w! t; r
  uint32_t   RedBlueSwap
! e5 a( n3 o8 x- |  E设置前景色或者背景色颜色格式中R通道和B通道的交换,具体支持的参数如下:6 @8 B+ ?( ?: g8 H( U, v2 X
0 a# V) V6 {) `& r
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */
    9 R1 k, f6 u) z1 W6 {. G
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码
" l( V( p1 Z9 `' ?
  uint32_t   ChromaSubSampling2 G9 B6 G2 {- ?
设置前景色或者背景色中YCbCr 颜色模式的采样格式,具体支持的参数如下:
  1. #define DMA2D_NO_CSS               ((uint32_t)0x00000000)  /* 4:4:4 */% }3 w; I. t" ]1 A. a, e
  2. #define DMA2D_CSS_422              ((uint32_t)0x00000001)  /* 4:2:2 */2 b, S7 }& W9 f6 {: L
  3. #define DMA2D_CSS_420              ((uint32_t)0x00000002)  /* 4:2:0 */  
复制代码
; I: Z2 j( P# `5 |" b  g% W
55.3.4 DMA2D句柄结构体DMA2D_HandleTypeDef
0 @8 l4 @' t- O/ i5 P5 a0 X
HAL库在DMA2D_TypeDef, DMA2D_InitTypeDef和DMA2D_LayerCfgTypeDef的基础上封装了一个结构体DMA2D_HandleTypeDef,定义如下:
* ]% v$ R! H) ?4 ?
) I" F& H' k! ]( N# q
  1. typedef struct __DMA2D_HandleTypeDef2 l8 C- X6 W3 R3 h+ `* E7 O
  2. {5 Y$ Y( X1 E2 B- L  L
  3.   DMA2D_TypeDef               *Instance;                                                                                                                                                                                          
    ; p- B' }: V( `( c- T: _8 n3 h
  4.   DMA2D_InitTypeDef           Init;                                                        
    3 m) @3 B3 ?3 G# c) P% D- V
  5.   void                        (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                                                                             
      i7 O( U4 l$ j" r" W3 d
  6.   void                        (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                      
    * Q* ~$ x  V8 R. n
  7.   DMA2D_LayerCfgTypeDef       LayerCfg[MAX_DMA2D_LAYER];                                    5 m; U7 H* Z2 A5 h
  8.   HAL_LockTypeDef             Lock;                                                                                                                                                                                                   
    0 @' P# g7 ^* R) s/ p
  9.   __IO HAL_DMA2D_StateTypeDef State;                                                                                                                                                                                                   3 ^3 G1 S* U; c) Q' X! p
  10.   __IO uint32_t               ErrorCode;                                                   } DMA2D_HandleTypeDef;! {, f  B* v( N1 I/ o2 m
复制代码

* [8 p8 x9 q% |: `  H3 W; x下面将这几个参数逐一做个说明。  y* U. Z! a8 N7 J. E& R

  l& b( E9 W+ V3 F* Z/ l  DMA2D_TypeDef  *Instance
0 V0 |% a4 O" C6 C/ `6 t7 a0 [这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。7 ?9 j+ r$ n6 [7 c2 g

% Q! b* o. J, g% A  DMA2D_InitTypeDef  Init;  & X$ ?3 H6 H" Q$ e1 N$ P
这个参数是用户接触较多的,用于配置DMA2D的基本参数,详见本章3.2小节。  W8 u9 Y5 k2 U7 o8 l4 h7 `  _  x

& u3 e1 \8 Q' m+ ?1 S  void     (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);+ R- T5 n! `4 w" B1 x+ O
  void     (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);4 c* S+ b+ l. |# U
DMA2D中断服务程序里面执行的回调函数,一个是传输完成回调,另一个是传输错误回调。
/ L/ J+ R3 r6 F5 d1 o+ U: T5 R4 y* i  m/ }9 v. X. q# V
  DMA2D_LayerCfgTypeDef   LayerCfg[MAX_DMA2D_LAYER]9 @4 [- a  |& U$ m  c: |
这个参数用于前景色和背景色的设置,MAX_DMA2D_LAYER=2,详见本章3.3小节。
! Q3 u5 X) U: _9 M3 r- y9 x" j" }* i! w
  HAL_LockTypeDef   Lock
) O+ u! I& e$ b" ~/ l5 Q__IO uint32_t    State;& i9 O/ t6 }$ G3 D
( w1 O# q' A) E5 c! X4 h* E" x' m7 V* x
__IO uint32_t    ErrorCode- c" Y" K6 S( P  r: `+ e

5 h; S2 R- V6 z2 N这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置DMA2D通信状态,而ErrorCode用于配置代码错误。1 F# e8 S* s5 I1 Q# |

! W" z; a8 v; V: m3 W) C3 \55.3.5 DMA2D初始化流程总结
2 Z3 B% |1 H  b4 q8 g- F1 ~
对于DMA2D来说,其实不需要初始化流程,每个功能都可以直接封装出一个函数来,下个章节会为大家专门讲解,也是实际项目比较推荐的方式。/ D( ^' d0 [0 p% T7 h/ f+ a
1 \) y! T( l- v5 ?+ E( c
55.4 源文件stm32h7xx_hal_dma2d.c
# l0 ^( e2 w* H. E' o# T7 O这里把我们把如下几个常用到的函数做个说明:
, \* c# G3 ^" r
2 z7 c; B0 W* r2 x: c2 Y  HAL_DMA2D_Init
; I7 M$ c! J0 v) a0 h) R  HAL_DMA2D_ConfigLayer
* d- B3 `  m; y' h  HAL_DMA2D_Start_IT
) r! O. O0 m/ g$ U1 _, w  HAL_DMA2D_BlendingStart_IT
7 x" V3 F! H8 ?$ j; j% u$ x. b
9 h% d7 ^% c, [, V55.4.1 函数HAL_DMA2D_Init
. B/ h) a8 i& x% v函数原型:2 L+ Q9 ?1 F6 ^
7 {0 n  r) e% ^
  1. HAL_StatusTypeDef HAL_DMA2D_Init(DMA2D_HandleTypeDef *hdma2d)$ R9 G' K+ z" l: O+ m" S
  2. {
    5 g) I6 S3 s* M

  3.   a6 y" z, E! Z% s6 w
  4. /*  检测参数是否有效 *// ?% t# y5 S8 V) e1 i# f, G
  5.   if(hdma2d == NULL)2 N- ^+ V# S( m
  6.   {6 B1 v- l( P) x( h+ ?
  7.      return HAL_ERROR;
    0 k7 m+ d/ J9 _/ L& T. _
  8.   }
    $ R! t# `. r6 `

  9. ; k% W0 ?) I5 e, Z: a
  10.   /* 检测函数形参 */5 R- {+ W# Z% g2 C' R9 H4 c  M
  11.   assert_param(IS_DMA2D_ALL_INSTANCE(hdma2d->Instance));
    9 ^8 c/ K" Q7 J0 t7 Q# ]& j
  12.   assert_param(IS_DMA2D_MODE(hdma2d->Init.Mode));5 E( f: ~; W2 ~4 b2 m- C8 y5 ]
  13.   assert_param(IS_DMA2D_CMODE(hdma2d->Init.ColorMode));
    / ~& }' q# A9 m( o' F: J
  14.   assert_param(IS_DMA2D_OFFSET(hdma2d->Init.OutputOffset));: m; ^: Q# F2 L, k) D0 \
  15. 7 s, y8 P- M, e
  16.   if(hdma2d->State == HAL_DMA2D_STATE_RESET)
    - Y& i4 K- ]! o8 S4 G( e" e7 e  b
  17.   {$ m. `: U) s4 \# `7 x* v" q/ b
  18.     hdma2d->Lock = HAL_UNLOCKED;' M. r5 U+ h9 z: Y3 O3 \  k
  19.     /* 初始化GPIO,NVIC等 */; X& M! I# t0 t& u
  20.     HAL_DMA2D_MspInit(hdma2d);' Q8 S2 U1 W$ Q. j
  21.   }
    - f: O/ f! E% @- L
  22. 7 r8 Y8 _& ?* M2 h7 ~
  23.   /* 设置DAM2D外设状态 */
    + Y. k  h: I4 ^" c5 S$ u% a0 J2 o
  24.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  
    $ \+ c2 k7 v6 w+ }& b5 x/ h, X: [

  25. ' i# ^+ x, ^7 J) w# g' @1 Q
  26.   /* 设置DAM2D工作模式 -------------------------------------------*/
    $ t* J: Y2 y. m5 p
  27.   MODIFY_REG(hdma2d->Instance->CR, DMA2D_CR_MODE, hdma2d->Init.Mode);) l$ W/ w) Z: m# U2 l$ U- W

  28. ; e- h% L  k4 T
  29.   /* 设置输出颜色格式 ---------------------------------------*/% F7 ^$ X! ?1 i4 Y9 L# K/ S
  30.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_CM, hdma2d->Init.ColorMode);5 a9 n6 Y9 Q) E6 \& Z& {! O

  31. + X% G' }+ D( y* w2 y
  32.   /* 设置输出偏移 ------------------------------------------*/  
    * Z% o7 Q- }' _7 }: i) y, P
  33.   MODIFY_REG(hdma2d->Instance->OOR, DMA2D_OOR_LO, hdma2d->Init.OutputOffset);  
    9 b, i# j* X/ p9 e, T, h
  34. ( i: b2 l  e  J% z
  35.   /* 设置输出颜色格式中的Alpah值反转 */: A% E7 J: i+ j" {* K% e
  36.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_AI, (hdma2d->Init.AlphaInverted << DMA2D_POSITION_OPFCCR_AI));! z& b+ O( F1 }9 e

  37. ) ]& f1 E' c" g, t1 F/ [. M0 ]
  38.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_RBS,(hdma2d->Init.RedBlueSwap << DMA2D_POSITION_OPFCCR_RBS));
    2 k/ f0 ]# F, O. `# o
  39. . p* f  `, \1 N) t. e$ }; {/ Y& j

  40. ' N' ?. z; ~: u- C9 e/ u9 j
  41.   /* 无错误 */0 n/ I# K4 n/ K6 {9 C7 p
  42.   hdma2d->ErrorCode = HAL_DMA2D_ERROR_NONE;- V1 C7 ]5 C  \. ~8 P

  43. 8 X: s, D* c; p* \6 z
  44.   /* DAM2D就绪 */1 H. P+ e* c! y4 A5 p7 t) ]
  45.   hdma2d->State  = HAL_DMA2D_STATE_READY;3 r, a3 r& A8 L2 m) O7 N0 Q) R

  46. ( Z/ j9 n/ N2 [# A1 n$ s
  47.   return HAL_OK;& R8 r* x' h0 ^3 f
  48. }
复制代码

' z+ b& ?2 R. P5 j% L' P& N$ W函数描述:& R3 W& T! e/ I3 J
* q: }' N# J) S( Z: k2 T" a
此函数用于初始化DMA2D的工作模式和输出颜色格式。: R0 ]2 Q0 U8 D9 k- z8 v- k3 ]
7 s, ]6 B8 _- C& [1 X; H
函数参数:
) v4 c; Z5 k9 Q+ u: I2 W$ k
* t) I  e/ ]  r& `6 G! Z/ s; B3 {  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。+ [* n* R6 H* g# F* w8 s6 y
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
% o, W$ d, b) t& h9 K7 C, ?注意事项:! w" j( G# z# }6 s8 \
& u- j7 X5 y$ S4 E) N
函数HAL_DMA2D_MspInit用于初始化DMA2D的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
. T; w2 o1 `( Y/ P( u& n6 S如果形参hdma2d的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量DMA2D_HandleTypeDef Dma2dHandle。' n7 z; b; [. }9 }; D1 @
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_DMA2D_STATE_RESET  = 0x00U。+ M4 N7 V  Z- C) c. e
( y9 t& t4 n- c# {
解决办法有三
( M0 @# `, I5 `3 @
; j! I& n% [% i9 z) P9 N方法1:用户自己初始DMA2D底层。8 t6 _6 y" H2 d

3 ~3 ]" _# {5 d( m4 Y; \方法2:定义DMA2D_HandleTypeDef LtdcHandle为全局变量。( a& ^) `4 Q% \  O/ V- Z

  q/ f/ x' \# I6 E方法3:下面的方法
  1. if(HAL_DMA2D_DeInit(&Dma2dHandle) != HAL_OK)
    . S: T" B' w+ l+ _
  2. {
    . T6 |' y  e, s6 q
  3.     Error_Handler();
    ; I4 U. J) D7 k: B$ z9 j
  4. }  9 I- {/ @: p7 R2 F9 d1 v
  5. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)2 U- ]4 N$ k7 _% W, o+ Z3 z) z  q
  6. {
    ' P* k$ s) `( ]! Z
  7.     Error_Handler();
    ! V% N1 J/ @9 ^4 X
  8. }
复制代码
2 p2 U: s: [; d) I! b0 \! \

7 ~4 d2 o! [& I: V2 d/ A) M使用举例:
& b3 P9 d3 }. L  d6 A+ R
- w) H+ x& F8 C& ~% ~
  1. DMA2D_HandleTypeDef Dma2dHandle;8 V" q4 W# N1 i) N1 D/ H# c
  2. & }" U, G' H' o! |8 ^3 R
  3. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/- Y4 o! \2 b* W# c) N) ]2 m% @
  4. Dma2dHandle.Instance = DMA2D;# X5 Q: m; W# l# ]& U% s+ Q9 |- l

  5.   R3 v) [9 F  F- a6 C2 H
  6. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */" ?" Q3 i% l& D/ z9 `
  7. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */( P$ {/ f7 J! W1 O: L/ a* u4 C9 g
  8. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */
    ' C( a* t, J1 _$ ~
  9. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */) o& _9 t& z- q: n" b: u
  10. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */' `/ Z" K! Y0 [* ^6 n

  11. & v+ ~; v0 w) X6 I0 @) y
  12. /*##-2- DMA2D 回调函数配置 ######################################*/
    * B* E" @& v2 I/ W4 P- r% L" d
  13. Dma2dHandle.XferCpltCallback  = TransferComplete;! n3 T+ Q* |1 \+ ^2 ]
  14. Dma2dHandle.XferErrorCallback = TransferError;
    # A9 N3 l  |# c( F5 T* A5 I8 y
  15. . Y8 \. o& U! R1 u1 B% C
  16. /*##-3- 前景层配置 ###########################################*/
    5 j* X6 w$ |, i* e$ E; J. Z
  17. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */
    ; G2 l( d* A. x+ Z/ {6 b+ \
  18. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */* [6 @0 Y0 y4 |4 ^8 T0 F' N5 z
  19. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */
    5 }* h& A5 ~1 l+ u# l
  20. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */+ E! ^0 ]8 w& U( D) l7 r
  21. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/; k1 l6 L. g1 h' S3 O
  22. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/' C- |  p" s1 g$ Z7 K

  23. , b" C  b0 _1 r! H( m' J

  24. / E5 }8 e, q" T1 U5 h* i/ I, I
  25. /*##-4- DMA2D 初始化 ###############################################*/
    , s3 e/ s% ?2 Q
  26. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
    , A4 _4 d; R- C+ q% R
  27. {
    ' b7 S+ w- K; Q$ l+ j
  28.     Error_Handler();; L  O: W7 U& d  [( u
  29. }
复制代码

. I* j$ H: \7 ?55.4.2 函数HAL_DMA2D_ConfigLayer- ~8 ^  e; \5 u$ x
函数原型:% d3 D, ]( q; c; y

- }- H- E  t% ?- v# S; k4 G+ v
  1. HAL_StatusTypeDef HAL_DMA2D_ConfigLayer(DMA2D_HandleTypeDef *hdma2d, uint32_t LayerIdx)/ e6 y6 o, C" S- g
  2. {
    ; X  p; @8 \% V
  3.   DMA2D_LayerCfgTypeDef *pLayerCfg = &hdma2d->LayerCfg[LayerIdx];) Z7 ?, ~( o: y- a9 ?

  4. 2 j+ T3 H9 z+ ?8 J+ ?% O  z. }5 ~; m
  5.   uint32_t regMask = 0, regValue = 0;
    % ]  M8 F: o. s3 o2 N' T" f  k7 ~: T% d& N

  6. ; j( e. K- D' c: S, a% {
  7.   /* 检查参数 */
    . M! t, {$ s2 u7 K
  8.   assert_param(IS_DMA2D_LAYER(LayerIdx));  
    0 p1 F, W  W5 R" T* h
  9.   assert_param(IS_DMA2D_OFFSET(pLayerCfg->InputOffset));  4 ~1 \. U  n/ S# q+ X
  10.   if(hdma2d->Init.Mode != DMA2D_R2M)
    ; E( ?' J1 c8 [$ C' l5 g
  11.   {  
    1 c9 V' q5 l! [% z8 C6 h
  12.     assert_param(IS_DMA2D_INPUT_COLOR_MODE(pLayerCfg->InputColorMode));2 G, m: E* `  f2 H& Q$ n+ x7 K  ?% v
  13.     if(hdma2d->Init.Mode != DMA2D_M2M)
    5 k7 Y& f3 _- F! D
  14.     {2 z& p4 Z; F4 h- g, c
  15.       assert_param(IS_DMA2D_ALPHA_MODE(pLayerCfg->AlphaMode));$ d! f: s: |  E4 g
  16.     }# \1 \8 i% I" p
  17.   }
    # \# |1 y* Z) p* D# f( C9 \6 S

  18. 0 J: ?& F8 D& {
  19.   /* 上锁 */
    6 m$ n2 n* G5 C  y. B# s& F5 ^5 ~
  20.   __HAL_LOCK(hdma2d);
    ( w7 E# H9 U9 L& I' F

  21. 5 O* I! l* Y. b/ H/ z
  22.   /* 设置DMA2D外设状态 */" V6 V% Y! ~& p: i# K0 r2 D- r
  23.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  
    : X) O  V. ?: w' j! G. M6 k

  24. $ m0 o/ m0 E( l% ~) `
  25.   /* 准备好背景层或者前景层FPC寄存器配置参数*/
    ' \' k" a7 u) ?" l0 c! }
  26.   regValue = pLayerCfg->InputColorMode | (pLayerCfg->AlphaMode << DMA2D_POSITION_BGPFCCR_AM) | \! j9 S! f$ e4 V. y* ~) U
  27.             (pLayerCfg->AlphaInverted << DMA2D_POSITION_BGPFCCR_AI) | \0 t6 K) R% C: a# q5 q: Q
  28.             (pLayerCfg->RedBlueSwap << DMA2D_POSITION_BGPFCCR_RBS);
    : ?4 g1 _& `  r1 s7 e6 [! `2 ~
  29. , m; @: O# n& b- K2 y
  30.   regMask  = DMA2D_BGPFCCR_CM | DMA2D_BGPFCCR_AM | DMA2D_BGPFCCR_ALPHA | DMA2D_BGPFCCR_AI | DMA2D_BGPFCCR_RBS;
    - o. L! t; k) E: J

  31. . d) ?9 t' p- N. L1 o+ {
  32.   if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    ! H9 Q. r0 R5 ^2 D# N' _# d2 J
  33.   {( v$ f& K2 ~- x& }7 s# H' G9 X
  34.     regValue |= (pLayerCfg->InputAlpha & DMA2D_BGPFCCR_ALPHA);
    - L! W; h8 I2 J* k  s' r
  35.   }
    5 G- x$ W4 g8 E4 p6 W
  36.   else
    0 U7 r/ n; g. p( p3 `4 K
  37.   {3 @$ x5 M+ S2 A
  38.     regValue |=  (pLayerCfg->InputAlpha << DMA2D_POSITION_BGPFCCR_ALPHA);
    : N4 F1 [& k" b" U3 _9 Q1 \
  39.   }
    3 K+ d' o8 d8 F* |/ a) i
  40. , l5 E3 z; U* F( s7 @
  41.   /* 配置背景层 */5 q: P2 ?. y! \8 `, {
  42.   if(LayerIdx == 0)
    # p$ H4 e" w/ e: s& L- D3 \+ {
  43.   {( u, t$ m( S+ @1 `, T+ i$ c
  44.     /* DMA2D BGPFCCR 寄存器 */8 l6 n7 o1 g; X. C# s$ \" l- u3 D/ g
  45.     MODIFY_REG(hdma2d->Instance->BGPFCCR, regMask, regValue);2 }, |+ b7 a5 z3 y5 m

  46. - e% N7 ~4 [  J- b
  47.     /* DMA2D BGOR 寄存器 */  
    + k! \8 z8 B' s- e" ]
  48.     WRITE_REG(hdma2d->Instance->BGOR, pLayerCfg->InputOffset);
    , b5 c0 D9 o) K
  49. " v1 l- k8 ?9 y7 P
  50.     /* DMA2D BGCOLR 寄存器 */ 8 s. n5 E7 y! I) D
  51.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))% M7 l8 ?- G3 W* p
  52.     {   
    ( }( W. Z3 O0 [+ H+ M
  53.       WRITE_REG(hdma2d->Instance->BGCOLR, pLayerCfg->InputAlpha &
    # Q: y, U8 Q) f4 x6 h* X0 G
  54. (DMA2D_BGCOLR_BLUE|DMA2D_BGCOLR_GREEN|DMA2D_BGCOLR_RED));
    . u  g: F- j, y" K
  55.     }    / Z5 b0 y8 U' |; _3 q. f9 L$ U  G! a
  56.   }
    ; c# _) I7 E, G+ W6 Q1 p
  57.   /* 配置前景层 */
    5 J6 O/ m4 Y# y; F+ S  X
  58.   else+ R, c  f4 C* C) e9 K; L
  59.   {
    : I% L" G- X( U
  60.     if(pLayerCfg->InputColorMode == DMA2D_INPUT_YCBCR)
    + U( d  Z$ N5 ~9 j9 @5 ~
  61.     {
    . V5 W  U2 }, p$ l
  62.       regValue |= (pLayerCfg->ChromaSubSampling << DMA2D_POSITION_FGPFCCR_CSS);8 I5 T, S0 q$ r2 e* S
  63.       regMask  |= DMA2D_FGPFCCR_CSS;+ f, p) k% E' Z8 w
  64.     }
    3 u- J6 F5 [. u

  65. ) E$ x7 |* X5 ^
  66.      /* DMA2D FGPFCCR 寄存器 */% m4 S# [: s/ G+ a
  67.     MODIFY_REG(hdma2d->Instance->FGPFCCR, regMask, regValue);
    5 S- e  k+ \- G8 y
  68. 9 P6 _" |) E- l( F+ P
  69.     /* DMA2D FGOR 寄存器 */2 j% \1 |7 R. |! G. I9 {, }- z
  70.     WRITE_REG(hdma2d->Instance->FGOR, pLayerCfg->InputOffset);      
    3 H8 y8 P8 S5 |9 R9 |8 T" ~6 p
  71. 0 k# b! q, q/ T8 d1 g% t9 C- P
  72.     /* DMA2D FGCOLR 寄存器 */   
    - u: r# A) U1 j6 ]$ o0 m
  73.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    9 C2 w- F" P1 }1 _: I" l' ?
  74.     {
    / C- ], `6 T- \& F! l
  75.       WRITE_REG(hdma2d->Instance->FGCOLR, pLayerCfg->InputAlpha &
    # q% v* T; @- a9 |) t$ s
  76. (DMA2D_FGCOLR_BLUE|DMA2D_FGCOLR_GREEN|DMA2D_FGCOLR_RED));      , b9 Z  |$ a" t: h/ r4 m( u
  77.     }   
    $ \' {) B' b# R& X5 L9 T
  78.   }   
    / D0 z9 G6 a6 F( ^# A
  79.   /* DMA2D就绪 */
    , _1 u3 C+ v) s/ H
  80.   hdma2d->State = HAL_DMA2D_STATE_READY;
    0 I0 e$ w2 R1 t" e1 }) m4 y

  81. " b" y/ Z; \, S6 @/ b
  82.   /* 解锁 */
    , f0 H3 ]! u4 A% |% b5 P
  83.   __HAL_UNLOCK(hdma2d);  
    " O2 V/ d! I$ ~& F8 c4 ~

  84. 1 O# `5 o7 b0 M
  85.   return HAL_OK;
    0 `$ P3 ?, u2 ^
  86. }
复制代码
" l0 ~& |; R3 Y% |: l
函数描述:
, Y2 r; o# S6 J% q1 b8 [2 o
; Q4 {6 H( d* a此函数主要用于配置DMA2D要转换的前景层和背景层,即输入颜色配置。而前面的函数HAL_DMA2D_Init配置的输出颜色。
& G; H3 Y) I+ j% `/ d3 b
9 I- l" [# v7 A  r+ f函数参数:
: K4 w0 M/ g6 I9 q# W) l
  I: S# s; L5 y% s2 G9 x  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。& ?; n3 a5 k- x7 A8 ?# w; K
  第2个参数用于配置前景层和背景层,0表示背景层,1表示前景层。
6 D% A6 A5 u4 o' q: d% H$ N  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。1 N9 a9 A0 r5 @3 }
使用举例:0 o  e7 K0 y: o. s1 m
  1. ' g* e0 `: B! k5 |9 N; ~; I
  2. DMA2D_HandleTypeDef Dma2dHandle;
    5 ~  `7 Q. Q$ p- ^

  3. 2 D2 [9 i" A( ]4 K2 v- A% }

  4. 1 Q+ K! `, w" ^* V
  5. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/
    0 l4 d  ~2 K9 N9 R  K* _4 s/ @  T
  6. Dma2dHandle.Instance = DMA2D;( t  J. K! R1 f0 W# S/ B3 t$ Z5 P7 d
  7. 6 r5 T0 H- \/ @' x% h
  8. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */2 f; o6 p3 ^' v- h: }5 ]
  9. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */
    ' f; N) r7 a* M8 \
  10. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */
    # t6 b5 b. V9 @5 `0 O) u: z' G4 f
  11. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */
    * `! _; L: x" N4 O6 B4 v: S* c
  12. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */# {1 o( Y$ x$ X( I; g

  13. 5 M) m& \$ S4 Z
  14. /*##-2- DMA2D 回调函数配置 ######################################*/
    2 N& g* ]' U/ h! c! X
  15. Dma2dHandle.XferCpltCallback  = TransferComplete;
    : A! y0 {9 x+ h7 W  g/ c0 W
  16. Dma2dHandle.XferErrorCallback = TransferError;) X; B) I2 l- X. m( W% q$ o7 D5 L

  17. ! Q* E+ ?. b/ T
  18. /*##-3- 前景层配置 ###########################################*// {) w, o# ~2 M
  19. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */- ?" E; s, D1 B- X. o
  20. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */2 |1 j8 r* h2 V( _1 F& a
  21. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */1 O8 o3 z" F. e9 Q, Q2 x: X# L
  22. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */- X( y' c+ N" w/ P
  23. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*// l: z8 d+ M+ m# ]  e3 p! W. p( J
  24. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/' F" B# f* a' g$ g% b! e
  25. ) O3 ~. {0 u7 T% S: B' w& n
  26. /*##-4- DMA2D 初始化 ###############################################*/, o7 T' y, ?+ h8 U% A$ A. x
  27. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
    $ G' H8 V& J" ~) Q  F
  28. {
    - T, Y' z* i% {+ W
  29.     Error_Handler();
    % n8 i3 f5 h* O# ]
  30. }
    ; N0 U  Y7 q, v  g) o. c& F, e

  31. 6 Y! G, Z$ A7 X
  32. /* 配置前景层  */
    : b1 \' R6 y# H# }! y, U8 Z5 t+ @
  33. if(HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1) != HAL_OK)
    / }  w7 F; d, p- S$ v) ]) @/ ^
  34. {1 u2 m7 k% x, G: U
  35.    Error_Handler();
    $ h) @/ Y  O% X% s
  36. }
复制代码

" E) k  R1 I) {' G! G/ }( e9 f$ U) l1 F
55.4.3 函数HAL_DMA2D_Start_IT
4 |  E( f6 j& H7 l, s. @: J函数原型:
! a- H" v" b" T; t& N" s+ b- m/ F4 \( o+ F3 @- S' z: L
  1. HAL_StatusTypeDef HAL_DMA2D_Start_IT(DMA2D_HandleTypeDef *hdma2d, uint32_t pdata, uint32_t DstAddress, uint32_t Width,  uint32_t Height)3 h( D7 b$ [, R- l
  2. {' u! q  W9 X) b% m4 t
  3.   /* 检测函数形参 */! |; x$ F, z% \7 l# G" J, O
  4.   assert_param(IS_DMA2D_LINE(Height));
    ' P6 m. Y( G( d' A7 |& Q5 ^
  5.   assert_param(IS_DMA2D_PIXEL(Width));# R# T! q: l$ n  V; Z
  6. . d! S" L4 L9 d1 M
  7.   /* 上锁 */
    & T: n3 t' _5 s: L$ Z" [
  8.   __HAL_LOCK(hdma2d);
    5 @9 o9 }# q3 ?# u( O2 R
  9. 8 i6 d8 C9 K3 l# c) c6 [% n: c
  10.   /* 设置DMA2D外设状态 */+ ^! [: r* h1 J5 l
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;6 |6 I5 V  |& \8 r7 d! o, {

  12. + ?! j4 c6 @$ Y6 _
  13.   /* 设置源地址,目的地址和数据大小 */
    # G/ J4 z& n& J4 p# Y
  14.   DMA2D_SetConfig(hdma2d, pdata, DstAddress, Width, Height);5 j+ M* l) e  @5 p" v' X# K2 Y
  15. " L$ {, f/ D  Y& J# V& ?$ Q: [0 F
  16.   /* 使能DMA2D的传输完成中断,传输错误中断和配置错误中断 */  B& r; |4 q% N  p. f
  17.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);6 c/ V+ n) c* P  M, ^

  18. 5 M! p7 k4 A+ ]% E9 W+ S) T6 _( @
  19.   /* 使能DMA2D */3 X1 h$ b3 b0 e+ w
  20.   __HAL_DMA2D_ENABLE(hdma2d);
    " |0 V1 y5 z4 I3 Y" m
  21. 9 y5 I  m2 {! M' E4 t
  22.   return HAL_OK;5 `0 ?. A1 R! H" o
  23. }
复制代码

. u  i. v4 Z- R% P! h5 e  C" K7 u+ t函数描述:* d0 i, ^* i3 W
6 u/ M; q/ B6 Q7 b% H- Y& k: W7 p
此函数用于启动DMA2D数据传输。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。
# ^  s1 y& A! c& C" n% I, Y4 c9 T) {% w' g- }2 f
函数参数:! w8 E! G) D) @# F$ ?3 Q- T

- z/ R+ X- ?' l/ R  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。/ ^: W# R' |, V7 K) n1 w
  第2个参数是源数据地址。6 m* r* c4 l& B/ a; d% J
  第3个参数是目的数据地址。$ y8 n7 o7 Z5 p/ h. p2 Q
  第4个参数是源数据的长度,即每行的像素个数。
+ N: l* k( u; d, j; e  W  第5个参数是源数据的高度,即行数。, `# W8 ^6 g* e7 ^" o9 ]* ^. |
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。9 A( F. O; c- E7 K4 O$ ~9 K6 W( ?
使用举例:0 P3 I. \1 [0 G& q) C! D

6 ~0 s( n! Z) w& {( p
  1. DMA2D_HandleTypeDef Dma2dHandle;1 V/ L. f5 s" a; W7 J2 L

  2. , x$ G+ \# E9 ]( Y
  3. if(HAL_DMA2D_Start_IT(&Dma2dHandle,            /* DMA2D句柄 */
    : a: W3 A( Z& O( z: [+ k2 l: u
  4.                       (uint32_t)&BufferInput,  /* 源地址 */
    6 w8 U( t6 F& T  b6 D
  5.                       (uint32_t)&BufferResult, /* 目的地址 */9 S3 ^3 y; X- C/ q) Y$ Z
  6.                       SIZE_X,                  /* 源数据长度,单位像素个数*/8 `# O( M2 ]+ D8 ?+ u4 {
  7.                       SIZE_Y)                  /* 源数据行数 */# _, x2 {  R4 R$ p1 q& _, x* G
  8.    != HAL_OK); X+ {$ g0 g  x5 G
  9. {
    3 Y) D. \" w; m2 T/ j% V9 t- F
  10.    Error_Handler();
    " r, g# A! i, W% I4 q7 n
  11. }
复制代码
6 M, z" `9 Z1 M. B
55.4.4 函数HAL_DMA2D_BlendingStart_IT3 v7 t/ m+ h% y, P/ }8 ~
函数原型:
) u4 v/ b. q8 B/ @1 I3 y
! D$ L4 V9 C: S
  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); r8 s" h# J5 s7 Y! n' ?
  2. {# _2 E$ R) R6 X3 G7 w4 p- b8 q( o
  3.   /* 检测参数 */
    ' b7 Q+ t2 S2 D- i! w% A2 w+ S. x! N
  4.   assert_param(IS_DMA2D_LINE(Height));
    ' |5 {- [) X8 K
  5.   assert_param(IS_DMA2D_PIXEL(Width));8 o1 M2 d2 t+ @5 J9 ?- Q
  6. ' p- Z8 m- s$ y0 F- }/ ]
  7.   /* 上锁 */
    0 k6 _9 J% y5 M7 t, q
  8.   __HAL_LOCK(hdma2d);  @- ?; G" ~: a( C( `  ~$ J

  9. 3 C- ?7 }% r5 E+ i' T: O- X( F& I: G
  10.   /* 设置DMA2D外设状态 */9 R. f$ {% u+ J
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;$ a7 Y2 p" M' o/ o

  12. 1 i! {; Z  y, \, _9 k9 ~& i; g9 j
  13.   /* 配置DMA2D源地址2 */
    5 k7 q! e9 }. b) e
  14.   WRITE_REG(hdma2d->Instance->BGMAR, SrcAddress2);
    ( w3 w. I6 U' S! I' m6 T9 H
  15. * u& O5 g3 A% |" G: f; ?. m. K
  16.   /* 配置源地址1,目的地址和数据大小 */
    0 U; a, ]) O6 l; g+ b
  17.   DMA2D_SetConfig(hdma2d, SrcAddress1, DstAddress, Width, Height);; c9 Y  ]; B/ Z1 J+ t
  18. ; X$ m1 r8 E" k5 Z
  19.   /* 使能DMA2D传输完成中断,传输错误中断和配置错误中断 */
    $ u3 s1 R' {3 M5 Z' P
  20.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);
    ! t; v# a. d# F' A
  21. - v4 o; N* i# r* F
  22.   /* 使能DMA2D */4 c% j  n) Q9 z$ k, u& `' x2 |
  23.   __HAL_DMA2D_ENABLE(hdma2d);6 v- I8 i3 h4 O* I. {
  24. # c) w4 M4 ~# d& g% Y/ k  ?
  25.   return HAL_OK;
    ( ^7 |9 u. |1 F' m
  26. }
复制代码
  [8 v; T( C% g4 b, Y
函数描述:
$ ]3 u( f1 ?* N9 _. p
7 d/ f$ c' ]! F4 D6 u; D8 h此函数用于启动DMA2D传输,除了数据传输以外,还支持颜色格式转换和颜色混合。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。$ s  {2 n% E6 V, P2 B

* w. K; q9 L! w) d; }# v函数参数:
* Q$ |9 S* L% \: n+ x' P* B, @5 d
$ B" K' Q) P) l! E7 t  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。7 E' H. T. }! t) b( p
  第2个参数是源数据地址1。4 P; _, d# I3 M$ U+ D
  第3个参数是源数据地址2。8 m) F, y3 V0 ~5 M& G
  第4个参数是目的数据地址。/ p- z6 L# i( R1 N$ d/ ?
  第5个参数是源数据的长度,即每行的像素个数。- L7 g* d4 t" w: e2 W+ a9 d* u
  第6个参数是源数据的高度,即行数。
: j- `4 l0 g1 y- ]4 d3 j2 @/ w  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。) {, k; t$ V5 s. q3 z" a- o
使用举例:
+ G9 l+ ]' u% q0 M
! \0 j2 T2 N9 A, i7 z) U
  1. DMA2D_HandleTypeDef Dma2dHandle;9 e- y- K) O& H9 e" t9 _

  2. " ?9 v- w9 \/ W0 W' Z
  3. if(HAL_DMA2D_BlendingStart_IT(&Dma2dHandle,           /* DMA2D句柄 */1 i) X# G8 }) i$ R# i6 B8 {2 }
  4.                              (uint32_t)&BufferInput1, /* 源地址1,前景色 */
    / }9 S4 Z  d  r3 }
  5.                              (uint32_t)&BufferInput2, /* 源地址2,背景色 */
    # ]0 K6 S5 u$ ~8 s7 T/ M4 N
  6.                              (uint32_t)&BufferResult, /* 目的地址 */
    " m! B) l0 A4 g% j( S2 m# r
  7.                               SIZE_X,                 /* 源数据长度,单位像素个数*/
    ! Y5 S- b3 i$ w: I& J5 ?" C
  8.                               SIZE_Y)                 /* 源数据行数 */
    3 f+ T# O/ H& |% Q
  9.    != HAL_OK)
    1 `: m0 O7 b7 A7 _4 T
  10. {
    / F& e$ y; r0 b: y% J  s) G( f
  11.    Error_Handler();+ [2 c" {- u7 b% V1 S
  12. }
复制代码
* ~1 R' @. G9 q' R3 E/ x
0 Y* W# v; w: U, a8 x* T1 B
55.5 总结
$ ^' L: o7 t3 U/ \" q7 {3 q本章节就为大家讲解这么多,DMA2D功能比较重要,一定要做到熟练使用。) `, f2 J) c+ v3 }# z8 p, h0 g

0 C1 K9 `, a- p" H; r; V
  Q8 G  R3 g# i5 I. n
" j3 i& F. P+ A( W# g+ t
收藏 评论0 发布时间:2021-12-24 17:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版