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

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

[复制链接]
STMCU小助手 发布时间:2021-12-13 08:50
基础知识简介$ T. D, s9 C4 V. `9 F9 B0 B: F
RGBLCD

' }& @& z3 ]$ Z9 I) w1.RGBLCD的信号2 @" s. V8 h, r' {+ J
20210720093227878.png
3 Y/ K2 o7 d* R" N6 H2 m3 {( k

( U0 t- I# {* A: x% n5 {% ~! y一般的 RGB 屏有 24 根颜色数据线(RGB 各站 8 根,即RGB888 格式),这样可以表示最多 1600W 色,DE、VS、HS 和 DCLK,用于控制数据传输。
; a1 |, d# d5 e' [: C! s) G
/ w3 b5 V( T, Q2.RGBLCD驱动模式

0 c, Y/ ?+ m4 m其驱动模式主要分为两种) S+ y! j/ _, b2 _7 U+ I" E% G

. \6 l$ F+ f8 u+ O, T      DE模式& C9 e! u$ ?; q; a2 x/ o! P
      DE 模式使用 DE 信号来确定有效数据,DE 为高/低时,数据有效3 _% p0 O; E0 E# L
      HV模式
5 W0 k! Y: l( d; C2 B3 Q$ w; q      HV模式需要行同步和列同步,来表示扫描的行和列- v4 J2 M' w  y' ~, |  v. ]3 h7 k
' T' T3 N2 b3 K4 _3 I+ \
LTDC
% n$ ]* S9 W; I; R) B6 \STM32F767xx 系列芯片都带有 TFT LCD 控制器,即 LTDC,通过这个 LTDC,STM32F767可以直接外接 RGBLCD 屏,实现液晶驱动。, z. \0 o& w. }$ S
% r( f8 a3 K! M( O
1.信号线: _" u3 N( L# e4 H
STM32F767 核心板板载的 LCD 接口引出为了,节省 IO,并提高图片显示速度,使用 RGB565 颜色格式,这样只需要 16 个 IO 口,当使用 RGB565 格式的时候,LCD 面板的数据线,必须连接到 LTDC 数据线的 MSB
4 k- A9 e6 Y! ~/ d$ W( x. _# u+ d' G3 `+ o; r) K
20210720100712790.png
* X# ~- x* }& g
: F5 L2 o8 c9 c6 d* v0 \" B
2.图像处理单元7 I+ Q" c+ H) g  L4 y1 K
 先从 AHB 接口获取显存中的图像数据,然后经过层 FIFO(有 2 个,对应 2 个层)缓存,每个层 FIFO 具有 64*32 位存储深度,然后经过像素格式转换器(PFC),把从层的所选输入像素格式转换为 ARGB8888 格式,再通过混合单元,把两层数据合并,混合得到单层要显示的数据,最后经过抖动单元处理(可选)后,输出给 LCD 显示。
0 v! _( H, `$ e6 ]1 r9 n7 x 混合单元首先将第一层与背景层进行混合,随后,第二层与第一层和第二层的混合颜色结果再次混合,完成混合后,送给 LCD显示。
9 l0 \, B: ^' B/ o- |( \3 w
! |- z; l9 A+ D7 v  E
20210720102457112.png

9 A8 I# W: a* }2 j+ H1 o& H
' [' T( n7 l2 b% A' T5 }2 s: V3.AHB 接口! X- t# g2 |3 |- C* f& [8 Y" H7 T
 由于 LTDC 驱动 RGBLCD 的时候,需要有很多内存来做显存,比如一个 800480 的屏幕,按一般的 16 位 RGB565 模式,一个像素需要 2 个字节的内存,总共需要:800480*2=768K 字节内存,STM32 内部是没有这么多内存的,所以必须借助外部 SDRAM,而 SDRAM 是挂在AHB 总线上的,LTDC 的 AHB 接口,就是用来将显存数据,从 SDRAM 存储器传输到 FIFO 里面。
* ~! _5 `& K+ }2 R* `2 ]8 F
  p# x: O' _& g, s7 n. x5 z4.LTDC相关寄存器及使用方法

- V0 y' J" L) T' f4 |( `LTDC 的各种配置寄存器以及状态寄存器,用于控制整个 LTDC 的工作参数,
7 Z" Q+ T: }* ~  Z% {: U主要有:各信号的有效电平、垂直/水平同步时间参数、像素格式、数据使能等等。
* x3 o; _5 z# J7 A7 d' o' Z如果 RGBLCD 使用的是 DE 模式,需要设置如下参数,然后 LTDC会根据这些设置,自动控制 DE 信号。$ x0 V$ y/ t* A; W' H4 K

2 S' S! o% V- _# c/ K/ K2 nLTCD全局控制寄存器 LTCD_GCR
+ A, u) e% ~$ t* F
+ x$ W# n9 O: d# @
20210720104228854.png
( J" D, G3 N3 o6 w3 O* o. Y

' W1 ?+ G* u: p3 F3 T% J& m
]V@HJS%I_Y[%1XLYT61%0@2.png

3 X3 ?. k+ [* d% N0 x6 `2 u8 t
9 z' _% j( D0 L3 K" _8 u: dLTCD同步大小寄存器 LTDC_SSCR0 ~7 l2 w& o& C
该寄存器用于设置垂直同步高度(VSH)和水平同步宽度(HSW)
1 T( N" d# I, s5 [# X% l9 z5 ^" ^3 X0 z; h
20210720104959506.png
+ F* q- x. Z& @. L; k) I% B# K9 n
* ^2 ^# F! I1 X
0PRMT7%Y[QF2O{1W`AQ82~7.png

* i2 v& _0 r1 Y2 E
% u: W) h2 ^2 _% @
2 G* O5 d* @$ m7 `: \4 o% qLTDC有效宽度配置寄存器 LTDC_AWCR3 j7 Z% _1 A0 x
这里所说的有效高度和有效宽度,是指 LCD 面板的宽度和高度,构成分辨率  V. }" }; Y& `' p9 X# s  Q

0 |0 A) p! U) r1 H4 `$ |: Q
20210720110024135.png

8 B4 r$ M7 u# s$ D5 ^6 @- S+ g6 E+ {4 ]  Z8 N3 u
[AREI`HGZ@RRR{J@MJC8W]8.png

( n* Z& g; a4 [$ b2 Z7 j
- s" @; ?) F5 ?# \# n# u; k     
. h) O; l: h7 S# HLTDC 总宽度配置寄存器 LTDC_TWCR

: Q0 ^  I6 Y5 f; x$ a! c8 ^
% k( g/ X3 c: }
20210720110931326.png
1 r- r4 H, U+ S& J/ K6 K6 O3 G5 k* [4 M

( h9 `( D: `( s- ]
O6G8SGZNHK4ZYO{)JN[]USW.png
, p5 O; F$ T" r9 P, d

0 A" f& D" w3 n7 A- g; f       ' x' A6 ^& {* O: }, t
LTDC 背景色配置寄存器 LTDC_BCCR
/ |; n/ p& J4 X" @. d" w$ w! F7 [该寄存器定义背景层的颜色(RGB888),通过低 24 位配置,我们一般设置为全 0 即可。
' _1 p5 ^& V* ]; d: E6 ~& U: ~8 k* T9 D9 t
; U) [# \1 ?5 Y& s; x
20210720111141846.png
3 _4 K9 w- E  f( s( g
# `4 t) S& f* o$ d; ~3 G) m# }# @
LTDC当前位置状态寄存器 LTDC_CPSR
: w3 U$ F( X4 @/ @7 [, ?* v# V3 J5 v
a3355e745c2c73657ef826bf1a8f42f5.png

( O1 ~, l) b! V2 M
( {8 G2 Z9 j# E$ sCXPOS[31~16]:返回当前X坐标位置. A% y$ c: q7 t+ M# Q: x' J3 a
CYPOS[15~0]:返回当前Y坐标位置
' \5 ~9 K5 v/ H( m8 K) w4 f+ c8 k9 t( U) ]3 T
LTDC当前显示状态寄存器 LTDC_CDSR
7 u8 x5 a* @8 Z/ x; `此寄存器返回由 HSYNC、VSYNC 和水平/垂直 DE 信号控制的当前显示阶段的状态
( e* z5 M( R6 w, S, j( v. O5 r9 c0 u' @" Y* t( z
c1e72a8f7ff1155cd5391d05ba83e42d.png
: H1 I+ z8 U. P/ r8 }! r; N

' ^7 c+ H  ?+ z& P$ ]! U位 31:24 保留,必须保持复位值( r, A8 g- ^. |8 y5 i2 [1 ?/ B4 P
位 3 HSYNCS:水平同步显示状态 (Horizontal Synchronization display Status)
+ v1 x# }3 Z9 ~! c( h0:低电平有效
- }3 a7 s% {+ q. A. L6 ^8 e. M1:高电平有效& z: Z0 d3 e- T* @  `# |4 X  j
位 2 VSYNCS:垂直同步显示状态 (Vertical Synchronization display Status)
( Z3 g; d6 j0 h0:低电平有效2 |1 a4 I; F  e; D+ I
1:高电平有效! f- P  W5 V, ~7 ~$ m
位 1 HDES:水平数据使能显示状态 (Horizontal Data Enable display Status)  p# [7 B' z: ^) }  E
0:低电平有效$ a3 j; W9 f# i; j
1:高电平有效
2 s# W( x" k& \% i8 t) M! F位 0 VDES:垂直数据使能显示状态 (Vertical Data Enable display Status)
6 ?6 X7 V* k& E& A0:低电平有效& ]9 q/ w; m9 X* d
1:高电平有效
0 m) }2 b% J8 ?% N7 f& z4 e. M- d/ P8 A! K$ ]+ ?% ~7 O9 g3 W
LTDC 的层颜色帧缓冲区地址寄存器 LTDC_LxCFBAR(x=1/2)
3 o  q% e7 M* H该寄存器用来定义一层显存的起始地址。STM32F767 的 LTDC 支持 2 个层,所以总共有两个寄存器,分别设置层 1 和层 2 的显存起始地址。
; L$ J  Z" Q! u$ B5 d" |! s, T$ F1 i) i1 G
20210720111336311.png
% A8 J" i& }' L& R' x6 v. U9 P+ C; \
7 g# r$ S! j* S' u) Z( W& ]; T
LTDC 的层像素格式配置寄存器 LTDC_LxPFCR(x=1/2)8 n( F$ P/ B1 }2 f6 G
该寄存器只有最低 3 位有效,用于设置层颜色的像素格式,一般使用 RGB565 格式,即该寄存器设置为:010 即可。
! ~" K8 g- T0 h3 O5 J# m+ c' e; E/ g! }; z
STQ}OUE_D7Z(33OZ_E@73.png

3 |4 K# {7 g; ]( z- [% d; q0 {9 p
& e; w$ k$ j. g7 E# P& X
       6 `1 |% V# J8 j$ y, }" [
LTDC 的层恒定 Alpha 配置寄存器 LTDC_LxCACR(x=1/2)0 B6 F, A1 G" v( X3 b+ b. s+ \
该寄存器低 8 位(CONSTA)有效,这些位配置混合时使用的恒定 Alpha。恒定 Alpha 由硬件实现 255 分频。$ ^9 |/ j0 L& j5 g, r" ]

. D; P9 u; o3 _+ \8 w: c
20210720112235516.png

) H& X* Z, j4 Z: |8 p7 |7 p0 K9 i$ G
LTDC 的层默认颜色配置寄存器 LTDC_LxDCCR(x=1/2)

. ?) }; t5 P" ~1 {3 o该寄存器定义采用 ARGB8888 格式的层的默认颜色。默认颜色在定义的层窗口外使用或在层禁止时使用。一般情况下,用不到,所以该寄存器一般设置为 0 即可。( G1 T& l. ~/ I2 C7 B

7 y2 r& Y3 i' g4 L; a3 ]8 E- W
20210720112604555.png
/ M% W: t$ D/ p5 J" K

3 A. T4 ^; V) a) U" o; I/ JLTDC 层混合系数配置寄存器:LTDC_LxBFCR(x=1/2)! s, [% g7 p" w- N  @! g
该寄存器用于定义混合系数: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即可。
5 X5 B% m$ k( q4 j: L通用的混合公式为:BC=BF1C+BF2Cs
6 A& U& a( d1 @4 W# y/ m/ U; Y5 E/ M其中:BC=混合后的颜色;BF1=混合系数 1;C=当前层颜色,即我们写入层显存的颜色值;BF2=混合系数 2;Cs=底层混合后的颜色,对于层 1 来说,Cs=背景层的颜色,对于层 2 来说,Cs=背景层和层 1 混合后的颜色。
0 _! |7 j( X$ v; J. O( m; ~3 {  h1 l
2021072011293763.png
5 t0 V. |  Q0 ?. y) N2 b* r' g

. d- A/ O; ?% _% d3 I6 vLTDC 的层窗口水平位置配置寄存器 LTDC_LxWHPCR(x=1/2)

2 f; C4 ]# d; n8 x  A* q该寄存器定义第 1 层或第 2 层窗口的水平位置,第一个和最后一个像素( d( v3 S2 ~: g' Y

3 o1 R% _1 A. v( r4 `: G- H( U
20210720113448290.png
2 S& U+ R9 e  z: k( a

, \) L6 q+ W( i, v1 P8 [: ^* Y% {9 R, UWHSTPOS:窗口水平起始位置,定义层窗口的一行的第一个可见像素,
$ N) n: J. G; ?& u; cWHSPPOS:窗口水平停止位置,定义层窗口的一行的最后一个可见像素
( s2 T% R* |' H* V( w/ h. V7 {7 t9 b& i1 \8 Q. i+ m. R* b
LTDC 的层窗口垂直位置配置寄存器 LTDC_LxWVPCR(x=1/2)
" ^1 q3 L. J3 p- Q, n% a* v5 {
该寄存器定义第 1 层或第 2 层窗口的垂直位置(第一行或最后一行)
3 S) j, c# j/ P% N! {
# c! {! T0 X5 S- `- V- h
20210720133247145.png
9 [  L( j7 [2 ?1 [/ a9 Q9 z
0 Y9 \5 `3 A! l3 w; m
WVSTPOS:窗口垂直起始位置,定义层窗口的第一个可见行。
  r2 a6 ~5 O; O1 r5 ^WVSPPOS:窗口垂直停止位置,定义层窗口的最后一个可见行。& J3 h/ k% J" z) `9 z+ d- D
! D# g% {5 ~' `0 R- b/ M
LTDC 的层颜色帧缓冲区长度寄存器 LTDC_LxCFBLR(x=1/2)
: w! R- A6 ^" m% _, M- \7 K该寄存器定义颜色帧缓冲区的行长和行间距。. b3 N1 ?2 Q: A/ E6 P

5 U7 J! F4 C1 {1 j% [% {
20210720133802157.png

1 W! E2 m+ w9 @6 g. F
( p3 G. J0 F8 C% c- t* y' j# h( ICFBLL:这些位定义一行像素的长度(以字节为单位)+3。. F! ?6 Z; G( Z& X; @
行长的计算方法为:有效宽度 * 每像素的字节数 + 3。5 N/ E; c5 N- u1 z- G' C
比如,LCD 面板的分辨率为 800480,有效宽度为 800,采用 RGB565 格式,那么 CFBLL 需要设置为:8002+3=1603。
1 m5 Y: J# l: f& OCFBP:这些位定义从像素某行的起始处到下一行的起始处的增量(以字节为单位)。3 y2 F. R* O  J. B, f9 e9 c' k2 M
这个设置,其实同样是一行像素的长度,对于 800480 的 LCD 面板,RGB565 格式,设置 CFBP 为:8002=1600 即可。1 \) [, Q6 \: x7 k" K. T8 V6 @
$ l( n, k  A2 U7 P$ w# x4 i
LTDC 的层颜色帧缓冲区行数寄存器 LTDC_LxCFBLNR(x=1/2)# F& w& b+ X" Q0 `' s4 b: g4 p
该寄存器定义颜色帧缓冲区中的行数。8 @7 _& |! J- i% Z, U# t. z
比如,LCD 面板的分辨率为 800*480,那么帧缓冲区的行数为 480 行,则设置 CFBLNBR=480 即可
" o" ^) E% M: U1 M  L5 f9 `: F) z: F5 j1 I4 M  m. N% u. L
20210720133424485.png

! _8 W( J' I$ ?# M1 n+ o. [/ W1 c' ]2 ?: @9 ~2 q6 G
5.时钟域
# U/ }6 ?2 z9 i- W( v' G8 z* [. tLTDC 有三个时钟域:AHB 时钟域(HCLK)、APB2 时钟域(PCLK2)和像素时钟域(LCD_CLK),
) N1 [9 g- P) b6 iAHB 时钟域用于驱动 AHB 接口,读取存储器的数据到 FIFO 里面;% O* ?2 f  Z8 j5 J
APB2 时钟域用于配置寄存器;. J( `/ O: \( q8 l4 q1 d# r
LCD_CLK像素时钟域则用于生成 LCD 接口信号,LCD_CLK 的输出应按照 LCD 面板要求进行配置。' h5 F+ G! r) j( c$ m0 Z2 X/ g' i
9 B1 \9 d- T) u8 i# ^! @' B1 N
DMA2D
( t, V$ ~) b& W4 g; U为了提高STM32F767的图像处理能力,ST公司设计了一个专用于图像处理的专业 DMA,通过 DMA2D 对图像进行填充和搬运,可以完全不用CPU 干预,从而提高效率,减轻 CPU 负担。
- p, A' W3 E# S- z( e1 Z+ Q/ j, Y+ X, t
) }7 W& G, w  c: r# _/ G) V- [它可以执行下列操作:
& V: e8 n. m, u! G用特定颜色填充目标图像的一部分或全部(可用于快速单色填充)
, w% y4 l) [  t" A; `; l* @将源图像的一部分(或全部)复制到目标图像的一部分(或全部)中(可用于快速图像填充)9 m, b( x+ x7 t
通过像素格式转换将源图像的一部分(或全部)复制到目标图像的一部分(或全部)中
# D& K/ w8 J3 d4 M! A! }$ G将像素格式不同的两个源图像部分和/ 或全部混合,再将结果复制到颜色格式不同的部分或整个目标图像中- w( J! U3 u' D6 g$ z
5 e$ c( h( a" e6 o
! b1 G1 M2 P7 s. ]5 W$ R" S
DMA2D 有四种工作模式,通过 DMA2D_CR 寄存器的 MODE[1:0]位选择工作模式:
0 \" C0 O9 @4 M, R; j, z6 H1, 寄存器到存储器' Z! I9 k7 I* F9 l& `9 \2 n
2, 存储器到存储器
6 ]7 v  [+ T- m& p% J& H& @3, 存储器到存储器并执行 PFC
, \( {, U! U; m% G4, 存储器到存储器并执行 PFC 和混合" u: T. t% J0 k) i% C  T% K

: q& z5 g: T+ z, G- M0 D1 I% N$ P/ Y7 S6 o/ }4 v/ S' X! ?+ l
寄存器到储存器
1 u# [1 E8 D& z, e6 V0 F寄存器到存储器模式用于以预定义颜色填充用户自定义区域,也就是可以实现快速的单色5 k# K4 q* h1 i2 y
填充显示,比如清屏操作。
& K) \4 @/ O$ i, u0 \在该模式下:颜色格式在 DMA2D_OPFCCR 中设置,DMA2D 不从任何源获取数据,它只
( K( G% p7 R) F% X2 d4 e7 K是将 DMA2D_OCOLR 寄存器中定义的颜色写入通过 DMA2D_OMA 寻址以及 DMA2D_NLR 和
- t5 r0 h! j* [+ r: p- ^DMA2D_OOR 定义的区域7 x  D% s0 g  C* G7 d

9 ^) ]* o9 b# f& x# C4 ?9 F7 O# g! b- X
储存器到储存器
- s- y: b1 ~2 Q! H$ z% J0 E该模式下,DMA2D 不执行任何图形数据转换。前景层输入 FIFO 充当缓冲区,数据从- @& P+ l4 x+ p  b5 [5 K- y
DMA2D_FGMAR 中定义的源存储单元传输到 DMA2D_OMAR 寻址的目标存储单元,可用于快7 V& N/ w8 x; G7 L. G2 S% ?
速图像填充。DMA2D_FGPFCCR 寄存器的 CM[3:0]位中编程的颜色模式决定输入和输出的每像. a2 j; k' P$ z! G. l  J6 T
素位数。对于要传输的区域大小,源区域大小由 DMA2D_NLR 和 DMA2D_FGOR 寄存器定义,9 L# w0 D+ S' ]# u3 u* G# b9 M
目标区域大小则由 DMA2D_NLR 和 DMA2D_OOR 寄存器定义。
- Y( x4 {2 V  N+ `. z
- q3 d( G7 E0 F
! ~9 v+ F. m- X/ y0 U- e! n/ r以上两个工作模式,LTDC 在层帧缓存里面的开窗关系都一样的,经过如下三个寄存器的配置,就可以确定窗口的显示位置和大小。
& C/ ^) ^, d% @0 ?(1). 窗口显示区域的显存首地址由 DMA2D_OMAR 寄存器指定,5 ]' G  ~+ f. q# k9 v
(2).窗口宽度和高度由DMA2D_NRL 寄存器的 PL 和 NL 指定0 g8 m- o" t8 d( w/ _, n6 h
(3).行偏移(确定下一行的起始地址)由 DMA2D_OOR寄存器指定,0 }! `+ ^8 u! v' v  X1 R2 L

' P8 I3 j( {. i
20210720170136697.png
4 R$ C% e8 |/ N. O0 z6 d# v8 G

6 \" D, `* `' l1 M
: J, |. Y3 O3 ]$ J( x在寄存器到存储器模式下,在开窗完成后,DMA2D 可以将 DMA2D_OCOLR 指定的颜色,5 H% n7 @7 z9 S" w) }7 U+ K
自动填充到开窗区域,完成单色填充。* W; ]5 }" K1 S' J- b5 q: N3 N7 p
8 A4 Z. X. o+ S" n
6 v8 T, n- [+ o6 n3 O
在存储器到存储器模式下,需要完成两个开窗:前景层和显示层,完成配置后,图像数据从前景层拷贝到显示层(仅限窗口范围内),从而显示到 LCD 上面。显示层的开窗如上图所示,前景层也和上图类似,只是 DMA2D_OMAR 寄存器变成了DMA2D_FGMAR,DMA2D_OOR寄存器变成了DMA2D_FGOR,DMA2D_NRL则两个层共用,然后就可以完成对前景层的开窗,确定好两个窗口后,DMA2D 就将前景层窗口内的数据,拷贝到显示层窗口,完成快速图像填充。
) x3 H9 Y  R, P7 v) s8 F* k+ F" I/ B6 _, z  v2 O: h: d, z
+ n6 a8 y8 I0 w- W* \6 F
DMA2D相关寄存器
+ |+ X7 \/ B1 U1 a- z  PDMA2D控制寄存器 DMA2D_CR3 m" n9 X" N3 `$ s( t$ e
该寄存器,主要是MODE 和 START 这两个设置
5 l% @, {) _# k: w4 `. h
. _! w/ y0 o+ F/ q* Z& K1 ?8 V1 Y
20210720172154901.png
. L: C, N" T0 J: H' Z) C
( f4 E6 g  r! X. P; ]
MODE:表示 DMA2D 的工作模式,
! J9 |# ?% v% `0 S4 s00:存储器到存储器模式;01:存储器到存储器模式并执行 PFC;. |3 w; Q9 Z6 v
10:存储器到存储器并执行混合;11,寄存器到存储器模式;( P3 i: o0 ^4 M0 y$ h
START:该位控制 DMA2D 的启动,在配置完成后,设置该位为 1,启动 DMA2D 传输。
3 a* m& }" Q9 M; }3 [4 d. D( h7 U* G. @8 I
DMA2D输出 PFC 控制寄存器 DMA2D_OPFCCR
  n/ z/ q" o& b0 H# {该寄存器用于设置寄存器到存储器模式下的颜色格式
* s, w1 d. `  m1 I
' Q! O1 A; ^  y8 z) P
20210720172538112.png

# j/ k+ }1 Q1 L" ?' |0 ?) X, [% I
只有最低 3 位有效(CM[2:0]),表示的颜色格式有:# S/ g. f6 G! a  c+ A' ]) D
000,ARGB8888;001:RGB888;010:RGB565;
" l$ U4 B! i0 H: |( \$ P8 o011:ARGB1555;100:ARGB1444。
, i( M, g7 i' v* ~+ N6 v6 G: I8 Q我们一般使用的是 RGB565 格式,所以设置 CM[2:0]=010 即可。
( z4 ^3 x* E$ c( s( r
" t! A% {7 ~8 |# g6 y3 uDMA2D前景层 PFC 控制寄存器:DMA2D_FGPFCCR, I! R7 p% b8 Q% h5 I

# \2 A8 l! e$ E" z, a
20210720173213773.png
' w/ ~; Z( k) H  \" m* N: @! y
! w- k" D8 i1 k: d4 G
该寄存器,低 4 位:CM[3:0],用于设置存储器到存储器模式下的颜色格式,这四个位表示的颜色格式为:
- Q1 [' n; Q" v& g! G3 [, x0000:ARGB8888;0001:RGB888;0010:RGB565;$ |+ _( [- D7 k2 Z- e6 o" S$ r' U
0011:ARGB1555;0100:ARGB4444;0101:L8;* [' p( c$ u" h! w2 \: y; G
0110:AL44;0111:AL88;1000:L4;1001:A8;1010:A4;7 Q: t+ z& E2 {' v" }
我们一般使用 RGB565 格式,所以设置 CM[3:0]=0010 即可。
5 T: Y8 o) {9 t, u2 T; `- G2 Q8 \4 R1 _$ r
DMA2D输出偏移寄存器 DMA2D_OOR
; t7 ^  f# ?, P' g  y& x: L+ I. l3 H" A
20210720174740982.png

+ T+ y: X) X$ r: r- r/ ^, {该寄存器仅最低 14 位有效(LO[13:0]),用于设置输出行偏移,作用于显示层,以像素为
3 y+ h2 a- z% v3 H( l, P单位表示。此值用于生成地址。行偏移将添加到各行末尾,用于确定下一行的起始地址。
: b& z2 [" Z3 i' g1 @  J同样的,还有前景层偏移寄存器:DMA2D_FGOR,该寄存器同 DMA2D_OOR 一样,也是: A3 I' _. i- K/ a* q* B1 a$ v
低 14 位有效,用于控制前景层的行偏移,也是用于生成地址,添加到各行末尾,从而确定下一6 B( P  G( i5 ?9 p
行的起始地址。
4 q7 h8 q. ?6 P6 g" L& ]2 R
9 }  q5 v8 V2 u  Z- R& I# n1 C3 yDMA2D输出存储器地址寄存器 DMA2D_OMAR
9 ]5 n$ K) t9 G4 u+ I) ]  b1 w) S1 I6 H" C4 s
20210720175051288.png

8 D6 d' a! f* \& p- r3 `1 M3 J
! b% g. b, g5 p, L% `! c该寄存器设置由 MA[31:0]设置输出存储器地址,也就是输出 FIFO 所存储的数据地址,该地址需要根据开窗的起始坐标来进行设置。以 800480 的 LCD 屏为例,行长度为 800 像素,假定帧缓存数组为:ltdc_framebuf,我们设置窗口的起始地址为:sx(<800),sy(<480),颜色格式为 RGB565,每个像素 2 个字节,那么 MA 的设置值应该为:: e: @' v9 p9 H* A) f1 ?1 p
*MA[31:0]= framebuf+2(800sy+sx)**
# N- T  Y$ p8 `% {; R! f2 ~同样的,还有前景层偏移寄存器:DMA2D_ FGMAR,该寄存器同 DMA2D_OMAR 一样,4 Y7 Q; j& @: P3 E6 _
不过是用于控制前景层的存储器地址,计算方法同 DMA2D_OMAR。( k& b; _7 z% C! K; L0 T8 J8 W

4 J8 i: o+ M: e) R  r, PDMA2D行数寄存器 DMA2D_NLR) \2 Z2 |1 _2 \% M

* i, |* C5 ~9 b& w1 Y" l7 I
20210720180044872.png

, k' l  e/ Q7 [, X该寄存器用于控制每行的像素和行数,该寄存器的设置对前景层和显示层均有效,通过该寄存器的配置,就可以设置开窗的大小。其中:: R0 b  m7 R. w/ H
NL[15: 0]:设置待传输区域的行数,用于确定窗口的高度。! O2 j4 C" C* L2 o% J
PL[13: 0]:设置待传输区域的每行像素数,用于确定窗口的宽度
+ u+ Z+ c! r% C# a; C8 @% J, v$ [6 z7 b) s1 v* @- j$ E6 |
DMA2D输出颜色寄存器 DMA2D_OCOLR
) c6 ^- I* x+ x! Q& x" F
: V) z; M. S, ^; n6 o
20210720180520678.png
! V) @9 t5 u0 y0 s4 q1 {
该寄存器用于配置在寄存器到存储器模式下,填充时所用的颜色值,该寄存器是一个 32位寄存器,可以支持 ARGB8888 格式,也可以支持 RGB565 格式。我们一般使用 RGB565 格式,比如要填充红色,那么直接设置 DMA2D_OCOLR=0XF800 就可以了。& T2 C1 N, r1 s9 j' y3 s

$ b" ?2 I. s' I- dDMA2D中断状态寄存器 DMA2D_ISR# D7 [4 {# ]- |  w

8 y. }: `- `7 m  r
2021072018063162.png

$ P- j  L- s. f
: Z' d% w# K; C7 @该寄存器表示了 DMA2D 的各种状态标识
% S9 a3 N% R6 I8 K: MTCIF 位,表示 DMA2D 的传输完成中断标志。当 DMA2D 传输操作完成(仅限数据传输)时此位置 1,表示可以开始下一次 DMA2D 传输了
" @) D9 C5 O& b" D. wDMA2D 中断标志清零寄存器:DMA2D_IFCR,用于清除 DMA2D_ISR 寄存器对应位的标志。通过向该寄存器的第 1 位(CTCIF)写 1,可以用于清除 DMA2D_ISR 寄存器的 TCIF 位标志。
9 G* s! [' F' W3 }3 [# }& p* ^2 v( v7 Z0 B: S2 r1 E

) B1 c( c) M, ?1 ZLTDC具体使用步骤
- x- h- M# R0 E3 K5 E1.使能 LTDC 时钟,并配置 LTDC 相关的 IO 及其时钟使能。! N' G# [4 P5 `- j8 `
使用 LTDC,当然首先得开启其时钟。
5 W" W9 `; F; x6 [: Z! ^然后需要把 LCD_R/G/B 数据线、LCD_HSYNC和 LCD_VSYNC 等相关 IO 口,全部配置为复用输出,并使能各 IO 组的时钟。) b5 T. K( Z, E2 Q/ t

1 O8 X# R: l% y* n
  1. //LTDC底层IO初始化和时钟使能& V2 Q7 {$ r6 ?) H# _
  2. //此函数会被HAL_LTDC_Init()调用' @. ?% J+ ?( L
  3. //hltdc:LTDC句柄2 C& C+ z4 P6 F, \
  4. void HAL_LTDC_MspInit(LTDC_HandleTypeDef* hltdc)9 c( y; {7 v. n8 Q
  5. {7 }* P) K. Z+ f4 V( T% |# @8 p9 C
  6.     GPIO_InitTypeDef GPIO_Initure;; M9 A% G: o" M8 \2 u9 b
  7. & ~+ @% u4 ?7 @
  8.     __HAL_RCC_LTDC_CLK_ENABLE();                //使能LTDC时钟
    5 H' G; e! p& z7 W
  9.     __HAL_RCC_DMA2D_CLK_ENABLE();               //使能DMA2D时钟7 ?* E& I% N4 w' w, p
  10.     __HAL_RCC_GPIOB_CLK_ENABLE();               //使能GPIOB时钟
    8 q% ?& t4 j4 I! C/ ]6 l, S/ Z
  11.     __HAL_RCC_GPIOF_CLK_ENABLE();               //使能GPIOF时钟
    . s. o. a7 J# I" U3 s/ Q, A" K; |
  12.     __HAL_RCC_GPIOG_CLK_ENABLE();               //使能GPIOG时钟( @: H3 p! h/ C% j
  13.     __HAL_RCC_GPIOH_CLK_ENABLE();               //使能GPIOH时钟5 B- h! y9 m0 h1 a6 j+ E4 U
  14.     __HAL_RCC_GPIOI_CLK_ENABLE();               //使能GPIOI时钟/ S  C# j# k! H
  15. 6 B  w3 F& a6 N* u' V- |. E
  16.     //初始化PB5,背光引脚
    - z" o, J0 y% S
  17.     GPIO_Initure.Pin=GPIO_PIN_5;                //PB5推挽输出,控制背光
    1 w5 `# m4 O& H5 B
  18.     GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;      //推挽输出
    $ }7 Q0 i: ]- \/ t" G
  19.     GPIO_Initure.Pull=GPIO_PULLUP;              //上拉
    . k* J1 J0 ]: c7 a2 ]
  20.     GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速
    , F+ ~: O; o1 @( W2 t
  21.     HAL_GPIO_Init(GPIOB,&GPIO_Initure);
    ! D. f* o# }2 R! p* Y
  22. 0 f7 Q5 }( E. {3 l0 z+ \
  23.     //初始化PF10, B9 o- M* h3 x, j
  24.     GPIO_Initure.Pin=GPIO_PIN_10; 8 T# Q1 B/ X6 I+ ~" ?
  25.     GPIO_Initure.Mode=GPIO_MODE_AF_PP;          //复用. K% t" e  I2 @) j6 j
  26.     GPIO_Initure.Pull=GPIO_NOPULL;
    9 j# ?- e! k4 [
  27.     GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速
    - }( \  S3 {. C  L6 H" B% x
  28.     GPIO_Initure.Alternate=GPIO_AF14_LTDC;      //复用为LTDC3 Q5 z1 u! x$ F' A0 e" |. q
  29.     HAL_GPIO_Init(GPIOF,&GPIO_Initure);2 ~7 j2 T8 K3 V7 o& D; U9 A
  30. $ n  D2 m7 \( h" ~+ \8 |: e
  31.     //初始化PG6,7,11" Z7 v  @$ e& B( o+ U$ l
  32.     GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_11;2 \6 V' N% Z% P; w3 R; @1 N6 e" _' f. M
  33.     HAL_GPIO_Init(GPIOG,&GPIO_Initure);
    ) m1 j6 j* b" K$ r! K

  34. 2 M* O0 m$ H, y: K: L9 _
  35.     //初始化PH9,10,11,12,13,14,15: W9 Q6 G( ^& c3 ]) C2 B
  36.     GPIO_Initure.Pin=GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|\. Y2 R' Z" V. L& T5 b7 c/ {
  37.                      GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
      k* z$ F; u5 y: g
  38.     HAL_GPIO_Init(GPIOH,&GPIO_Initure);- X& d+ _- J: v6 j6 l5 h* \9 n1 R0 x

  39. & }8 D" U% Z0 U# X
  40.     //初始化PI0,1,2,4,5,6,7,9,102 r% h1 T7 i7 Q! W/ Q& v& S( c* U
  41.     GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|\
    % o4 |0 A; H0 e6 C) |
  42.                      GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_9|GPIO_PIN_10;5 q9 p# A7 Y( k3 v
  43.     HAL_GPIO_Init(GPIOI,&GPIO_Initure);
    3 m# G4 r; M% J) M! A! m
  44. }
复制代码

! X) c7 f' A3 h% T' x3 N8 Z2.设置LCD_CLK时钟1 S" Z4 D* R9 ?! [; o" W/ s
配置 LCD 的像素时钟,根据 LCD 的面板参数进行设置,LCD_CLK 由 PLLSAI进行配置,配置使用到的 HAL 库函数为:
7 d4 E8 }) a$ W7 {/ [( J: h2 B9 g& \
  1.         //pllsain:SAI时钟倍频系数N,取值范围:50~432.  
    8 T, i% j3 i1 y3 D
  2.         //pllsair:SAI时钟的分频系数R,取值范围:2~79 i$ V! V, N! d6 g
  3.         //pllsaidivr:LCD时钟分频系数,取值范围:0~3,对应分频2~16
    ' R) U' n  V: p& E
  4.         //假设:外部晶振为25M,pllm=25的时候,Fin=1Mhz.
    4 u  X5 _* |- `. K# d  [% [
  5.         //例如:要得到20M的LTDC时钟,则可以设置:pllsain=400,pllsair=5,pllsaidivr=13 d& ~8 A, v/ B$ u' X; v
  6.         //Fdclk=1*396/3/2*2^1=396/12=33Mhz
    9 |+ _8 C7 M+ |* V6 a
  7.     RCC_PeriphCLKInitTypeDef PeriphClkIniture;
    # ~; P. z. Z' ]' W

  8. 9 e& B; I/ F$ a/ z
  9.     //LTDC输出像素时钟,需要根据自己所使用的LCD数据手册来配置!
    . Q2 G/ a" h- ?: s
  10.     PeriphClkIniture.PeriphClockSelection=RCC_PERIPHCLK_LTDC;       //LTDC时钟
    : q1 j/ n( M3 b. w) [1 {
  11.     PeriphClkIniture.PLLSAI.PLLSAIN=pllsain;
    + I4 [$ ?' q2 ?* N, l
  12.     PeriphClkIniture.PLLSAI.PLLSAIR=pllsair;" G+ n: v" _7 c3 \: D
  13.     PeriphClkIniture.PLLSAIDivR=pllsaidivr;
    ; N" K5 G/ Y' ^" u, ]
  14.         HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef *PeriphClkInit)
复制代码
# |9 N, o0 @0 c! z
3.设置RGBLCD相关参数,并使能LTDC
# Y6 x* N2 h" S& g% |
  1. typedef struct
    4 g( q, {5 Z4 T4 ]  i
  2. {
    ; r1 `8 a/ Y3 F' [& Z
  3. uint32_t HSPolarity;                         //水平同步极性' \0 u6 |! s! Y
  4. uint32_t VSPolarity;                         //垂直同步极性
    2 G2 Y; i! t* i
  5. uint32_t DEPolarity;                         //数据使能极性1 j! }9 |1 k; I( Q! f; t
  6. uint32_t PCPolarity;                         //像素时钟极性& a6 \. @0 F' E4 x2 `" P, @
  7. uint32_t HorizontalSync;                 //水平同步宽度 8 X' g- t; s+ K8 N! |
  8. uint32_t VerticalSync;                 //垂直同步高度
    ( E+ q  D4 P1 _* o! n& f
  9. uint32_t AccumulatedHBP;                 //水平同步后沿宽度; H) s) u0 ]+ h. m
  10. uint32_t AccumulatedVBP;                 //垂直同步后沿高度
      }; e9 `+ t9 X8 d8 ]3 ]
  11. uint32_t AccumulatedActiveW;         //累加有效宽度 0 q3 Q8 M! R/ H; F; n
  12. uint32_t AccumulatedActiveH;         //累加有效高度7 I9 w* d3 W* v
  13. uint32_t TotalWidth;                         //总宽度
    2 r2 N6 D8 h6 O* R1 H
  14. uint32_t TotalHeigh;                         //总高度; f7 X: ^/ }2 n* C
  15. LTDC_ColorTypeDef Backcolor;         //屏幕背景层颜色
    1 g$ }/ u( q3 Y7 y; q) ?
  16. } LTDC_InitTypeDef;. L. h* M! l0 f2 {6 l" C! r
  17.   N3 ~) h% p& H
  18. typedef struct
    " J* E+ T, I. [5 e& }2 ]
  19. {$ O9 A( x5 N; t, l4 n  I9 C
  20.   LTDC_TypeDef                *Instance;                /*Instance变量是LTDC_TypeDef结构体指针类型*/
    ) s& r4 l7 A4 t/ _
  21.   LTDC_InitTypeDef            Init;                     /*用来初始化LTDC的结构体变量*/
    . p7 O/ P, k1 K5 J  T: c2 x
  22.   LTDC_LayerCfgTypeDef        LayerCfg[MAX_LAYER];      /*保存LTDC层配置参数*/2 K5 h6 }# H# E. ^' X, ?. q6 ~' n
  23.   HAL_LockTypeDef             Lock;                     /*锁状态*/
    ! |+ z7 b! f2 Z0 n# V0 A
  24.   __IO HAL_LTDC_StateTypeDef  State;                    /*LTDC的状态*/
    3 C; p. A; k0 `3 S
  25.   __IO uint32_t               ErrorCode;                /*错误处理*// T" E4 q. [# y1 O  P9 `
  26. } LTDC_HandleTypeDef;, T, f- i0 B$ v' P$ o( p
  27. 5 _) u; v9 }) J* Z7 Q7 \( w. j
  28. LTDC_HandleTypeDef  LTDC_Handler;                                   //LTDC句柄5 u. o- ~3 a  ?0 I
  29. / p3 X4 Q: W/ {# F
  30. LTDC_Handler.Instance=LTDC;
    + [- R( w1 _+ H4 v% d
  31. LTDC_Handler.Init.HSPolarity=LTDC_HSPOLARITY_AL;                 //水平同步极性
    # m2 h/ X* ]! i  b* {
  32. LTDC_Handler.Init.VSPolarity=LTDC_VSPOLARITY_AL;                 //垂直同步极性# e( h" y2 m: a' K
  33. LTDC_Handler.Init.DEPolarity=LTDC_DEPOLARITY_AL;                 //数据使能极性- m" p) h2 k& i$ P( Y% D5 R
  34. LTDC_Handler.Init.PCPolarity=LTDC_PCPOLARITY_IPC;                 //像素时钟极性. }1 u5 Y0 Z( n, ^5 H. c
  35. LTDC_Handler.Init.HorizontalSync=10-1;                                         //水平同步宽度, |4 u2 q  g& X! P$ B7 I8 e
  36. LTDC_Handler.Init.VerticalSync=2-1;                                         //垂直同步宽度
    ; D# E9 j6 x/ ^7 J! c
  37. LTDC_Handler.Init.AccumulatedHBP=10+20-1;                                 //水平同步后沿宽度
    7 D3 R/ E9 @/ m" Q4 u1 U
  38. LTDC_Handler.Init.AccumulatedVBP=2+2-1;                                 //垂直同步后沿高度% B9 _3 x1 V% H4 q# `7 _* B
  39. LTDC_Handler.Init.AccumulatedActiveW=10+20+480-1;                 //有效宽度
    3 N2 ~: g. V0 Q( `3 l( N) Z
  40. LTDC_Handler.Init.AccumulatedActiveH=2+2+272-1;                 //有效高度/ O2 r( m! A* x" n8 T6 V6 M# h
  41. LTDC_Handler.Init.TotalWidth=10+20+480+10-1;                         //总宽度
    . f0 w: [  s5 V: N2 \3 ~0 S
  42. LTDC_Handler.Init.TotalHeigh=2+2+272+4-1;                                 //总高度
    4 }. u, k% u6 n$ ?6 s  [/ o
  43. LTDC_Handler.Init.Backcolor.Red=0;                                                 //屏幕背景层红色部分
    ! H- g# `8 d0 u) @1 y6 E
  44. LTDC_Handler.Init.Backcolor.Green=0;                                         //屏幕背景层绿色部分- ^' N! l# }+ H( O+ o5 j
  45. LTDC_Handler.Init.Backcolor.Blue=0;                                         //屏幕背景色蓝色部分
    $ C5 T- E; n$ Y: B3 f
  46. HAL_LTDC_Init(<DC_Handler);                                                         //设置 RGBLCD 的相关参数,并使能 LTDC,会调用HAL_LTDC_MspInit
复制代码
. D7 g- a: v& ^! S% g- G0 ^
4.设置 LTDC层参数0 ~7 ^( z' _( C% X2 r; d
  1. //layerx:层值,0/1.
    3 @+ l6 j& u* @. t7 w9 C& f+ A2 ?
  2. //bufaddr:层颜色帧缓存起始地址
    : X6 p/ q* j* }1 i  i+ s  p1 k
  3. //pixformat:颜色格式.0,ARGB8888;1,RGB888;2,RGB565;3,ARGB1555;4,ARGB4444;5,L8;6;AL44;7;AL88. D+ W& A% {* x
  4. //alpha:层颜色Alpha值,0,全透明;255,不透明* \1 p$ b6 f9 R  k# J& p0 c  K
  5. //alpha0:默认颜色Alpha值,0,全透明;255,不透明5 ^) I* L7 n6 ~" Q' P8 u
  6. //bfac1:混合系数1,4(100),恒定的Alpha;6(101),像素Alpha*恒定Alpha
    $ i, |" x3 E- [- l2 H" O
  7. //bfac2:混合系数2,5(101),恒定的Alpha;7(111),像素Alpha*恒定Alpha) S+ e2 O& S. ?( ~
  8. //bkcolor:层默认颜色,32位,低24位有效,RGB888格式
    ) D* P+ ]: |  c, d% M; m, w
  9. void LTDC_Layer_Parameter_Config(u8 layerx,u32 bufaddr,u8 pixformat,u8 alpha,u8 alpha0,u8 bfac1,u8 bfac2,u32 bkcolor)
    9 ]; L5 P( V7 |8 h6 u
  10. {" m% w2 V& j: e- s
  11.     LTDC_LayerCfgTypeDef pLayerCfg;. v! i' a  m* @

  12. , }6 A- I2 Q( C; ~/ W1 H
  13.     pLayerCfg.WindowX0=0;                                   //窗口起始X坐标8 O9 v3 u' H$ A! W9 s8 ^1 G/ f
  14.     pLayerCfg.WindowY0=0;                                   //窗口起始Y坐标# N3 C6 `! A$ T) ?% O9 V
  15.     pLayerCfg.WindowX1=lcdltdc.pwidth;                      //窗口终止X坐标: \+ _5 q2 [  Y, F$ ?( P) N$ [
  16.     pLayerCfg.WindowY1=lcdltdc.pheight;                     //窗口终止Y坐标) N/ r9 p  p' @7 o3 h' Z( w
  17.     pLayerCfg.PixelFormat=pixformat;                        //像素格式/ E5 d. {' R' t' D4 V
  18.     pLayerCfg.Alpha=alpha;                                  //Alpha值设置,0~255,255为完全不透明
    / a8 `* I6 r/ Q( x2 y4 z2 m' R' A
  19.     pLayerCfg.Alpha0=alpha0;                                //默认Alpha值
    & H  w3 d3 W4 n: `  [
  20.     pLayerCfg.BlendingFactor1=(u32)bfac1<<8;                //设置层混合系数: B, g9 c+ y* y! f2 V8 N1 i2 d
  21.     pLayerCfg.BlendingFactor2=(u32)bfac2<<8;                //设置层混合系数
    ' D2 l$ R/ R1 \* }
  22.     pLayerCfg.FBStartAdress=bufaddr;                        //设置层颜色帧缓存起始地址# k7 v: {4 B! F1 G7 d) S' g- Z
  23.     pLayerCfg.ImageWidth=lcdltdc.pwidth;                    //设置颜色帧缓冲区的宽度    , e, H7 v- A( `  Q! t% ^8 Q
  24.     pLayerCfg.ImageHeight=lcdltdc.pheight;                  //设置颜色帧缓冲区的高度
    . X4 |  V' g, n3 g$ G0 L: |
  25.     pLayerCfg.Backcolor.Red=(u8)(bkcolor&0X00FF0000)>>16;   //背景颜色红色部分
    - Y3 W9 o" f2 J7 c; p4 r, J! Q# S; {
  26.     pLayerCfg.Backcolor.Green=(u8)(bkcolor&0X0000FF00)>>8;  //背景颜色绿色部分, C* l: n& g# r7 {
  27.     pLayerCfg.Backcolor.Blue=(u8)bkcolor&0X000000FF;        //背景颜色蓝色部分- ]- v/ R* R9 @2 v% Z
  28.     HAL_LTDC_ConfigLayer(<DC_Handler,&pLayerCfg,layerx);  //设置所选中的层
    " a4 \) S2 A$ K8 B5 l; T
  29. }
    # Q: `( ^# e0 r: M
  30. 1 ~" g7 Q) ~. I0 @  t; A
  31. //在init时调用- Z4 g( X. ]) F, K  j' k) K+ [7 q
  32. LTDC_Layer_Parameter_Config(0(u32)ltdc_framebuf[0],LCD_PIXFORMAT,255,0,6,7,0X000000);  //层参数配置
复制代码
1 j' N+ ^; S7 S, X, v
5.设置LTDC层窗口9 B; W1 w( V/ l3 t) z  _
  1. //layerx:层值,0/1.
    & x7 X) F: K1 I0 d
  2. //sx,sy:起始坐标  E' G* r* p" \( _
  3. //width,height:宽度和高度. [4 d' R" Y' _
  4. void LTDC_Layer_Window_Config(u8 layerx,u16 sx,u16 sy,u16 width,u16 height)5 q4 D* p: H# }& Q4 k8 L2 }6 q4 E7 [9 P
  5. {
    3 e, D/ d! J$ Y5 m4 @% w
  6.     HAL_LTDC_SetWindowPosition(<DC_Handler,sx,sy,layerx);                                  //设置窗口的位置7 ~; |- T% o* D. R7 `* r# Z& e
  7.     HAL_LTDC_SetWindowSize(<DC_Handler,width,height,layerx);                                //设置窗口大小    $ T, M; y. D7 h7 S
  8. }$ d* |7 }# y$ n* F3 M6 o
  9. ! V  H; s! c3 p: D, \& M7 W
  10. //在init时调用
      l+ I+ \: T  `/ ^' O
  11. LTDC_Layer_Window_Config(0,0,0,lcdltdc.pwidth,lcdltdc.pheight);             //层窗口配置,以LCD面板坐标系为基准
复制代码

+ a" d5 e1 T( v! D, n: O+ U完成了 LTDC 的配置,可以控制 RGBLCD 显示了。4 N7 ^6 i9 ]1 l- @& z" X
9 g7 c9 l/ g; ]- F& i3 @. H: ~
使用DMA2D完成颜色填充
5 d2 ?2 l- M& }/ O使用官方提供的 HAL 库 DMA2D 相关库函数进行颜色填充效率极为低下,大量时间浪费在函数的入栈出栈以及过程处理,所以在项目开发中一般都不会使用 DMA2D 库函数进行颜色填充
  ]( K8 |& n. K! V& Y% I. m0 ]
( B! t8 ~/ Y* Q: t. \, d: T1)使能 DMA2D 时钟,并先停止 DMA2D。
: w& t0 h9 f( K; O/ i1 `要使用 DMA2D,先得开启其时钟。然后 DMA2D 在配置其相关参数的时候,需要先停止DMA2D 传输。 使能 DMA2D 时钟和停止 DMA2D 方法为:* y* C3 X2 }3 [  }2 j
  1. __HAL_RCC_DMA2D_CLK_ENABLE(); //使能 DM2D 时钟
    ) R: C) z* x" |# y9 y: B
  2. DMA2D->CR&=~DMA2D_CR_START; //停止 DMA2D
复制代码

/ I& Q/ S( [7 {2)设置 DMA2D 工作模式。( C8 [5 a$ v, w: J5 k
通过 DMA2D_CR 寄存器,配置 DMA2D 的工作模式。我们用了寄存器到存储器模式和存储器到存储器这两个模式。0 g$ {7 X( S. @/ q2 b
寄存器到存储器模式设置:
2 _1 Q& F+ r8 j* I: |% q5 |
  1. DMA2D->CR=DMA2D_R2M; //寄存器到存储器模式
复制代码
' D! |( X( v. `
存储器到存储器模式设置:6 C8 f+ D. ~: t# k1 @9 s1 `. L# ]7 `
  1. DMA2D->CR= DMA2D_M2M; //存储器到存储器模式
复制代码

! n- v5 b: S5 t* {, T% C3)设置 DMA2D 的相关参数。
% x$ N& i, J/ D6 B1 p# w这一步,我们需要设置:颜色格式、输出窗口、输出存储器地址、前景层地址(仅存储器到存储器模式需要设置)、颜色寄存器(仅寄存器到存储器模式需要设置)等,由:DMA2D_OPFCCR、DMA2D_FGPFCCR、DMA2D_OOR、DMA2D_FGOR 、DMA2D_OMAR、DMA2D_FGMAR 和 DMA2D_NLR 等寄存器进行配置。具体配置过程请参考实验源码。
7 v+ I4 z+ G. d6 O  P1 m( z# _% ^" m/ s
4)启动 DMA2D 传输。
/ m8 K6 D$ _+ o1 E/ z通过 DMA2D_CR 寄存器配置开启 DMA2D 传输,实现图像数据的拷贝填充,方法为:* y& E/ ^  E/ o

3 b. U5 r5 w; t/ e* YDMA2D->CR|=DMA2D_CR_START; //启动 DMA2D* g0 W/ g( o* A# n) D
1/ ^/ U8 O) T3 S7 d" \
5)等待 DMA2D 传输完成,清除相关标识。
% \4 a- g3 {, ~2 l最后,在传输过程中,不要再次设置 DMA2D,否则会打乱显示,所以一般在启动 DMA2D后,需要等待 DMA2D 传输完成(判断 DMA2D_ISR),在传输完成后,清除传输完成标识(设置 DMA2D_IFCR),以便启动下一次 DMA2D 传输。
$ L. y! L9 z) u4 O) p, E
3 b6 [- P9 O- t( C
  1. while((DMA2D->ISR&DMA2D_FLAG_TC)==0) ; //等待传输完成' \- L  e" R* {+ }! R# Z
  2. DMA2D->IFCR|=DMA2D_FLAG_TC; //清除传输完成标志
复制代码
5 [! H- C3 P' x3 Z
通过以上几个步骤,我们就完成了 DMA2D 填充
, R" F4 u- Q$ v1 l: R  e& ?* ]" `2 @
使用示例
6 u3 o( ^8 l; W' k
  1. //LCD LTDC重要参数集/ P" Y- F9 Y7 }
  2. typedef struct  
    " I+ _" M3 A3 @5 U4 D
  3. {; p0 S* g8 ^/ W
  4.     u32 pwidth;         //LCD面板的宽度,固定参数,不随显示方向改变,如果为0,说明没有任何RGB屏接入6 E+ B: g4 N; z# g8 B. ]& Y0 R
  5.     u32 pheight;        //LCD面板的高度,固定参数,不随显示方向改变2 h4 \) e4 Y7 O4 Z1 ^
  6.     u16 hsw;            //水平同步宽度 Horizontal synchronization width8 d6 q: P* M, u  `
  7.     u16 vsw;            //垂直同步宽度 Vertical synchronization width
    , U9 d" Z* D) x, j2 X
  8.     u16 hbp;            //水平后廊6 x& o6 Y( N  m4 ?% K- q
  9.     u16 vbp;            //垂直后廊' r! O, S) W2 h  ?0 t
  10.     u16 hfp;            //水平前廊
    6 [/ n& T( W7 X
  11.     u16 vfp;            //垂直前廊- Y" h8 c) l; P6 z, @9 l
  12.     u8 activelayer;     //当前层编号:0/1
    ; s% V0 L+ [6 z+ G# `; k6 Q
  13.     u8 dir;             //0,竖屏;1,横屏;, N) u6 S- D8 c# ^8 z# n
  14.     u16 width;          //LCD宽度
    * S  o; r# ?& A+ F1 K! q1 ]
  15.     u16 height;         //LCD高度
    & ~) _# d4 @2 l3 F+ G) G
  16.     u32 pixsize;        //每个像素所占字节数
    ! s% b! D# L4 Q  P- e2 r7 W$ Z6 h
  17. }_ltdc_dev;
    ! N2 f# O9 T) P4 N

  18. 2 @# x' B* N  T
  19. _ltdc_dev lcdltdc;                //管理LCD LTDC的重要参数0 Y; q8 j+ T$ N/ O' ?7 f1 r

  20. - i2 S# T. ]6 D3 H* P
  21. //LTDC填充矩形,DMA2D填充
    / s  X' b$ P* p
  22. //(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)   # b  t; D3 L  Z, {) M; Z/ S
  23. //注意:sx,ex,不能大于lcddev.width-1;sy,ey,不能大于lcddev.height-1!!!- t, N7 p' R) l; x5 P
  24. //color:要填充的颜色" z4 s" [6 O+ H
  25. void LTDC_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u32 color). N; x/ L, _. [5 P& p
  26. {
    8 \9 U4 H. d2 f
  27.     u32 psx,psy,pex,pey;                        //以LCD面板为基准的坐标系,不随横竖屏变化而变化2 P% @- Q# L6 n# w' R
  28.     u32 timeout=0; . @7 u& g6 B/ R# ^
  29.     u16 offline;- z  j- n+ _2 A! P
  30.     u32 addr;
    ( O% h# V, u7 O4 O: [' y  H8 |- X7 J
  31.     //坐标系转换! q# T: T  c3 n) s7 ?
  32.     if(lcdltdc.dir)                             //横屏; ~0 Z" e: F& d) x* l* A2 p- v
  33.     {
    8 Y0 F5 t3 u# u. a6 i( |- Q
  34.         psx=sx;psy=sy;
    . A1 V2 R$ I2 Z, {
  35.         pex=ex;pey=ey;
    . e  V7 E: v' v  N* ?! H3 C
  36.     }else                                       //竖屏
    , J& R' [1 j- ?1 [5 ~
  37.     {( t* Y- @# ~1 f6 W& z
  38.         psx=sy;psy=lcdltdc.pheight-ex-1;# `9 U" A$ J+ e' T3 G' f
  39.         pex=ey;pey=lcdltdc.pheight-sx-1;
    3 y) {: f9 z% }! l# K2 W
  40.     }
      \7 E8 l  u9 a" V% F$ X
  41.     offline=lcdltdc.pwidth-(pex-psx+1);
    8 y2 U9 i0 X% |6 U- k9 c4 [. Y
  42.     addr=((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*psy+psx));
    , {; I9 ]. m* P3 ^  ~' s! M
  43.     RCC->AHB1ENR|=1<<23;                        //使能DM2D时钟& z4 M1 y  f; V" o* T9 G5 |
  44.     DMA2D->CR=3<<16;                            //寄存器到存储器模式2 i4 W! T, F5 Q3 H2 h8 T
  45.     DMA2D->OPFCCR=LCD_PIXFORMAT;                //设置颜色格式
    " d5 |% @& r3 E6 m/ J5 u: u
  46.     DMA2D->OOR=offline;                         //设置行偏移
    ; y7 l. S% [3 t9 Z! t. S& Z4 v7 d
  47.     DMA2D->CR&=~(1<<0);                         //先停止DMA2D
    0 }  r3 j; K5 K+ k9 k& N
  48.     DMA2D->OMAR=addr;                           //输出存储器地址
    # |  d% ?" y4 P7 P7 z# n- c
  49.     DMA2D->NLR=(pey-psy+1)|((pex-psx+1)<<16);   //设定行数寄存器
      z$ ]- E$ i4 `
  50.     DMA2D->OCOLR=color;                         //设定输出颜色寄存器
    8 i; i% z, N( p3 r
  51.     DMA2D->CR|=1<<0;                            //启动DMA2D& r/ y# y# B8 @& I0 r; q
  52.     while((DMA2D->ISR&(1<<1))==0)               //等待传输完成
    & i* z( o& _5 U* Z# R
  53.     {
    + _& m' q' \' [  s5 E
  54.         timeout++;
    , y) m& C8 f: O7 A; w
  55.         if(timeout>0X1FFFFF)break;              //超时退出0 O# S- `& ^. M: V' a
  56.     }  
    3 n2 j+ @# E4 K! A" Y
  57.     DMA2D->IFCR|=1<<1;                          //清除传输完成标志* g& M' Y" ]  H# p. u/ Z/ U9 o% m
  58. }& G0 R; t. ?8 E) A5 d* n4 K6 g! y

  59. ) l& B. C7 x! u+ W
  60. //LCD清屏
    . N$ h6 x9 t& q
  61. //color:颜色值  r" \9 x/ i1 z4 }# s
  62. void LTDC_Clear(u32 color)
    8 `$ ~, i$ R5 {3 r
  63. {2 n- t" f1 w5 w0 j, o* G/ c2 K6 s: b
  64.     LTDC_Fill(0,0,lcdltdc.width-1,lcdltdc.height-1,color);, V( ~3 |/ `( H6 K5 \4 u
  65. }
    ; r: K. ~6 K' \- m- P
  66. 4 T# x0 t% @( e- P  ^
  67. 5 P3 N4 U4 X( _/ S* U4 p( {4 ~! u
复制代码

. O) Z% K- y- L7 B4 B4 S" T
4 X! |+ U# k/ M
)0J3WVNZQ8DQ6O089(M6FJW.png
收藏 评论0 发布时间:2021-12-13 08:50

举报

0个回答

所属标签

相似技术帖

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