请选择 进入手机版 | 继续访问电脑版

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

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

[复制链接]
STMCU小助手 发布时间:2021-12-13 08:50
基础知识简介; V( v7 a) U; I
RGBLCD

. a/ Q- M8 X" G+ \5 J1.RGBLCD的信号
9 K  v) i" C  {) E+ E6 h$ G% g
20210720093227878.png

9 {* e; r% E4 x8 D
. t. Z+ ^; X3 D1 n1 y& F一般的 RGB 屏有 24 根颜色数据线(RGB 各站 8 根,即RGB888 格式),这样可以表示最多 1600W 色,DE、VS、HS 和 DCLK,用于控制数据传输。( V+ b- c5 j/ @8 f: [* n( p
* d1 c2 G& M6 u0 U9 M# |- n1 w9 y9 k
2.RGBLCD驱动模式

4 Z) O5 Z, k" u+ r/ |- W其驱动模式主要分为两种) W6 X) Z$ a; z' E% V/ m( |3 k8 B
6 }7 L2 F8 w6 ^' O1 |/ P( x
      DE模式2 N) ^# k6 r$ b3 \$ D; E# E1 K
      DE 模式使用 DE 信号来确定有效数据,DE 为高/低时,数据有效  i: N* c: v' _, p4 q* e0 C
      HV模式7 g( f3 ?) i$ s( T2 y& t4 |" G7 X
      HV模式需要行同步和列同步,来表示扫描的行和列& ^( d: M2 S0 X  m! k0 Z/ K1 `, P

; K/ c( E6 M0 N' n5 t9 U( Z. @LTDC0 ^, y0 j- g' N0 [4 N
STM32F767xx 系列芯片都带有 TFT LCD 控制器,即 LTDC,通过这个 LTDC,STM32F767可以直接外接 RGBLCD 屏,实现液晶驱动。
2 g' U* g+ W: j& [  v4 _. T. h: T
5 A! @9 t( c$ b1.信号线
' f" g3 x% K& x6 GSTM32F767 核心板板载的 LCD 接口引出为了,节省 IO,并提高图片显示速度,使用 RGB565 颜色格式,这样只需要 16 个 IO 口,当使用 RGB565 格式的时候,LCD 面板的数据线,必须连接到 LTDC 数据线的 MSB
6 p; s/ b( r3 {0 p+ ^
6 q0 l- A7 P# k: _+ @! S
20210720100712790.png

; Z" S% h  y6 n! d4 R$ N9 W/ z  h8 T6 n0 ^- O# P
2.图像处理单元2 Q/ ^4 A! U$ N
 先从 AHB 接口获取显存中的图像数据,然后经过层 FIFO(有 2 个,对应 2 个层)缓存,每个层 FIFO 具有 64*32 位存储深度,然后经过像素格式转换器(PFC),把从层的所选输入像素格式转换为 ARGB8888 格式,再通过混合单元,把两层数据合并,混合得到单层要显示的数据,最后经过抖动单元处理(可选)后,输出给 LCD 显示。
' K: b0 ~; R4 T! P 混合单元首先将第一层与背景层进行混合,随后,第二层与第一层和第二层的混合颜色结果再次混合,完成混合后,送给 LCD显示。
7 [4 |0 u% j) M  o7 R
- k: o. s3 H: b0 Q7 Q4 ]
20210720102457112.png
  ^" F" P6 Q) U9 B# ]

' A3 K0 r) Z+ F, U4 c: ]9 Y, R/ w3.AHB 接口  a1 X) P) r6 l# S
 由于 LTDC 驱动 RGBLCD 的时候,需要有很多内存来做显存,比如一个 800480 的屏幕,按一般的 16 位 RGB565 模式,一个像素需要 2 个字节的内存,总共需要:800480*2=768K 字节内存,STM32 内部是没有这么多内存的,所以必须借助外部 SDRAM,而 SDRAM 是挂在AHB 总线上的,LTDC 的 AHB 接口,就是用来将显存数据,从 SDRAM 存储器传输到 FIFO 里面。9 ]4 F- N$ v: n. p* _

2 Q9 C* L# l2 E3 @2 Z4.LTDC相关寄存器及使用方法
9 x8 \3 t2 O3 E8 w
LTDC 的各种配置寄存器以及状态寄存器,用于控制整个 LTDC 的工作参数,
& z% t- |) F( c" F$ R5 H# m主要有:各信号的有效电平、垂直/水平同步时间参数、像素格式、数据使能等等。# b" o; l; h" L: a; \& Q
如果 RGBLCD 使用的是 DE 模式,需要设置如下参数,然后 LTDC会根据这些设置,自动控制 DE 信号。+ p3 Z2 K# |" X% k1 H

! V7 K0 [, p  H  F1 ~- ~LTCD全局控制寄存器 LTCD_GCR
& {" Q! V4 S5 \/ f8 y: N2 \

/ K$ l$ w! a( h
20210720104228854.png
2 b, v: q& i2 i0 b8 Y
; h* {  F( V# I8 @! o
]V@HJS%I_Y[%1XLYT61%0@2.png
" K! K( n; n: d9 Y6 J; D2 Q
8 M- C5 r9 K5 a% N# P  N
LTCD同步大小寄存器 LTDC_SSCR" c9 p0 F& y+ J* {: D
该寄存器用于设置垂直同步高度(VSH)和水平同步宽度(HSW)1 B% t/ J0 E! {, E# S

' H! x0 X& d  R, g* ?3 I! [6 z
20210720104959506.png
- S, H2 u3 v0 Q( N# v: ?, d
7 c4 \! Y/ \9 o/ R4 j+ |
0PRMT7%Y[QF2O{1W`AQ82~7.png

4 Z$ O1 M* o: ?0 Y; ]$ H4 @" H5 G0 u: w
3 @& T2 |! L( X- J8 W
LTDC有效宽度配置寄存器 LTDC_AWCR
/ P9 m+ K! w$ W" ?这里所说的有效高度和有效宽度,是指 LCD 面板的宽度和高度,构成分辨率: t/ H: Z8 L0 ]/ j
! B1 j9 h3 o8 `. f4 u6 I
20210720110024135.png

. v' b+ c4 I: `4 l$ D, I& Z
# y) r& i* f6 i4 {7 N6 a5 H' \
[AREI`HGZ@RRR{J@MJC8W]8.png
- L( b$ g! i9 f+ e1 h2 |' `( e$ o
* L% ~. W( f& X- s( o% T6 ]% Z
     
  w+ N, Q# O4 P+ N0 GLTDC 总宽度配置寄存器 LTDC_TWCR
2 g& i) b. m' G0 E
2 X  _) o" p  Z) e- c  z9 v" s
20210720110931326.png

0 x  z0 q! w+ B1 d/ h0 P$ I1 F0 u; Z; c! |
O6G8SGZNHK4ZYO{)JN[]USW.png
5 c5 ~1 w4 S* _  ~5 [0 j/ ^

0 e" m! E5 L/ \6 }* s      
/ q/ H1 A+ q( H" K" w) fLTDC 背景色配置寄存器 LTDC_BCCR6 n# i8 I. S7 `
该寄存器定义背景层的颜色(RGB888),通过低 24 位配置,我们一般设置为全 0 即可。
, b# X$ c" u' I; \& W& x
3 G4 c, }0 d2 G) o! Q. }8 }9 Y) r: R1 o! K* W  a/ |0 c
20210720111141846.png
! f2 {) ]! F# [/ V

. N6 b, j6 q( {. k1 L3 X/ @, [, v% FLTDC当前位置状态寄存器 LTDC_CPSR
8 Z" M. q$ o3 ~# I$ Z- I3 N5 p+ m5 m" _& n+ A: q6 a$ u0 j
a3355e745c2c73657ef826bf1a8f42f5.png

4 i1 y1 {4 v/ R! Z  }" Q0 X
  V1 b0 q9 ?. R0 m. ECXPOS[31~16]:返回当前X坐标位置8 ]5 B' {, L% g
CYPOS[15~0]:返回当前Y坐标位置
& I. c3 v# E6 L
3 t8 g. u5 |8 I4 q8 zLTDC当前显示状态寄存器 LTDC_CDSR
6 k+ n, e8 l) r3 W. i& Y8 x5 G& p此寄存器返回由 HSYNC、VSYNC 和水平/垂直 DE 信号控制的当前显示阶段的状态
7 A/ O  M5 ]6 o. r# ^1 q: Y* ~  @# {$ w$ Z
c1e72a8f7ff1155cd5391d05ba83e42d.png

3 @+ p0 p" l1 S8 m: Z( _) O' j
1 G) t* i. ^- S1 o% E位 31:24 保留,必须保持复位值
5 A- }0 H7 `9 h; r& X位 3 HSYNCS:水平同步显示状态 (Horizontal Synchronization display Status), b5 H1 f, |% b9 \- S/ C
0:低电平有效
5 T$ |0 y4 |" s' r8 ~7 `1:高电平有效1 g+ O; A1 G. Z1 I
位 2 VSYNCS:垂直同步显示状态 (Vertical Synchronization display Status)
! U4 o3 p& _" d2 C( _! ~0:低电平有效0 A3 H3 {! ]+ c5 ^" m/ o) \: E
1:高电平有效) g+ w* Z: ^( b4 W
位 1 HDES:水平数据使能显示状态 (Horizontal Data Enable display Status)8 a. U' H. g0 ~# k8 p# b
0:低电平有效; M) I0 Z% h3 F' x/ G
1:高电平有效6 B* t) v& m/ M0 ]7 G& p) o/ x# p
位 0 VDES:垂直数据使能显示状态 (Vertical Data Enable display Status)
0 i) F+ c! Z4 |/ q/ R# W' q0:低电平有效
+ Z& s- }( q0 L9 d1:高电平有效1 V9 I6 j: W2 V+ I' ?4 _. k: A4 c
/ T' O) t- H) f/ g" \" H8 @0 E
LTDC 的层颜色帧缓冲区地址寄存器 LTDC_LxCFBAR(x=1/2)
- X& o3 J% B( \+ n/ |% x% I该寄存器用来定义一层显存的起始地址。STM32F767 的 LTDC 支持 2 个层,所以总共有两个寄存器,分别设置层 1 和层 2 的显存起始地址。
1 z" C9 G6 Z3 c8 i' v5 J6 Z/ J' H% J& j1 L0 ?% c
20210720111336311.png

, o; C2 r$ O& Y8 V7 M' N5 c! P: R
5 b' T7 l/ K% Y: u: lLTDC 的层像素格式配置寄存器 LTDC_LxPFCR(x=1/2)3 V6 j4 X2 `4 h
该寄存器只有最低 3 位有效,用于设置层颜色的像素格式,一般使用 RGB565 格式,即该寄存器设置为:010 即可。" g% q/ f6 q- r1 c9 Z* s( W4 q

4 G* [* z, M) G  K6 T, E8 I
STQ}OUE_D7Z(33OZ_E@73.png

4 c: ~9 j: o2 U9 s+ U4 D
. u/ Y0 I5 O% g6 E6 V$ c2 ^9 ~$ G: ?. v
      
! e: \, s7 D5 WLTDC 的层恒定 Alpha 配置寄存器 LTDC_LxCACR(x=1/2)5 j( X( B; @6 {
该寄存器低 8 位(CONSTA)有效,这些位配置混合时使用的恒定 Alpha。恒定 Alpha 由硬件实现 255 分频。
& O, M3 u" m' |2 Z$ e' W* U8 @% B1 S" \4 \" |  H8 k5 Y1 w
20210720112235516.png

) w6 C4 L+ r' w. w0 J9 e8 A2 k& J7 d" \* }4 ~! t/ m
LTDC 的层默认颜色配置寄存器 LTDC_LxDCCR(x=1/2)

2 I. D9 M4 o) i$ h6 u该寄存器定义采用 ARGB8888 格式的层的默认颜色。默认颜色在定义的层窗口外使用或在层禁止时使用。一般情况下,用不到,所以该寄存器一般设置为 0 即可。) j6 _# e% i+ ?$ m' C) L! c
$ E* ]. o2 J% M9 ]4 e
20210720112604555.png

: Q# d( O7 a0 m  a- y; t# j7 i8 T+ w3 ?9 u. x
LTDC 层混合系数配置寄存器:LTDC_LxBFCR(x=1/2)
2 o, k' F) j) k! v5 B* |- o该寄存器用于定义混合系数: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即可。2 C! l- G; Z7 O- A9 T+ v, p5 x
通用的混合公式为:BC=BF1C+BF2Cs
( E7 e: x8 X1 I1 a2 w9 E其中:BC=混合后的颜色;BF1=混合系数 1;C=当前层颜色,即我们写入层显存的颜色值;BF2=混合系数 2;Cs=底层混合后的颜色,对于层 1 来说,Cs=背景层的颜色,对于层 2 来说,Cs=背景层和层 1 混合后的颜色。
5 M9 l/ |8 U1 s- [* d5 r; g, W- ?+ N( D+ ?0 r0 M0 o* L
2021072011293763.png
0 b# n) W; y- B
3 \: t2 U5 C, z8 _0 ^( _6 c
LTDC 的层窗口水平位置配置寄存器 LTDC_LxWHPCR(x=1/2)
6 H5 a6 f* z' H' m) y) x0 K
该寄存器定义第 1 层或第 2 层窗口的水平位置,第一个和最后一个像素
9 ~- i1 B0 ?6 H1 B1 }
6 W3 k/ l7 b5 E& |
20210720113448290.png
2 Z# ]9 G+ O" O! s. x1 ^# P1 v8 v4 O
+ ?9 S) [+ }9 d2 K$ f8 y6 ]! z3 J" H
WHSTPOS:窗口水平起始位置,定义层窗口的一行的第一个可见像素,* ^+ G# r. g" g6 b+ ]: \
WHSPPOS:窗口水平停止位置,定义层窗口的一行的最后一个可见像素
( g$ B; G' }4 W, e0 P% x# f* f4 x
3 o5 E$ R# I9 v' N4 oLTDC 的层窗口垂直位置配置寄存器 LTDC_LxWVPCR(x=1/2)

6 h/ X) i" D7 k该寄存器定义第 1 层或第 2 层窗口的垂直位置(第一行或最后一行)
3 L) x; [8 U5 o7 Z0 x: @! W" U& F8 l: N" q0 K& @+ l" y' {
20210720133247145.png
# [  o5 |- X1 y# b7 f! z* X
; t% Q& }1 o+ ]4 z4 e: r8 `
WVSTPOS:窗口垂直起始位置,定义层窗口的第一个可见行。
+ |4 J7 t0 o3 O: YWVSPPOS:窗口垂直停止位置,定义层窗口的最后一个可见行。
! p$ }* I" q" R; N
% M2 p0 c$ b9 ULTDC 的层颜色帧缓冲区长度寄存器 LTDC_LxCFBLR(x=1/2)) |5 L6 D5 _/ L9 c& b8 X
该寄存器定义颜色帧缓冲区的行长和行间距。
5 E3 I- s) I+ ?6 P0 S1 H
2 r5 ^4 ]/ t( n. w2 D* f$ V' j9 j
20210720133802157.png
/ [7 J$ R! ^: }" j, _

( k  P; P# q# Q" `5 W# lCFBLL:这些位定义一行像素的长度(以字节为单位)+3。
5 S( ^5 f2 U2 ?行长的计算方法为:有效宽度 * 每像素的字节数 + 3。
2 d2 z7 x! P% y1 f' d- N6 H比如,LCD 面板的分辨率为 800480,有效宽度为 800,采用 RGB565 格式,那么 CFBLL 需要设置为:8002+3=1603。
; c& G# L) C" w( L; B. m6 LCFBP:这些位定义从像素某行的起始处到下一行的起始处的增量(以字节为单位)。
3 }+ [5 F0 U$ {$ H  D- d这个设置,其实同样是一行像素的长度,对于 800480 的 LCD 面板,RGB565 格式,设置 CFBP 为:8002=1600 即可。
, U7 G0 |$ @0 X; ~  q, l) V, @
9 P6 ]! g1 g* `  tLTDC 的层颜色帧缓冲区行数寄存器 LTDC_LxCFBLNR(x=1/2)- i/ ~# M9 y( a3 q+ m
该寄存器定义颜色帧缓冲区中的行数。4 X4 y3 l+ g7 C4 L6 o' I* G
比如,LCD 面板的分辨率为 800*480,那么帧缓冲区的行数为 480 行,则设置 CFBLNBR=480 即可
$ B- D, @8 m& @' |7 C" |) H1 B+ I3 j& j, _1 d. N2 M
20210720133424485.png

2 e$ Z% m0 N0 |) B* N% c
1 w  K+ [/ ^) j8 t7 t& t5.时钟域
4 Q  H  \  w. `" ]  U/ t4 nLTDC 有三个时钟域:AHB 时钟域(HCLK)、APB2 时钟域(PCLK2)和像素时钟域(LCD_CLK),! {* M3 W* P4 {& X
AHB 时钟域用于驱动 AHB 接口,读取存储器的数据到 FIFO 里面;& ~* T# g' ]$ z0 ?- Q) `9 n8 K+ I
APB2 时钟域用于配置寄存器;6 R0 d' c- R+ p" B, f: R& d& B3 z' j
LCD_CLK像素时钟域则用于生成 LCD 接口信号,LCD_CLK 的输出应按照 LCD 面板要求进行配置。6 M/ h, g) v0 [4 z4 \

5 B# I+ s' ~$ ?" p( s# \DMA2D
* F: b9 m2 ^6 _8 a) J9 v1 A为了提高STM32F767的图像处理能力,ST公司设计了一个专用于图像处理的专业 DMA,通过 DMA2D 对图像进行填充和搬运,可以完全不用CPU 干预,从而提高效率,减轻 CPU 负担。* U$ v! M4 J, t. {/ ~6 d, C$ h( S
  K' ^9 r2 s! Q) K: H
它可以执行下列操作:) r% l" T% N4 U, h0 Y
用特定颜色填充目标图像的一部分或全部(可用于快速单色填充)
8 q9 g  x; J4 A; J6 R将源图像的一部分(或全部)复制到目标图像的一部分(或全部)中(可用于快速图像填充)
5 _! {. L5 }0 I, T! f0 h通过像素格式转换将源图像的一部分(或全部)复制到目标图像的一部分(或全部)中) f8 d9 j+ [* E( H2 w5 u
将像素格式不同的两个源图像部分和/ 或全部混合,再将结果复制到颜色格式不同的部分或整个目标图像中0 |( j+ T7 i" P, n  s: ?
7 c' D$ \* S" l6 j1 n1 O- |
1 e8 C& x2 m% i. g& E0 X
DMA2D 有四种工作模式,通过 DMA2D_CR 寄存器的 MODE[1:0]位选择工作模式:
$ Y% j& D0 h: J% F! s1, 寄存器到存储器- M/ Z% j, Q1 _: Z
2, 存储器到存储器
! ?  Q7 E  m" I/ d6 a* o3, 存储器到存储器并执行 PFC
9 n# I; A4 b& K# P6 e& E/ [% U4, 存储器到存储器并执行 PFC 和混合
1 ?) K3 }7 V) z3 m6 ]/ @1 u5 ~! X
, w* \6 n8 V8 g( @* u# ?: K
寄存器到储存器% t1 b! T3 N. j! O! y
寄存器到存储器模式用于以预定义颜色填充用户自定义区域,也就是可以实现快速的单色
! `4 b+ _9 W% m$ K( ]) o填充显示,比如清屏操作。
9 f2 r! v$ C' L7 b在该模式下:颜色格式在 DMA2D_OPFCCR 中设置,DMA2D 不从任何源获取数据,它只; O: _1 {5 B# X* g, |( U# g
是将 DMA2D_OCOLR 寄存器中定义的颜色写入通过 DMA2D_OMA 寻址以及 DMA2D_NLR 和( v& i2 I' h8 l; V  S2 |  d# d& g
DMA2D_OOR 定义的区域- z6 S* b2 t2 S; ], U/ `
7 A2 l/ w& g9 g

2 v4 K2 X4 k, z  A储存器到储存器$ w. G$ P+ F  N' ^! G8 Y
该模式下,DMA2D 不执行任何图形数据转换。前景层输入 FIFO 充当缓冲区,数据从
8 f; D9 P9 `! D; Y  @1 C) ?* ?DMA2D_FGMAR 中定义的源存储单元传输到 DMA2D_OMAR 寻址的目标存储单元,可用于快5 x2 b2 g. J/ G
速图像填充。DMA2D_FGPFCCR 寄存器的 CM[3:0]位中编程的颜色模式决定输入和输出的每像
% d. y) o- D: Q' l素位数。对于要传输的区域大小,源区域大小由 DMA2D_NLR 和 DMA2D_FGOR 寄存器定义,: L3 D5 h7 x0 x5 D' [% w
目标区域大小则由 DMA2D_NLR 和 DMA2D_OOR 寄存器定义。. G( T$ U. t) }3 Y

% M+ x+ |- c8 t& [: l
6 b: c7 c4 ?. L$ m( `) E以上两个工作模式,LTDC 在层帧缓存里面的开窗关系都一样的,经过如下三个寄存器的配置,就可以确定窗口的显示位置和大小。1 G1 r; q. I" N- a$ h% d3 g
(1). 窗口显示区域的显存首地址由 DMA2D_OMAR 寄存器指定,
6 Y/ ]4 }" Q4 a(2).窗口宽度和高度由DMA2D_NRL 寄存器的 PL 和 NL 指定/ J- {8 N! t$ y6 J* ^5 D% o" p
(3).行偏移(确定下一行的起始地址)由 DMA2D_OOR寄存器指定,4 z3 _. t; c) w1 T) X: R, @

: J7 ~7 \& L6 e$ A2 `
20210720170136697.png
; ^, |! I% H& F5 D& p' ~
* q3 A- v7 f6 B9 T( ^
7 H, V" T$ T0 ^. L
在寄存器到存储器模式下,在开窗完成后,DMA2D 可以将 DMA2D_OCOLR 指定的颜色,
. r  M4 ~9 l' g8 X& P# L自动填充到开窗区域,完成单色填充。
0 s/ A% ]+ E& e
8 I1 n0 l9 H0 G& }& N% P0 c' U; |8 E. d- o% L8 G. ]
在存储器到存储器模式下,需要完成两个开窗:前景层和显示层,完成配置后,图像数据从前景层拷贝到显示层(仅限窗口范围内),从而显示到 LCD 上面。显示层的开窗如上图所示,前景层也和上图类似,只是 DMA2D_OMAR 寄存器变成了DMA2D_FGMAR,DMA2D_OOR寄存器变成了DMA2D_FGOR,DMA2D_NRL则两个层共用,然后就可以完成对前景层的开窗,确定好两个窗口后,DMA2D 就将前景层窗口内的数据,拷贝到显示层窗口,完成快速图像填充。( q1 U+ ?( x% g; @  {2 U* i4 f  L

3 F3 N5 ~6 [8 c5 C: k. i* v- z( m% N$ X  R- B! e: g6 i
DMA2D相关寄存器& V0 U4 K# ]. m3 D9 y2 z
DMA2D控制寄存器 DMA2D_CR. A5 r- a% g5 W: h
该寄存器,主要是MODE 和 START 这两个设置
- R" y) |$ n9 Y9 O( w. s9 K# f2 c. ?/ y- @  d! T0 u4 K$ G2 ]
20210720172154901.png
+ v) T* f8 H2 Y( v+ a' y! ?6 [

8 _3 |" K& ?0 [( y" c, |MODE:表示 DMA2D 的工作模式,
, T2 b( t7 {% y2 S00:存储器到存储器模式;01:存储器到存储器模式并执行 PFC;& d) a7 P' A. l& b% b# s
10:存储器到存储器并执行混合;11,寄存器到存储器模式;' X" I  |! ^* D1 b. V* s9 ^
START:该位控制 DMA2D 的启动,在配置完成后,设置该位为 1,启动 DMA2D 传输。
( T: u4 P5 D& ]% @: S5 \3 Q4 p
' h6 o: o9 j0 j0 ~! ZDMA2D输出 PFC 控制寄存器 DMA2D_OPFCCR
& O, i% H5 Q+ s' ]1 R6 y该寄存器用于设置寄存器到存储器模式下的颜色格式* D* U" E5 g! g) a- t

5 x, C4 {+ u  T; o$ B( g/ x
20210720172538112.png

/ o! u2 H/ M- s) g9 t: @2 Y. o- s  W3 v3 O5 |& o
只有最低 3 位有效(CM[2:0]),表示的颜色格式有:
/ P( e* m" _! t; S# H! X  P9 U/ _000,ARGB8888;001:RGB888;010:RGB565;
: ~$ y6 f" H- C/ O. d) F( P011:ARGB1555;100:ARGB1444。. q2 o9 _5 [1 H& D
我们一般使用的是 RGB565 格式,所以设置 CM[2:0]=010 即可。
; ^, q0 d  [* J! x9 ~: ^- z  O, i9 V
- Q- Q- p- U5 ^" z; u& D. @DMA2D前景层 PFC 控制寄存器:DMA2D_FGPFCCR
! O" o8 N& K( |
+ }- C  H* K6 I# _: q3 W) v
20210720173213773.png
5 x% S- n5 e3 ~& q  J
6 h/ K2 ^5 q4 Q  z4 ]/ {' u3 j
该寄存器,低 4 位:CM[3:0],用于设置存储器到存储器模式下的颜色格式,这四个位表示的颜色格式为:
+ O$ G6 F# @" D% k6 I0000:ARGB8888;0001:RGB888;0010:RGB565;
2 O( _3 {* o+ n0011:ARGB1555;0100:ARGB4444;0101:L8;
7 Z8 l; M+ A# Z, M- ^5 i. ], |0110:AL44;0111:AL88;1000:L4;1001:A8;1010:A4;9 y; e0 B+ U( M( M
我们一般使用 RGB565 格式,所以设置 CM[3:0]=0010 即可。
0 E9 \2 h9 J& H% l
1 z  A/ K8 F4 P0 ODMA2D输出偏移寄存器 DMA2D_OOR' t) i6 k0 b3 R7 j

. D5 X" S0 y1 J
20210720174740982.png
$ k" Y5 d/ V5 v; u
该寄存器仅最低 14 位有效(LO[13:0]),用于设置输出行偏移,作用于显示层,以像素为+ a2 s: [& d: ]  P6 [2 M0 D6 m
单位表示。此值用于生成地址。行偏移将添加到各行末尾,用于确定下一行的起始地址。
4 O0 G# p/ Y" l/ H9 W- }' o# S, D, I同样的,还有前景层偏移寄存器:DMA2D_FGOR,该寄存器同 DMA2D_OOR 一样,也是% S& N$ X( K, e0 s
低 14 位有效,用于控制前景层的行偏移,也是用于生成地址,添加到各行末尾,从而确定下一
; B8 D7 a6 H# G- s, M行的起始地址。
, B9 [) _2 @) F* E$ t* u7 u
' X1 [& G% ~+ B' F/ m/ \DMA2D输出存储器地址寄存器 DMA2D_OMAR& ?  M1 e) l2 `3 ]) {5 g. Y( I) F

6 _7 {/ N2 X9 ?& _
20210720175051288.png

" W' ]5 ~* A# R- e, w  X3 g  i. e$ A7 H" _* N5 A
该寄存器设置由 MA[31:0]设置输出存储器地址,也就是输出 FIFO 所存储的数据地址,该地址需要根据开窗的起始坐标来进行设置。以 800480 的 LCD 屏为例,行长度为 800 像素,假定帧缓存数组为:ltdc_framebuf,我们设置窗口的起始地址为:sx(<800),sy(<480),颜色格式为 RGB565,每个像素 2 个字节,那么 MA 的设置值应该为:1 C/ G7 a) x. U( g4 E
*MA[31:0]= framebuf+2(800sy+sx)**& y  S! d5 h' |0 y4 D% q# [6 v
同样的,还有前景层偏移寄存器:DMA2D_ FGMAR,该寄存器同 DMA2D_OMAR 一样,9 B: P) s+ y* Q4 ?
不过是用于控制前景层的存储器地址,计算方法同 DMA2D_OMAR。  s; F% b; {" h) v& p- D

: J0 ?+ z' E% a- N6 z: rDMA2D行数寄存器 DMA2D_NLR
# Z9 q; K; r( z, M! a
3 a! B9 o# s8 E
20210720180044872.png
6 A/ J1 m5 G) H+ {6 e
该寄存器用于控制每行的像素和行数,该寄存器的设置对前景层和显示层均有效,通过该寄存器的配置,就可以设置开窗的大小。其中:
9 O: r2 @2 w5 ~9 r7 _8 sNL[15: 0]:设置待传输区域的行数,用于确定窗口的高度。
  T" f, ]% z) k3 ]( rPL[13: 0]:设置待传输区域的每行像素数,用于确定窗口的宽度- A* y* h" e4 N8 ~6 ~) F/ _
- I* Q1 U+ {/ |1 P# D2 f1 _' Y
DMA2D输出颜色寄存器 DMA2D_OCOLR
% I6 Y3 j6 Q7 F: W6 D! h; g9 `2 l
( q: Z# |7 `4 ]% ]* E
20210720180520678.png

0 k: z4 O1 W5 B该寄存器用于配置在寄存器到存储器模式下,填充时所用的颜色值,该寄存器是一个 32位寄存器,可以支持 ARGB8888 格式,也可以支持 RGB565 格式。我们一般使用 RGB565 格式,比如要填充红色,那么直接设置 DMA2D_OCOLR=0XF800 就可以了。
' n7 Y& G- X! O. x6 o" b0 n
& A0 b) `' u8 V1 o7 M8 ZDMA2D中断状态寄存器 DMA2D_ISR+ v; A! V4 f. e
# P0 I9 n8 \7 S
2021072018063162.png

2 _' |" q1 s) o+ y5 G/ o0 ~& o& k4 {, G1 h( ~- n8 ]
该寄存器表示了 DMA2D 的各种状态标识
% D' t4 ~: \) Y' {: }# A9 ATCIF 位,表示 DMA2D 的传输完成中断标志。当 DMA2D 传输操作完成(仅限数据传输)时此位置 1,表示可以开始下一次 DMA2D 传输了
1 x6 r1 k2 h# MDMA2D 中断标志清零寄存器:DMA2D_IFCR,用于清除 DMA2D_ISR 寄存器对应位的标志。通过向该寄存器的第 1 位(CTCIF)写 1,可以用于清除 DMA2D_ISR 寄存器的 TCIF 位标志。
# ]8 Q- }) _' K7 b( z
  T! j% o- p% p1 Y! N: [1 Z2 l6 O) }+ A& P
LTDC具体使用步骤
; `* f; }- Q# z3 l: |* t9 a: T1.使能 LTDC 时钟,并配置 LTDC 相关的 IO 及其时钟使能。" k' l" b; U) B9 q# `# m7 l" x
使用 LTDC,当然首先得开启其时钟。
* g# Q: C6 }  s2 ?8 F然后需要把 LCD_R/G/B 数据线、LCD_HSYNC和 LCD_VSYNC 等相关 IO 口,全部配置为复用输出,并使能各 IO 组的时钟。0 |/ [0 z, u' r, h$ }

8 I- N9 t4 j  q3 A8 w- O
  1. //LTDC底层IO初始化和时钟使能
    7 x8 w/ g1 L8 t$ l6 [. y
  2. //此函数会被HAL_LTDC_Init()调用
    2 J: V9 h5 k* h3 @
  3. //hltdc:LTDC句柄
    " C8 d, K$ K3 G8 l
  4. void HAL_LTDC_MspInit(LTDC_HandleTypeDef* hltdc)
    3 ?! i5 P: ]5 e* g5 e& W, g
  5. {
    6 Y9 \9 G5 D" b: ?& c. p) d1 v
  6.     GPIO_InitTypeDef GPIO_Initure;6 ^+ I/ |- h& x2 Z
  7. 4 `+ W7 m2 i! n5 O
  8.     __HAL_RCC_LTDC_CLK_ENABLE();                //使能LTDC时钟  T# d9 M" [( J7 ^% J' [
  9.     __HAL_RCC_DMA2D_CLK_ENABLE();               //使能DMA2D时钟
    9 f- r& {) I, `: M- F, A
  10.     __HAL_RCC_GPIOB_CLK_ENABLE();               //使能GPIOB时钟
    $ K( {. P1 N) n, @: O6 @0 H
  11.     __HAL_RCC_GPIOF_CLK_ENABLE();               //使能GPIOF时钟( C5 O; ~& e2 T8 n, h4 [# m" D
  12.     __HAL_RCC_GPIOG_CLK_ENABLE();               //使能GPIOG时钟7 s' V, _' y( d2 O/ c
  13.     __HAL_RCC_GPIOH_CLK_ENABLE();               //使能GPIOH时钟" a8 @* o. j; l* ~. r2 I* J' q
  14.     __HAL_RCC_GPIOI_CLK_ENABLE();               //使能GPIOI时钟
    3 X6 T9 f* s0 h

  15. 1 a. f' V7 ^+ ~! t; Q, {
  16.     //初始化PB5,背光引脚
    + G# d+ g, i9 f* k% P% V, z* W
  17.     GPIO_Initure.Pin=GPIO_PIN_5;                //PB5推挽输出,控制背光
    9 s9 w$ E& K# M3 q% k
  18.     GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;      //推挽输出
    6 D& C$ X% e3 E+ g( L2 ~  D
  19.     GPIO_Initure.Pull=GPIO_PULLUP;              //上拉
    % @: c' b9 v. d, w
  20.     GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速3 K. N- p# m  ]5 P8 p
  21.     HAL_GPIO_Init(GPIOB,&GPIO_Initure);
    ) [: h7 c9 W3 {

  22. % j: I1 E  t9 O% B4 }
  23.     //初始化PF10
    - z! P4 L+ o: q% i( u
  24.     GPIO_Initure.Pin=GPIO_PIN_10; 5 u9 a; i. d) [' S4 H
  25.     GPIO_Initure.Mode=GPIO_MODE_AF_PP;          //复用+ |* s' {7 X+ y/ V
  26.     GPIO_Initure.Pull=GPIO_NOPULL;
    7 J! X5 a; U; e* O
  27.     GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速/ O4 g- c* S6 D8 c- e9 C
  28.     GPIO_Initure.Alternate=GPIO_AF14_LTDC;      //复用为LTDC- M) \* |" a. P. D  D
  29.     HAL_GPIO_Init(GPIOF,&GPIO_Initure);: F; k) X# a' P
  30. # K" H$ U- [1 s- z2 F
  31.     //初始化PG6,7,119 d( q9 Q2 E# i. s) w6 s) P
  32.     GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_11;1 `5 q& \5 i4 D, q2 R
  33.     HAL_GPIO_Init(GPIOG,&GPIO_Initure);9 }0 s. N, o5 v( a! v8 r

  34. . T& _" x0 x% L  _1 `
  35.     //初始化PH9,10,11,12,13,14,15
    - u9 _4 E, i0 q9 G6 t$ I/ U
  36.     GPIO_Initure.Pin=GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|\
    4 e& `$ j9 Q0 _; T+ a3 B  t
  37.                      GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;; y8 M. M, ]! r: w9 Z# c4 Q% A
  38.     HAL_GPIO_Init(GPIOH,&GPIO_Initure);
    $ G5 S# u% F! A' x. r; u
  39. " T# R* u' j. i7 I# ?; J' F) n9 }# `; w
  40.     //初始化PI0,1,2,4,5,6,7,9,10
    ; |! Z# p  Q: T+ \$ d4 c" |
  41.     GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|\
    - }% R+ @4 G1 s. y: \
  42.                      GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_9|GPIO_PIN_10;* u* R1 R9 V$ Y0 Z0 H- \
  43.     HAL_GPIO_Init(GPIOI,&GPIO_Initure);
    ; T+ b# G8 Z. {8 L$ \3 M; w( ?
  44. }
复制代码
5 ]- q* d) J8 K) a6 |
2.设置LCD_CLK时钟$ N7 c4 D, p$ [0 |
配置 LCD 的像素时钟,根据 LCD 的面板参数进行设置,LCD_CLK 由 PLLSAI进行配置,配置使用到的 HAL 库函数为:
! V7 i) j, |- j8 J9 w
; I5 E0 {0 J! H2 j! N
  1.         //pllsain:SAI时钟倍频系数N,取值范围:50~432.  
    % l/ x2 _0 x1 q# W( x
  2.         //pllsair:SAI时钟的分频系数R,取值范围:2~74 @3 n# Z4 T/ v4 k9 q: P+ q
  3.         //pllsaidivr:LCD时钟分频系数,取值范围:0~3,对应分频2~16 / C( F- a( B- k! c$ v
  4.         //假设:外部晶振为25M,pllm=25的时候,Fin=1Mhz.
    $ a' r! |5 |( P& ~4 U
  5.         //例如:要得到20M的LTDC时钟,则可以设置:pllsain=400,pllsair=5,pllsaidivr=1
    5 V) Y! \* h) m/ K! o
  6.         //Fdclk=1*396/3/2*2^1=396/12=33Mhz
    ' ]) Q/ _- ]' V/ ?% n7 K/ N
  7.     RCC_PeriphCLKInitTypeDef PeriphClkIniture;2 g9 |2 m  a/ j8 [8 p' l

  8. 6 S1 V9 [. _6 l8 k9 ~' K
  9.     //LTDC输出像素时钟,需要根据自己所使用的LCD数据手册来配置!
    1 F! B/ c9 Y( o. t! k/ A3 O/ Q: {
  10.     PeriphClkIniture.PeriphClockSelection=RCC_PERIPHCLK_LTDC;       //LTDC时钟
    7 D' e! f  d, a, ]+ X) I" P
  11.     PeriphClkIniture.PLLSAI.PLLSAIN=pllsain;$ x# \! i! W1 `7 _3 z
  12.     PeriphClkIniture.PLLSAI.PLLSAIR=pllsair;
    + ?9 i! L/ ^1 y* D6 n8 d
  13.     PeriphClkIniture.PLLSAIDivR=pllsaidivr;
    3 e7 G# r) W2 G: t4 h. p
  14.         HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef *PeriphClkInit)
复制代码

/ F' `7 I  d6 ?: n+ E3.设置RGBLCD相关参数,并使能LTDC2 x7 g* ~8 M* Z9 H
  1. typedef struct
    9 w5 O% F! w" x
  2. {" `/ F3 y) u- a' x& ^0 @& X
  3. uint32_t HSPolarity;                         //水平同步极性
    ) o# J; x1 X( @: b% u- a
  4. uint32_t VSPolarity;                         //垂直同步极性 / t5 C) o% m% m2 O. X$ D/ N
  5. uint32_t DEPolarity;                         //数据使能极性
    , h& }, W; {6 x( a" k  H
  6. uint32_t PCPolarity;                         //像素时钟极性  l0 P! C; T, q& e, N
  7. uint32_t HorizontalSync;                 //水平同步宽度 % q$ N! O; E1 F7 U% X7 q2 `, c
  8. uint32_t VerticalSync;                 //垂直同步高度: |$ M$ z! R4 _
  9. uint32_t AccumulatedHBP;                 //水平同步后沿宽度
    2 u$ k) D; k7 o) E% r) B
  10. uint32_t AccumulatedVBP;                 //垂直同步后沿高度 * `7 c3 a) `9 F( _, v5 j! {' P# S  [
  11. uint32_t AccumulatedActiveW;         //累加有效宽度 2 P3 I& R# @, J( {5 s
  12. uint32_t AccumulatedActiveH;         //累加有效高度. {" Y: X* Q( K
  13. uint32_t TotalWidth;                         //总宽度+ D- R) L; N4 L9 X% d
  14. uint32_t TotalHeigh;                         //总高度- K( T( m* x. ?6 k
  15. LTDC_ColorTypeDef Backcolor;         //屏幕背景层颜色
    5 L4 l% a3 q) J2 g6 g8 g
  16. } LTDC_InitTypeDef;
    8 w( O! s( C2 p7 P0 p3 x6 |

  17. 0 S* e$ |4 j5 G& A0 O
  18. typedef struct
    5 |- K# i9 [$ H  D' C
  19. {" u/ L/ D# d, h# |) F2 v* s: m
  20.   LTDC_TypeDef                *Instance;                /*Instance变量是LTDC_TypeDef结构体指针类型*/7 _# W! P: I1 N, }0 g
  21.   LTDC_InitTypeDef            Init;                     /*用来初始化LTDC的结构体变量*/
    . v5 g) T5 K  {* l
  22.   LTDC_LayerCfgTypeDef        LayerCfg[MAX_LAYER];      /*保存LTDC层配置参数*/
    ! P" q6 \/ f' N
  23.   HAL_LockTypeDef             Lock;                     /*锁状态*/( d9 {# X9 z. a9 e: c- Z
  24.   __IO HAL_LTDC_StateTypeDef  State;                    /*LTDC的状态*/
    - T# H  R3 Y8 \. ~/ a. l/ I
  25.   __IO uint32_t               ErrorCode;                /*错误处理*/
    $ h8 z! A- ?. U* `; _8 u
  26. } LTDC_HandleTypeDef;$ m8 \# k) h' R" y& S  H
  27. $ P+ [: w$ s" `  W( D
  28. LTDC_HandleTypeDef  LTDC_Handler;                                   //LTDC句柄
    " P: v6 [) u6 A* H
  29. . j# Y  m) i3 D! R
  30. LTDC_Handler.Instance=LTDC;; y6 s4 G7 T. b8 P- N6 i
  31. LTDC_Handler.Init.HSPolarity=LTDC_HSPOLARITY_AL;                 //水平同步极性
    4 E# q8 g' w3 a6 G& |  {
  32. LTDC_Handler.Init.VSPolarity=LTDC_VSPOLARITY_AL;                 //垂直同步极性
    3 r; H0 L/ \3 s) i
  33. LTDC_Handler.Init.DEPolarity=LTDC_DEPOLARITY_AL;                 //数据使能极性- U4 }# [' f% b
  34. LTDC_Handler.Init.PCPolarity=LTDC_PCPOLARITY_IPC;                 //像素时钟极性
    ' |3 B' D: E9 f* h
  35. LTDC_Handler.Init.HorizontalSync=10-1;                                         //水平同步宽度* i8 P$ t2 d. K3 Z+ Q: [; t
  36. LTDC_Handler.Init.VerticalSync=2-1;                                         //垂直同步宽度
    + B* c' i  n+ b5 w" C
  37. LTDC_Handler.Init.AccumulatedHBP=10+20-1;                                 //水平同步后沿宽度
    ( C( g# ]. l% Z/ h& L8 D" n9 J: O  l
  38. LTDC_Handler.Init.AccumulatedVBP=2+2-1;                                 //垂直同步后沿高度" C, I- w0 U, Q" U$ |) c
  39. LTDC_Handler.Init.AccumulatedActiveW=10+20+480-1;                 //有效宽度
    & B; ]: W1 P/ [/ `/ K; @' E+ [" u
  40. LTDC_Handler.Init.AccumulatedActiveH=2+2+272-1;                 //有效高度% X3 z) X/ x- g: d/ C
  41. LTDC_Handler.Init.TotalWidth=10+20+480+10-1;                         //总宽度( v5 B2 {8 b1 f# a; r
  42. LTDC_Handler.Init.TotalHeigh=2+2+272+4-1;                                 //总高度9 @+ Q2 L8 O% y. r3 J
  43. LTDC_Handler.Init.Backcolor.Red=0;                                                 //屏幕背景层红色部分. Q1 G3 J" c% E; s3 s$ ]
  44. LTDC_Handler.Init.Backcolor.Green=0;                                         //屏幕背景层绿色部分7 `* o2 a7 B& h% ?. s  M# Y3 R& q
  45. LTDC_Handler.Init.Backcolor.Blue=0;                                         //屏幕背景色蓝色部分, s' N# S0 t+ Q8 @1 V  O' K8 O
  46. HAL_LTDC_Init(<DC_Handler);                                                         //设置 RGBLCD 的相关参数,并使能 LTDC,会调用HAL_LTDC_MspInit
复制代码

/ ?" O; ^1 Q- t# B+ P4.设置 LTDC层参数
2 F, c8 e6 g& h' U* v: A, z2 |
  1. //layerx:层值,0/1.
    0 g5 {: [, N  L+ x8 v- I
  2. //bufaddr:层颜色帧缓存起始地址# q/ s  z. b- M- J
  3. //pixformat:颜色格式.0,ARGB8888;1,RGB888;2,RGB565;3,ARGB1555;4,ARGB4444;5,L8;6;AL44;7;AL88
    5 d" m8 @, K8 P) t3 Z7 Y
  4. //alpha:层颜色Alpha值,0,全透明;255,不透明
    , q' K. k, O4 K0 u4 |
  5. //alpha0:默认颜色Alpha值,0,全透明;255,不透明% J. `* r. y' c* V' n- g0 j8 }9 T
  6. //bfac1:混合系数1,4(100),恒定的Alpha;6(101),像素Alpha*恒定Alpha
    1 I) n2 Q! n' @1 I- S6 y" w
  7. //bfac2:混合系数2,5(101),恒定的Alpha;7(111),像素Alpha*恒定Alpha
    # M4 {9 `; d; Z, h7 l) }
  8. //bkcolor:层默认颜色,32位,低24位有效,RGB888格式2 m4 n4 R$ c% L. ^; g$ \
  9. void LTDC_Layer_Parameter_Config(u8 layerx,u32 bufaddr,u8 pixformat,u8 alpha,u8 alpha0,u8 bfac1,u8 bfac2,u32 bkcolor)
    1 w) M0 {5 ^6 ?4 `+ D
  10. {& n* O& x2 g8 d; v; T  t; f7 m
  11.     LTDC_LayerCfgTypeDef pLayerCfg;
    / i; `, p& r3 h; b; z4 X5 y

  12. - {. r) I. V- P& U# p* C
  13.     pLayerCfg.WindowX0=0;                                   //窗口起始X坐标
    ( l( G8 X, k; g0 V3 a8 x
  14.     pLayerCfg.WindowY0=0;                                   //窗口起始Y坐标1 A0 \6 d5 _/ F8 R4 a" L1 c
  15.     pLayerCfg.WindowX1=lcdltdc.pwidth;                      //窗口终止X坐标
    , n5 H# Y9 O" w, ~. D/ m$ K% z* z1 X
  16.     pLayerCfg.WindowY1=lcdltdc.pheight;                     //窗口终止Y坐标
    * X" O  o' H8 Y3 J
  17.     pLayerCfg.PixelFormat=pixformat;                        //像素格式7 W5 i8 P; v$ k: n" ?/ v
  18.     pLayerCfg.Alpha=alpha;                                  //Alpha值设置,0~255,255为完全不透明9 K$ K2 X! x6 z) H- m. a
  19.     pLayerCfg.Alpha0=alpha0;                                //默认Alpha值
    , V/ v3 N, ?/ J
  20.     pLayerCfg.BlendingFactor1=(u32)bfac1<<8;                //设置层混合系数
    , [$ U; x5 K! W# ~* G% U
  21.     pLayerCfg.BlendingFactor2=(u32)bfac2<<8;                //设置层混合系数$ ^! \8 C: S9 M
  22.     pLayerCfg.FBStartAdress=bufaddr;                        //设置层颜色帧缓存起始地址: q; Q5 b: c/ Z3 E" B
  23.     pLayerCfg.ImageWidth=lcdltdc.pwidth;                    //设置颜色帧缓冲区的宽度   
    0 R/ `! k, j5 u" w: Z
  24.     pLayerCfg.ImageHeight=lcdltdc.pheight;                  //设置颜色帧缓冲区的高度
    / T3 X- {, n  s
  25.     pLayerCfg.Backcolor.Red=(u8)(bkcolor&0X00FF0000)>>16;   //背景颜色红色部分( ^! W1 E9 k% A, w* u. f5 H6 A
  26.     pLayerCfg.Backcolor.Green=(u8)(bkcolor&0X0000FF00)>>8;  //背景颜色绿色部分/ {# o7 c) t! y! e
  27.     pLayerCfg.Backcolor.Blue=(u8)bkcolor&0X000000FF;        //背景颜色蓝色部分
    1 p% B2 G1 B# k" f! U
  28.     HAL_LTDC_ConfigLayer(<DC_Handler,&pLayerCfg,layerx);  //设置所选中的层5 t3 c* t1 U; a: J
  29. }$ L3 E0 _# A/ S7 J# z/ p" N& b
  30. 5 A) h& d4 \% q  }$ h& V
  31. //在init时调用
    8 @" z  P6 q1 U; X. ?6 h* i
  32. LTDC_Layer_Parameter_Config(0(u32)ltdc_framebuf[0],LCD_PIXFORMAT,255,0,6,7,0X000000);  //层参数配置
复制代码
9 z" Q6 h, r% j
5.设置LTDC层窗口
2 H7 ~5 n, V  h6 P. [4 X" r0 ?
  1. //layerx:层值,0/1.
    $ T; E. U! F0 ^* v- v* o% Z( M* D
  2. //sx,sy:起始坐标
    ' q5 f6 w2 S7 ?4 M9 X5 V: W
  3. //width,height:宽度和高度
    7 P3 X: }* y2 c" `1 K; G' w- K$ f
  4. void LTDC_Layer_Window_Config(u8 layerx,u16 sx,u16 sy,u16 width,u16 height)0 N- f( L( @' i- H0 A# Y
  5. {4 ]' y1 I6 n& s- \( t2 f
  6.     HAL_LTDC_SetWindowPosition(<DC_Handler,sx,sy,layerx);                                  //设置窗口的位置
      }+ J2 Q% @! P# y( Q: p4 B! S
  7.     HAL_LTDC_SetWindowSize(<DC_Handler,width,height,layerx);                                //设置窗口大小   
    ; B: e  R- F0 Y- F5 f) s
  8. }; k5 V: r/ [$ ~

  9. / L; u0 }' Q2 d6 t
  10. //在init时调用+ [4 R  e- A% g+ a6 u5 m
  11. LTDC_Layer_Window_Config(0,0,0,lcdltdc.pwidth,lcdltdc.pheight);             //层窗口配置,以LCD面板坐标系为基准
复制代码
7 f/ V2 e1 H- v$ J; X& c0 f# s/ Y0 V0 c
完成了 LTDC 的配置,可以控制 RGBLCD 显示了。9 B  X9 M% t2 G4 _

. x% m; O0 t/ V0 ^' F使用DMA2D完成颜色填充1 B$ h( v! n! `9 h
使用官方提供的 HAL 库 DMA2D 相关库函数进行颜色填充效率极为低下,大量时间浪费在函数的入栈出栈以及过程处理,所以在项目开发中一般都不会使用 DMA2D 库函数进行颜色填充& F; w& B# h0 ?- Y

: g& ^: `& e) Z6 [1)使能 DMA2D 时钟,并先停止 DMA2D。
* a7 |7 D! |- I要使用 DMA2D,先得开启其时钟。然后 DMA2D 在配置其相关参数的时候,需要先停止DMA2D 传输。 使能 DMA2D 时钟和停止 DMA2D 方法为:
) T% T- y3 r& T! _
  1. __HAL_RCC_DMA2D_CLK_ENABLE(); //使能 DM2D 时钟
    $ V, O3 K+ o$ v( L
  2. DMA2D->CR&=~DMA2D_CR_START; //停止 DMA2D
复制代码

) e7 Q7 g- n0 Y% _$ X1 I2)设置 DMA2D 工作模式。8 Q2 H. n- e& P6 v5 B
通过 DMA2D_CR 寄存器,配置 DMA2D 的工作模式。我们用了寄存器到存储器模式和存储器到存储器这两个模式。
  R; o9 ~6 Z# J) [寄存器到存储器模式设置:
: H) l2 J& w, ?* ]
  1. DMA2D->CR=DMA2D_R2M; //寄存器到存储器模式
复制代码

. u8 i, c3 o, ]% |存储器到存储器模式设置:2 I- Z, R! [5 d2 J
  1. DMA2D->CR= DMA2D_M2M; //存储器到存储器模式
复制代码
- Y- r) F  {9 j
3)设置 DMA2D 的相关参数。
6 a6 x4 I. q' m5 v) K这一步,我们需要设置:颜色格式、输出窗口、输出存储器地址、前景层地址(仅存储器到存储器模式需要设置)、颜色寄存器(仅寄存器到存储器模式需要设置)等,由:DMA2D_OPFCCR、DMA2D_FGPFCCR、DMA2D_OOR、DMA2D_FGOR 、DMA2D_OMAR、DMA2D_FGMAR 和 DMA2D_NLR 等寄存器进行配置。具体配置过程请参考实验源码。8 @! R% G$ e0 P  w1 e
, X8 v! u9 X# ^* S- ~7 \/ j; o. \
4)启动 DMA2D 传输。
7 C* S2 H. M$ e通过 DMA2D_CR 寄存器配置开启 DMA2D 传输,实现图像数据的拷贝填充,方法为:
# ~  y/ z& Z. B2 H* H( u( J, t: j/ @" R5 }  F
DMA2D->CR|=DMA2D_CR_START; //启动 DMA2D+ ]2 p0 j# `3 s1 h, t* |! G( k
13 Q$ Z% y5 S$ ~1 @: @5 @$ A7 @: B9 \
5)等待 DMA2D 传输完成,清除相关标识。
$ J7 c2 e* Z- K最后,在传输过程中,不要再次设置 DMA2D,否则会打乱显示,所以一般在启动 DMA2D后,需要等待 DMA2D 传输完成(判断 DMA2D_ISR),在传输完成后,清除传输完成标识(设置 DMA2D_IFCR),以便启动下一次 DMA2D 传输。
, b6 N. e4 y" e$ ^7 v( E
$ g" U+ j$ A0 H$ ~' N8 k0 c
  1. while((DMA2D->ISR&DMA2D_FLAG_TC)==0) ; //等待传输完成5 t3 D" [& J! ~. N: r
  2. DMA2D->IFCR|=DMA2D_FLAG_TC; //清除传输完成标志
复制代码

4 L* U" F# m# k$ f' y通过以上几个步骤,我们就完成了 DMA2D 填充
  u2 x# r" |; _, z: R: Z* _+ Z  _3 i& I7 k8 ]& \
使用示例
) X8 \3 s& c: p: [- ~
  1. //LCD LTDC重要参数集- b2 r- v3 }* P; ^4 u8 b( g3 Y
  2. typedef struct    D( ~% i8 u7 y
  3. {
    " _: Y# w: ~# U6 e; W
  4.     u32 pwidth;         //LCD面板的宽度,固定参数,不随显示方向改变,如果为0,说明没有任何RGB屏接入
    3 g2 M9 I+ o. r/ |, {+ b& C8 K
  5.     u32 pheight;        //LCD面板的高度,固定参数,不随显示方向改变
    9 D0 _. \5 h2 l% d
  6.     u16 hsw;            //水平同步宽度 Horizontal synchronization width% K) o6 |4 n3 F
  7.     u16 vsw;            //垂直同步宽度 Vertical synchronization width& Q5 a9 A# E' T% Z1 Y1 Q: q3 X
  8.     u16 hbp;            //水平后廊7 ]* R3 C; f1 y0 O
  9.     u16 vbp;            //垂直后廊6 g/ }7 P+ z2 e. O5 n# i
  10.     u16 hfp;            //水平前廊0 j( R, n) V* [7 c8 W' }6 g
  11.     u16 vfp;            //垂直前廊( _; v8 x; K; T9 y
  12.     u8 activelayer;     //当前层编号:0/1- [4 |$ Q. H3 N' O
  13.     u8 dir;             //0,竖屏;1,横屏;! i1 l+ }3 ~) Y. o, ^% }: ?
  14.     u16 width;          //LCD宽度% L# {0 r# V4 o0 U9 A+ B
  15.     u16 height;         //LCD高度% ^0 q# e% O+ f# ?( j: y* }
  16.     u32 pixsize;        //每个像素所占字节数9 b! |. w& R: `3 D8 b5 {. y& R2 s6 g
  17. }_ltdc_dev;! P# }8 P7 T1 X* |; n
  18. , i3 J4 Y0 F$ K% o: A6 c7 ~
  19. _ltdc_dev lcdltdc;                //管理LCD LTDC的重要参数
    8 v, g/ d3 `5 U. W  d5 N
  20. ) ?) Q, p$ t4 T' }
  21. //LTDC填充矩形,DMA2D填充0 B5 h) [3 V/ Q4 J: U
  22. //(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)   
    4 ?% @$ D9 d% o( k, Z, S6 H
  23. //注意:sx,ex,不能大于lcddev.width-1;sy,ey,不能大于lcddev.height-1!!!
    - o5 Y1 F' U, @/ H& N5 a) r
  24. //color:要填充的颜色
    # q2 u1 l+ K2 P. G  H0 B, R
  25. void LTDC_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u32 color)
    3 d0 O$ E5 e# H- q$ S
  26. {
    ; L% ^5 J9 I# {8 a" L& D* q5 o/ m
  27.     u32 psx,psy,pex,pey;                        //以LCD面板为基准的坐标系,不随横竖屏变化而变化2 ~8 G- q% ^" K+ g& d8 P5 b
  28.     u32 timeout=0; 3 `0 X' T6 q) D, |6 H( q( R
  29.     u16 offline;- K& e3 \, m7 B- E
  30.     u32 addr;
    . l5 l2 n& c/ e) }/ d' x: k
  31.     //坐标系转换
    " |- p! T8 N7 F  ~* _
  32.     if(lcdltdc.dir)                             //横屏: r. Z* D% P. z; U  q5 O" {
  33.     {+ F: k* t. }6 d" }9 D
  34.         psx=sx;psy=sy;2 f* R7 O8 b% w$ D2 l5 w
  35.         pex=ex;pey=ey;
    4 ^6 z9 }% _; g: R% K4 U
  36.     }else                                       //竖屏
    2 u* _" y0 c( z1 _: T; P8 y3 @
  37.     {
    ; O- A9 x% s4 ^& N8 Q1 O" v$ q9 S
  38.         psx=sy;psy=lcdltdc.pheight-ex-1;) [5 j% ~/ z2 ~/ c
  39.         pex=ey;pey=lcdltdc.pheight-sx-1;
    # u5 X& g- \% |( F. @- u  i
  40.     }
    : g; m6 U) B9 g- ^. p% ?
  41.     offline=lcdltdc.pwidth-(pex-psx+1);
    7 b# c# Z3 F+ H6 H
  42.     addr=((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*psy+psx));
    3 M/ h+ E9 p# ^6 u1 _$ X# [( W
  43.     RCC->AHB1ENR|=1<<23;                        //使能DM2D时钟
    - w! {5 V+ E1 I. t9 y
  44.     DMA2D->CR=3<<16;                            //寄存器到存储器模式
    6 r( a1 C* L# {* L& \8 j0 x
  45.     DMA2D->OPFCCR=LCD_PIXFORMAT;                //设置颜色格式
    2 Y2 k+ _; f5 j9 t
  46.     DMA2D->OOR=offline;                         //设置行偏移
    % e7 }( I* _5 B# N% A$ [& @+ z
  47.     DMA2D->CR&=~(1<<0);                         //先停止DMA2D" d- }. s$ b( N) S: j
  48.     DMA2D->OMAR=addr;                           //输出存储器地址9 p: N! _- s; Q" T. t' S
  49.     DMA2D->NLR=(pey-psy+1)|((pex-psx+1)<<16);   //设定行数寄存器
    2 i) m: ?7 t' V5 B
  50.     DMA2D->OCOLR=color;                         //设定输出颜色寄存器 , q: P' p6 [' B1 z
  51.     DMA2D->CR|=1<<0;                            //启动DMA2D" s! e, ?+ f# n) H; Q
  52.     while((DMA2D->ISR&(1<<1))==0)               //等待传输完成5 b# e( h: V& S9 Y: K8 z7 z. _
  53.     {% E% V* d, _) V  n7 B  y; z/ ]# y$ l
  54.         timeout++;
    9 I/ l/ j$ s1 E9 d4 M& [: q
  55.         if(timeout>0X1FFFFF)break;              //超时退出1 Y5 @  b( ]; {8 c
  56.     }  7 r) X. Z/ B: D, Z1 j5 F6 y
  57.     DMA2D->IFCR|=1<<1;                          //清除传输完成标志
    & z  d" Z# h2 m
  58. }
    5 ^7 Q! A: A+ H1 [% G/ L

  59. / n: p% H% N" I6 W0 C& n" O2 ?
  60. //LCD清屏# l! ]9 Q( C6 u* c' |  R
  61. //color:颜色值7 P1 n* B( ^/ X
  62. void LTDC_Clear(u32 color)
    ) d8 D- E4 |/ V" t( M% n, p/ i- F$ z
  63. {6 P: i4 l5 |& g' l( t
  64.     LTDC_Fill(0,0,lcdltdc.width-1,lcdltdc.height-1,color);5 V% U$ \& z# O/ h4 {0 b, \- E* N
  65. }
    " E0 _: l) E5 a1 z2 o) W6 g/ o" C! x

  66. ! k% r& |% M4 D% U$ B

  67. 6 v) V* L/ `% [# C6 E6 [; w' {
复制代码
) m) o2 z6 n5 X. ^5 B5 @& Q  _

  Z. \2 g4 A6 A! z, _
)0J3WVNZQ8DQ6O089(M6FJW.png
收藏 评论0 发布时间:2021-12-13 08:50

举报

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