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

【经验分享】STM32F7--->使用LTDC接口驱动RGBLCD,并使用DMA2D图形加速

[复制链接]
STMCU小助手 发布时间:2021-12-13 08:50
基础知识简介! Y2 `$ R' [% X7 a& \& `- ~
RGBLCD

  p( D% H' N( [. @- T1.RGBLCD的信号
2 X9 W$ L% R. l8 f$ Y
20210720093227878.png

9 \% y$ \' S. H( ?  \' h5 g& Z6 B8 h
一般的 RGB 屏有 24 根颜色数据线(RGB 各站 8 根,即RGB888 格式),这样可以表示最多 1600W 色,DE、VS、HS 和 DCLK,用于控制数据传输。
+ u' y5 D) C! q2 y; y
+ F3 ?% U: {, J% `2.RGBLCD驱动模式

3 _0 ^) f, w- y! T8 O其驱动模式主要分为两种
/ v  Q* |: N/ `  T6 I
, Z$ |2 d2 B* Y1 }# X0 j* J) I# _+ D, f* f      DE模式
7 G0 ^7 a' o$ ^9 O" c" \0 X      DE 模式使用 DE 信号来确定有效数据,DE 为高/低时,数据有效6 G* j6 C. \2 R* Z$ w9 p
      HV模式: i: D1 y! C  i: k, h- A; W
      HV模式需要行同步和列同步,来表示扫描的行和列, l  h7 j! I: l7 ^" k( C5 e" U$ m
: C1 b! D4 h% `* N0 N7 d
LTDC
! `3 y) V( K7 R$ f' }STM32F767xx 系列芯片都带有 TFT LCD 控制器,即 LTDC,通过这个 LTDC,STM32F767可以直接外接 RGBLCD 屏,实现液晶驱动。
2 R) {* q/ Y, d
3 }) }& I1 E1 R4 A  z1 x- M* }1.信号线
6 I5 F  L- h! zSTM32F767 核心板板载的 LCD 接口引出为了,节省 IO,并提高图片显示速度,使用 RGB565 颜色格式,这样只需要 16 个 IO 口,当使用 RGB565 格式的时候,LCD 面板的数据线,必须连接到 LTDC 数据线的 MSB  @7 m5 \; ?1 T* q4 p* z
* |! L5 K% l& s: w) z0 i& J( b
20210720100712790.png
  G, |- p5 n* o# h' }
" k0 f& S1 e. `" j
2.图像处理单元. ?. z0 o+ }- D( {
 先从 AHB 接口获取显存中的图像数据,然后经过层 FIFO(有 2 个,对应 2 个层)缓存,每个层 FIFO 具有 64*32 位存储深度,然后经过像素格式转换器(PFC),把从层的所选输入像素格式转换为 ARGB8888 格式,再通过混合单元,把两层数据合并,混合得到单层要显示的数据,最后经过抖动单元处理(可选)后,输出给 LCD 显示。
) p& E- Y+ f) ~7 ~3 A( I; K! s4 ] 混合单元首先将第一层与背景层进行混合,随后,第二层与第一层和第二层的混合颜色结果再次混合,完成混合后,送给 LCD显示。* _! I) r; {# M; L/ n$ N

, e8 U$ ^0 S0 M  N0 n5 c' F
20210720102457112.png

" q  K( U/ E5 H
! m, o5 p. P8 v3.AHB 接口
( \  ^% P* ~% \( [; M* b5 o 由于 LTDC 驱动 RGBLCD 的时候,需要有很多内存来做显存,比如一个 800480 的屏幕,按一般的 16 位 RGB565 模式,一个像素需要 2 个字节的内存,总共需要:800480*2=768K 字节内存,STM32 内部是没有这么多内存的,所以必须借助外部 SDRAM,而 SDRAM 是挂在AHB 总线上的,LTDC 的 AHB 接口,就是用来将显存数据,从 SDRAM 存储器传输到 FIFO 里面。
  I! p4 P5 `* c8 D0 @  Z: x2 e* a) U( Y
4.LTDC相关寄存器及使用方法

4 \* k' A* a1 H8 \. k- `9 uLTDC 的各种配置寄存器以及状态寄存器,用于控制整个 LTDC 的工作参数,6 a. L, p4 {* L) j
主要有:各信号的有效电平、垂直/水平同步时间参数、像素格式、数据使能等等。
! j- V/ B2 W6 U如果 RGBLCD 使用的是 DE 模式,需要设置如下参数,然后 LTDC会根据这些设置,自动控制 DE 信号。" F0 g: J5 s2 d

, l' o; T5 X; C) TLTCD全局控制寄存器 LTCD_GCR

  B  ?* m0 Q9 N$ v$ b/ {8 q  g8 z8 D% y7 ^! W% P
20210720104228854.png

5 X" H, F! M9 f1 S' a& W
6 F' L, S; z' Z  c, _6 ^. F
]V@HJS%I_Y[%1XLYT61%0@2.png

! I, B! N; R0 \' \8 o3 d" t
' `/ d: ~7 `; e9 Y5 h; N# _LTCD同步大小寄存器 LTDC_SSCR( X5 R% p9 c% U* q" X' D
该寄存器用于设置垂直同步高度(VSH)和水平同步宽度(HSW)
6 R5 w$ c+ [/ L$ D0 C! _
+ ~  N: T" C+ k5 ~! h% K
20210720104959506.png

; R4 f* w- h8 W* I8 d5 W  O
/ |+ s0 Q1 \6 I" @1 ~' X& z
0PRMT7%Y[QF2O{1W`AQ82~7.png

  F! R- I; W& Z& X
) f  Y8 W. E3 K' y) `) ?% [4 ]5 y4 \  S* n
LTDC有效宽度配置寄存器 LTDC_AWCR' S2 e, ^# o# |% g; |3 f, O) k
这里所说的有效高度和有效宽度,是指 LCD 面板的宽度和高度,构成分辨率
; w; J5 y3 _- n$ _+ a, a5 a3 w6 t$ d( R8 h; o' `
20210720110024135.png
) }* }8 H0 i6 ^5 v+ Z

0 y* u( i4 V" C
[AREI`HGZ@RRR{J@MJC8W]8.png
) Y$ s4 h' {8 \& V6 p
4 i. r- C$ Z& _4 J) Q+ Y4 p4 m  i- [
     6 J. @8 A1 z' a+ F; W$ Y: O
LTDC 总宽度配置寄存器 LTDC_TWCR
3 {2 w3 \8 Y7 L, _( f

' V9 C+ R4 S2 m, H
20210720110931326.png

7 i; s$ c( F! R" n" `6 h) ?$ W2 f! Y! {' k: R! {
O6G8SGZNHK4ZYO{)JN[]USW.png

  C: I' \9 G3 D5 b" B, b# O3 `3 L0 d$ u/ g
      
* ]. E  R* e% c5 h8 q* ~LTDC 背景色配置寄存器 LTDC_BCCR2 h6 E6 h( M3 I& V
该寄存器定义背景层的颜色(RGB888),通过低 24 位配置,我们一般设置为全 0 即可。8 o0 ^- H8 x7 r" \: ~
, K8 }1 [( L2 Q
7 t4 ^& u5 p, |/ B! v. Z
20210720111141846.png

1 ]+ y+ B' v2 x$ ^6 E8 V
& J' v6 K: I4 Q! b. G4 ?LTDC当前位置状态寄存器 LTDC_CPSR
+ N: o4 v. }* ]. n, i6 t& p/ [6 W; e5 o! Y8 A0 |
a3355e745c2c73657ef826bf1a8f42f5.png
+ c5 [* R6 R; ?. p$ \0 o
1 l  {5 f# t0 `* i6 _) E! V
CXPOS[31~16]:返回当前X坐标位置1 L2 Z& R9 E9 {" \+ ~: ~
CYPOS[15~0]:返回当前Y坐标位置& C% K0 U0 C- ^

2 E" C' i! e4 NLTDC当前显示状态寄存器 LTDC_CDSR
3 a2 j, R2 L2 \. u; Z& I此寄存器返回由 HSYNC、VSYNC 和水平/垂直 DE 信号控制的当前显示阶段的状态
  H! s) v* Z+ S, ~( D- M0 A5 R% [( X  t. c5 S; }- W& Z6 z
c1e72a8f7ff1155cd5391d05ba83e42d.png

3 g. I3 r4 [0 w, Z2 L/ u
. H- e$ t4 L" B, w* Q位 31:24 保留,必须保持复位值
  z! F4 x9 j# Y& o: t- z6 Z$ u) V位 3 HSYNCS:水平同步显示状态 (Horizontal Synchronization display Status); G, H3 L. n2 z4 b: c
0:低电平有效7 z5 K  _2 G3 u
1:高电平有效: R# o. S2 L6 f* ]* o3 S
位 2 VSYNCS:垂直同步显示状态 (Vertical Synchronization display Status)
1 r* ^, y/ N+ e$ Q: D0:低电平有效& K, w0 X* I; _; Q' k
1:高电平有效* v. r' u: z7 l0 W/ Z! c4 i! n
位 1 HDES:水平数据使能显示状态 (Horizontal Data Enable display Status)
" s4 U( J; n3 G7 B0:低电平有效0 s2 w0 n7 ^9 e' G7 w
1:高电平有效# k& l( k: \3 w' ?, A
位 0 VDES:垂直数据使能显示状态 (Vertical Data Enable display Status)
$ {1 \5 {; \( U0:低电平有效% ?, ^4 L2 D  @- S& T! R5 I. _) a8 m
1:高电平有效+ R+ |" O! v9 I- p' Z3 u

& y- F, X7 M9 Y2 ~: a( WLTDC 的层颜色帧缓冲区地址寄存器 LTDC_LxCFBAR(x=1/2)
+ Y% e/ T7 g2 c- Z4 V该寄存器用来定义一层显存的起始地址。STM32F767 的 LTDC 支持 2 个层,所以总共有两个寄存器,分别设置层 1 和层 2 的显存起始地址。8 y) Y0 [1 k9 A7 s. e1 i

8 @/ N& x# g1 I6 d& t# {' x
20210720111336311.png
) n1 X/ j" O; r* L

/ K# k* `9 a5 I% @9 @" k) eLTDC 的层像素格式配置寄存器 LTDC_LxPFCR(x=1/2)
6 h8 V6 m- U# B2 p, I. a- E该寄存器只有最低 3 位有效,用于设置层颜色的像素格式,一般使用 RGB565 格式,即该寄存器设置为:010 即可。
1 }. x. A1 p( r- t: i+ J: [% m: T
STQ}OUE_D7Z(33OZ_E@73.png

  d3 c0 l; E$ y4 n/ H( C
4 z+ \8 |# q* ]# i; P
) P+ T' d0 B4 _0 L1 ]0 y1 \2 b      
( R* s& P5 ^, M; ~LTDC 的层恒定 Alpha 配置寄存器 LTDC_LxCACR(x=1/2)! R* y5 n( X) I6 _0 X: u
该寄存器低 8 位(CONSTA)有效,这些位配置混合时使用的恒定 Alpha。恒定 Alpha 由硬件实现 255 分频。' d+ N9 A( t: U8 X+ s9 ?

: e3 H: ]/ \1 P) C+ o
20210720112235516.png

1 p4 G. |* ?; E9 O; o  P8 i
2 a+ \, E* }4 FLTDC 的层默认颜色配置寄存器 LTDC_LxDCCR(x=1/2)
/ m3 n' I5 g5 D0 L+ C1 a
该寄存器定义采用 ARGB8888 格式的层的默认颜色。默认颜色在定义的层窗口外使用或在层禁止时使用。一般情况下,用不到,所以该寄存器一般设置为 0 即可。3 E5 a- a* x5 |" K+ U7 B

+ |$ E9 o6 @0 ~) M4 D! v+ V
20210720112604555.png
0 Z+ S+ k0 v/ g7 k: A4 p, ^# b
" ?9 A( ?1 c4 o
LTDC 层混合系数配置寄存器:LTDC_LxBFCR(x=1/2); T; U  m4 d1 f& @+ j3 i
该寄存器用于定义混合系数:BF1 和 BF2。BF1=100 的时候,使用恒定的 Alpha 混合系数(由LTDC_LxCACR寄存器设置恒定Alpha值),BF1=110的时候,使用像素Alpha恒定Alpha。像素 Alpha 即 ARGB 格式像素的 A 值(Alpha 值),仅限 ARGB 颜色格式时使用。在 RGB565格式下,我们设置 BF1=100 即可。BF2 同 BF1 类似,BF2=101 的时候,使用恒定的 Alpha 混合系数,BF2=111 的时候,使用像素 Alpha恒定 Alpha。在 RGB565 格式下,我们设置 BF2=101即可。- a( `+ ?3 i9 ?6 E
通用的混合公式为:BC=BF1C+BF2Cs
4 v# g* c" O% c2 R7 U/ o其中:BC=混合后的颜色;BF1=混合系数 1;C=当前层颜色,即我们写入层显存的颜色值;BF2=混合系数 2;Cs=底层混合后的颜色,对于层 1 来说,Cs=背景层的颜色,对于层 2 来说,Cs=背景层和层 1 混合后的颜色。
# J( l. g$ q8 Q7 X# J  |/ Y2 Q$ n8 A0 C5 v# J( d; h
2021072011293763.png

3 N* f7 J' X2 C7 F! G! d/ z0 V6 u. }1 m/ ^
LTDC 的层窗口水平位置配置寄存器 LTDC_LxWHPCR(x=1/2)
5 V4 F  h9 `; b- o
该寄存器定义第 1 层或第 2 层窗口的水平位置,第一个和最后一个像素
+ m. V8 q4 d4 b7 ?
& X! V/ g9 V! O* |
20210720113448290.png

/ S1 R( Y) g3 k7 A$ |( a% q) A* U2 ^2 k6 c( K% m
WHSTPOS:窗口水平起始位置,定义层窗口的一行的第一个可见像素,
# j8 n/ Y7 L' k4 IWHSPPOS:窗口水平停止位置,定义层窗口的一行的最后一个可见像素% F; w# C2 Y- {2 x; L

; ~" e6 ]4 E. n$ I% tLTDC 的层窗口垂直位置配置寄存器 LTDC_LxWVPCR(x=1/2)
- v7 a2 f& p% M/ E9 Y9 V$ M
该寄存器定义第 1 层或第 2 层窗口的垂直位置(第一行或最后一行)5 s# J8 n) q7 }% u( h& {
' m) _) S- c- r2 Y0 L& o% K
20210720133247145.png
; g- M% [9 s8 C2 P8 ?7 L' r

7 s/ L" E: O6 h" r- O/ R0 E# ]WVSTPOS:窗口垂直起始位置,定义层窗口的第一个可见行。3 U7 G. L6 A$ p
WVSPPOS:窗口垂直停止位置,定义层窗口的最后一个可见行。9 X5 }8 i3 s8 D0 Y" |* n( I3 P0 r
$ I& w# r. l. y& s2 y
LTDC 的层颜色帧缓冲区长度寄存器 LTDC_LxCFBLR(x=1/2)
) T' }: ~+ K7 m7 Y+ a& c该寄存器定义颜色帧缓冲区的行长和行间距。# P/ r9 |4 ^( M4 S( ^  C5 t

# c0 n+ T) \4 E
20210720133802157.png
' [' \7 Z9 [8 h' [3 [0 I. d
; M: j$ z- O" z1 Z9 O2 [6 _
CFBLL:这些位定义一行像素的长度(以字节为单位)+3。
8 }1 ]/ P4 n/ j/ `1 ~) A行长的计算方法为:有效宽度 * 每像素的字节数 + 3。# }: W$ M; E4 ^" Y7 o% J0 t
比如,LCD 面板的分辨率为 800480,有效宽度为 800,采用 RGB565 格式,那么 CFBLL 需要设置为:8002+3=1603。- s3 j. i8 M+ t% x. u
CFBP:这些位定义从像素某行的起始处到下一行的起始处的增量(以字节为单位)。) M' P9 v; {1 f/ k
这个设置,其实同样是一行像素的长度,对于 800480 的 LCD 面板,RGB565 格式,设置 CFBP 为:8002=1600 即可。
  U% U& {' M+ v- J/ I, P/ L2 U- m! d  }* @  h
LTDC 的层颜色帧缓冲区行数寄存器 LTDC_LxCFBLNR(x=1/2)
. N8 Y. R6 `: t. j1 `- e3 E该寄存器定义颜色帧缓冲区中的行数。
) p1 M5 o3 z; p, y, P/ q6 g1 i# J比如,LCD 面板的分辨率为 800*480,那么帧缓冲区的行数为 480 行,则设置 CFBLNBR=480 即可& Z: l# [( K" y& j4 f9 j6 s8 c
( {8 f; B9 t: E  e" a
20210720133424485.png
* B- ?* j% d$ \- l1 B+ k
# d5 a. c# |  ?1 y9 n% @
5.时钟域$ q" ?6 g( z" V$ ^# K
LTDC 有三个时钟域:AHB 时钟域(HCLK)、APB2 时钟域(PCLK2)和像素时钟域(LCD_CLK),8 u- x! H5 D; @/ p/ H; W& I/ O# k
AHB 时钟域用于驱动 AHB 接口,读取存储器的数据到 FIFO 里面;. ~* b8 z4 [+ D- E& Q
APB2 时钟域用于配置寄存器;
: y% A# G; ^$ p0 }! q' _LCD_CLK像素时钟域则用于生成 LCD 接口信号,LCD_CLK 的输出应按照 LCD 面板要求进行配置。$ v% L' r0 y* \7 B& e' H

  {4 y/ l" j9 C0 Z  PDMA2D7 S7 {) N% }6 R( H) _2 M9 T
为了提高STM32F767的图像处理能力,ST公司设计了一个专用于图像处理的专业 DMA,通过 DMA2D 对图像进行填充和搬运,可以完全不用CPU 干预,从而提高效率,减轻 CPU 负担。1 r3 J5 h. |6 V. k, @' \% I
! z& X# b5 f3 z4 A4 C9 j
它可以执行下列操作:% A" w! A# S" c9 n
用特定颜色填充目标图像的一部分或全部(可用于快速单色填充)
( H; k4 @: K: v( b" a& s3 J将源图像的一部分(或全部)复制到目标图像的一部分(或全部)中(可用于快速图像填充)
( ~/ r4 C1 X# i' V通过像素格式转换将源图像的一部分(或全部)复制到目标图像的一部分(或全部)中( v, B" f, b$ _2 U6 K
将像素格式不同的两个源图像部分和/ 或全部混合,再将结果复制到颜色格式不同的部分或整个目标图像中, Z5 f% g& i; a& O% A: \9 v" j& Z
- w1 A) D' ?7 V1 ]7 K( w
3 w2 z  p' E& w# K7 L2 z) a( e
DMA2D 有四种工作模式,通过 DMA2D_CR 寄存器的 MODE[1:0]位选择工作模式:
# U- z9 S! g* s6 O2 J. r& c1, 寄存器到存储器6 u$ Z8 o) c; B7 L; v. ]
2, 存储器到存储器
0 ~8 X8 |6 U$ E" I8 H) u2 ^, A: V3, 存储器到存储器并执行 PFC
7 ^2 {( k8 L# b. P4, 存储器到存储器并执行 PFC 和混合2 i* g3 Y8 u' X, p
  L5 ^" l; z3 n, d# P3 n* I
% g5 h9 |- H* W. H% N0 C) w5 P
寄存器到储存器
2 C3 X5 ?+ C0 T) g# U寄存器到存储器模式用于以预定义颜色填充用户自定义区域,也就是可以实现快速的单色
; t: w) _9 B2 e+ ^! Z填充显示,比如清屏操作。7 E+ f& J1 q" q: _; j
在该模式下:颜色格式在 DMA2D_OPFCCR 中设置,DMA2D 不从任何源获取数据,它只  P- S' e7 o$ T: [/ ?5 K0 P7 @
是将 DMA2D_OCOLR 寄存器中定义的颜色写入通过 DMA2D_OMA 寻址以及 DMA2D_NLR 和1 h) r; o0 D: o4 C! w" M% U
DMA2D_OOR 定义的区域
/ r# G" w2 y' ]  z! A# v
' Z& N; ?  r" K! R* M8 {
. l& N% [% m) _; Y. Q储存器到储存器
0 B1 t6 X3 c, Y) e2 f( O该模式下,DMA2D 不执行任何图形数据转换。前景层输入 FIFO 充当缓冲区,数据从; ~4 K  @. }" ~) L
DMA2D_FGMAR 中定义的源存储单元传输到 DMA2D_OMAR 寻址的目标存储单元,可用于快4 Z3 n6 v5 L  s; _* \* e9 u& s- i- Y
速图像填充。DMA2D_FGPFCCR 寄存器的 CM[3:0]位中编程的颜色模式决定输入和输出的每像$ \2 U5 H9 p$ |; J, ~
素位数。对于要传输的区域大小,源区域大小由 DMA2D_NLR 和 DMA2D_FGOR 寄存器定义,
2 F: a" q& R$ \/ V, c9 q目标区域大小则由 DMA2D_NLR 和 DMA2D_OOR 寄存器定义。8 N) z) ]. }. A6 T
" ]& @/ n) ?( R* E) D

0 n* G5 w4 ?7 e$ r8 [/ T! q- S4 v以上两个工作模式,LTDC 在层帧缓存里面的开窗关系都一样的,经过如下三个寄存器的配置,就可以确定窗口的显示位置和大小。
5 \9 M! C9 d( C3 k0 B(1). 窗口显示区域的显存首地址由 DMA2D_OMAR 寄存器指定,; a9 o, [7 ~+ Y6 u$ |% H
(2).窗口宽度和高度由DMA2D_NRL 寄存器的 PL 和 NL 指定
( W  q( U8 K- G# |& Y(3).行偏移(确定下一行的起始地址)由 DMA2D_OOR寄存器指定,' U( t8 P4 }: C/ _$ b/ f5 a

. x( E  b- i3 V& {7 w% U. c
20210720170136697.png
8 H; _8 q( ^1 `. t0 D1 e6 f+ V5 i

7 a1 v3 \1 N* R, S3 R7 i) c% s1 H( E' x0 X( A
在寄存器到存储器模式下,在开窗完成后,DMA2D 可以将 DMA2D_OCOLR 指定的颜色,
) W' V8 l- c7 g9 b# W1 s/ p5 V自动填充到开窗区域,完成单色填充。( q8 m/ X1 |4 K8 ?: [

4 o* Z0 p# u- _" e# R6 ~& p+ _& N2 S1 ^5 x# B  N" I. s
在存储器到存储器模式下,需要完成两个开窗:前景层和显示层,完成配置后,图像数据从前景层拷贝到显示层(仅限窗口范围内),从而显示到 LCD 上面。显示层的开窗如上图所示,前景层也和上图类似,只是 DMA2D_OMAR 寄存器变成了DMA2D_FGMAR,DMA2D_OOR寄存器变成了DMA2D_FGOR,DMA2D_NRL则两个层共用,然后就可以完成对前景层的开窗,确定好两个窗口后,DMA2D 就将前景层窗口内的数据,拷贝到显示层窗口,完成快速图像填充。
2 b5 ?7 y8 g/ b' U
0 ^4 W8 I1 r9 X, P6 U! {# v" V! W; p6 z
DMA2D相关寄存器  y  l. X! p; N. \) o* h. s) J. }
DMA2D控制寄存器 DMA2D_CR+ j2 I  w9 `! P! d  L2 c* u' Z
该寄存器,主要是MODE 和 START 这两个设置2 I6 O4 c3 F' y2 U* X  r

9 t+ c# K4 V* d( p  h
20210720172154901.png
8 ^, t* e4 ~; Q# G: k- K( a
+ D. {# ^% v0 }# ]+ w- `5 Q/ y
MODE:表示 DMA2D 的工作模式,; ?5 G! {; }9 u  Y
00:存储器到存储器模式;01:存储器到存储器模式并执行 PFC;# [; s$ Z" y0 r
10:存储器到存储器并执行混合;11,寄存器到存储器模式;' Z$ U/ V/ i: Y8 j% s: H
START:该位控制 DMA2D 的启动,在配置完成后,设置该位为 1,启动 DMA2D 传输。
1 y4 {( U6 ^4 B* J$ B: ~4 p) Q( e1 u' T  D* o* O$ ]2 j; C" m
DMA2D输出 PFC 控制寄存器 DMA2D_OPFCCR
% ?* ?. r4 [% f' z% V该寄存器用于设置寄存器到存储器模式下的颜色格式: k' F7 C+ ~6 c, L! e9 K3 F

2 O4 G; K7 z+ `6 p" T6 P  K
20210720172538112.png
# @# {* P2 r% d: _# ^3 l
2 L. A" b+ |2 o9 e8 |  B, \9 Y9 R- F5 v
只有最低 3 位有效(CM[2:0]),表示的颜色格式有:8 a" P( J3 |* y/ l5 Z
000,ARGB8888;001:RGB888;010:RGB565;
' q0 E2 z; B$ l% f0 w* d011:ARGB1555;100:ARGB1444。
) Z/ a! M" `7 Z我们一般使用的是 RGB565 格式,所以设置 CM[2:0]=010 即可。
+ |# T1 n$ p" @1 h( M
' M  ^8 H7 h, Z5 MDMA2D前景层 PFC 控制寄存器:DMA2D_FGPFCCR
! M$ {0 q4 y1 Z7 e
( A) i# T' ]+ \# ^/ a
20210720173213773.png

) w% p" K5 a: L" C( S7 Z6 F# d0 p6 v2 _- z( ^; R
该寄存器,低 4 位:CM[3:0],用于设置存储器到存储器模式下的颜色格式,这四个位表示的颜色格式为:6 ~( P+ f; e5 L8 q2 Z2 V. R
0000:ARGB8888;0001:RGB888;0010:RGB565;2 _: Q# G* \! C" n! A4 ^  Q
0011:ARGB1555;0100:ARGB4444;0101:L8;
: D6 ^& c( W6 o& I  Q; s9 U0110:AL44;0111:AL88;1000:L4;1001:A8;1010:A4;9 L9 {$ G5 E4 Z  p- Z; Y( ?( J
我们一般使用 RGB565 格式,所以设置 CM[3:0]=0010 即可。
! }4 l" D. Q6 F: U
! D$ S/ r& ^# c0 c# S9 m0 ]4 @DMA2D输出偏移寄存器 DMA2D_OOR1 b4 Z5 U( D9 b' C6 T

' t0 a. R8 v, C+ L
20210720174740982.png
/ \) u3 t' c% m3 h
该寄存器仅最低 14 位有效(LO[13:0]),用于设置输出行偏移,作用于显示层,以像素为" j6 a7 i( @- c3 q) K. l
单位表示。此值用于生成地址。行偏移将添加到各行末尾,用于确定下一行的起始地址。3 q& D5 g( G$ S
同样的,还有前景层偏移寄存器:DMA2D_FGOR,该寄存器同 DMA2D_OOR 一样,也是
- z, \' L3 Y+ W3 D低 14 位有效,用于控制前景层的行偏移,也是用于生成地址,添加到各行末尾,从而确定下一: G4 e; F% l! L
行的起始地址。
% m7 A" R) g" J4 N8 J0 T9 m; e9 p. a0 M/ I4 Y7 u1 L0 ?& X
DMA2D输出存储器地址寄存器 DMA2D_OMAR6 R, ?: ~3 K" a
! O8 Z1 u  I# f
20210720175051288.png

! }/ g: a9 Q! s8 O7 }2 R2 y* C: W6 c. f( U6 l
该寄存器设置由 MA[31:0]设置输出存储器地址,也就是输出 FIFO 所存储的数据地址,该地址需要根据开窗的起始坐标来进行设置。以 800480 的 LCD 屏为例,行长度为 800 像素,假定帧缓存数组为:ltdc_framebuf,我们设置窗口的起始地址为:sx(<800),sy(<480),颜色格式为 RGB565,每个像素 2 个字节,那么 MA 的设置值应该为:% @' ~0 q/ y: Q+ ^5 V$ u8 z
*MA[31:0]= framebuf+2(800sy+sx)**; {5 ?  D. }* B
同样的,还有前景层偏移寄存器:DMA2D_ FGMAR,该寄存器同 DMA2D_OMAR 一样,
9 Z9 Z& r  @1 L5 K不过是用于控制前景层的存储器地址,计算方法同 DMA2D_OMAR。
, q7 m  d: z" T) o4 M
4 U6 g5 ~( p4 s  O1 p3 l1 EDMA2D行数寄存器 DMA2D_NLR7 T6 }# E! k4 B9 Z/ n# O# h/ K/ P

* O. d! I( e( B  J; l% x0 t
20210720180044872.png

) ^. V! w2 B# P) D9 v4 n该寄存器用于控制每行的像素和行数,该寄存器的设置对前景层和显示层均有效,通过该寄存器的配置,就可以设置开窗的大小。其中:) G& W* S6 _% L' y0 V/ l( C/ F
NL[15: 0]:设置待传输区域的行数,用于确定窗口的高度。
7 ?" y3 {! O, f* A9 _. P' XPL[13: 0]:设置待传输区域的每行像素数,用于确定窗口的宽度; P6 F& ?) e# R( K" B
6 t! n) u9 f+ e
DMA2D输出颜色寄存器 DMA2D_OCOLR
1 k' I* ]+ |4 x% u& z' L& B
2 K, m+ _9 C0 y5 Q& v7 I
20210720180520678.png

4 G. V( D2 r( U+ s该寄存器用于配置在寄存器到存储器模式下,填充时所用的颜色值,该寄存器是一个 32位寄存器,可以支持 ARGB8888 格式,也可以支持 RGB565 格式。我们一般使用 RGB565 格式,比如要填充红色,那么直接设置 DMA2D_OCOLR=0XF800 就可以了。3 j2 {5 R: V$ a+ S9 V# |3 a! W
, ]! s( s/ w/ a6 \% D
DMA2D中断状态寄存器 DMA2D_ISR
- t& x7 O/ l; j. L. g4 N3 o
, C7 Z* v, x5 S' G& O2 }7 S( B4 V4 r
2021072018063162.png
8 k- f. @! v, {3 z
$ i) I2 }# @1 v9 ]
该寄存器表示了 DMA2D 的各种状态标识1 D( z$ [- S4 T" d6 d  N
TCIF 位,表示 DMA2D 的传输完成中断标志。当 DMA2D 传输操作完成(仅限数据传输)时此位置 1,表示可以开始下一次 DMA2D 传输了
0 C3 j1 \  X# h4 Y* |DMA2D 中断标志清零寄存器:DMA2D_IFCR,用于清除 DMA2D_ISR 寄存器对应位的标志。通过向该寄存器的第 1 位(CTCIF)写 1,可以用于清除 DMA2D_ISR 寄存器的 TCIF 位标志。
, n7 {: _3 g3 M4 [9 c, D# x" k+ V
- F0 C8 F' X1 H- s
! s7 P3 m, s3 n$ \7 DLTDC具体使用步骤
; ]/ h* `' z- H% w  r: O. J+ g" b  K1.使能 LTDC 时钟,并配置 LTDC 相关的 IO 及其时钟使能。# K) L3 ?# ?/ h) J. v9 {; T( j
使用 LTDC,当然首先得开启其时钟。6 G5 T$ v0 i4 H/ u; H7 q
然后需要把 LCD_R/G/B 数据线、LCD_HSYNC和 LCD_VSYNC 等相关 IO 口,全部配置为复用输出,并使能各 IO 组的时钟。
: P* v  C) F0 s4 ]$ T3 A7 ?$ n* W. ~- C" V
  1. //LTDC底层IO初始化和时钟使能
    4 [( f: i: B  n3 t2 n
  2. //此函数会被HAL_LTDC_Init()调用
    ' y8 Y3 b  T1 b0 f0 P' D9 u
  3. //hltdc:LTDC句柄
    / A1 @, R+ J- S
  4. void HAL_LTDC_MspInit(LTDC_HandleTypeDef* hltdc)
    0 w  O0 G) U4 g2 [
  5. {
    0 \/ B. \+ j1 ]: j6 e
  6.     GPIO_InitTypeDef GPIO_Initure;1 _8 l& K5 M  E4 k0 Q
  7. ! ~: Q+ B# P2 S1 E2 S3 E5 F% E: _
  8.     __HAL_RCC_LTDC_CLK_ENABLE();                //使能LTDC时钟. w5 v6 S& J+ Z7 D1 z& O* c
  9.     __HAL_RCC_DMA2D_CLK_ENABLE();               //使能DMA2D时钟
    " [4 A" {8 ^) ~+ l* \+ Z, }7 b8 e
  10.     __HAL_RCC_GPIOB_CLK_ENABLE();               //使能GPIOB时钟
    $ L, G0 g/ n" f- G5 v
  11.     __HAL_RCC_GPIOF_CLK_ENABLE();               //使能GPIOF时钟1 w  }/ I3 ^& c* I& i
  12.     __HAL_RCC_GPIOG_CLK_ENABLE();               //使能GPIOG时钟
    , g4 C, T- n; V  ^) e* B5 q" ~3 {
  13.     __HAL_RCC_GPIOH_CLK_ENABLE();               //使能GPIOH时钟
    # f+ X8 _2 W# @* G/ O0 D0 I
  14.     __HAL_RCC_GPIOI_CLK_ENABLE();               //使能GPIOI时钟5 {5 Q% G9 b2 U8 R
  15. , B) |2 G4 I, V+ ~
  16.     //初始化PB5,背光引脚, I: a1 G3 M! X7 M( a9 y
  17.     GPIO_Initure.Pin=GPIO_PIN_5;                //PB5推挽输出,控制背光5 r: j- c1 n) _
  18.     GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;      //推挽输出5 c' \7 \+ T% _9 h5 s. y
  19.     GPIO_Initure.Pull=GPIO_PULLUP;              //上拉
    9 u, e& }2 M3 Z$ S
  20.     GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速
    & `3 k1 J5 R7 M, c9 p! ]
  21.     HAL_GPIO_Init(GPIOB,&GPIO_Initure);  w8 h/ |) p5 z5 J

  22.   z7 c8 ?3 U6 \
  23.     //初始化PF10
    : s: M: D1 F3 N+ F( W$ o2 [# ~
  24.     GPIO_Initure.Pin=GPIO_PIN_10; ( z  D" r9 |5 C' K5 {) m
  25.     GPIO_Initure.Mode=GPIO_MODE_AF_PP;          //复用. c3 ?1 M/ Q% i
  26.     GPIO_Initure.Pull=GPIO_NOPULL;
    ' x, Z, H5 ^) N3 b3 W6 b+ [% O( ^
  27.     GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速
    2 W, z- V3 e  i% o  I- l
  28.     GPIO_Initure.Alternate=GPIO_AF14_LTDC;      //复用为LTDC  H9 t8 N0 S2 L1 |9 p( M
  29.     HAL_GPIO_Init(GPIOF,&GPIO_Initure);
    * R6 [5 z: O/ `9 c" V
  30. 7 k1 t5 r+ f9 S, q$ H
  31.     //初始化PG6,7,11
    % T& X  I- f8 i
  32.     GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_11;
    , d; h$ W' `7 [/ H/ ]# X$ p2 A
  33.     HAL_GPIO_Init(GPIOG,&GPIO_Initure);
    1 g  \- v, A$ A& @; b
  34. " Z3 T$ ]7 P. Y7 w. }) Y
  35.     //初始化PH9,10,11,12,13,14,15' S5 q% N3 m( R4 ?4 A, Z" l/ O
  36.     GPIO_Initure.Pin=GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|\
    7 Q* `; X# _0 f: M$ N- f
  37.                      GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
    * I. h7 c$ N% L
  38.     HAL_GPIO_Init(GPIOH,&GPIO_Initure);) D& V2 j  h" q( w8 @4 Q, l1 ^

  39. 1 `) B6 x" i2 I2 N" M4 w* y8 |
  40.     //初始化PI0,1,2,4,5,6,7,9,105 E4 L2 A( O* U* N) `: l
  41.     GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|\
    9 V* P1 X6 \$ q( d# q
  42.                      GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_9|GPIO_PIN_10;8 R2 e8 a# y, z
  43.     HAL_GPIO_Init(GPIOI,&GPIO_Initure); 3 h3 A4 e' o" [# u% z6 r
  44. }
复制代码

, H' p5 a& H5 H* W" Y- T2.设置LCD_CLK时钟4 ?' R! P" ]7 X' n* N
配置 LCD 的像素时钟,根据 LCD 的面板参数进行设置,LCD_CLK 由 PLLSAI进行配置,配置使用到的 HAL 库函数为:
& o% C5 p7 c2 r5 T2 o0 i& Q3 U2 v( h  h/ E/ l0 o! n, C
  1.         //pllsain:SAI时钟倍频系数N,取值范围:50~432.  5 c& ?* n  `, k( C# t6 E7 ~
  2.         //pllsair:SAI时钟的分频系数R,取值范围:2~70 ]! |2 \# l( V( @7 ]# j/ v0 @1 r  g
  3.         //pllsaidivr:LCD时钟分频系数,取值范围:0~3,对应分频2~16 / D2 b6 J/ ]4 ^" ~
  4.         //假设:外部晶振为25M,pllm=25的时候,Fin=1Mhz.% X4 b0 A4 r0 O, \" Z
  5.         //例如:要得到20M的LTDC时钟,则可以设置:pllsain=400,pllsair=5,pllsaidivr=1
    - w# _6 x: ~- |
  6.         //Fdclk=1*396/3/2*2^1=396/12=33Mhz0 g' B7 e, h. ]% k7 x: \9 o8 f- @: r
  7.     RCC_PeriphCLKInitTypeDef PeriphClkIniture;1 W# D; n# K, }8 W
  8. 9 N/ T3 A" i7 J' N/ }1 s  r  ~+ ~! P+ v- `2 Y
  9.     //LTDC输出像素时钟,需要根据自己所使用的LCD数据手册来配置!
      U9 m( j$ r* l% O/ t) S# z, b
  10.     PeriphClkIniture.PeriphClockSelection=RCC_PERIPHCLK_LTDC;       //LTDC时钟/ H% P( a7 ~+ ?3 A, C' L4 Q$ K6 ]
  11.     PeriphClkIniture.PLLSAI.PLLSAIN=pllsain;
    5 z0 Q+ c3 [; q6 ?1 ~
  12.     PeriphClkIniture.PLLSAI.PLLSAIR=pllsair;
    8 W3 w' X" g3 ]+ V7 A( H
  13.     PeriphClkIniture.PLLSAIDivR=pllsaidivr;" s* U. y; E7 L; y5 S. y
  14.         HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef *PeriphClkInit)
复制代码

9 }7 j- s' M" \7 v5 o3.设置RGBLCD相关参数,并使能LTDC
2 E. f4 V+ k; ], M- A& Q
  1. typedef struct7 S* l/ N* P( ~" Q+ s
  2. {$ ~/ T, x: C9 k! G$ g
  3. uint32_t HSPolarity;                         //水平同步极性& u# T" D* [" m) R! j
  4. uint32_t VSPolarity;                         //垂直同步极性 3 `( z0 R7 @: z
  5. uint32_t DEPolarity;                         //数据使能极性% W, `0 c/ O- @- w/ e/ P8 \
  6. uint32_t PCPolarity;                         //像素时钟极性9 p! R/ r1 ^; [$ @$ l
  7. uint32_t HorizontalSync;                 //水平同步宽度
    " Y+ F1 ?7 y4 l, Y, n8 B- W
  8. uint32_t VerticalSync;                 //垂直同步高度
    # ]3 I4 y7 B6 s8 S
  9. uint32_t AccumulatedHBP;                 //水平同步后沿宽度' ]6 |$ I) o9 p6 y
  10. uint32_t AccumulatedVBP;                 //垂直同步后沿高度 , `' _, v+ j* \, i! a+ X1 u( u
  11. uint32_t AccumulatedActiveW;         //累加有效宽度
    & X; k5 p+ `8 c3 J6 M, H  f5 K
  12. uint32_t AccumulatedActiveH;         //累加有效高度% ^3 J  x  B) H- ]  g. j; q
  13. uint32_t TotalWidth;                         //总宽度2 r: F9 p* y4 X& L3 \7 q
  14. uint32_t TotalHeigh;                         //总高度# U* N2 l% c4 _5 Z% {( e( \
  15. LTDC_ColorTypeDef Backcolor;         //屏幕背景层颜色 ( ]2 h0 F9 Y4 f+ I( q5 y& c1 w
  16. } LTDC_InitTypeDef;8 d) v% \+ o- @
  17. + R. c" \, l" O' u* Y. F
  18. typedef struct/ c7 c' g9 ?: q" {, W8 z# D
  19. {
    7 l* t; O5 A+ m8 S2 O4 L( ], `
  20.   LTDC_TypeDef                *Instance;                /*Instance变量是LTDC_TypeDef结构体指针类型*/' A: Q$ _% k, f/ k$ Q- u
  21.   LTDC_InitTypeDef            Init;                     /*用来初始化LTDC的结构体变量*/
    9 M1 s) {4 w/ y4 l1 [$ g% _
  22.   LTDC_LayerCfgTypeDef        LayerCfg[MAX_LAYER];      /*保存LTDC层配置参数*/4 J- {+ M5 Y* U! r* \: A+ m
  23.   HAL_LockTypeDef             Lock;                     /*锁状态*/
    + N: r, W; J8 k0 ~9 F; }
  24.   __IO HAL_LTDC_StateTypeDef  State;                    /*LTDC的状态*/4 N$ [6 `: m0 T  f; g# H
  25.   __IO uint32_t               ErrorCode;                /*错误处理*/; R0 [3 v- B7 U$ f' L! S) [
  26. } LTDC_HandleTypeDef;* k3 F+ f+ }7 y' Y1 k: k' \
  27. $ o- L8 [" v/ ^
  28. LTDC_HandleTypeDef  LTDC_Handler;                                   //LTDC句柄( g# k& ?) g, m
  29. 2 A# L  `2 ~  D
  30. LTDC_Handler.Instance=LTDC;
    / b2 R* y2 `7 N0 d
  31. LTDC_Handler.Init.HSPolarity=LTDC_HSPOLARITY_AL;                 //水平同步极性( p6 n: W1 Z8 @9 W
  32. LTDC_Handler.Init.VSPolarity=LTDC_VSPOLARITY_AL;                 //垂直同步极性+ F7 G/ m# P. r6 D2 J) _+ X- n$ T
  33. LTDC_Handler.Init.DEPolarity=LTDC_DEPOLARITY_AL;                 //数据使能极性- ]- N; S- `+ b% j
  34. LTDC_Handler.Init.PCPolarity=LTDC_PCPOLARITY_IPC;                 //像素时钟极性" I. Y! n4 W" k2 o3 f
  35. LTDC_Handler.Init.HorizontalSync=10-1;                                         //水平同步宽度
    # i2 q& F8 e; _  c- {! k" q% J
  36. LTDC_Handler.Init.VerticalSync=2-1;                                         //垂直同步宽度
    $ ^& A$ G6 O& P7 j6 |8 U$ [
  37. LTDC_Handler.Init.AccumulatedHBP=10+20-1;                                 //水平同步后沿宽度$ c3 k# w) K9 W
  38. LTDC_Handler.Init.AccumulatedVBP=2+2-1;                                 //垂直同步后沿高度
    ! l9 z; g& X2 l2 k$ J7 _
  39. LTDC_Handler.Init.AccumulatedActiveW=10+20+480-1;                 //有效宽度; s$ D6 L$ C; T6 o- k( K" V, B, L
  40. LTDC_Handler.Init.AccumulatedActiveH=2+2+272-1;                 //有效高度: M% y# ~6 R* j
  41. LTDC_Handler.Init.TotalWidth=10+20+480+10-1;                         //总宽度6 {: X# k# f6 h! @( g, t
  42. LTDC_Handler.Init.TotalHeigh=2+2+272+4-1;                                 //总高度. A: ^9 J) x  e' O+ q9 S
  43. LTDC_Handler.Init.Backcolor.Red=0;                                                 //屏幕背景层红色部分/ A6 t* y' J/ R; C+ _0 T+ Z
  44. LTDC_Handler.Init.Backcolor.Green=0;                                         //屏幕背景层绿色部分: z3 ~, i/ S! ?* g
  45. LTDC_Handler.Init.Backcolor.Blue=0;                                         //屏幕背景色蓝色部分
    9 N6 ^0 S1 }/ M6 {, Y) _  c
  46. HAL_LTDC_Init(<DC_Handler);                                                         //设置 RGBLCD 的相关参数,并使能 LTDC,会调用HAL_LTDC_MspInit
复制代码

, P, x5 ~/ k0 D9 Z9 k: a+ Q4.设置 LTDC层参数
4 A% ~& l+ S- ]+ z+ {* z  S
  1. //layerx:层值,0/1.
    ' j, z% n2 m8 w( r6 J7 G8 C1 T5 d
  2. //bufaddr:层颜色帧缓存起始地址
    % S7 u5 v8 `, N9 s" D6 ~/ O
  3. //pixformat:颜色格式.0,ARGB8888;1,RGB888;2,RGB565;3,ARGB1555;4,ARGB4444;5,L8;6;AL44;7;AL88+ l. G- t( D  O% ~$ w+ e$ X
  4. //alpha:层颜色Alpha值,0,全透明;255,不透明
    8 b2 o/ |2 f; E9 A' Y
  5. //alpha0:默认颜色Alpha值,0,全透明;255,不透明
    5 a2 `" b+ x6 `2 `
  6. //bfac1:混合系数1,4(100),恒定的Alpha;6(101),像素Alpha*恒定Alpha
    . i6 T* s* X# N. t! |0 s2 t6 q
  7. //bfac2:混合系数2,5(101),恒定的Alpha;7(111),像素Alpha*恒定Alpha, u- y( V7 h! `& W7 f- \) i
  8. //bkcolor:层默认颜色,32位,低24位有效,RGB888格式
    , _" K" n; F- j7 c6 X# o) W. C
  9. void LTDC_Layer_Parameter_Config(u8 layerx,u32 bufaddr,u8 pixformat,u8 alpha,u8 alpha0,u8 bfac1,u8 bfac2,u32 bkcolor)6 _$ _; p, U+ h3 W
  10. {
    # L9 N' k+ I6 y$ Y( F4 W
  11.     LTDC_LayerCfgTypeDef pLayerCfg;
    - ?$ R" X$ l" Y& \4 y3 I
  12. * T, r4 ~" J( r  T( I
  13.     pLayerCfg.WindowX0=0;                                   //窗口起始X坐标
    " i: f5 K7 M5 R0 z
  14.     pLayerCfg.WindowY0=0;                                   //窗口起始Y坐标- `/ Q4 J0 q. @# O. y  C8 z$ m
  15.     pLayerCfg.WindowX1=lcdltdc.pwidth;                      //窗口终止X坐标; D0 Z# B* z5 T$ l* ]9 t: l
  16.     pLayerCfg.WindowY1=lcdltdc.pheight;                     //窗口终止Y坐标
    + A) o. d- |+ u4 e0 e- J
  17.     pLayerCfg.PixelFormat=pixformat;                        //像素格式
    / v3 B2 C  E5 Q: |
  18.     pLayerCfg.Alpha=alpha;                                  //Alpha值设置,0~255,255为完全不透明9 u* d5 W  {. {2 O
  19.     pLayerCfg.Alpha0=alpha0;                                //默认Alpha值' t  i  j4 r8 {& O8 m1 P- F
  20.     pLayerCfg.BlendingFactor1=(u32)bfac1<<8;                //设置层混合系数
    $ g) _$ z7 @0 f( z
  21.     pLayerCfg.BlendingFactor2=(u32)bfac2<<8;                //设置层混合系数
    7 {4 D$ m- u- W9 m+ `
  22.     pLayerCfg.FBStartAdress=bufaddr;                        //设置层颜色帧缓存起始地址
    7 ]# r) r0 k0 g0 t5 i2 }( e- _
  23.     pLayerCfg.ImageWidth=lcdltdc.pwidth;                    //设置颜色帧缓冲区的宽度   
    * t) h# V) W; i0 K! O# |
  24.     pLayerCfg.ImageHeight=lcdltdc.pheight;                  //设置颜色帧缓冲区的高度& E2 n, ^/ i: h5 l( m& \
  25.     pLayerCfg.Backcolor.Red=(u8)(bkcolor&0X00FF0000)>>16;   //背景颜色红色部分
    , E5 X! d% L. v8 D6 N& h1 W: B
  26.     pLayerCfg.Backcolor.Green=(u8)(bkcolor&0X0000FF00)>>8;  //背景颜色绿色部分% n3 i9 i2 R3 b% a5 }& X1 {- h
  27.     pLayerCfg.Backcolor.Blue=(u8)bkcolor&0X000000FF;        //背景颜色蓝色部分4 P9 E4 {- O6 c6 R4 A/ q' W
  28.     HAL_LTDC_ConfigLayer(<DC_Handler,&pLayerCfg,layerx);  //设置所选中的层: M. J) k$ h7 j
  29. }4 r: K: z( j3 }0 D/ F
  30. 6 y2 S0 |  l8 u  X! k2 I
  31. //在init时调用
    4 Z7 }* v8 M) H) [& Y
  32. LTDC_Layer_Parameter_Config(0(u32)ltdc_framebuf[0],LCD_PIXFORMAT,255,0,6,7,0X000000);  //层参数配置
复制代码

  B# z) P' |  y7 [: ~5.设置LTDC层窗口. r& |4 F) [1 X' U- H# c9 A
  1. //layerx:层值,0/1.- [- D' ^3 J* [. h1 U
  2. //sx,sy:起始坐标+ u! A& c( {7 ~3 K4 [$ ^( v4 D
  3. //width,height:宽度和高度
    8 O& p4 r* J7 ?" W5 z
  4. void LTDC_Layer_Window_Config(u8 layerx,u16 sx,u16 sy,u16 width,u16 height), ]( {2 M+ a  _# f- K
  5. {
    8 L; z- }. ~% n) ~- B
  6.     HAL_LTDC_SetWindowPosition(<DC_Handler,sx,sy,layerx);                                  //设置窗口的位置
    & P- u6 a. N$ V! A3 `+ G6 b
  7.     HAL_LTDC_SetWindowSize(<DC_Handler,width,height,layerx);                                //设置窗口大小   
    ; Y& R! |  d3 Q, {# F' a7 G( |
  8. }- {# X' K# z. i: M5 I$ @, ~$ J
  9. & ?; j. n' M  S! x/ ]
  10. //在init时调用
    ' A3 `* C* P* r0 O& i
  11. LTDC_Layer_Window_Config(0,0,0,lcdltdc.pwidth,lcdltdc.pheight);             //层窗口配置,以LCD面板坐标系为基准
复制代码

  n* Z7 R: P' x5 ], S  e; `  S/ a完成了 LTDC 的配置,可以控制 RGBLCD 显示了。
0 Y! {, [& ~7 O5 ~/ D, e: o. W
& T; J% b# i& M+ K/ a  ?" k使用DMA2D完成颜色填充/ U$ o- S3 _; p, u& x
使用官方提供的 HAL 库 DMA2D 相关库函数进行颜色填充效率极为低下,大量时间浪费在函数的入栈出栈以及过程处理,所以在项目开发中一般都不会使用 DMA2D 库函数进行颜色填充! e! `3 H. h) o

6 Z3 c8 B8 n2 j  V6 R8 A1)使能 DMA2D 时钟,并先停止 DMA2D。
* _$ U, {& W: J+ }8 M要使用 DMA2D,先得开启其时钟。然后 DMA2D 在配置其相关参数的时候,需要先停止DMA2D 传输。 使能 DMA2D 时钟和停止 DMA2D 方法为:
" v- |7 Y' d2 b/ S( |  H8 ^
  1. __HAL_RCC_DMA2D_CLK_ENABLE(); //使能 DM2D 时钟
    0 M/ _. O9 R9 d# P& [) q; |% |
  2. DMA2D->CR&=~DMA2D_CR_START; //停止 DMA2D
复制代码
( b* ?: B, N) i. N( f
2)设置 DMA2D 工作模式。3 V/ w: O: h0 B: x! A( d
通过 DMA2D_CR 寄存器,配置 DMA2D 的工作模式。我们用了寄存器到存储器模式和存储器到存储器这两个模式。) F" o( S+ U+ L9 A. s
寄存器到存储器模式设置:  S+ C( X% e+ p, D
  1. DMA2D->CR=DMA2D_R2M; //寄存器到存储器模式
复制代码
+ K5 I9 k6 Z' E! X* S: p2 Z- Q' F
存储器到存储器模式设置:$ a* ]7 Q( n8 {# I+ ]9 v1 y" v, l
  1. DMA2D->CR= DMA2D_M2M; //存储器到存储器模式
复制代码
" t+ h6 k" _+ l" z
3)设置 DMA2D 的相关参数。2 L  h# Q% Y: u% w6 q: C* q
这一步,我们需要设置:颜色格式、输出窗口、输出存储器地址、前景层地址(仅存储器到存储器模式需要设置)、颜色寄存器(仅寄存器到存储器模式需要设置)等,由:DMA2D_OPFCCR、DMA2D_FGPFCCR、DMA2D_OOR、DMA2D_FGOR 、DMA2D_OMAR、DMA2D_FGMAR 和 DMA2D_NLR 等寄存器进行配置。具体配置过程请参考实验源码。3 }4 m5 r, ^4 T- j

" u( V/ a( Y$ \. P; O. }4)启动 DMA2D 传输。
) _% ?: {; k8 [3 n" s. x通过 DMA2D_CR 寄存器配置开启 DMA2D 传输,实现图像数据的拷贝填充,方法为:
% Y+ V4 m6 E, N( w1 ~; t+ L! U
, C5 z, K$ A8 Y  B3 l! zDMA2D->CR|=DMA2D_CR_START; //启动 DMA2D( H+ R; i# o0 q- ]! G9 y
1
7 |1 v5 y" g# v2 n/ D# |5)等待 DMA2D 传输完成,清除相关标识。: h2 N" o% W- U+ l3 X# \0 T" c
最后,在传输过程中,不要再次设置 DMA2D,否则会打乱显示,所以一般在启动 DMA2D后,需要等待 DMA2D 传输完成(判断 DMA2D_ISR),在传输完成后,清除传输完成标识(设置 DMA2D_IFCR),以便启动下一次 DMA2D 传输。) Z; |' _: S5 M  }5 Q$ K0 m

8 Y5 ^- t0 n( G1 p
  1. while((DMA2D->ISR&DMA2D_FLAG_TC)==0) ; //等待传输完成
    4 B+ N# |; \* x6 u% V; t7 Y4 _
  2. DMA2D->IFCR|=DMA2D_FLAG_TC; //清除传输完成标志
复制代码
. |' d2 c" q8 ~( U7 U7 @
通过以上几个步骤,我们就完成了 DMA2D 填充; q( ^4 A* o) H( X6 `
( o1 A0 H4 I$ M6 K7 ^
使用示例9 z# D0 ^4 p0 R! w
  1. //LCD LTDC重要参数集1 C7 l/ s9 a0 O1 A
  2. typedef struct  9 J; s  k8 \$ g* Q/ ?0 [& X
  3. {
    ( B: p2 e& m. }* y
  4.     u32 pwidth;         //LCD面板的宽度,固定参数,不随显示方向改变,如果为0,说明没有任何RGB屏接入
    0 |4 y. y4 w; j# i& F
  5.     u32 pheight;        //LCD面板的高度,固定参数,不随显示方向改变0 P* Q* a, e. T3 l2 g
  6.     u16 hsw;            //水平同步宽度 Horizontal synchronization width5 e" @4 N+ Y/ N1 \5 ~. r8 f
  7.     u16 vsw;            //垂直同步宽度 Vertical synchronization width
    5 l' o2 T; {/ s; b/ d6 N
  8.     u16 hbp;            //水平后廊  O2 @! U' J. i3 X4 F) C+ p- F% S
  9.     u16 vbp;            //垂直后廊
    / f6 E! p/ {0 A6 ]' H) {! O
  10.     u16 hfp;            //水平前廊2 d* f$ v, m7 ]$ ~2 E, @" C
  11.     u16 vfp;            //垂直前廊
    ' ]4 N3 F+ P* E/ H+ O# W
  12.     u8 activelayer;     //当前层编号:0/1) g! u. g* Q3 W' n: I( \* J" @2 |
  13.     u8 dir;             //0,竖屏;1,横屏;
    1 i5 Q, q1 K( @  W+ u/ F
  14.     u16 width;          //LCD宽度, j2 M  u# w/ Q) w: T3 r
  15.     u16 height;         //LCD高度
    1 \8 O. v5 `4 ?  Z5 J# z# y
  16.     u32 pixsize;        //每个像素所占字节数+ [4 G9 s7 k! v! \. d
  17. }_ltdc_dev;
    + m7 @. U2 n" u. T: p1 I
  18. 4 N* u2 s5 W0 A6 {7 m: y) }
  19. _ltdc_dev lcdltdc;                //管理LCD LTDC的重要参数& ]. K* H- A+ `/ ~, e$ m

  20. - H# u" C. e: Y8 p9 l" z
  21. //LTDC填充矩形,DMA2D填充
    8 B* z$ _3 T6 C; y: g/ s! @
  22. //(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)   9 K0 w1 C' B: i% U
  23. //注意:sx,ex,不能大于lcddev.width-1;sy,ey,不能大于lcddev.height-1!!!; C% Y& C- S7 s9 s1 Z: L
  24. //color:要填充的颜色
    + W7 x' |  l4 z* L+ M
  25. void LTDC_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u32 color). o( X/ O2 t- M$ `6 r. j7 x
  26. { / o3 S3 K1 U% c; |
  27.     u32 psx,psy,pex,pey;                        //以LCD面板为基准的坐标系,不随横竖屏变化而变化+ D4 p& l' k  x
  28.     u32 timeout=0;
    4 W. t; s: i( J9 c& `8 [+ M
  29.     u16 offline;' D: }" k: I  G/ n- Q/ T+ P
  30.     u32 addr; 8 g, e% L# }! o- x2 R
  31.     //坐标系转换
    + a& s3 V  l2 w9 ?% W8 z9 G
  32.     if(lcdltdc.dir)                             //横屏) ~  T% F, q* }, f6 i. z7 O3 y
  33.     {; N7 o2 X4 a; ]6 J5 ]. m1 v  S
  34.         psx=sx;psy=sy;
    ' t* O; u6 v) g' C% R0 Z
  35.         pex=ex;pey=ey;5 \/ X6 d" j3 m
  36.     }else                                       //竖屏* z8 U% g2 U) L* m9 f
  37.     {6 E) l7 W. o2 e* v3 E) O
  38.         psx=sy;psy=lcdltdc.pheight-ex-1;2 A) m1 o1 t6 U7 ^
  39.         pex=ey;pey=lcdltdc.pheight-sx-1;- @! Y6 ?  ^: w$ m0 @
  40.     } ' s' S, t% G5 B1 |8 ?
  41.     offline=lcdltdc.pwidth-(pex-psx+1);3 S: Q" e+ K( E$ X! k0 |3 N
  42.     addr=((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*psy+psx));
    / [& a9 c3 ~0 c1 W- S) |5 Q5 V
  43.     RCC->AHB1ENR|=1<<23;                        //使能DM2D时钟
    & T8 M  v. s$ U2 p, u; x1 Q/ v' B
  44.     DMA2D->CR=3<<16;                            //寄存器到存储器模式; ^. V0 K# L* t# w
  45.     DMA2D->OPFCCR=LCD_PIXFORMAT;                //设置颜色格式0 b3 j, b# z! s1 @% v
  46.     DMA2D->OOR=offline;                         //设置行偏移
    8 W/ d8 a& y, R5 [6 J
  47.     DMA2D->CR&=~(1<<0);                         //先停止DMA2D! n, K0 \/ F4 Q; e. E4 F
  48.     DMA2D->OMAR=addr;                           //输出存储器地址
    9 k5 Z+ \8 a' q+ b1 n
  49.     DMA2D->NLR=(pey-psy+1)|((pex-psx+1)<<16);   //设定行数寄存器# p0 G, h% u0 g- a& d- a0 ^
  50.     DMA2D->OCOLR=color;                         //设定输出颜色寄存器
    / Q1 l* h. D. r! p/ X  f
  51.     DMA2D->CR|=1<<0;                            //启动DMA2D
    ! S) g, n/ m, `% R6 p
  52.     while((DMA2D->ISR&(1<<1))==0)               //等待传输完成
    + V' R5 k  |5 S6 x) k% l
  53.     {
    % ~0 M2 i3 W9 ]) l( ~
  54.         timeout++;; \- [( @3 n! ~6 m5 [
  55.         if(timeout>0X1FFFFF)break;              //超时退出: x# t; p) v+ R4 d4 |! k9 M: d5 p
  56.     }  
    3 Q( B- s; r; T/ ?6 q/ r- v
  57.     DMA2D->IFCR|=1<<1;                          //清除传输完成标志
    ! I, Z* H2 ?! n* u/ d/ e
  58. }
    ' j7 t# d! L. b9 g( v8 T

  59. . M8 x. Q) n( ]) }( V
  60. //LCD清屏
    ! w+ u. s( y: Q8 k6 W
  61. //color:颜色值
    + M6 n$ p4 I# u5 ^. u
  62. void LTDC_Clear(u32 color)
    % t- ~/ h$ Y( g, Q2 ~
  63. {
    - n& k! U! G2 e. l3 O
  64.     LTDC_Fill(0,0,lcdltdc.width-1,lcdltdc.height-1,color);7 h  j! M8 F9 j7 D1 O
  65. }+ `- d4 y+ A4 A* L- p) W

  66. 6 x1 j( @* a3 A- ?: R( i1 E8 \( Q4 w
  67.   R- d+ c" O0 u/ ?: q. C! s
复制代码
' m' [& t7 k& o9 c. Z7 x

$ ?% H( g6 u- y- t( E! V1 q! K4 |+ v
)0J3WVNZQ8DQ6O089(M6FJW.png
收藏 评论0 发布时间:2021-12-13 08:50

举报

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