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

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

[复制链接]
STMCU小助手 发布时间:2021-12-24 17:00
55.1 初学者重要提示
9 b, Q% l; ^5 D$ t, W* v8 V1 p4 E  DMA2D是专门用于LCD加速的,特别是刷单色屏,刷图片,刷Alpah(透明)混合效果全靠它,而且可以大大降低CPU利用率。
. E7 X! G3 d" [" W- ^4 n" E. i  测评STM32H7的LTDC+DMA2D性能,100Hz以上无压力,刷800*480图片和色块仅需2.6ms一张
- u2 \# _- g7 P" r8 Q  H7的DMA2D与F429的DMA2D最大区别是支持了ARGB和ABGR互转,而且支持H7的硬解JEPG输出格式YCbCr转RGB,方便LCD显示。, G! x, }  _  |; q. r; M
  特别注意,大家只需对HAL库提供的DMA2D操作API有个了解即可,实际工程中,并不使用这些API,我们需要使用更加高效的寄存器直接操作,在下一章节会为大家说明。
$ {5 T2 \7 h) a4 ?55.2 DMA2D基础知识8 X" g2 k, H' x, Z* x2 Q) m4 {
DMA2D主要实现了两个功能,一个是DMA数据传输功能,另一个是2D图形加速功能。
0 V  C) f: C2 h. I' X/ A
4 A7 e& G. {% _9 A2 X9 V  DMA数据传输
% F. ]# N7 b3 E主要是两种方式,一个是寄存器到存储器,另一个是存储器到存储器。通过DMA可以大大降低CPU的利用率。
& W& G4 j2 q1 T7 V, N! `9 x5 Z
+ w# L0 U7 ^& o% H; e$ q  r  2D图形加速功能
; r. y8 o" Z6 \: G! v$ D* s' {支持硬件的颜色格式转换和Alpha混合效果。
. T6 M8 Z0 F8 U  K' a/ C& {
1 E4 B1 V' J' P" Z55.2.1 DMA2D硬件框图
) C, T2 r" b  F1 W认识一个外设,最好的方式就是看它的框图,方便我们快速地了解DMA2D的基本功能,然后再看手册了解细节。框图如下所示:/ X, o9 f0 F" L. s

1 E9 y2 {0 m( B+ b% r8 ~
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
) V. Q% \9 O5 H# {

+ C) c% |3 w; e通过这个框图,我们可以得到如下信息:
8 I* {; U9 D% q5 B: t
9 f* s. Z5 O; N  dma2d_aclk; Z0 d4 }* n; x0 M) d+ ?1 D; u
AXI 总线时钟输入。
7 n! `% k! s; e% S  y' r" z1 m; O+ Z3 f3 B% w5 {& V
  dma2d_gbl_it
) q9 T: Z9 Z1 c. I; Y2 JDMA2D全局中断输出。
! r3 L6 n& v! e9 z$ ]( G6 Z3 F( I3 p0 L! Q
  dma2d_clut_trg
! j. u# |, p$ {# KCLUT传输完成信号输出,可以触发MDMA。& \& d! O5 T+ E* m

% o6 d& e! U( f2 ]+ `( x  dma2d_tc_trg; r+ A# V% U% g8 U) B5 |& y8 C
传输完成信号输出,可以触发MDMA。7 P9 d9 ^: R( U; l5 k3 ~1 o6 N- d3 F- d

5 [7 P2 S  _+ S# G1 m/ k0 g- s  dma2d_tw_trg
* K, M) b. T. G, ~! O# X传输watermark信号输出,可以触发MDMA。
* z1 X1 s6 a& J7 R6 M( `
) i; O+ D) {6 H$ [! @! R# R( v/ L" y将这个硬件框图简化一下,就是下面这样:) v1 V' }0 p  E4 L9 D) c% U
6 H8 M6 h! }+ k. p
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
2 i& ~. ~- j( i% ^/ z/ V) k

6 M* H: B# f8 s下面按照简化的硬件框图,对每个部分做个说明。& H5 E0 Q# U( p1 X! k# R' R

5 k9 G+ K; H5 S5 _55.2.2 DMA2D工作模式# p: R/ u# ^3 x2 n8 d
DMA2D支持的工作模式如下:2 {* n6 `( x6 S

4 t: [8 [+ }4 h. \# R% ]. p" q  模式1:寄存器到存储器模式) O% S7 o7 d% i) v0 p6 U
这个模式主要用于清屏,也即是将显示屏清为单色效果。
7 j1 U6 ~2 i) C5 M! l/ a
. O" t1 T7 q$ r' @& a( _; Z4 b  模式2:存储器到存储器模式, t3 K* l) h+ o  f- w5 e
这个模式用于从一个存储器复制一块数据到另一个存储器,比如将摄像头OV7670的输出图像复制到LCD显存就可以采用这种方式。
. q/ P  v; J( c* P1 [- b0 I' l4 n3 c; k+ g8 W, F' w5 Z: Z8 U( V+ _
  模式3:存储器到存储器模式,带颜色格式转换
5 n1 Y# ]! y0 Y这个模式比模式2多了一个颜色格式转换,比如我们要显示一幅RGB888颜色格式的位图到RGB565颜色格式的显示屏,就需要用到这个模式,只需输入端配置为RGB888,输出端配置RGB565即可。位图颜色格式转换后会显示到显示屏上。. j# M% O/ B1 R+ f+ v7 v( W7 a
( U* r5 u  N6 G( j0 T
  模式4:存储器到存储器模式,带颜色格式转换和混合) }+ W  J( w8 v* O
这个模式比模式3多了一个混合操作,通过混合,可以将两种效果进行混合显示。
" }) ]  Q- T  ?; e' N: A; s; x6 c( \% M
  模式5:存储器到存储器模式,带颜色格式转换和混合,前景色是固定的' Z9 p/ Q$ U9 y, F
同模式4,只是前景色的颜色值是固定的。! D- X; G- o6 K9 T- W+ h# R& J" b

8 H% U, ^% q& h8 y* F6 j55.2.3 前景层和背景层的输入以及颜色格式转换
5 W3 F5 B; q0 I- H7 |. L+ \4 u) h前景层和背景层是指的用户绘制图形时的前景色和背景色,比如我们显示汉字,字体会有一个颜色,也就是前景色,还有一个背景色。又比如我们绘制两幅图片,想将两幅图片混合,那就可以将一幅图片作为前景层,另一个幅图片作为背景层。! E; P( m2 x: O( m, \

2 W% F& @2 s: w! l# z! eDMA2D支持的输入颜色格式如下,前景层和背景层一样:5 C! N5 S6 W9 s

- z% M( Z5 F' q+ ?
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
' P; G2 w% \! \! z0 T1 [
9 v$ Y% d( |) a1 V' R; Z
前8种颜色格式在第50章的第2小节开头有介绍,这里把后四种做个说明:0 ~& x; U0 Q8 B

  p$ W( L8 ~/ t0 F1 n' [  L4 (4-bit luminance or CLUT)
5 y. v7 k6 n/ X4位颜色格式,实际上仅仅是4位索引值,范围0–15,而每个索引值的具体颜色值在查色表CLUT里面存储。
9 o& [+ h8 f. {
& }. m  @) R, U/ I& S  A4和A8
' t# p6 M8 Q" C! @  eA4和A8用于特定的Alpha模式,既不存储颜色信息,也没有索引值。: l( [0 W& \; {- }! e5 g2 Y
( o- R2 n- e) d
  YCbCr
& ^) O6 ^0 B0 K0 A% x% n这个是H7的硬件JPEG输出的颜色格式,后面JPEG章节为大家专门做讲解。0 o, X# n  K' f. S& S0 [$ r

6 l" C* C9 H% Z( B这里特别注意一点,输入颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。; r+ O. J# G/ |* ]
' N0 o7 L/ ^0 H
55.2.4 前景层和背景层混合
8 A" x2 v) s& t0 ODMA2D混合器用于混合前景色和背景色,这个功能不需要任何配置,仅需要通过DMA2D_CR寄存器使能即可。混合公式如下:
( a# M9 ]) Q! I% l  K# o
5 i! {' p) x; W; I. ~
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png

# q3 H( x, |: S2 [
* D( {! g) w9 a+ u' m8 S55.2.5 DMA2D输出颜色格式
: |: p7 t- J8 f; hDMA2D支持的输出颜色格式如下:
+ f. }- D7 E6 y0 v/ C! `
  J$ N& n8 i& v4 D9 T; M
aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
+ \3 @8 C" Y! U
+ F/ W; u, K5 r, e6 B! I
这里特别注意一点,输出颜色格式的Alpha值是可以设置的,而且颜色格式里面的R通道和B通道可以交换位置。
: I& |& ^# q0 Y$ K: e; ~4 M& K: {( t1 M: j# ?. O% @9 D# K4 _1 a
55.3 DMA2D的HAL库用法
$ t; @" y) M+ y+ {2 f& HDMA2D的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置时钟,并根据需要配置NVIC、中断。下面我们逐一展开为大家做个说明。  H3 u0 T7 p* E9 U6 i8 x' s

) c0 [' r' ?5 Z4 k55.3.1 DMA2D寄存器结构体DMA2D_TypeDef
$ [; [  S1 ?; WDMA2D相关的寄存器是通过HAL库中的结构体DMA2D_TypeDef定义的,在stm32h743xx.h中可以找到它们的具体定义:8 y3 B2 S* H; N1 a* |% C5 W% \
: X4 f7 Y% S1 p, ^2 b
  1. typedef struct
    & l1 R' H2 R' X3 I: I: S- j
  2. {
    ! W5 g, t' h$ [
  3.   __IO uint32_t CR;            /*!< DMA2D Control Register,                         Address offset: 0x00 */. p% c" |! N* a
  4.   __IO uint32_t ISR;           /*!< DMA2D Interrupt Status Register,                Address offset: 0x04 */
    ) {/ ~/ `+ |" R! O
  5.   __IO uint32_t IFCR;          /*!< DMA2D Interrupt Flag Clear Register,            Address offset: 0x08 *// W$ Y. |5 J4 b
  6.   __IO uint32_t FGMAR;         /*!< DMA2D Foreground Memory Address Register,       Address offset: 0x0C */
    3 \$ {# _* Y* ?! o: \& B0 v6 W
  7.   __IO uint32_t FGOR;          /*!< DMA2D Foreground Offset Register,               Address offset: 0x10 */2 O2 `0 U) B8 e7 `+ P, ]
  8.   __IO uint32_t BGMAR;         /*!< DMA2D Background Memory Address Register,       Address offset: 0x14 */
    9 i3 h3 O9 ~+ b
  9.   __IO uint32_t BGOR;          /*!< DMA2D Background Offset Register,               Address offset: 0x18 */
    - F; T" T/ e2 a: d
  10.   __IO uint32_t FGPFCCR;       /*!< DMA2D Foreground PFC Control Register,          Address offset: 0x1C */
    + q) M9 S7 L8 q0 B& u- |7 u, H
  11.   __IO uint32_t FGCOLR;        /*!< DMA2D Foreground Color Register,                Address offset: 0x20 */
    ! W+ S1 a9 Z- u
  12.   __IO uint32_t BGPFCCR;       /*!< DMA2D Background PFC Control Register,          Address offset: 0x24 */
    4 J2 K& h- h% B
  13.   __IO uint32_t BGCOLR;        /*!< DMA2D Background Color Register,                Address offset: 0x28 */
    3 ?  N1 W3 i" t( i1 t( C# f
  14.   __IO uint32_t FGCMAR;        /*!< DMA2D Foreground CLUT Memory Address Register,  Address offset: 0x2C */3 U- ]. P- T% ^
  15.   __IO uint32_t BGCMAR;        /*!< DMA2D Background CLUT Memory Address Register,  Address offset: 0x30 */
    : I" n  t+ X: `+ U8 U8 @5 Y
  16.   __IO uint32_t OPFCCR;        /*!< DMA2D Output PFC Control Register,              Address offset: 0x34 */
    . a* k. q0 M5 h
  17.   __IO uint32_t OCOLR;         /*!< DMA2D Output Color Register,                    Address offset: 0x38 */
    5 R3 p4 m$ R6 o5 u0 c3 {
  18.   __IO uint32_t OMAR;          /*!< DMA2D Output Memory Address Register,           Address offset: 0x3C */) o# C) ^( R' i5 l/ j$ ?  s5 i
  19.   __IO uint32_t OOR;           /*!< DMA2D Output Offset Register,                   Address offset: 0x40 */7 l" [  g# d  P
  20.   __IO uint32_t NLR;           /*!< DMA2D Number of Line Register,                  Address offset: 0x44 */
    ) b" Y8 G; W) y( t( x# I
  21.   __IO uint32_t LWR;           /*!< DMA2D Line Watermark Register,                  Address offset: 0x48 */
    + u0 Z! h* b) z; f/ I6 l
  22.   __IO uint32_t AMTCR;         /*!< DMA2D AHB Master Timer Configuration Register,  Address offset: 0x4C */  r5 h: Y. T8 \7 i  k: y# L
  23.   uint32_t      RESERVED[236]; /*!< Reserved, 0x50-0x3FF */
    % }. e6 A  ?7 N8 P/ M, {0 O
  24.   __IO uint32_t FGCLUT[256];   /*!< DMA2D Foreground CLUT,                          Address offset:400-7FF */4 }% s' v* i! h' j
  25.   __IO uint32_t BGCLUT[256];   /*!< DMA2D Background CLUT,                          Address offset:800-BFF */
    ; i" [7 ?3 C5 G" g5 A* k
  26. } DMA2D_TypeDef;
复制代码

0 w! T2 @+ r$ m3 X. z8 }7 V9 ]  Y  X! O
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
7 p2 Q3 p" Z+ C7 b& Y: I" _3 ]8 D6 k# z- ~& b$ F& X8 t
  1. #define     __O     volatile             /*!< Defines 'write only' permissions */
    4 }# ]+ R6 m( }
  2. #define     __IO    volatile             /*!< Defines 'read / write' permissions */
复制代码

$ d7 w8 H- J/ x! g; {3 Q) F下面我们再看DMA2D的定义,在stm32h743xx.h文件。
  1. #define PERIPH_BASE              ((uint32_t)0x40000000) ! _% n; U+ {% W" j
  2. #define D1_AHB1PERIPH_BASE       (PERIPH_BASE + 0x12000000)+ N/ ~+ W1 ^2 E0 `! n( a
  3. #define DMA2D_BASE               (D1_AHB1PERIPH_BASE + 0x1000)# Z4 ^  u4 }. ?) e6 O
  4. #define DMA2D                    ((DMA2D_TypeDef *) DMA2D_BASE) <----- 展开这个宏,(DMA2D_TypeDef *) 0x52001000
复制代码

- L/ [1 E: z  z/ E& k! F6 Q4 \2 o我们访问DMA2D的ISR寄存器可以采用这种形式:DMA2D->ISR = 0。) {3 J& ^2 U5 b& o1 I
  ~! B* K) Q3 B
55.3.2 DMA2D参数初始化结构体DMA2D_InitTypeDef) Q* |* [. H$ _3 |: P% C# W1 e
此结构体用于配置DMA2D的基本参数,具体定义如下:
+ p% K. O9 U" O% s& g6 q; ?) T" P9 \3 E+ T$ U2 D
  1. typedef struct
    8 R8 w0 d# K% X% H; X( l7 ^
  2. {. a& m1 i$ O2 y7 _# o9 q+ }  ?- N
  3.   uint32_t             Mode;              
    7 f2 q8 R5 x" W- r% u- L" @
  4.   uint32_t             ColorMode;        2 V( E1 G4 {2 O4 k+ ^. g
  5.   uint32_t             OutputOffset;       3 Z$ _# x- w+ U# G( o
  6.   uint32_t             AlphaInverted;    # R; d* n( o) t) e7 Z
  7.   uint32_t             RedBlueSwap;      
    7 p3 a) x$ E' |) J5 {0 u& i$ F* s
  8. } DMA2D_InitTypeDef;
复制代码

. \! T% |2 ]$ a, s) h" r下面将这几个参数逐一为大家做个说明:% V- W9 v6 U8 N6 x, i; V

; W- y; g; s( Q# M7 v" M$ T  uint32_t   Mode
0 ?0 N! g7 Y: ~4 @/ ~% G) m此参数用于设置DMA2D的传输模式,具体支持的参数如下:8 f* [$ B5 \: i, g2 K/ D! \

& y) V0 n! J3 _% n
  1. #define DMA2D_M2M        ((uint32_t)0x00000000U)  /*存储器到存储传输模式 */2 w4 G2 F( F# I
  2. #define DMA2D_M2M_PFC     DMA2D_CR_MODE_0         /*存储器到存储器传输模式,并执行FPC像素格式转 */" d% p* I" A' e
  3. #define DMA2D_M2M_BLEND   DMA2D_CR_MODE_1         /* 存储器到存储器模式,并执行像素格式转换和混合 */
    / R6 u; ]! m6 S, y& n' E) C) a
  4. #define DMA2D_R2M         DMA2D_CR_MODE           /* 寄存器到存储器传输模式 */
    3 H3 f: l/ [' O
复制代码
% I6 s/ f( ^  y1 \& V

1 q/ W% o! C4 F! r7 @  }8 j; X- a  uint32_t   ColorMode
  d. d9 t6 Y) g/ A$ v此参数用于设置DMA2D的输出颜色格式,具体支持的参数如下:
$ N3 m3 a, R  ~0 B# T2 M! ~: I
; z* l% x5 o3 D# s$ ?( Y' y. O
  1. #define DMA2D_OUTPUT_ARGB8888       ((uint32_t)0x00000000U)               /* ARGB8888 */
    2 ^" H2 ]1 f  W. S2 [) J% A
  2. #define DMA2D_OUTPUT_RGB888         DMA2D_OPFCCR_CM_0                     /* RGB888 */
    7 ^$ B  p) y7 W2 m
  3. #define DMA2D_OUTPUT_RGB565         DMA2D_OPFCCR_CM_1                     /* RGB565 */
    8 ?& h& M0 B7 o0 a
  4. #define DMA2D_OUTPUT_ARGB1555       (DMA2D_OPFCCR_CM_0|DMA2D_OPFCCR_CM_1) /* ARGB1555 *// q6 {3 _4 R: y1 d% v
  5. #define DMA2D_OUTPUT_ARGB4444       DMA2D_OPFCCR_CM_2                     /* ARGB4444 */
    ! ]  M/ D0 N7 v3 {7 P4 \0 R9 R
复制代码

" B# I3 q9 G* N8 b
( F/ a' \; {/ |2 b  uint32_t   OutputOffset
9 C& D& V8 M  W1 U此参数用于设置输出位置的偏移值,参数范围0x0000到0x3FFF。
( q7 e0 _; j  _# T, ~1 i* |2 {1 C# A% y! T7 H
  uint32_t   AlphaInverted
( A) V" a0 m" N! ?6 x2 m此参数用于设置DMA2D的输出颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:     ; A+ W2 p/ ~+ t4 X  w+ F

( Q' @8 G( z( n) b1 u0 t
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */
    9 _& f% a6 F! D. D; S
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */
复制代码
6 J. Y/ [' ~1 e5 j/ _: z+ P
  uint32_t   RedBlueSwap7 I. P3 u1 c  u
此参数用于设置DMA2D的输出颜色格式中R通道和B通道的交换,具体支持的参数如下:9 Z8 n8 E2 q; `8 d$ J8 i8 l& k( {

8 `3 R8 e* u, p+ X# g* _
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */4 z( a$ Q9 o* x* s5 U3 J
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码

1 O/ W. Z, y' |* Z& O* ?55.3.3 DMA2D的图层结构体DMA2D_LayerCfgTypeDef
8 h, `: ?9 b3 I* e3 h此结构体用于配置前景色和背景色。; N1 e2 U4 ^$ J5 P
+ ^9 Y1 {6 P4 |( u2 }' G
  1. typedef struct
    - h) k' A  h" v
  2. {; Y# [6 ]; P9 @4 v+ w' `, {
  3.   uint32_t             InputOffset;       5 ]" T/ m" ]! X: J
  4.   uint32_t             InputColorMode;    1 E, t) |4 T$ y6 `. ~! g
  5.   uint32_t             AlphaMode;        2 U$ L' Y% e8 z4 ]6 l
  6.   uint32_t             InputAlpha;        
    % a; U8 z" T* q- b
  7.   uint32_t             AlphaInverted;   
    6 F+ S5 \$ r0 P7 ?. J
  8.   uint32_t             RedBlueSwap;       : U) X" e  }0 k( ]/ d8 ?0 A' J9 Q
  9.   uint32_t             ChromaSubSampling;2 v6 R6 D, h2 q7 \# H
  10. } DMA2D_LayerCfgTypeDef;
复制代码
* Q' u8 X  L: U: I" @
下面将这几个参数逐一为大家做个说明。
/ D. M( r6 ^/ Y# N) b% z: b! i
0 f. ]$ m& u- y. Y5 e- L7 P  uint32_t  InputOffset
( b( h) B( Z, F4 t) U设置前景色或者背景色的输入偏移,范围0x000到0x3FFF。) j; k1 Z9 ~$ z
& f7 g7 ]- l* M* W
  uint32_t  InputColorMode
3 g, E. T% T- E# c( \3 @设置前景色或者背景色的输入颜色格式,具体支持的参数如下:/ J- @' T3 D% t- r

2 A& }  f$ i# @
  1. #define DMA2D_INPUT_ARGB8888        ((uint32_t)0x00000000U)  /* ARGB8888 */
    % t# ?4 |9 Q0 N$ ^
  2. #define DMA2D_INPUT_RGB888          ((uint32_t)0x00000001U)  /* RGB888   */
    0 O+ @5 x) Z+ t
  3. #define DMA2D_INPUT_RGB565          ((uint32_t)0x00000002U)  /* RGB565   */
    6 X. ^+ G5 A: z8 L* {5 |/ c# z
  4. #define DMA2D_INPUT_ARGB1555        ((uint32_t)0x00000003U)  /* ARGB1555 */
    " }, d) o0 J* U' \+ M: W  Y. W1 ^) Q
  5. #define DMA2D_INPUT_ARGB4444        ((uint32_t)0x00000004U)  /* ARGB4444 */
    $ X2 ^- c$ E9 t; I& q) }# G) N3 D
  6. #define DMA2D_INPUT_L8              ((uint32_t)0x00000005U)  /* L8       */, z- d7 }  C6 I6 a- R5 H$ y! n  z+ @
  7. #define DMA2D_INPUT_AL44            ((uint32_t)0x00000006U)  /* AL44     */
    6 W4 ]- r) B* [% s# s- U# |
  8. #define DMA2D_INPUT_AL88            ((uint32_t)0x00000007U)  /* AL88     */
    . G5 W) `  J! N6 p) H# x" |
  9. #define DMA2D_INPUT_L4              ((uint32_t)0x00000008U)  /* L4       */+ j" l6 V  v' p) b
  10. #define DMA2D_INPUT_A8              ((uint32_t)0x00000009U)  /* A8       */
    ; H/ G. [+ t2 K
  11. #define DMA2D_INPUT_A4              ((uint32_t)0x0000000AU)  /* A4       */. ^8 [# [2 V$ V' C
  12. #define DMA2D_INPUT_YCBCR           ((uint32_t)0x0000000BU)  /* YCbCr    */
复制代码

" S2 |( p& _4 y% `9 c- u9 L! @3 t) v  uint32_t AlphaMode6 I. m) Q  p8 O( e
设置前景色或者背景色的Alpha模式,具体支持的参数如下:, `+ `( c2 x- X5 H+ \. n. }
9 q/ x$ b9 k# q7 H' N7 w! S
  1. #define DMA2D_NO_MODIF_ALPHA   ((uint32_t)0x00000000U)  /* 不修改Alpha通道值 */
    * |4 l- b9 c4 ~6 R3 \, u
  2. #define DMA2D_REPLACE_ALPHA    ((uint32_t)0x00000001U)  /* 用新设置的Alpha值替换原始Alpha值 */6 z; ^* \; c1 x/ p/ ]5 L6 H/ C# o3 |
  3. #define DMA2D_COMBINE_ALPHA    ((uint32_t)0x00000002U)  /* 用新设置的Alpha值与原始Alpha值的乘积替换原始Alaha值*/
复制代码
" R& j+ s( S6 x% Q7 B
  uint32_t  InputAlpha
+ F: E  _: D- @; ~; |7 `; z设置前景色或者背景色的Alpha值,范围0x00到0xFF,如果颜色格式是A4或者A8,那么此参数的范围是0x00000000到0xFFFFFFFF,标准的ARGB8888格式。
/ i0 v: L7 Y, u/ `* o5 n8 F% p( s+ A' w
  uint32_t AlphaInverted1 t- ^0 }- s4 @; }9 n4 n, S: f
设置前景色或者背景色的输入颜色格式Alpha值反转(即255-原来数值),具体支持的参数如下:       _9 h2 x7 I6 q2 e' p9 h

" ]; j8 f8 N, `# f; i
  1. #define DMA2D_REGULAR_ALPHA      ((uint32_t)0x00000000U)  /* 正常输出 */  a5 I/ Q2 Z$ Y# a. x
  2. #define DMA2D_INVERTED_ALPHA     ((uint32_t)0x00000001U)  /* 反转输出 */     
复制代码
- J+ I% S: N; {: @
  uint32_t   RedBlueSwap
0 f5 i2 e9 Z4 p9 I设置前景色或者背景色颜色格式中R通道和B通道的交换,具体支持的参数如下:1 A: ~# _4 Z1 ?( O" h( p
1 c" R4 r/ s$ _' D
  1. #define DMA2D_RB_REGULAR   ((uint32_t)0x00000000U)  /* 不交换(RGB or ARGB) */
    - T9 U7 A" D: y# u
  2. #define DMA2D_RB_SWAP      ((uint32_t)0x00000001U)  /* 交换(BGR or ABGR) */
复制代码
1 |+ |5 \' E  E
  uint32_t   ChromaSubSampling$ n+ J3 W2 Z* P- i7 S% h
设置前景色或者背景色中YCbCr 颜色模式的采样格式,具体支持的参数如下:
  1. #define DMA2D_NO_CSS               ((uint32_t)0x00000000)  /* 4:4:4 */
    ( y3 d0 b$ v1 i* r0 E8 s  S2 q2 G
  2. #define DMA2D_CSS_422              ((uint32_t)0x00000001)  /* 4:2:2 */% _* x0 T9 s" d: j
  3. #define DMA2D_CSS_420              ((uint32_t)0x00000002)  /* 4:2:0 */  
复制代码

* r' p0 }- f6 L7 K' N5 E55.3.4 DMA2D句柄结构体DMA2D_HandleTypeDef
1 G8 x+ @" j- ~
HAL库在DMA2D_TypeDef, DMA2D_InitTypeDef和DMA2D_LayerCfgTypeDef的基础上封装了一个结构体DMA2D_HandleTypeDef,定义如下:
/ n  z( T! G3 b- ~* C1 |0 l/ G3 t( `0 l0 F6 k
  1. typedef struct __DMA2D_HandleTypeDef" }: x; }5 O4 J, O  `; f
  2. {; g1 h) M: C3 z: g. |$ t$ m
  3.   DMA2D_TypeDef               *Instance;                                                                                                                                                                                          
    ) c; |( F% c& Z5 R* u, Y
  4.   DMA2D_InitTypeDef           Init;                                                        4 @: T5 f" z" y# n8 p! @
  5.   void                        (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                                                                             : t( W6 T) _5 _. m! b  m
  6.   void                        (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);                                                                                      # i6 `& {2 S0 L9 W/ b
  7.   DMA2D_LayerCfgTypeDef       LayerCfg[MAX_DMA2D_LAYER];                                    
    . e4 ?1 r  p1 m& k; H# K
  8.   HAL_LockTypeDef             Lock;                                                                                                                                                                                                   
    / p2 @# D* w. D9 J$ O: `1 _/ M  G
  9.   __IO HAL_DMA2D_StateTypeDef State;                                                                                                                                                                                                   3 t( Y: S1 n2 j( A& {
  10.   __IO uint32_t               ErrorCode;                                                   } DMA2D_HandleTypeDef;$ @) u1 @1 k; t5 m2 W
复制代码

  e$ B4 e) ?* X' K; M" C( A下面将这几个参数逐一做个说明。# G3 Y4 i# n5 I2 Y' Q" d( x7 E
$ G& j1 j$ \- g# l3 F# u) S
  DMA2D_TypeDef  *Instance
( N! ?6 B( D) X  z: ~这个参数是寄存器的例化,方便操作寄存器,详见本章3.1小节。4 M3 o0 a; j. i% x5 |

3 n- `1 O9 L9 b' u  DMA2D_InitTypeDef  Init;  0 G0 w: }, b8 h- H3 r6 b3 L& d
这个参数是用户接触较多的,用于配置DMA2D的基本参数,详见本章3.2小节。3 p! p* O2 _6 }/ |
. k' Z5 O! M' r
  void     (* XferCpltCallback)(struct __DMA2D_HandleTypeDef * hdma2d);
9 W+ E- W3 E3 Z& O  void     (* XferErrorCallback)(struct __DMA2D_HandleTypeDef * hdma2d);8 Q/ d. R+ Z7 ?
DMA2D中断服务程序里面执行的回调函数,一个是传输完成回调,另一个是传输错误回调。
+ F: S9 o9 K6 J0 F8 I& L
( C' N7 X" Q# c+ J  X  N* [9 {  DMA2D_LayerCfgTypeDef   LayerCfg[MAX_DMA2D_LAYER]
4 X3 J0 y2 r7 c" i! D" F这个参数用于前景色和背景色的设置,MAX_DMA2D_LAYER=2,详见本章3.3小节。
: p$ V; u; X& D- m. B1 R4 Y' x0 i% _% H9 W$ n, r
  HAL_LockTypeDef   Lock2 y8 y& a& X2 p; d
__IO uint32_t    State;
4 a+ X4 X8 o7 O( s/ {- ?! y7 e7 K: E
__IO uint32_t    ErrorCode5 d. ]$ H- P$ ~$ X+ g
* e( d4 L! [! e. R3 {
这三个变量主要供函数内部使用。Lock用于设置锁状态,State用于设置DMA2D通信状态,而ErrorCode用于配置代码错误。
1 U4 r' a, C* R  S2 a! ~
+ v  ]' N  @1 G( [3 `55.3.5 DMA2D初始化流程总结

! i6 P, R# L& \+ L( _. M4 K对于DMA2D来说,其实不需要初始化流程,每个功能都可以直接封装出一个函数来,下个章节会为大家专门讲解,也是实际项目比较推荐的方式。( J2 H2 f. j2 o: R/ C% @

( e( Y0 v8 e9 X* P7 Q55.4 源文件stm32h7xx_hal_dma2d.c, {8 M8 h# ~+ ^$ v; O5 }9 c2 Z3 R3 y
这里把我们把如下几个常用到的函数做个说明:2 Z3 Q4 p# q( I3 K: ]

  ~, k- z- V8 H, D% L( ?" X& C  HAL_DMA2D_Init& m& D( e  R0 `0 s3 ?9 U
  HAL_DMA2D_ConfigLayer
5 ]. q: X. J- U  HAL_DMA2D_Start_IT* l* ~* n/ H5 [6 ^: H
  HAL_DMA2D_BlendingStart_IT1 X& m" C' Q! ^' L7 i
) A& I' N# M0 g4 }, e* [
55.4.1 函数HAL_DMA2D_Init
6 U  }% ^% J  W+ D6 z& V函数原型:
0 k6 I  K4 \/ P2 _& Q2 w* h! L8 k* f- w. ]3 `9 c
  1. HAL_StatusTypeDef HAL_DMA2D_Init(DMA2D_HandleTypeDef *hdma2d)
    7 ]/ m9 k$ c6 d, M/ H
  2. { # r! l; m" M; m( l$ [% ]( ~

  3. 5 v3 B8 [' O$ }, T4 m* _
  4. /*  检测参数是否有效 */8 [: I: y% E0 |3 I
  5.   if(hdma2d == NULL)
    , I1 ?6 n% @/ @+ [" G" h
  6.   {
    0 ?: v+ ~: c6 C0 H! a, O% ]
  7.      return HAL_ERROR;9 g9 ]- p0 X6 g& C( z. j! i, F
  8.   }  `- ^$ O9 o1 D9 `0 i' ~
  9. 9 S! S! l0 c$ [; v4 ]" e4 l' k
  10.   /* 检测函数形参 */
    2 ^& b' |& x" e7 j' ~2 ^8 b
  11.   assert_param(IS_DMA2D_ALL_INSTANCE(hdma2d->Instance));$ @+ c9 D& j, H+ q# G
  12.   assert_param(IS_DMA2D_MODE(hdma2d->Init.Mode));0 W9 t. K) k( y9 ^" w6 M
  13.   assert_param(IS_DMA2D_CMODE(hdma2d->Init.ColorMode));
    0 C9 N# [. F& s. U- W
  14.   assert_param(IS_DMA2D_OFFSET(hdma2d->Init.OutputOffset));1 b% f4 P' Y  @* p. @2 _
  15. ; h1 b* O; ^( g) B4 O1 _
  16.   if(hdma2d->State == HAL_DMA2D_STATE_RESET)6 y, m" X& e" N  N" f5 M
  17.   {3 E4 h, q! ^5 ]. D; \* O+ x
  18.     hdma2d->Lock = HAL_UNLOCKED;+ S- x9 h; Y( X  R7 ^
  19.     /* 初始化GPIO,NVIC等 */2 ]8 i) Q$ D! g. a5 ~
  20.     HAL_DMA2D_MspInit(hdma2d);5 h2 `4 I+ B/ u: @8 ]8 ]# I: o
  21.   }
    0 d8 t1 C0 G8 v

  22. * Z/ m7 H( a8 M3 X2 L5 H) u
  23.   /* 设置DAM2D外设状态 */
    7 p# c% \" T+ F' }
  24.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  . o$ f& ~8 C* g# I7 }& }

  25. 0 |2 [9 C. Z8 K$ N
  26.   /* 设置DAM2D工作模式 -------------------------------------------*/
    % D" r: M6 _1 u% K) @
  27.   MODIFY_REG(hdma2d->Instance->CR, DMA2D_CR_MODE, hdma2d->Init.Mode);% v3 `- ?7 l! ~' W7 a& Q

  28. 6 K4 g7 m, V" s- x& R
  29.   /* 设置输出颜色格式 ---------------------------------------*/* H* Z7 z6 a/ {/ s+ K
  30.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_CM, hdma2d->Init.ColorMode);2 `6 R' j  c. w0 T& f5 o; r

  31. ) ~- a+ y9 N3 i# k
  32.   /* 设置输出偏移 ------------------------------------------*/  . {5 e# k$ T' ]0 Z9 m
  33.   MODIFY_REG(hdma2d->Instance->OOR, DMA2D_OOR_LO, hdma2d->Init.OutputOffset);  # V, J8 G$ }1 a, i$ R

  34. & r: D& S1 }1 G/ }7 L
  35.   /* 设置输出颜色格式中的Alpah值反转 */
    & |% z4 p' t0 W6 O9 Y+ Q; s) O
  36.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_AI, (hdma2d->Init.AlphaInverted << DMA2D_POSITION_OPFCCR_AI));
    5 Q9 @; n' h/ Z5 k( @; a

  37. / h  ^/ F% Z$ G5 L" \. r
  38.   MODIFY_REG(hdma2d->Instance->OPFCCR, DMA2D_OPFCCR_RBS,(hdma2d->Init.RedBlueSwap << DMA2D_POSITION_OPFCCR_RBS));
    " L" }, l* A* |$ ]5 ]# A
  39. ; O& z8 v* ~; m# [' q. _; Z! D1 V
  40. : O& V$ N1 g& V( |
  41.   /* 无错误 */4 g8 U! r/ H; F& _0 a5 k
  42.   hdma2d->ErrorCode = HAL_DMA2D_ERROR_NONE;
    4 V8 \% H, C7 F* Y4 o; T. W; f

  43. 7 P9 C) x  u5 F/ T) P5 P0 N3 s
  44.   /* DAM2D就绪 */
    , A* ~& G" \: i# ~
  45.   hdma2d->State  = HAL_DMA2D_STATE_READY;
    . B8 s+ u' k! ^' }* |( v

  46. 1 N+ \" C9 n2 b5 ~2 C
  47.   return HAL_OK;- e: q5 P1 O. ^0 z7 m7 j. N
  48. }
复制代码
, T, D, m. e3 I# t9 e/ m/ z$ l
函数描述:
* I9 n) H* U8 Y2 T: K/ K; R; e, a$ d6 J6 z- p
此函数用于初始化DMA2D的工作模式和输出颜色格式。" r, o' N/ }) j/ A; c8 k1 `

1 r% y7 {1 c  \# O& D: N& T: `) `函数参数:
3 s( V% Z% R" K7 u& x. D" O  @# P) e* z0 @% S
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置要初始化的参数,结构体变量成员的详细介绍看本章3.4小节。) r! R) X6 u: Q* t, Z
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。
' a# p+ \1 G" v* B; u9 c/ G9 H注意事项:7 A/ F" {4 E# w6 @. ]
3 |' [. ^' z. G7 a5 {* M
函数HAL_DMA2D_MspInit用于初始化DMA2D的底层时钟、NVIC等功能。需要用户自己在此函数里面实现具体的功能。由于这个函数是弱定义的,允许用户在工程其它源文件里面重新实现此函数。当然,不限制一定要在此函数里面实现,也可以像早期的标准库那样,用户自己初始化即可,更灵活些。% Q0 `/ w8 W' q8 u/ D4 f9 X
如果形参hdma2d的结构体成员State没有做初始状态,这个地方就是个坑。特别是用户搞了一个局部变量DMA2D_HandleTypeDef Dma2dHandle。
, r5 V# W6 V& U/ A4 ]+ W3 P% q# ~对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_DMA2D_STATE_RESET  = 0x00U。
; j7 F6 k, Z+ C% Z
3 C" c; o7 a: r* R- u. E解决办法有三
* I$ j% d# n" N
- m" y" n0 U0 x% A9 C4 w方法1:用户自己初始DMA2D底层。
. l% [' X. U$ {5 c
! W& T! }2 Z6 `2 R. J方法2:定义DMA2D_HandleTypeDef LtdcHandle为全局变量。
: M  R2 d. f; k
( Q% J/ ^* ?$ Z6 x- w3 A% P& I方法3:下面的方法
  1. if(HAL_DMA2D_DeInit(&Dma2dHandle) != HAL_OK)6 Q+ D' ~. [0 N- t2 U+ a
  2. {% Y. `6 F6 }! E7 B8 K# U5 q
  3.     Error_Handler();4 u. Y9 b, a0 G5 R9 X8 ?0 V
  4. }  0 M* ]% \8 T* z7 g# L
  5. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
    1 K; @+ T, T3 f  F( k
  6. {3 ~9 a" S$ V4 V# P: \" N! t0 v! P
  7.     Error_Handler();7 V+ U5 q1 V4 Z, |
  8. }
复制代码
$ x7 ]! l0 v/ \7 Q! A' B7 \
/ G" ?; o) y" x# S" u2 K
使用举例:
* c3 \; S0 P/ t( I. F7 a5 L+ w0 o2 N
  1. DMA2D_HandleTypeDef Dma2dHandle;6 M# x% o) \3 X) b+ j) D9 w7 M
  2. 3 X8 x3 V2 |& B" N4 v
  3. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/
      R" p4 K( a& p% o
  4. Dma2dHandle.Instance = DMA2D;
    6 Y+ b" P7 H' d) F' x: N6 e! f' b

  5. % q2 O* l: g' v
  6. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */
    ! j, Z" q7 t2 P( j9 N% c
  7. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */
    % T' ~1 J* \$ E5 w6 H
  8. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */9 g6 N; S. p# m# q. l* w
  9. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */
    ' m' V1 o+ S( V0 m9 t6 P
  10. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */
    - W% k; s! X3 X: S9 |  @

  11. 7 |& a# v$ ^& x. M2 d1 L
  12. /*##-2- DMA2D 回调函数配置 ######################################*/
    $ x$ d8 T6 R2 L
  13. Dma2dHandle.XferCpltCallback  = TransferComplete;
    6 O! E; W' c8 y: Z  h% ]
  14. Dma2dHandle.XferErrorCallback = TransferError;4 N7 |) }& W# g) @

  15. ; F9 M) @6 J( J6 y4 n) b  `
  16. /*##-3- 前景层配置 ###########################################*/' X" J+ }) P# `3 y' N7 O  B1 Y
  17. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */
    ( j& ]% ~$ q, k1 Q+ }. H4 |
  18. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */
    ! H: d% ?- V! c7 v+ {! w" ^" Y& G- f
  19. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */: c+ k* W4 \7 T, b- p, ^' ]
  20. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */" \/ I7 @& b: t# ?# m" R* J
  21. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/
    $ R7 p5 P  d2 S: K+ m6 ^' e: {
  22. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/9 m4 [& e: l# x. }8 O
  23. ; G+ w3 z& g' F' T

  24. ( G8 Q( {- |# s% ~
  25. /*##-4- DMA2D 初始化 ###############################################*/9 L" V4 R1 q8 f  V
  26. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)% P1 I0 @* s; F4 R. t1 e! I
  27. {
    * C) D7 U, F& q" ?6 P$ P
  28.     Error_Handler();. d3 g6 J: L5 E6 J% n
  29. }
复制代码
) Z( G& K; t3 `9 t9 G. Y" P1 X
55.4.2 函数HAL_DMA2D_ConfigLayer4 h( t# [# B: Z: b) ?
函数原型:
* t3 A" J0 K7 h! Z0 L0 i6 R; `8 r, z) ~* b
  1. HAL_StatusTypeDef HAL_DMA2D_ConfigLayer(DMA2D_HandleTypeDef *hdma2d, uint32_t LayerIdx)8 {+ B4 |' e1 O5 q
  2. { , K0 a! R3 o. \0 n/ ?' x
  3.   DMA2D_LayerCfgTypeDef *pLayerCfg = &hdma2d->LayerCfg[LayerIdx];6 p$ ~7 T, L2 `$ u4 k' N! ?# h
  4. 6 d8 M4 C0 q% E5 @- @3 Y
  5.   uint32_t regMask = 0, regValue = 0;: C9 Z& a7 Z% ^9 ?# `  x5 J( T

  6. 6 t+ e) l7 Q5 \, X# k6 R' b9 F
  7.   /* 检查参数 */
    6 U0 ?3 s7 p9 G: R* @
  8.   assert_param(IS_DMA2D_LAYER(LayerIdx));  
    ; {5 K, O. b4 P1 F, ?, Z
  9.   assert_param(IS_DMA2D_OFFSET(pLayerCfg->InputOffset));  
    8 x. I6 J& O9 K* f) ]+ N, m
  10.   if(hdma2d->Init.Mode != DMA2D_R2M)5 j: R' g" G) H1 V" z/ {# k, N3 _
  11.   {  : Z  F$ T& d6 M, D- f4 G! T
  12.     assert_param(IS_DMA2D_INPUT_COLOR_MODE(pLayerCfg->InputColorMode));
    ' ~) m4 E" c; W# _- D. Z+ o
  13.     if(hdma2d->Init.Mode != DMA2D_M2M)* p; B* }/ b2 `. a, I6 b+ k% X# i
  14.     {
    & g/ b/ h, l# B( H
  15.       assert_param(IS_DMA2D_ALPHA_MODE(pLayerCfg->AlphaMode));
    ; z; m6 ?+ N1 n) q3 i" w
  16.     }
    % z( w1 g. z2 u9 Y6 O% w
  17.   }
    ( K% t3 c& P4 x: N

  18. & `4 w& v' }9 s$ O! ]
  19.   /* 上锁 */
    , z0 K2 \. a# e% u1 c# E0 r
  20.   __HAL_LOCK(hdma2d);
    " s. d! N2 I9 K2 f" e
  21. & r7 ~% V" L0 F" c5 b' l" s5 ^
  22.   /* 设置DMA2D外设状态 */
    ' V7 r( k) o2 O4 L7 C+ Z, \8 M7 u
  23.   hdma2d->State = HAL_DMA2D_STATE_BUSY;  " n, c& z6 h2 D" s& g

  24. 0 X8 g$ C) b% E
  25.   /* 准备好背景层或者前景层FPC寄存器配置参数*/
    / C! ^/ U( h/ n6 o: h
  26.   regValue = pLayerCfg->InputColorMode | (pLayerCfg->AlphaMode << DMA2D_POSITION_BGPFCCR_AM) | \
    - _- [9 {2 Z1 b* I4 w
  27.             (pLayerCfg->AlphaInverted << DMA2D_POSITION_BGPFCCR_AI) | \
    5 a2 z9 Y& V8 @: ~
  28.             (pLayerCfg->RedBlueSwap << DMA2D_POSITION_BGPFCCR_RBS);
    ! i3 i8 \8 V  [; m: I* y

  29. # `, d; R# Z) r$ z; n- W, [) h/ h/ _
  30.   regMask  = DMA2D_BGPFCCR_CM | DMA2D_BGPFCCR_AM | DMA2D_BGPFCCR_ALPHA | DMA2D_BGPFCCR_AI | DMA2D_BGPFCCR_RBS;) B6 ~) C( \! Z
  31. # A+ Q6 C! Z5 O
  32.   if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    . h2 g+ c* e& X4 {+ M; r
  33.   {
    + s8 M$ N. e7 r5 I! u
  34.     regValue |= (pLayerCfg->InputAlpha & DMA2D_BGPFCCR_ALPHA);
    5 U; k' l* o- w' R' g
  35.   }; e4 v- L/ Z* e. @6 l+ h3 m
  36.   else
    4 V4 F  }7 X4 S* {. i3 @
  37.   {% R# f6 @) Y$ X, I2 `5 P5 ~
  38.     regValue |=  (pLayerCfg->InputAlpha << DMA2D_POSITION_BGPFCCR_ALPHA);( t, Z; c% [  Z) C! g  C
  39.   }, D4 V) M+ O9 A7 F0 t- C

  40.   o! ]2 I1 @8 C# M+ c& C
  41.   /* 配置背景层 */
    % |% ]0 c' z  c) B) C3 l
  42.   if(LayerIdx == 0)
    # z' h$ e/ [7 C* x
  43.   {
    : g. R  f9 t# o( I! b8 l, q, H
  44.     /* DMA2D BGPFCCR 寄存器 */2 w& Z& d9 V+ n& d8 w( i
  45.     MODIFY_REG(hdma2d->Instance->BGPFCCR, regMask, regValue);
    % s2 v, I$ G1 Q2 ^& V- A* Y
  46. ' |$ }1 X* Q2 b9 X  h
  47.     /* DMA2D BGOR 寄存器 */  , U4 E. ~" {4 |' m" t
  48.     WRITE_REG(hdma2d->Instance->BGOR, pLayerCfg->InputOffset);/ @" V7 b5 ]) _$ X9 e4 D3 \
  49. , b# N7 r# K* ]2 D0 c: t
  50.     /* DMA2D BGCOLR 寄存器 */ 0 F$ L" T$ H( U2 B" A
  51.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    : M" F$ \% Q$ U0 p7 I! |4 e
  52.     {    ; {4 W" Z; v) T) c3 C: n
  53.       WRITE_REG(hdma2d->Instance->BGCOLR, pLayerCfg->InputAlpha & 5 ^. \3 s6 z, w
  54. (DMA2D_BGCOLR_BLUE|DMA2D_BGCOLR_GREEN|DMA2D_BGCOLR_RED));& N' o3 _. @! e5 X) n& X) v/ N' E
  55.     }   
    + s  k+ i" }# O5 `! r. I
  56.   }' s, v- O: E# q
  57.   /* 配置前景层 */3 s4 O( @2 L" ?
  58.   else9 _2 B; G" ?2 w2 M+ f0 @6 _& {. i
  59.   {
    . \' e( G7 b8 s/ I0 d2 {
  60.     if(pLayerCfg->InputColorMode == DMA2D_INPUT_YCBCR)) \- y8 T7 g7 Z
  61.     {3 W+ f$ e* Y3 v5 M( ]3 e  y
  62.       regValue |= (pLayerCfg->ChromaSubSampling << DMA2D_POSITION_FGPFCCR_CSS);
    * v( M: K- z6 A6 q/ d, N0 J" F
  63.       regMask  |= DMA2D_FGPFCCR_CSS;
    9 y) S$ L' Y  D) x& c: \
  64.     }; R& k* X9 S. M! o3 F
  65.   a; ~$ V0 r( l: T6 ~3 Z
  66.      /* DMA2D FGPFCCR 寄存器 */
    2 G5 B; z1 v9 n4 [8 a
  67.     MODIFY_REG(hdma2d->Instance->FGPFCCR, regMask, regValue);  V2 t- m. T7 j* E

  68. ) ]& y/ B, ]0 j7 b" L/ p
  69.     /* DMA2D FGOR 寄存器 */- e! }; I) f2 z" ^% i5 C8 w
  70.     WRITE_REG(hdma2d->Instance->FGOR, pLayerCfg->InputOffset);      
    5 J! Q: r) E: ?6 O5 ]" Z( \
  71. 5 T# A+ q  |8 A( _
  72.     /* DMA2D FGCOLR 寄存器 */   " {& K: `4 z+ I. b. Y7 q3 M  ]
  73.     if ((pLayerCfg->InputColorMode == DMA2D_INPUT_A4) || (pLayerCfg->InputColorMode == DMA2D_INPUT_A8))
    ' M  p0 B' H9 X7 a) z. |% T8 j
  74.     {
    " ?. _1 s7 [+ L  Z" I3 S
  75.       WRITE_REG(hdma2d->Instance->FGCOLR, pLayerCfg->InputAlpha & 6 p4 p. a4 @, n& y& F- T5 ?
  76. (DMA2D_FGCOLR_BLUE|DMA2D_FGCOLR_GREEN|DMA2D_FGCOLR_RED));      
    $ H% A; s' f/ P% q7 w1 d1 C
  77.     }   
    % ~& x# s% s% e, l& y$ i; B+ b
  78.   }   
    3 w5 F% |& [& I9 @9 ^$ y/ o
  79.   /* DMA2D就绪 */3 S+ V& B1 v' A: f( @/ b+ U
  80.   hdma2d->State = HAL_DMA2D_STATE_READY;
    ' W: f) B4 E% Z! t  c4 Z% a, z- c
  81. 5 ]: G" t# p$ g0 e: N/ x2 X% i
  82.   /* 解锁 */
    ( c4 ^% i& u/ Z4 q& L5 p; i
  83.   __HAL_UNLOCK(hdma2d);    ~) i4 K7 L+ \0 E

  84. + M# C+ s( E& k) {1 s( s1 h2 s3 V
  85.   return HAL_OK;
    ) Z: E5 U( w  f# q+ T' w
  86. }
复制代码

! e9 X4 b9 K' f. |) ~* l" p1 @函数描述:
( D: [& L( M$ g) M
7 d: |6 h- Z4 |$ U: o1 h此函数主要用于配置DMA2D要转换的前景层和背景层,即输入颜色配置。而前面的函数HAL_DMA2D_Init配置的输出颜色。
: y: Y/ ~2 b7 [- V/ A, M' Y1 V# W. K1 q, x& U8 M4 K# n& E
函数参数:8 M" E+ ~( }/ T9 M/ v$ f

8 H7 D: x9 G$ i$ S  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。
- F  V+ U! H9 W: G. B# ]  第2个参数用于配置前景层和背景层,0表示背景层,1表示前景层。
$ O2 e6 z/ m$ i8 v5 h, r2 i9 Z  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。6 c2 g+ n2 {. m# q1 _
使用举例:
2 T. h% j" K- _8 A' K+ ]7 E
  1. ' r. l8 O# x0 i; Y) W) Q3 E
  2. DMA2D_HandleTypeDef Dma2dHandle;( v3 ~, L* I; L4 y
  3. . y' T/ F* F9 S% h/ \

  4. ( y9 N/ e) R$ r3 ^
  5. /*##-1- 配置DMA工作模式,输出颜色格式和输出偏移 #############*/
    , F4 E! S" {% g% C1 u
  6. Dma2dHandle.Instance = DMA2D;, l, W& c. {' ^$ c/ s
  7. ; N8 Q* W- ^/ S# ^. b
  8. Dma2dHandle.Init.Mode          = DMA2D_M2M;             /* 存储器到存储器模式 */' g+ T8 A. R; c3 Y( N+ I# F
  9. Dma2dHandle.Init.ColorMode     = DMA2D_OUTPUT_ARGB4444; /* 输出颜色格式 */6 h# p& Y0 n$ W; X* Y
  10. Dma2dHandle.Init.OutputOffset  = 0x0;                   /* 无输出偏移 */, L9 L5 F: x$ f0 s/ U$ Y
  11. Dma2dHandle.Init.RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输出颜色的R/B通过不切换 */" U: i  b. ~% G, B- y* H, o4 Z, K
  12. Dma2dHandle.Init.AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输出颜色的Alpha通道数值不翻转 */4 m; \8 s8 a$ D* n9 y

  13. ) v, }$ ^; o! D6 R0 y. e% K
  14. /*##-2- DMA2D 回调函数配置 ######################################*/! B- X% e" g* I" |/ s
  15. Dma2dHandle.XferCpltCallback  = TransferComplete;
    5 o  q% p# Y* f3 N' M! p, S3 y+ s
  16. Dma2dHandle.XferErrorCallback = TransferError;7 v( W5 Y- Z/ M

  17. ! O" Y; T2 E2 c" R, _# M  E
  18. /*##-3- 前景层配置 ###########################################*/
    - _! m" F/ j) C% D; S
  19. Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;      /* 保持输入颜色格式中的Alpha值 */
    ' @. d1 O4 l0 f/ d2 N, v- d
  20. Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;                     /* 完全不透明 */' g& ?+ _1 W* _& Y& M& {1 O
  21. Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB4444; /* 输入颜色格式 */7 z$ B3 k0 a& h9 p1 |* V
  22. Dma2dHandle.LayerCfg[1].InputOffset = 0x0;                     /* 输入无偏移 */
    ' V/ M& s8 D. w5 |$ N' n/ }9 Z
  23. Dma2dHandle.LayerCfg[1].RedBlueSwap   = DMA2D_RB_REGULAR;      /* 输入颜色的R/B通过不切换*/% }2 f2 q5 l1 K
  24. Dma2dHandle.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA;   /* 输入颜色的Alpha通道数值不翻转*/
    " Z6 C; h6 R! S6 ^% ]2 z" `
  25. * V4 i& q/ X% g" A  M9 {
  26. /*##-4- DMA2D 初始化 ###############################################*/2 c, y0 w8 q( B4 v+ _- d
  27. if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK)
    ( T# |8 E& X# u4 @
  28. {
    ( [8 b0 O, O: ~/ m2 ]
  29.     Error_Handler();  R5 y& F+ Q* }
  30. }
    7 N- ]( w6 ]7 l8 X2 g* _* }7 e
  31. ) P; b6 b% T$ o" |# n
  32. /* 配置前景层  */
    - J( v; I+ f: E; }, q; a2 n9 t$ p
  33. if(HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1) != HAL_OK)
    0 ~# \/ L/ g) Z, m* J/ |
  34. {& U0 |8 s( H# ]! t
  35.    Error_Handler();
    ! i( ~! {  k/ c" R5 L
  36. }
复制代码
$ ^' R7 U( ]5 v, ~" J9 [) W3 ?
$ o$ {; E' i* k* K/ \
55.4.3 函数HAL_DMA2D_Start_IT; u  W* ^% D5 q8 F7 D% V
函数原型:
' n) z' x. O& M5 j( u/ b
. Q; j3 ^1 c3 d9 d7 N: |9 ~7 T6 ~
  1. HAL_StatusTypeDef HAL_DMA2D_Start_IT(DMA2D_HandleTypeDef *hdma2d, uint32_t pdata, uint32_t DstAddress, uint32_t Width,  uint32_t Height)
    ' j& H. S% x8 N
  2. {
    8 o6 U* H1 D, O$ o& a; I& h
  3.   /* 检测函数形参 */
    ) i0 P1 g. D: d4 m
  4.   assert_param(IS_DMA2D_LINE(Height));9 V5 ~. t  x1 Y9 t
  5.   assert_param(IS_DMA2D_PIXEL(Width));1 T& R0 w1 z. U. W
  6. ; D1 k$ _$ L) E; W% B( j
  7.   /* 上锁 */: x2 `- g; c+ }( s
  8.   __HAL_LOCK(hdma2d);
    * f0 w% Q0 n) x0 I% D

  9. 9 z& v. u$ O# j+ Z
  10.   /* 设置DMA2D外设状态 */2 M% X5 B7 P/ Q! N
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;
    " C! v- O& G- w# s) x/ O
  12. 3 U$ M  `, i. y9 v7 n7 W" Q
  13.   /* 设置源地址,目的地址和数据大小 */$ t* t! M- A4 l/ F1 o
  14.   DMA2D_SetConfig(hdma2d, pdata, DstAddress, Width, Height);
    ; l5 G: s/ o% W. i: Q/ m* b2 P/ Z

  15. ; f: \+ _+ h! H2 y) M
  16.   /* 使能DMA2D的传输完成中断,传输错误中断和配置错误中断 */
    * k+ K; s& S' W( D; k* P. w: l/ A( G
  17.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);
    ( K0 Q+ Q2 p. W6 ]5 f: o8 K# b

  18. , R, q! g3 i7 I, C+ n9 m) l& f- i
  19.   /* 使能DMA2D */
    . Z) G1 Z- M$ _9 [
  20.   __HAL_DMA2D_ENABLE(hdma2d);
    5 O9 G2 X) y' ]- e

  21.   t5 {9 Z1 F) h7 H9 J
  22.   return HAL_OK;
    ! q$ e* j: {5 M0 H
  23. }
复制代码
1 x* ?! T+ e0 J0 F
函数描述:8 y. V! g5 [$ P9 u1 n0 p5 g- F
; u* s# H6 d# I7 B
此函数用于启动DMA2D数据传输。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。
$ v4 h  V+ B* Y% `% ]
6 D' B2 b4 W- J; a# @函数参数:
6 o& Y9 B5 O" ]& K! ?( ?6 g2 r0 v& `  A4 y% e
  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。# D- \: P  A& h- X1 ^8 j8 w" D
  第2个参数是源数据地址。
& V: _, \* x- C3 N4 W  第3个参数是目的数据地址。( V9 S7 h; y  Y8 \! \
  第4个参数是源数据的长度,即每行的像素个数。0 R+ t) Q5 ^+ v
  第5个参数是源数据的高度,即行数。8 l4 r* `& H6 y. b, `: c( [! c
  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。$ {1 E1 e( Z! e. N# m6 D# _
使用举例:
- x/ d) ^2 e- \
& U3 l  `5 Z0 h! B6 O( ^
  1. DMA2D_HandleTypeDef Dma2dHandle;. a) C% Z( y7 v8 E: J- [5 V
  2. " ~1 G0 e3 t4 I/ J7 Z& e3 [
  3. if(HAL_DMA2D_Start_IT(&Dma2dHandle,            /* DMA2D句柄 */; H* N2 U" ~  N! [% [
  4.                       (uint32_t)&BufferInput,  /* 源地址 */
      [7 ~$ w1 o( \& @
  5.                       (uint32_t)&BufferResult, /* 目的地址 */
    " Q: m- g8 @' h5 e1 M0 D* ^
  6.                       SIZE_X,                  /* 源数据长度,单位像素个数*/$ k, m# O- J% f
  7.                       SIZE_Y)                  /* 源数据行数 */" L+ G# o+ u1 q6 w, e% y' }, }
  8.    != HAL_OK)
    7 T4 i5 Y* F8 L9 L! j* v: t8 G
  9. {
    0 q; f6 G- ?/ S: s
  10.    Error_Handler();; O1 K2 F- Y/ x' }( c! |0 G9 |( J
  11. }
复制代码

6 v- K' w& }. }55.4.4 函数HAL_DMA2D_BlendingStart_IT
, y' V, k( H2 [  K. e. I$ Z1 n) r2 U函数原型:" [8 N  B; k$ v
- `. Z  U( t, u  N
  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)
    3 v- B( ~, M# {; `" k6 y+ g7 b" {4 j
  2. {2 T9 O$ U. r3 y7 r1 y; D( o1 K' Q' G
  3.   /* 检测参数 */
    ' s1 J! i$ |+ w( ]; s
  4.   assert_param(IS_DMA2D_LINE(Height));
    6 z9 G5 P+ O  j* |
  5.   assert_param(IS_DMA2D_PIXEL(Width));
    ( s& ~' k" U- j5 b" ~% r: v
  6. 3 Q8 X1 i3 K5 l7 G3 e) ]
  7.   /* 上锁 */% l5 c0 m# Q4 b
  8.   __HAL_LOCK(hdma2d);
    % G" r0 `9 C) ?" ]; x  H2 b
  9. 6 D! ^% Q, @- p: d# x9 H) Y
  10.   /* 设置DMA2D外设状态 */$ M( ^" y; H( L
  11.   hdma2d->State = HAL_DMA2D_STATE_BUSY;2 v6 D$ O0 @6 r$ [+ ^

  12. # E- O7 j5 [7 D' D! M
  13.   /* 配置DMA2D源地址2 */
    ) u3 J, ]4 F- a: X( Z
  14.   WRITE_REG(hdma2d->Instance->BGMAR, SrcAddress2);' Z4 \3 i1 I: _0 n" b5 ]% T" a' _
  15. " |$ k- q1 |" [2 S# e
  16.   /* 配置源地址1,目的地址和数据大小 */
    * N' w0 U6 Q4 O7 b6 k: w
  17.   DMA2D_SetConfig(hdma2d, SrcAddress1, DstAddress, Width, Height);: Z% q6 L$ x+ J; O0 F+ {

  18.   Z5 m+ D" c- h3 q7 V
  19.   /* 使能DMA2D传输完成中断,传输错误中断和配置错误中断 */
    % H) M& t' c5 K( d+ {
  20.   __HAL_DMA2D_ENABLE_IT(hdma2d, DMA2D_IT_TC|DMA2D_IT_TE|DMA2D_IT_CE);
    ) C: T4 ?) F* f& g4 @# }! z
  21. ( |3 i" g- [. I* e9 ]  I# s* |
  22.   /* 使能DMA2D */& {, g& k3 ?7 ]" L* T( Y8 r
  23.   __HAL_DMA2D_ENABLE(hdma2d);7 a+ p/ O: O, V; V9 c
  24. ' t$ Z$ v. k" J0 f
  25.   return HAL_OK;+ F1 t# l% C0 A
  26. }
复制代码
* j2 e2 n/ x: Z8 H# V! v
函数描述:& P6 e. ^$ }' W7 d

. Q' w4 P, }5 G4 u; \此函数用于启动DMA2D传输,除了数据传输以外,还支持颜色格式转换和颜色混合。由于采用的中断方式,此函数使能了多个DMA2D中断,不要忘记DMA2D中断服务程序的处理。
, j) n7 a. M5 l0 E7 K* ]6 K) @0 m0 g. g2 I0 B
函数参数:
* I! ~1 a: n* z7 f$ e; P. n. q
; f* R9 S) E( J: ]' [  第1个参数是DMA2D_HandleTypeDef类型结构体指针变量,用于配置DMA2D的基本参数,结构体变量成员的详细介绍看本章3.4小节。" _: T; C+ e  n& F, @- v# _$ }
  第2个参数是源数据地址1。
; t, X2 W2 A  e9 n9 H; N  第3个参数是源数据地址2。
, ^# k  B  J8 S: v  第4个参数是目的数据地址。' y; C+ w$ O  c) V; Q0 @  L
  第5个参数是源数据的长度,即每行的像素个数。. z8 I4 j% n! n$ `* F' T7 r6 j
  第6个参数是源数据的高度,即行数。
) X4 ~( C9 }- r1 q3 N' o  返回值,返回HAL_ERROR表示配置失败,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示时间溢出。3 a, ~1 [+ C8 v3 O
使用举例:
) U4 k; a8 R/ G$ {. d7 A3 |. j, l# G- V
  1. DMA2D_HandleTypeDef Dma2dHandle;
    : b+ V( O) L, ?5 S& G& m/ c4 Y

  2. % [1 f# [4 X( R4 J4 u) V# h
  3. if(HAL_DMA2D_BlendingStart_IT(&Dma2dHandle,           /* DMA2D句柄 */- ~% B8 J- Q+ S
  4.                              (uint32_t)&BufferInput1, /* 源地址1,前景色 */ / k9 `; Y0 C$ r' `5 ^$ {
  5.                              (uint32_t)&BufferInput2, /* 源地址2,背景色 */- a6 g: i) P" o  c3 q' p1 A+ e
  6.                              (uint32_t)&BufferResult, /* 目的地址 */$ k2 y9 Y  B+ |$ m
  7.                               SIZE_X,                 /* 源数据长度,单位像素个数*/
    $ A" x1 c" ~7 R4 n# c& \( [8 s
  8.                               SIZE_Y)                 /* 源数据行数 */+ f/ ^5 k- p  Q' w+ {2 o
  9.    != HAL_OK)1 |# X( B4 v" w# J& G6 ?- E
  10. {0 v8 q( g# F' p1 W' h
  11.    Error_Handler();
    # D+ ~+ P( T+ W& `4 y
  12. }
复制代码

! g; p/ K$ T* E+ ?$ \! T/ Q! L9 p% T" [" r! `8 M/ p
55.5 总结4 o9 b( e, O: W* T! _
本章节就为大家讲解这么多,DMA2D功能比较重要,一定要做到熟练使用。8 S  F3 V# @% C0 @5 s& s

8 y; l1 t# E5 g
4 v( R# y3 p0 P1 T# ]2 g
1 D. d3 ~1 j8 m4 M4 E
收藏 评论0 发布时间:2021-12-24 17:00

举报

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