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

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

[复制链接]
STMCU小助手 发布时间:2021-12-24 17:00
55.1 初学者重要提示$ E  u: s- z% t) Y! `
  DMA2D是专门用于LCD加速的,特别是刷单色屏,刷图片,刷Alpah(透明)混合效果全靠它,而且可以大大降低CPU利用率。! D4 F4 J) l& G7 ^) j& u
  测评STM32H7的LTDC+DMA2D性能,100Hz以上无压力,刷800*480图片和色块仅需2.6ms一张
' j; Q" z# z. ^; z  H7的DMA2D与F429的DMA2D最大区别是支持了ARGB和ABGR互转,而且支持H7的硬解JEPG输出格式YCbCr转RGB,方便LCD显示。4 S6 v. E) Z. J1 Q0 c
  特别注意,大家只需对HAL库提供的DMA2D操作API有个了解即可,实际工程中,并不使用这些API,我们需要使用更加高效的寄存器直接操作,在下一章节会为大家说明。
1 [% D, e+ T3 H5 D55.2 DMA2D基础知识
+ c' }4 ~! C" YDMA2D主要实现了两个功能,一个是DMA数据传输功能,另一个是2D图形加速功能。
  w$ u6 e8 j$ w; S. y, ~# o2 g1 |' A) \- U% g
  DMA数据传输/ r- m, x( A) l  k+ g
主要是两种方式,一个是寄存器到存储器,另一个是存储器到存储器。通过DMA可以大大降低CPU的利用率。
2 ]& K; k6 B0 i; m8 N# d3 n0 u. c- V
  2D图形加速功能" ^5 i; h+ O- `
支持硬件的颜色格式转换和Alpha混合效果。
1 E) Z7 M! |) F  a8 d: Y4 r/ }; C+ \5 t/ ]/ O+ j: ^) q& L8 p6 Q
55.2.1 DMA2D硬件框图
/ m; d7 e+ k1 t* O9 }认识一个外设,最好的方式就是看它的框图,方便我们快速地了解DMA2D的基本功能,然后再看手册了解细节。框图如下所示:- Q9 ?7 j, `9 F. M6 J  C
7 E! N, _: b5 h* V; u
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
1 X1 J1 h; r9 q: ~$ |# R7 s* O
$ ]6 D3 v1 z! l" e0 s( ~4 g5 }4 g
通过这个框图,我们可以得到如下信息:
4 m% @, t% A5 e- r; o3 B: M* m2 t
' I/ B' X8 D) z8 a: _  dma2d_aclk
- s; s8 L" [% q- X" v) f# yAXI 总线时钟输入。
/ Z5 S  B* [0 i
' V" p; S5 C! q. N' `$ K/ u5 L  dma2d_gbl_it3 S+ A& y! F$ e& }5 W% t
DMA2D全局中断输出。
$ G& G' |. K1 |! [+ M- z
% a% \, ?4 A' k  dma2d_clut_trg; T4 }2 {( O3 E, W7 [+ O8 K
CLUT传输完成信号输出,可以触发MDMA。6 g2 z# |, B7 L- l

7 f+ Y; ~1 N! u, |1 V2 _" V8 ^' k  dma2d_tc_trg: X, u6 M0 |1 L; o) a% U6 c8 M
传输完成信号输出,可以触发MDMA。/ m( w# s+ v' U  Y! ~) C# t4 i* w

' l3 {8 g* v2 Z  g8 G9 }  dma2d_tw_trg & T* Y* b% b9 \/ f7 @0 d" W: H; J
传输watermark信号输出,可以触发MDMA。
7 H& R2 G& x# M: ]; u: T$ X0 F
$ \' f- e: B* E3 r将这个硬件框图简化一下,就是下面这样:/ d& n" r6 K+ \

* X6 H8 I/ _$ }( y  |# M( m  Z- ~7 x
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

3 u- f+ u) J+ L- K( E3 z/ x. m3 N: P4 B% A$ P
下面按照简化的硬件框图,对每个部分做个说明。
  U" [. T7 u3 w5 U# N
3 o* k" n+ ~2 l# J) t6 ]$ C55.2.2 DMA2D工作模式8 l. F. F. L8 z7 N( ^
DMA2D支持的工作模式如下:" o7 ?+ q& W8 {+ p9 Q
7 o; t# _1 {/ v7 H
  模式1:寄存器到存储器模式
3 i5 L( s: o; c( \9 K5 u这个模式主要用于清屏,也即是将显示屏清为单色效果。
% U: x/ v5 a& f' a3 }4 `# ^  X) B% K, L- ~
  模式2:存储器到存储器模式0 C4 K$ n$ _3 |" J8 x3 E; K
这个模式用于从一个存储器复制一块数据到另一个存储器,比如将摄像头OV7670的输出图像复制到LCD显存就可以采用这种方式。1 g- ^2 o. c2 z) V
/ @! Y8 Q6 s5 o$ T# i' m
  模式3:存储器到存储器模式,带颜色格式转换
7 }/ j* K/ |. o# {) |: z( b, l这个模式比模式2多了一个颜色格式转换,比如我们要显示一幅RGB888颜色格式的位图到RGB565颜色格式的显示屏,就需要用到这个模式,只需输入端配置为RGB888,输出端配置RGB565即可。位图颜色格式转换后会显示到显示屏上。
: @; P6 S4 x0 C  q" _
: u; Q- M& ]- w- r. w  模式4:存储器到存储器模式,带颜色格式转换和混合
! ?9 T. I( i' z+ }! ?0 ?$ x这个模式比模式3多了一个混合操作,通过混合,可以将两种效果进行混合显示。, U+ s  k1 e! o
" t7 `# @$ k, d6 T( z* v" ~
  模式5:存储器到存储器模式,带颜色格式转换和混合,前景色是固定的
/ k6 f5 X: w% ?+ m- W. v同模式4,只是前景色的颜色值是固定的。
5 T$ J7 |; ]- X( ]2 s$ T( A2 @$ v% Y. Q
55.2.3 前景层和背景层的输入以及颜色格式转换) j+ t4 `. U$ b" z
前景层和背景层是指的用户绘制图形时的前景色和背景色,比如我们显示汉字,字体会有一个颜色,也就是前景色,还有一个背景色。又比如我们绘制两幅图片,想将两幅图片混合,那就可以将一幅图片作为前景层,另一个幅图片作为背景层。5 y# G6 i8 {# G
0 H5 A" ~# j/ g
DMA2D支持的输入颜色格式如下,前景层和背景层一样:
+ G" ?. T; w. m' Z1 J$ d: v# \6 R% {! \- f. H
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
) \! T5 |1 _  H3 @
) E6 Y% S4 g2 L/ R  e
前8种颜色格式在第50章的第2小节开头有介绍,这里把后四种做个说明:- y) a4 s8 ~6 c% ?
0 M( m' d( c; [  y0 f; \) m, e
  L4 (4-bit luminance or CLUT)
. i# b/ O/ t3 o  A4位颜色格式,实际上仅仅是4位索引值,范围0–15,而每个索引值的具体颜色值在查色表CLUT里面存储。
. @" q  H8 G+ k7 t" v  ~0 R3 T/ g4 i& T( W
  A4和A89 x6 e( y8 J, u3 \% n6 y' g- R- l% j
A4和A8用于特定的Alpha模式,既不存储颜色信息,也没有索引值。+ u, q. F% [. |" ^- K
7 a2 r' ], ~8 h
  YCbCr/ T& }! [4 c9 ?1 \
这个是H7的硬件JPEG输出的颜色格式,后面JPEG章节为大家专门做讲解。
  \+ d! z6 U5 Q" Y3 r& r+ c0 m# h" ]* U- s6 l# Y* ^
这里特别注意一点,输入颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。
1 q) B: O  n- ?' {
1 v1 i$ R7 O4 \55.2.4 前景层和背景层混合! I7 ~( b8 z& }* F3 c; ]. T
DMA2D混合器用于混合前景色和背景色,这个功能不需要任何配置,仅需要通过DMA2D_CR寄存器使能即可。混合公式如下:4 {. A) V$ R8 U& _; c2 P! D

" q  F  n$ }1 z
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

. `/ b( D, i; H# b7 N+ S+ R9 U* A7 `6 j& I/ S% R7 z
55.2.5 DMA2D输出颜色格式" u* L& |, ]0 \- e: i* A; h# F
DMA2D支持的输出颜色格式如下:
$ p" x. D- N; Y; p* M1 p8 m( |2 Y* R9 g" R$ ~# F6 \' o( `- N2 s
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
; R  j) @4 O8 C; j. J! G
0 w2 b- U4 X1 h) w" ^
这里特别注意一点,输出颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。$ Z+ o8 p/ Q+ l" ]' T

( H$ w4 a( w* X$ ~7 R55.3 DMA2D的HAL库用法
/ M7 C+ H! a; fDMA2D的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断。下面我们逐一展开为大家做个说明。
- v. A- S& _. ~- }: S) b0 u' l( e& T  ^$ L& D4 v8 r' M$ |$ L
55.3.1 DMA2D寄存器结构体DMA2D_TypeDef. c4 V2 H* O5 l# @' X0 Y5 F3 y
DMA2D相关的寄存器是通过HAL库中的结构体DMA2D_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:5 W. v7 M4 q. t$ e; u, O$ x; g  |

8 }1 t4 S  |8 g6 \
  1. typedef struct+ ^- D! Z6 R5 U0 J
  2. {
    $ f( s7 A3 U" r* z0 g: {
  3.   __IO uint32_t CR;            /*!< DMA2D Control Register,                         Address offset: 0x00 */3 |# M- m3 d# y5 l) S
  4.   __IO uint32_t ISR;           /*!< DMA2D Interrupt Status Register,                Address offset: 0x04 */! n" {, V! H& W' h" o: S5 d5 c6 c
  5.   __IO uint32_t IFCR;          /*!< DMA2D Interrupt Flag Clear Register,            Address offset: 0x08 */8 I' k- u" m+ @$ l  M/ m
  6.   __IO uint32_t FGMAR;         /*!< DMA2D Foreground Memory Address Register,       Address offset: 0x0C */
    1 G, }$ t0 R/ w: o" [1 x- P
  7.   __IO uint32_t FGOR;          /*!< DMA2D Foreground Offset Register,               Address offset: 0x10 */2 B1 p' [; a$ r2 B$ _
  8.   __IO uint32_t BGMAR;         /*!< DMA2D Background Memory Address Register,       Address offset: 0x14 */4 W; O3 |# a/ k6 d. |8 S
  9.   __IO uint32_t BGOR;          /*!< DMA2D Background Offset Register,               Address offset: 0x18 */$ }8 _4 v" }7 i% @
  10.   __IO uint32_t FGPFCCR;       /*!< DMA2D Foreground PFC Control Register,          Address offset: 0x1C */
    ; n6 V' |# W2 Q& t, c7 L' y- ~
  11.   __IO uint32_t FGCOLR;        /*!< DMA2D Foreground Color Register,                Address offset: 0x20 */
    3 X. y7 ?0 F; E  n$ Z" _+ g" A
  12.   __IO uint32_t BGPFCCR;       /*!< DMA2D Background PFC Control Register,          Address offset: 0x24 */% X# o1 v5 m9 ]' h7 H1 u1 W& t
  13.   __IO uint32_t BGCOLR;        /*!< DMA2D Background Color Register,                Address offset: 0x28 */( D6 Y, Q- x4 s. R# s9 E
  14.   __IO uint32_t FGCMAR;        /*!< DMA2D Foreground CLUT Memory Address Register,  Address offset: 0x2C */2 `  \" _+ R/ I
  15.   __IO uint32_t BGCMAR;        /*!< DMA2D Background CLUT Memory Address Register,  Address offset: 0x30 */
      i; v: f  s0 w% ]! n: h! s
  16.   __IO uint32_t OPFCCR;        /*!< DMA2D Output PFC Control Register,              Address offset: 0x34 *// |  e* R1 w7 @( o
  17.   __IO uint32_t OCOLR;         /*!< DMA2D Output Color Register,                    Address offset: 0x38 */4 G' s- @+ c- K! c5 X) z
  18.   __IO uint32_t OMAR;          /*!< DMA2D Output Memory Address Register,           Address offset: 0x3C */
    2 z; k: N3 y$ O* K
  19.   __IO uint32_t OOR;           /*!< DMA2D Output Offset Register,                   Address offset: 0x40 */! w, ~" M+ S, x- Q! x& J8 n
  20.   __IO uint32_t NLR;           /*!< DMA2D Number of Line Register,                  Address offset: 0x44 */
    ( n9 i& l7 R$ k- V. E3 l% O/ v
  21.   __IO uint32_t LWR;           /*!< DMA2D Line Watermark Register,                  Address offset: 0x48 */
    + z7 P; A' u3 u* u
  22.   __IO uint32_t AMTCR;         /*!< DMA2D AHB Master Timer Configuration Register,  Address offset: 0x4C */
    * x" \: V2 e6 O
  23.   uint32_t      RESERVED[236]; /*!< Reserved, 0x50-0x3FF */
    ! S. x' y/ {! o/ U
  24.   __IO uint32_t FGCLUT[256];   /*!< DMA2D Foreground CLUT,                          Address offset:400-7FF */- o, N' ~& p. Y
  25.   __IO uint32_t BGCLUT[256];   /*!< DMA2D Background CLUT,                          Address offset:800-BFF */
    2 q6 ]2 L8 i2 w# t( v& \  z7 S2 V
  26. } DMA2D_TypeDef;
复制代码

7 b: H, ^, a" E* c' ~8 C+ u4 N0 O6 g; A# I
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:- U$ p9 R. x% O4 x, U
; `4 S, E9 o: V( w0 Q
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */! f7 a3 \4 R" h" y7 Y0 I
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码
5 l0 j1 Q& z( v5 h6 N
下面我们再看DMA2D的定义,在stm32h743xx.h文件。
  1. #define PERIPH_BASE              ((uint32_t)0x40000000)
    9 B8 C' l- [. C3 [0 r
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000)/ M5 y5 E- X6 j% c/ L
  3. #define DMA2D_BASE               (D1_AHB1PERIPH_BASE + 0x1000)
    ! E  e# X& L! z
  4. #define DMA2D                    ((DMA2D_TypeDef *) DMA2D_BASE) <----- 展开这个宏,(DMA2D_TypeDef *) 0x52001000
复制代码

2 X( m& a  @: V" }  t/ {0 H我们访问DMA2D的ISR寄存器可以采用这种形式:DMA2D->ISR = 0。$ z! }- h! M5 ^5 |) ?1 z. W
! Z5 h$ \( ^2 H) K7 I
55.3.2 DMA2D参数初始化结构体DMA2D_InitTypeDef
/ p/ g& R* o' w' W; x( I此结构体用于配置DMA2D的基本参数,具体定义如下:
" R/ Y+ X* S% D+ l& z. \! {1 ?% o" K2 E! c
  1. typedef struct
    8 i2 @* I4 W1 H2 A" _
  2. {
    1 E1 M+ x  L+ L' s8 t- R; j
  3.   uint32_t             Mode;              
    , y0 j# _  j5 ?5 G
  4.   uint32_t             ColorMode;        
    9 B7 s+ d# d( l. I" Y( I
  5.   uint32_t             OutputOffset;      
    $ g- x8 d1 v$ A0 ]4 f6 A( ^3 W, r( D
  6.   uint32_t             AlphaInverted;    0 x1 }! R& V2 t
  7.   uint32_t             RedBlueSwap;      
    3 M1 s, K* J: \1 X  _: X+ V
  8. } DMA2D_InitTypeDef;
复制代码

" N' D, E# b/ Z! r" S5 L# l# D* U下面将这几个参数逐一为大家做个说明:
* ?) {1 N. B) n; r* D# H, X  j9 k$ B7 z! G5 o! a: K
  uint32_t   Mode8 t; k, ?9 S3 A* K; N* p% [2 q
此参数用于设置DMA2D的传输模式,具体支持的参数如下:
; H4 B4 W0 O/ e$ U
$ {! v. v; L. X" h
  1. #define DMA2D_M2M        ((uint32_t)0x00000000U)  /*存储器到存储传输模式 */
    2 j; t) L% ]" c2 E& V' C  m% u
  2. #define DMA2D_M2M_PFC     DMA2D_CR_MODE_0         /*存储器到存储器传输模式,并执行FPC像素格式转 */% B; j7 ]2 {* e
  3. #define DMA2D_M2M_BLEND   DMA2D_CR_MODE_1         /* 存储器到存储器模式,并执行像素格式转换和混合 */0 L: g' C$ q& s4 j/ |0 A
  4. #define DMA2D_R2M         DMA2D_CR_MODE           /* 寄存器到存储器传输模式 */
    / f# D1 d7 L& |" q$ J, ^" L' c
复制代码

( P4 K' Y1 ?0 U
+ c6 L* T1 m+ j) v- ^5 w  uint32_t   ColorMode
. v" [9 ~8 s; k2 Y. J此参数用于设置DMA2D的输出颜色格式,具体支持的参数如下:
2 R) k1 Y8 P5 h0 B* `6 G
, _1 j% n( a8 a
  1. #define DMA2D_OUTPUT_ARGB8888       ((uint32_t)0x00000000U)               /* ARGB8888 */( X) ]9 u9 }3 ]: q2 s1 W0 h0 ~, J1 h
  2. #define DMA2D_OUTPUT_RGB888         DMA2D_OPFCCR_CM_0                     /* RGB888 */
    ) H1 p" o# M" A- i1 Q
  3. #define DMA2D_OUTPUT_RGB565         DMA2D_OPFCCR_CM_1                     /* RGB565 */
    2 l: C* x% {! n, X  ~! f
  4. #define DMA2D_OUTPUT_ARGB1555       (DMA2D_OPFCCR_CM_0|DMA2D_OPFCCR_CM_1) /* ARGB1555 */8 T9 a( O" k" }( _% W4 G0 p
  5. #define DMA2D_OUTPUT_ARGB4444       DMA2D_OPFCCR_CM_2                     /* ARGB4444 */
    , t$ s0 ~7 r4 ]/ a
复制代码

) u4 ?3 C3 p7 Y' j4 ], q; {' }( I- b
  uint32_t   OutputOffset9 s2 W5 a' c/ Q$ k6 b2 a5 v3 Z
此参数用于设置输出位置的偏移值,参数范围0x0000到0x3FFF。
0 M8 A, t6 n  P
; K% X- p% ?9 n  uint32_t   AlphaInverted& H& e, N! w4 `# |9 K
此参数用于设置DMA2D的输出颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     
& p$ ?5 S  ^7 w7 H6 ]( {" D5 z7 G
& O/ P" a% }8 f2 J- Y6 g/ `
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */
    6 D5 ]- ]9 I: T: l( ~8 r
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */
复制代码
& S7 o# k: Y( J' M7 h* f
  uint32_t   RedBlueSwap
, r; l: i) K- E9 w+ e! d$ `7 T/ Y+ i此参数用于设置DMA2D的输出颜色格式中R通道和B通道的交换,具体支持的参数如下:. p. q% y* |" C( }  Z3 c
% B/ U8 b# M8 a! Z' Q
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */
    9 i3 H7 ~7 t7 \3 P  X
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码
3 f9 t- z1 i3 U  z& u$ a
55.3.3 DMA2D的图层结构体DMA2D_LayerCfgTypeDef
5 f; v4 \0 h5 m# r此结构体用于配置前景色和背景色。
" W* w) e. M! w4 t5 \. g$ t, W/ _. Y4 k: \3 e
  1. typedef struct/ w' A" C+ L- B
  2. {
    2 v: M7 B0 Z# @4 z
  3.   uint32_t             InputOffset;      
    ( h. }$ P0 q1 [$ J; N  b( W
  4.   uint32_t             InputColorMode;   
    : X  j7 v; i0 z
  5.   uint32_t             AlphaMode;        
    ; L- k  t! {" N! @8 Z. P" [$ m
  6.   uint32_t             InputAlpha;        ( a' i: G* {+ l% W$ k
  7.   uint32_t             AlphaInverted;    ! k5 D, X' C: _) y: n7 j" P0 H
  8.   uint32_t             RedBlueSwap;       2 f" a- L- L/ N5 n( P
  9.   uint32_t             ChromaSubSampling;
    5 J: f5 N, E1 x( e
  10. } DMA2D_LayerCfgTypeDef;
复制代码

. D2 i3 j0 R1 H' e  c下面将这几个参数逐一为大家做个说明。7 h& j4 C! P  k% m2 X- n, H+ q5 G
* ^) B# m5 m. H/ `2 B  r2 k
  uint32_t  InputOffset
) v5 S& x" o0 i: M设置前景色或者背景色的输入偏移,范围0x000到0x3FFF。
( u  V  y* t9 F1 L. D- F+ {0 x7 w0 u4 _1 \
  uint32_t  InputColorMode4 k/ W& E5 C0 G
设置前景色或者背景色的输入颜色格式,具体支持的参数如下:
* ?/ Y  @$ E3 O* \& V5 i) |) e6 m; s  g* G# F- ?3 K' ~1 Q; Z
  1. #define DMA2D_INPUT_ARGB8888        ((uint32_t)0x00000000U)  /* ARGB8888 */
    + v8 Y+ y" V/ h3 p5 X% G
  2. #define DMA2D_INPUT_RGB888          ((uint32_t)0x00000001U)  /* RGB888   *// h; T) h0 H" p5 X# L: m  t; D
  3. #define DMA2D_INPUT_RGB565          ((uint32_t)0x00000002U)  /* RGB565   */
    # C: h8 g3 N  ?- `' v- U2 N* c- [
  4. #define DMA2D_INPUT_ARGB1555        ((uint32_t)0x00000003U)  /* ARGB1555 */
    9 k2 `4 C, Z% a! b
  5. #define DMA2D_INPUT_ARGB4444        ((uint32_t)0x00000004U)  /* ARGB4444 */
    2 G7 s8 W3 f! k7 p5 X
  6. #define DMA2D_INPUT_L8              ((uint32_t)0x00000005U)  /* L8       */& x; Q: o, u2 Q+ _, t
  7. #define DMA2D_INPUT_AL44            ((uint32_t)0x00000006U)  /* AL44     */6 m; U# d% `  W! k2 k
  8. #define DMA2D_INPUT_AL88            ((uint32_t)0x00000007U)  /* AL88     */
    5 _; x9 l4 W. M9 I( g1 G) Z/ q% V# \' L
  9. #define DMA2D_INPUT_L4              ((uint32_t)0x00000008U)  /* L4       */2 f& g* q. ~1 r& |  a
  10. #define DMA2D_INPUT_A8              ((uint32_t)0x00000009U)  /* A8       */
    + D: S& W+ T- Y: h/ E
  11. #define DMA2D_INPUT_A4              ((uint32_t)0x0000000AU)  /* A4       */3 C0 C7 @+ x/ g* `# ^# }; C
  12. #define DMA2D_INPUT_YCBCR           ((uint32_t)0x0000000BU)  /* YCbCr    */
复制代码

8 C8 M  z4 d5 i/ g  uint32_t AlphaMode7 R4 v# W+ X7 n. n
设置前景色或者背景色的Alpha模式,具体支持的参数如下:+ j0 R6 w4 C1 i) c7 n" V# y
7 o8 N& b; m1 Y" t3 m
  1. #define DMA2D_NO_MODIF_ALPHA   ((uint32_t)0x00000000U)  /* 不修改Alpha通道值 */
    # U4 }# W2 w# W1 q0 d8 n
  2. #define DMA2D_REPLACE_ALPHA    ((uint32_t)0x00000001U)  /* 用新设置的Alpha值替换原始Alpha值 */
    / m2 l9 M" m2 N+ I
  3. #define DMA2D_COMBINE_ALPHA    ((uint32_t)0x00000002U)  /* 用新设置的Alpha值与原始Alpha值的乘积替换原始Alaha值*/
复制代码
( Y. y; \6 G# v& P, g: N: z
  uint32_t  InputAlpha# [- y9 _4 g5 B$ k4 L
设置前景色或者背景色的Alpha值,范围0x00到0xFF,如果颜色格式是A4或者A8,那么此参数的范围是0x00000000到0xFFFFFFFF,标准的ARGB8888格式。0 ^" Y3 {: E8 t' f. I
0 ?8 M2 i( L. T! y" C) O( {3 u2 n
  uint32_t AlphaInverted
8 @- a. W6 ~& V* ~7 x) T设置前景色或者背景色的输入颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:       {* J- ?3 B% d8 Y4 r+ C# }
0 [+ D- c" P! p+ f2 r9 y1 Z
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */
    . g1 a5 _8 H( M! x. Y* n! X2 D
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */     
复制代码

' B  ^6 ], F) W6 l3 v2 X  uint32_t   RedBlueSwap7 R& w* v! W0 B& a" K( {
设置前景色或者背景色颜色格式中R通道和B通道的交换,具体支持的参数如下:, T3 L) H! m4 F' V5 F' U& t& \
! h8 z6 p; k8 _# O
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */! Z8 j+ Q. g) I# Z: K
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码

' w  F7 J' e% D, Q. f( K  uint32_t   ChromaSubSampling0 l: E' Q4 V! _7 J
设置前景色或者背景色中YCbCr 颜色模式的采样格式,具体支持的参数如下:
  1. #define DMA2D_NO_CSS               ((uint32_t)0x00000000)  /* 4:4:4 */
    , s  Y; G8 ^% {! X9 C' m
  2. #define DMA2D_CSS_422              ((uint32_t)0x00000001)  /* 4:2:2 */
    4 J4 A+ ~1 J9 o) q" [, C$ V( h# H% l! D" ?
  3. #define DMA2D_CSS_420              ((uint32_t)0x00000002)  /* 4:2:0 */  
复制代码

% q0 y! w4 q, M  Y9 Z$ Z; j0 J5 \55.3.4 DMA2D句柄结构体DMA2D_HandleTypeDef

7 _9 V# c$ R7 q) d  rHAL库在DMA2D_TypeDef, DMA2D_InitTypeDef和DMA2D_LayerCfgTypeDef的基础上封装了一个结构体DMA2D_HandleTypeDef,定义如下:/ a8 H* W1 h4 k: S
7 L! e% }, D% L( v% }4 [' U
  1. typedef struct __DMA2D_HandleTypeDef
    4 \; H; F# U+ O( s. x8 \
  2. {* T7 {9 c3 E$ s7 {3 T4 z
  3.   DMA2D_TypeDef               *Instance;                                                                                                                                                                                          ( A, q# y) R# D8 y& T
  4.   DMA2D_InitTypeDef           Init;                                                          w2 A- @' }$ `3 s6 I! U+ Q
  5.   void                        (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                                                                             6 u+ S3 A* d+ E7 N+ C9 y* M/ J
  6.   void                        (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                      
    . U* I& \+ Y2 f: p
  7.   DMA2D_LayerCfgTypeDef       LayerCfg[MAX_DMA2D_LAYER];                                    
    - K8 Z6 ]' O' _. H
  8.   HAL_LockTypeDef             Lock;                                                                                                                                                                                                   
    / o7 M( s/ j3 ~# e3 p" @
  9.   __IO HAL_DMA2D_StateTypeDef State;                                                                                                                                                                                                   ( k$ W5 A! N4 q" k4 O6 d1 [
  10.   __IO uint32_t               ErrorCode;                                                   } DMA2D_HandleTypeDef;
    0 d/ n& X% G, M- v1 o
复制代码
6 I* {5 z4 N" u% C8 D! C
下面将这几个参数逐一做个说明。3 G% ]9 ?7 R+ g) \1 t2 r; |3 T

, K1 ~+ g$ n: }# Q8 _$ T7 |* k  DMA2D_TypeDef  *Instance0 L$ [/ l  T' O; L6 H) S8 D
这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。6 }% d% N% t! J1 D

) y  A( y/ T( q5 k9 m+ Z  DMA2D_InitTypeDef  Init;  - X3 ?4 J3 m* q, L6 ~
这个参数是用户接触较多的,用于配置DMA2D的基本参数,详见本章3.2小节。( z' D; i+ W2 w8 y- N
- F) G( v5 P# K
  void     (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);
  S8 M  P) V2 X) Z/ m  void     (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);
- @, a& e4 o& u; Y* l0 l; z! ~; @DMA2D中断服务程序里面执行的回调函数,一个是传输完成回调,另一个是传输错误回调。
' ^' E$ d' s0 x# x2 T3 [
  ?2 }8 U+ T  i  DMA2D_LayerCfgTypeDef   LayerCfg[MAX_DMA2D_LAYER]: H& [. Y; s: G: Q9 C" T5 v% j+ S% g
这个参数用于前景色和背景色的设置,MAX_DMA2D_LAYER=2,详见本章3.3小节。  T. ^$ q3 g1 B' q

; d* B) b' D8 ~& O  HAL_LockTypeDef   Lock
/ Y. ]  u" l- Y4 v4 b__IO uint32_t    State;. P, T' V- z& I% l& ~

8 ~8 _% r8 O) w. N- b__IO uint32_t    ErrorCode
( i% D0 A) `* C; f& E; k2 |
- ~& q# L( r% `5 U9 h8 c这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置DMA2D通信状态,而ErrorCode用于配置代码错误。* w2 {  F1 K  o  w( i& j8 i
* m: _' M, E( G# Y7 U7 }. c* w
55.3.5 DMA2D初始化流程总结

4 c- R4 X1 W  X, E6 B6 Q对于DMA2D来说,其实不需要初始化流程,每个功能都可以直接封装出一个函数来,下个章节会为大家专门讲解,也是实际项目比较推荐的方式。
* c$ F$ w% |- Y' {6 k7 i. A
' b9 v/ s, E) U0 f. J7 s55.4 源文件stm32h7xx_hal_dma2d.c
& N, _) P) W5 _5 v这里把我们把如下几个常用到的函数做个说明:
+ f- o; r( l* m9 V: p5 \+ m$ v& G
* x% a. N, E/ X* ?  HAL_DMA2D_Init
; c, L% W0 a" J8 ]1 k% g$ R# L  HAL_DMA2D_ConfigLayer
; a6 e. C7 `' d  HAL_DMA2D_Start_IT; n9 q- R, N4 k3 }
  HAL_DMA2D_BlendingStart_IT
# |7 N6 k9 A" m, P
7 n3 \/ H  F& F0 z, ]  \55.4.1 函数HAL_DMA2D_Init* @+ y; b4 X) D8 k5 ]
函数原型:3 v7 j( ^  l1 m7 g7 g6 c, n
, n; e% f1 l4 I1 n+ m
  1. HAL_StatusTypeDef HAL_DMA2D_Init(DMA2D_HandleTypeDef *hdma2d)
    ! o$ t4 O9 ?8 e2 N. S: k
  2. {
    2 @: G" S) o- G, L
  3. , E2 R& @. ?0 K7 T  M# O5 c
  4. /*  检测参数是否有效 */& h9 M0 _5 t" e' D2 {
  5.   if(hdma2d == NULL)
    * F* B. q+ F1 |+ R0 M
  6.   {
    9 w8 e# m) j0 ]. r
  7.      return HAL_ERROR;
    # D& ^6 M0 N0 w' x
  8.   }, B4 ?, ]7 {( r9 S* F
  9. 2 Q! E9 e; W. ?& D; F* i
  10.   /* 检测函数形参 */7 f0 g  s# C$ ~, r- l
  11.   assert_param(IS_DMA2D_ALL_INSTANCE(hdma2d->Instance));
    ' ]3 E6 D) P" u, y0 D# |! P
  12.   assert_param(IS_DMA2D_MODE(hdma2d->Init.Mode));
    6 s7 {! X% P1 @7 R" H
  13.   assert_param(IS_DMA2D_CMODE(hdma2d->Init.ColorMode));" T+ W& p* H% ~- G0 V4 L
  14.   assert_param(IS_DMA2D_OFFSET(hdma2d->Init.OutputOffset));, D8 w2 S3 K0 p; u

  15. ( k5 L+ |" Q1 k" L
  16.   if(hdma2d->State == HAL_DMA2D_STATE_RESET)
    ! t. u6 a- Z0 f7 u+ Z, F# x: A: _
  17.   {
    8 c0 z7 {+ F/ D, {  j# |
  18.     hdma2d->Lock = HAL_UNLOCKED;
    1 u* J! \) Y& f% Y# ]7 `/ M% [
  19.     /* 初始化GPIO,NVIC等 */
    8 X$ w! r& _0 H$ n3 D0 }; J7 r
  20.     HAL_DMA2D_MspInit(hdma2d);
    ' L0 C$ Y7 [* B$ F8 a! W
  21.   }6 y" r4 \7 I# W8 D+ Q/ q
  22. 4 D. G6 {! o& b# {
  23.   /* 设置DAM2D外设状态 */
    6 G/ X6 f6 _4 [6 E5 p
  24.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  
    1 z$ d1 k0 n2 u- O! o  g0 {5 H: J

  25. 3 \- ^7 D% z' z/ ^. m9 w! \# h
  26.   /* 设置DAM2D工作模式 -------------------------------------------*/" A! ]! w. v6 L# m
  27.   MODIFY_REG(hdma2d->Instance->CR, DMA2D_CR_MODE, hdma2d->Init.Mode);
    1 ^) U8 C* h7 S# F/ z

  28. . |3 I& l: g3 O0 h2 g  B. A
  29.   /* 设置输出颜色格式 ---------------------------------------*/% ~9 o2 k# u2 u6 l4 N% N
  30.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_CM, hdma2d->Init.ColorMode);+ t; _8 r2 t% _- q( D& o' H+ i
  31. ) b5 a/ `5 g8 O
  32.   /* 设置输出偏移 ------------------------------------------*/  ( `8 f- H$ k$ u% X& g$ @, J
  33.   MODIFY_REG(hdma2d->Instance->OOR, DMA2D_OOR_LO, hdma2d->Init.OutputOffset);  
    ' b4 ~  a; j3 T3 z/ ]' D7 n

  34. ; u* k0 r" U  f. ~4 t
  35.   /* 设置输出颜色格式中的Alpah值反转 */
    - ~  i/ i3 M2 |( z) |2 v; m5 O
  36.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_AI, (hdma2d->Init.AlphaInverted << DMA2D_POSITION_OPFCCR_AI));
    ) r, Q) v% Y7 j) i/ ^3 Z
  37. : a6 @* r* f8 @3 b7 f; V2 i
  38.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_RBS,(hdma2d->Init.RedBlueSwap << DMA2D_POSITION_OPFCCR_RBS));
    ! N& h+ e4 d3 D
  39. 9 j6 a( ~$ \6 ?4 o' u- N! Q# v

  40. 7 r/ n' ~% |& |* [1 _8 O; d2 d
  41.   /* 无错误 */, q* D/ T$ U/ S2 @" ]7 d
  42.   hdma2d->ErrorCode = HAL_DMA2D_ERROR_NONE;$ }' q/ ?5 w+ j! R$ G5 R1 ?9 }
  43. 2 V% {9 S/ g% \9 R
  44.   /* DAM2D就绪 */
    . c- _$ y: |9 ?- ]
  45.   hdma2d->State  = HAL_DMA2D_STATE_READY;
    / J( n& c9 j, ?; D$ G: z

  46. ; Q- c+ I# u, @; B( l: h
  47.   return HAL_OK;  E/ J) `, {4 n  m! e3 a
  48. }
复制代码

$ D8 \2 E% K/ S4 P' e3 L2 I函数描述:- H) C. M( L6 f9 g! z

. M( ?. ~/ v) Q7 R$ ^! t) u! J6 O此函数用于初始化DMA2D的工作模式和输出颜色格式。
8 f5 p8 z# p4 m/ F5 ]3 F9 J0 h' l9 k" G  i
函数参数:
2 Z$ Y; M4 C" _" q* k4 k" z8 m+ ]6 Q4 O! s$ x9 l+ p: \
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。
. F* c3 r& i" \  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
5 D. S1 E5 V# p6 X: G8 [+ [注意事项:7 V! u" U/ \! d& T
9 K3 j  M& Z* H
函数HAL_DMA2D_MspInit用于初始化DMA2D的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。
! N8 A/ V5 q, _9 u$ \如果形参hdma2d的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量DMA2D_HandleTypeDef Dma2dHandle。: J) |% j( |! Y  W
对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_DMA2D_STATE_RESET  = 0x00U。
1 l! {2 Q! N. P
" w* w0 r, f' q解决办法有三
" l8 v$ B  T9 L, D# [2 ?5 X& J' D! z$ C+ G* Y4 T8 x9 u
方法1:用户自己初始DMA2D底层。
' y* W, M2 g$ T2 t; f* i
! S! v- V1 L* W6 C' v# p1 E方法2:定义DMA2D_HandleTypeDef LtdcHandle为全局变量。
& ^/ A  e" S2 p0 e% d3 B  C: F) d+ N7 Z, p7 [
方法3:下面的方法
  1. if(HAL_DMA2D_DeInit(&Dma2dHandle) != HAL_OK)/ G1 _* {& {* o
  2. {) ^! J) ]. n% ~) l, C4 a
  3.     Error_Handler();
    + B/ x/ F6 ]3 k3 q. `) ?
  4. }  * @) O1 G6 J. T1 f2 N* N( T" ~
  5. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)" W6 D& h3 ~! p% z
  6. {
    * Q+ b) v% `# G! J
  7.     Error_Handler();4 D0 [+ w9 X9 _9 y! c2 u3 a
  8. }
复制代码

& |* j! V2 n+ T1 A, O* B2 M/ J& \: H% V, `% J( G+ s
使用举例:3 D" g2 @3 c3 D- z5 a

9 {6 o1 i- @" M, p
  1. DMA2D_HandleTypeDef Dma2dHandle;2 R3 ~4 D( M' A4 A, N3 M

  2. # n0 {  t9 o+ ^' i3 o, t% h
  3. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/
    2 c% D  x1 d9 _$ p: `
  4. Dma2dHandle.Instance = DMA2D;1 s3 x  _# A& r( w7 W9 @7 V
  5.   M# F  Z# F" c2 X4 o) h8 \
  6. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */* K( M+ N6 Y: n: c
  7. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */$ r4 A# M1 D6 S/ ~
  8. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */
    ' j- i7 D- ^. Z! y7 e
  9. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */- Y) E3 ]7 R! d! |. H
  10. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */
    6 I9 F- H# f, @) i( ^, W
  11. & u( A- R' t6 \4 `
  12. /*##-2- DMA2D 回调函数配置 ######################################*/
    9 C( @' c8 |+ N/ u- g2 ?- ]
  13. Dma2dHandle.XferCpltCallback  = TransferComplete;9 D1 w0 O; |- y4 u& m
  14. Dma2dHandle.XferErrorCallback = TransferError;
    * e& k  \# K! S! e* H+ P+ p
  15. + k7 V( W! d: K  X6 j- D
  16. /*##-3- 前景层配置 ###########################################*/# s: r2 z4 _5 P
  17. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */
      e) }2 q' z8 x& F( p) _
  18. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */1 j2 M6 ?8 V+ g! ~
  19. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */5 Y( R8 U$ l& y; r* I
  20. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */- O/ s4 {, t1 Q
  21. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/
    # i% E; J& N, u9 G$ Z: d- i
  22. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/: K" a% D+ O) l) p, Y
  23. 8 \8 N& y! m$ Y* m6 p2 P
  24. % ]" d0 m1 }+ A6 a$ f
  25. /*##-4- DMA2D 初始化 ###############################################*/& e4 v6 s' B% G; o/ v* J7 [
  26. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)6 {; l; ]7 d# x& x
  27. {
      p3 m; E7 \" f7 e, C! w5 u" ^& Y1 r
  28.     Error_Handler();
    7 P2 n" l$ r6 t% f, ?* U  f
  29. }
复制代码

/ d- x( V$ D% R; r55.4.2 函数HAL_DMA2D_ConfigLayer
, y1 |" s3 u- ]: }函数原型:
7 a" o9 [* C4 t" }3 d/ c, C; f$ X, @: S* Z1 ?- a. t7 r
  1. HAL_StatusTypeDef HAL_DMA2D_ConfigLayer(DMA2D_HandleTypeDef *hdma2d, uint32_t LayerIdx)
    $ ^4 d) G- y* j- q
  2. {
      O& y0 ]. p8 |( s, d
  3.   DMA2D_LayerCfgTypeDef *pLayerCfg = &hdma2d->LayerCfg[LayerIdx];
    8 G6 b: \, c# H! N

  4. ' Q  r+ g( @8 {; I! _4 R1 }
  5.   uint32_t regMask = 0, regValue = 0;
    6 `0 ~% Q6 u. R6 b
  6. 5 H3 L" Z, y* r/ Q1 z* ~% }& p
  7.   /* 检查参数 */
    , {1 w7 A& J# d9 H2 \9 ]0 x- B9 m
  8.   assert_param(IS_DMA2D_LAYER(LayerIdx));  
    4 _5 ?' e$ B8 N) ?+ F1 O: _
  9.   assert_param(IS_DMA2D_OFFSET(pLayerCfg->InputOffset));  6 S1 d- l0 G6 u' C4 D( s
  10.   if(hdma2d->Init.Mode != DMA2D_R2M)
    0 P2 n% r! G0 T- ?
  11.   {  
    ' o1 ]6 Y4 J  e: e3 I7 p
  12.     assert_param(IS_DMA2D_INPUT_COLOR_MODE(pLayerCfg->InputColorMode));' j# S. D7 h0 X6 h) y8 u& X1 Z
  13.     if(hdma2d->Init.Mode != DMA2D_M2M)9 z+ w9 F6 }* t6 O# n* w5 S; T
  14.     {
    ( ^+ Q# ?9 b5 P6 P" n
  15.       assert_param(IS_DMA2D_ALPHA_MODE(pLayerCfg->AlphaMode));
    $ l4 D9 m" J; e6 T' t. v
  16.     }
    9 \' ?0 H! V( ~2 _* W8 Y
  17.   }
    ) q2 Z5 A9 Q8 d' q
  18. . R7 l* }# S7 T
  19.   /* 上锁 */
    - P6 w8 E# g' q- O5 o5 N+ _
  20.   __HAL_LOCK(hdma2d);
    + y. S, o. V2 t) a& U! ?
  21. , j  j) d5 g& L+ w
  22.   /* 设置DMA2D外设状态 */. d& H- Q% }7 b
  23.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  
    8 n6 F, A1 U2 u- u2 m! a( l. y

  24. 1 J* j4 g: G2 Z0 N( p5 U
  25.   /* 准备好背景层或者前景层FPC寄存器配置参数*/
    4 K6 c; q2 [9 }1 \/ w: o9 [
  26.   regValue = pLayerCfg->InputColorMode | (pLayerCfg->AlphaMode << DMA2D_POSITION_BGPFCCR_AM) | \
    9 b  r! q1 ?  d( v5 z/ ]
  27.             (pLayerCfg->AlphaInverted << DMA2D_POSITION_BGPFCCR_AI) | \
    ' _/ _% N6 f- U# b
  28.             (pLayerCfg->RedBlueSwap << DMA2D_POSITION_BGPFCCR_RBS);
    , Q/ D5 k! e" B" Y7 l0 @
  29. - v" w- [+ R7 l# _0 x2 N. l
  30.   regMask  = DMA2D_BGPFCCR_CM | DMA2D_BGPFCCR_AM | DMA2D_BGPFCCR_ALPHA | DMA2D_BGPFCCR_AI | DMA2D_BGPFCCR_RBS;' ~; d$ b+ H; h& Z0 p
  31. 6 }" g8 [* ~* J: C9 A9 R
  32.   if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))/ ^. C, ]. `  ^* z
  33.   {+ P3 v/ d  ]- S$ f5 ?; S7 P0 }. F
  34.     regValue |= (pLayerCfg->InputAlpha & DMA2D_BGPFCCR_ALPHA);
    & Y' _5 [7 d' Q1 ~/ H; @/ ^
  35.   }! b3 T& d  X' D2 i
  36.   else: ^; @. ]  N/ }/ G6 W/ u& t, m
  37.   {
    7 @; @& {9 z, Q
  38.     regValue |=  (pLayerCfg->InputAlpha << DMA2D_POSITION_BGPFCCR_ALPHA);1 x$ k. u2 z; p  g& {8 t: o
  39.   }2 Y! |7 A0 [" ?

  40. 1 ]& k' V/ h$ e$ V) I
  41.   /* 配置背景层 */+ H- ]& j7 l  X2 v
  42.   if(LayerIdx == 0)5 }; f: j1 ]# ~: o. P( {
  43.   {  M9 v2 P) u4 v( z, C& O
  44.     /* DMA2D BGPFCCR 寄存器 */
    & f& M' D. B3 m
  45.     MODIFY_REG(hdma2d->Instance->BGPFCCR, regMask, regValue);
    & r7 Z! q5 }! {. `6 L0 ]; }- I

  46. " g/ Y+ M2 h) R3 w5 g. W
  47.     /* DMA2D BGOR 寄存器 */  $ D# c4 A9 S6 t5 J( {; C$ F
  48.     WRITE_REG(hdma2d->Instance->BGOR, pLayerCfg->InputOffset);
    ! S1 S! ^3 c$ _

  49. " s- H% m& h" T$ \+ p
  50.     /* DMA2D BGCOLR 寄存器 */
    ; V1 o. H1 i" S0 q" U9 C2 |* E
  51.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8)), e  X5 w7 t( }7 K$ E1 Y& b$ c
  52.     {   
      _# ?, U- a" {2 c$ p5 T3 o
  53.       WRITE_REG(hdma2d->Instance->BGCOLR, pLayerCfg->InputAlpha &
    2 P# L8 P# T) `5 `; r
  54. (DMA2D_BGCOLR_BLUE|DMA2D_BGCOLR_GREEN|DMA2D_BGCOLR_RED));
    . p; _: r- j9 `$ }9 I5 R, p: B  o1 e
  55.     }   
    : N; ^( z) m  h8 O  t# k3 Y) Z
  56.   }( F6 s1 ^' X, u$ F
  57.   /* 配置前景层 */
    ( }- W8 W2 E5 s/ W/ O# Q8 Q
  58.   else
    3 w1 A  x! E/ w" c2 s0 O
  59.   {
    $ H5 e" e. ^2 T$ U! d6 e
  60.     if(pLayerCfg->InputColorMode == DMA2D_INPUT_YCBCR)2 q% a+ T3 N5 d  }: }
  61.     {
    7 @. z& R9 q1 M3 g$ C
  62.       regValue |= (pLayerCfg->ChromaSubSampling << DMA2D_POSITION_FGPFCCR_CSS);, V; p( ?( ^, B+ s  Y# r
  63.       regMask  |= DMA2D_FGPFCCR_CSS;. {8 Z% _8 @3 F' ^2 R" R
  64.     }
    7 q# @7 h4 J3 ]5 {' E6 p& Y
  65. / @: B% L' a9 _( ]4 U, h
  66.      /* DMA2D FGPFCCR 寄存器 */
    , f! Z( G8 G, z' ^' N
  67.     MODIFY_REG(hdma2d->Instance->FGPFCCR, regMask, regValue);1 Y9 l- H2 o) h' |9 r8 y, W
  68. ! n+ ~3 r7 n5 T0 H3 Y
  69.     /* DMA2D FGOR 寄存器 */
    ) D9 H& q- P* m8 Y/ Q
  70.     WRITE_REG(hdma2d->Instance->FGOR, pLayerCfg->InputOffset);      
    0 [3 l; g* ~  [* f
  71. ! J: b% A6 g& R% v4 b
  72.     /* DMA2D FGCOLR 寄存器 */   ' v; t4 p$ T' F
  73.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    1 R+ j0 r, y' F- [, q! w
  74.     {" b+ j4 m- T/ X( O1 N
  75.       WRITE_REG(hdma2d->Instance->FGCOLR, pLayerCfg->InputAlpha & / I) a6 K0 ^) M# v% G! X
  76. (DMA2D_FGCOLR_BLUE|DMA2D_FGCOLR_GREEN|DMA2D_FGCOLR_RED));      
    + _, y" r+ z% G5 d  @. n
  77.     }   & j/ {. Q4 e' @' i
  78.   }   
    7 _3 R7 r: C; f3 y2 w( u7 c1 j
  79.   /* DMA2D就绪 */
    2 s- [; B+ n5 a. ^, R+ [
  80.   hdma2d->State = HAL_DMA2D_STATE_READY;
    9 S& U: ^+ d' h3 U+ r

  81. 9 r1 D' |% v7 p, F
  82.   /* 解锁 */" ?! U: ~) r  A8 M
  83.   __HAL_UNLOCK(hdma2d);  
      c$ F1 ]3 D9 M2 q

  84. 4 O  ^) F+ f) g. E% X! t
  85.   return HAL_OK;
    % k6 _9 ~, K2 E5 f0 K# x1 i
  86. }
复制代码
9 I4 @4 d9 u+ W4 x9 c0 K, z
函数描述:: w- x4 T  @5 |. I5 I/ `; t' q2 s

1 t8 N/ {1 S( j2 c7 n! C& `此函数主要用于配置DMA2D要转换的前景层和背景层,即输入颜色配置。而前面的函数HAL_DMA2D_Init配置的输出颜色。* }; y, Q- V3 J' D$ `  f5 R

3 j  Q& E0 D2 X4 Z函数参数:# E4 l" o* S9 h7 }& y
5 |2 [( ?5 o/ V  p) E/ L1 t7 k" q
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。5 R9 z& ~& r4 q! O
  第2个参数用于配置前景层和背景层,0表示背景层,1表示前景层。4 c9 W; I) M! @# k  R5 o
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。8 c2 h1 q$ `3 S$ t! J2 H
使用举例:$ D. r, X# O4 w) _2 h) z
  1. . C( O' U9 n7 O+ d/ l7 w
  2. DMA2D_HandleTypeDef Dma2dHandle;; f0 p. Q; |/ H! j# k
  3. 3 f) ?% C' o- i6 f6 o: y
  4. : H6 `$ n& E7 z6 j1 E
  5. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/
    ' e3 e% u  Q2 Q, V
  6. Dma2dHandle.Instance = DMA2D;
    6 D: }! V  V, [/ K

  7. $ q% G. \( G: \2 n, Q  k. H
  8. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */
    & f, w7 L. U; y' {6 e
  9. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */, S7 e7 x/ q, u. ~$ J4 {5 `
  10. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */) c8 l! Y& i- W# p: R+ ?
  11. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */7 @7 N5 c1 V9 i$ i& f7 z+ f
  12. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */
    " [" ^$ ]+ x5 Y# }; {+ S
  13. + g5 A" K$ P7 m1 T4 q$ M4 @7 A
  14. /*##-2- DMA2D 回调函数配置 ######################################*/# p( ~  \& R, c2 U$ Q9 C0 F
  15. Dma2dHandle.XferCpltCallback  = TransferComplete;0 ?: L, D* _! L/ ?5 D# a, m5 q+ e0 S
  16. Dma2dHandle.XferErrorCallback = TransferError;/ J6 c4 l2 O% S1 {2 E& F' n
  17. 3 X& T* {2 D+ w2 s
  18. /*##-3- 前景层配置 ###########################################*// _' c  C8 {, H# ]8 q
  19. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */
    " z% }0 G0 G" }! _4 @! d6 T. v  L, @/ [
  20. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */
    " ?* _* ^( N$ e, d0 ~
  21. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */
    + S+ h5 o. ]( B( U( ]# W
  22. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */
    % {4 J. L1 I: p7 R
  23. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/+ \2 Q9 y( D, l
  24. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/) @' X: a5 q; Y

  25. . L8 ]/ j/ @2 [# v3 P% u  N
  26. /*##-4- DMA2D 初始化 ###############################################*/
    ! z) I( w0 }  a1 Q- k
  27. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK). [/ O. r( ?7 T
  28. {+ J) k, Y. |/ G, P6 S$ v
  29.     Error_Handler();
    1 Q+ A/ N+ p8 ?# _
  30. }
    ' x# ]+ v* n0 r! [
  31. 6 }" u, F8 D6 s6 ]2 b
  32. /* 配置前景层  */
    8 L$ Z2 }+ W5 z5 _& n) ~+ }  m
  33. if(HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1) != HAL_OK)
    + _& q9 b2 r# v9 h
  34. {7 i6 C. o$ ?  _
  35.    Error_Handler();
    3 t2 J& N. c; S3 h5 V" m# w6 Q/ I
  36. }
复制代码

  k7 i$ k! H) H
8 q! L3 h( i  C# b4 Q- ]& o55.4.3 函数HAL_DMA2D_Start_IT9 y9 K2 ^2 N2 T. T0 U3 E* Q6 l5 |3 L
函数原型:
! c: }+ O  Y! H+ t* K; ]
2 @! ]" p2 V+ p- u' W5 a
  1. HAL_StatusTypeDef HAL_DMA2D_Start_IT(DMA2D_HandleTypeDef *hdma2d, uint32_t pdata, uint32_t DstAddress, uint32_t Width,  uint32_t Height)
    # `8 P# s. T. M
  2. {
    5 B: X+ @( Q0 [/ Y
  3.   /* 检测函数形参 */
    ( ]! W  {9 H5 O% b9 r& {6 v" k; f
  4.   assert_param(IS_DMA2D_LINE(Height));
    ) A+ P+ F9 q. Q, k; {  z7 x$ r
  5.   assert_param(IS_DMA2D_PIXEL(Width));7 w2 b1 g- c( A( D1 \2 ]' N

  6. 7 s7 ]! Z9 x1 _! U& {/ {6 J, X
  7.   /* 上锁 */
    $ q4 W) w5 d, l' v: R5 w  F
  8.   __HAL_LOCK(hdma2d);8 N/ F8 y% F* x6 B

  9. 9 c) C. |9 Q6 U6 z" n9 e
  10.   /* 设置DMA2D外设状态 */
    3 X$ }/ D, F0 x- g2 O- f" E  u4 K
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;2 e# n0 I$ i. }$ J6 k
  12. 8 Y$ [& H# j/ w
  13.   /* 设置源地址,目的地址和数据大小 */3 `( ]3 Y. g: {+ [5 R+ }0 l
  14.   DMA2D_SetConfig(hdma2d, pdata, DstAddress, Width, Height);" D% J! M+ Q' D; F9 H

  15. - q) F! [6 E- R' _
  16.   /* 使能DMA2D的传输完成中断,传输错误中断和配置错误中断 */9 ?/ Y/ i% }- w( g
  17.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);
    $ l$ l# z9 F. U

  18. " m% C; e% R' \) O$ G& E
  19.   /* 使能DMA2D */5 W' E5 U; i4 I5 @
  20.   __HAL_DMA2D_ENABLE(hdma2d);) L8 t2 `3 y# r# g( |: M* b
  21. ) E! d# n8 ]' k* f' A; Q
  22.   return HAL_OK;6 C0 Z8 \6 _1 R0 @9 ^3 I+ X0 u4 P
  23. }
复制代码

, N7 j7 B- |/ Q1 z7 h* `& l+ }9 ?函数描述:
2 Z7 |% Z, A+ Y* Y$ n9 T' e* ^. |8 R. A5 {8 T4 h
此函数用于启动DMA2D数据传输。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。
" }' R- n, B; c, ]! U9 r: ]2 Q; @& F1 H+ ?+ M7 t, E" B
函数参数:
4 X" w* N1 z# O# |, K
" @: G# Q- f8 u8 U8 Y: v& W  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。
7 j- B6 `2 W5 B8 k9 O5 r+ D  第2个参数是源数据地址。/ o  E8 p6 u  P9 ^# C- U) \
  第3个参数是目的数据地址。. [+ y5 G: ^7 y- W. O% i5 A: J
  第4个参数是源数据的长度,即每行的像素个数。# {* m7 E1 `0 c8 b6 ~% H, x; @  U
  第5个参数是源数据的高度,即行数。+ M; h" p/ K/ x
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。1 a4 U5 c5 Z/ h% D% L
使用举例:
8 a6 d, B' _( |' b  u  Q
% A; [8 ~4 v/ [  A% x
  1. DMA2D_HandleTypeDef Dma2dHandle;9 q9 c2 u" P2 r& _0 d" U2 s
  2. & c0 g9 C3 w4 t, {+ @
  3. if(HAL_DMA2D_Start_IT(&Dma2dHandle,            /* DMA2D句柄 */5 k3 A8 U! }( m: p( P. T4 k
  4.                       (uint32_t)&BufferInput,  /* 源地址 */ 9 f( I3 q  |2 k! G0 b6 w- m- M
  5.                       (uint32_t)&BufferResult, /* 目的地址 */
    * c8 i/ m; m' C6 u" @1 S- ~" h; P
  6.                       SIZE_X,                  /* 源数据长度,单位像素个数*/
    $ Y3 t; l7 G: q5 N, T- }
  7.                       SIZE_Y)                  /* 源数据行数 */
    0 t+ X5 K! G) j. u: h
  8.    != HAL_OK)
    ) E" `  ~5 T) s- n5 ]7 r! m
  9. {
    3 }4 j2 X: j8 \* h/ S
  10.    Error_Handler();" j7 E/ E3 u: X7 \5 S
  11. }
复制代码

4 n: P9 G" w1 M' H2 P3 f5 g55.4.4 函数HAL_DMA2D_BlendingStart_IT
4 e# _: x) i8 N函数原型:, _6 ~7 y: c* \2 ?6 u

7 C2 A/ E8 I- i9 D# M
  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)
    / N$ ?7 t+ V) `/ F9 J! K
  2. {8 ~; ~- |( }  g6 E
  3.   /* 检测参数 */) T" }; p# e3 [- {4 Z
  4.   assert_param(IS_DMA2D_LINE(Height));
    5 i+ J. y2 ?4 Z- Z! H
  5.   assert_param(IS_DMA2D_PIXEL(Width));
    / e  Y' @9 ?6 E  `9 }- V( B

  6. 2 g, y+ M3 V1 l' t
  7.   /* 上锁 */; T* L  i) r9 ^: L" N& t4 {
  8.   __HAL_LOCK(hdma2d);
    9 c& p+ o+ [* }* @& l! z
  9. : J/ [6 C) \4 R' f0 V
  10.   /* 设置DMA2D外设状态 */4 q  r4 k. \# I0 D4 u9 C2 {! M
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;
    # Z5 ?1 }; V! Q" C" }3 R& R
  12. 8 A9 t( D: e7 w( ^1 c3 v
  13.   /* 配置DMA2D源地址2 */
    1 U6 L6 B. ?, g5 o
  14.   WRITE_REG(hdma2d->Instance->BGMAR, SrcAddress2);
      }( z( j! A' u, p- H

  15. ; p  t8 f4 n  z9 n, |
  16.   /* 配置源地址1,目的地址和数据大小 */+ A3 u& m( o4 u9 [% q) h" N
  17.   DMA2D_SetConfig(hdma2d, SrcAddress1, DstAddress, Width, Height);& F* d- r9 b. q: Z: V/ n4 y4 ]
  18. 6 ~! w4 @7 H, o$ h+ c+ Y
  19.   /* 使能DMA2D传输完成中断,传输错误中断和配置错误中断 */2 z) E" }1 f1 N( f) P7 X
  20.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);
    ) @, Q# d# K5 [, T
  21. ; n0 v$ Q3 G& D4 w3 y% e* v( q
  22.   /* 使能DMA2D */
    % P  u# ^, ~! f: a  Z) c! y
  23.   __HAL_DMA2D_ENABLE(hdma2d);
    " U, S$ Z/ E6 e$ F, x4 x! n6 a9 s7 O

  24. . t/ n" {6 ^) v. ]# u
  25.   return HAL_OK;
    7 D9 z$ N+ E+ r+ Z" X$ p. p
  26. }
复制代码

0 T2 c1 \% H4 U2 |2 R函数描述:" O% ~2 n9 v$ K/ E% b
' i" F  C1 B% }4 w" {  y6 W9 S
此函数用于启动DMA2D传输,除了数据传输以外,还支持颜色格式转换和颜色混合。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。% V2 l% `" q1 X5 d5 {8 y

0 u, D3 c" r' w' d- w3 b. R! Z函数参数:
; [% U( Y2 Q# z% e# g& t) G4 T: d6 a& ]; E
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。6 g8 Z' {, o" I$ U
  第2个参数是源数据地址1。. G6 p6 \- |/ V- q# Z
  第3个参数是源数据地址2。/ P5 {' C2 \" \; K' y  b
  第4个参数是目的数据地址。
; C$ C2 T: F2 q) o6 d) m  V  第5个参数是源数据的长度,即每行的像素个数。
, D) n& Y4 x/ a) J1 T/ L  第6个参数是源数据的高度,即行数。
) r8 ^, b" X, D: O4 u* Q! j9 a" {  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。3 b: R+ r- G8 M  S% d4 [
使用举例:" |+ O: [# n: M& D# W' |

% Q$ o- ]/ S8 A8 x" b- u, }
  1. DMA2D_HandleTypeDef Dma2dHandle;9 I$ u6 z8 e$ A% y) K
  2. % v. Y8 o* j4 W7 Q0 Y; |1 J( U2 ^" E, O
  3. if(HAL_DMA2D_BlendingStart_IT(&Dma2dHandle,           /* DMA2D句柄 */
    % m4 F* e  j+ q" l& b! t! U
  4.                              (uint32_t)&BufferInput1, /* 源地址1,前景色 */ * X  U; H) j, K$ M' H
  5.                              (uint32_t)&BufferInput2, /* 源地址2,背景色 */9 d* {4 `. Y1 Y" S  ~- T
  6.                              (uint32_t)&BufferResult, /* 目的地址 */
    # j# M- A; x( L1 r
  7.                               SIZE_X,                 /* 源数据长度,单位像素个数*/) {( v1 |9 d* F# z' s8 `% ?
  8.                               SIZE_Y)                 /* 源数据行数 */4 p5 F3 g( Z: S+ d
  9.    != HAL_OK), l4 ?9 K1 n) I  l8 e, S3 Z+ N
  10. {
    5 R2 e' D, ?6 A! \$ ?8 Q- ?
  11.    Error_Handler();
    : R6 l# H! }: X: K% N8 a3 {. `: B
  12. }
复制代码
" R! y+ c) U4 N' ^

; w7 D$ w) B+ K& K55.5 总结
* v6 `5 z# u1 x6 B2 G7 W1 Y5 R2 }) t本章节就为大家讲解这么多,DMA2D功能比较重要,一定要做到熟练使用。% f- j0 P* h: z2 k$ {
- H- {" u" ^6 q5 M! Z

7 j6 }& }5 a  b2 c1 L  k8 }- w. I- _. V) [; e
收藏 评论0 发布时间:2021-12-24 17:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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