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

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

[复制链接]
STMCU小助手 发布时间:2021-12-13 08:50
基础知识简介; K3 C  D, j. _7 k, ~5 `  d* u
RGBLCD

. c9 O4 k, v7 Q/ n1.RGBLCD的信号: L5 _2 _! a# o1 p4 {
20210720093227878.png

+ p( q# W1 [+ s3 L, u$ Y. m$ q7 k. B+ b7 T0 U; a- x6 N( ~5 b. i& h
一般的 RGB 屏有 24 根颜色数据线(RGB 各站 8 根,即RGB888 格式),这样可以表示最多 1600W 色,DE、VS、HS 和 DCLK,用于控制数据传输。4 H) a1 L* g/ Y5 X4 c4 a; W3 X
5 u3 {& e; `7 U. H
2.RGBLCD驱动模式

) E' a- P# J5 @. R- {其驱动模式主要分为两种( d! I/ `; _+ `2 v% Q2 S5 f

/ ^: G" }7 [% k8 Q$ T      DE模式6 n7 @& Y( X5 W7 a& I: O
      DE 模式使用 DE 信号来确定有效数据,DE 为高/低时,数据有效
. F; o& v2 n! J      HV模式$ z; j  N# b4 Q4 b2 }5 l' U  W# W/ ?
      HV模式需要行同步和列同步,来表示扫描的行和列
& }& d# r* q3 ^3 c; R3 w4 X+ \! {+ w: y
LTDC
  k  }/ n( T0 [0 PSTM32F767xx 系列芯片都带有 TFT LCD 控制器,即 LTDC,通过这个 LTDC,STM32F767可以直接外接 RGBLCD 屏,实现液晶驱动。
6 g6 ?. n: m- Q: V  y* K/ `  x( \# g# e+ A# a- ^
1.信号线" o( q7 m7 I# n9 V) ]% e
STM32F767 核心板板载的 LCD 接口引出为了,节省 IO,并提高图片显示速度,使用 RGB565 颜色格式,这样只需要 16 个 IO 口,当使用 RGB565 格式的时候,LCD 面板的数据线,必须连接到 LTDC 数据线的 MSB
0 u+ D% m, Z. M, k; C, J8 x8 W+ [5 |' u6 {$ l
20210720100712790.png

- b2 `8 b( m2 Q4 ~' _- B
& X& ]) l5 r9 W- I$ T/ {2.图像处理单元" J% D, F+ |, h$ T. t7 [
 先从 AHB 接口获取显存中的图像数据,然后经过层 FIFO(有 2 个,对应 2 个层)缓存,每个层 FIFO 具有 64*32 位存储深度,然后经过像素格式转换器(PFC),把从层的所选输入像素格式转换为 ARGB8888 格式,再通过混合单元,把两层数据合并,混合得到单层要显示的数据,最后经过抖动单元处理(可选)后,输出给 LCD 显示。- G- n4 t: W" v$ \" c  a
 混合单元首先将第一层与背景层进行混合,随后,第二层与第一层和第二层的混合颜色结果再次混合,完成混合后,送给 LCD显示。
& R& e7 X( c  F  \6 A5 h0 e3 J. S8 x$ U/ l3 E6 Y& k9 h
20210720102457112.png

/ o3 q' Z  x6 }5 q/ ^( _6 b# t+ g* k9 ^( n! C! R- e5 L
3.AHB 接口. e$ d# l) v& N! }4 l: D% L
 由于 LTDC 驱动 RGBLCD 的时候,需要有很多内存来做显存,比如一个 800480 的屏幕,按一般的 16 位 RGB565 模式,一个像素需要 2 个字节的内存,总共需要:800480*2=768K 字节内存,STM32 内部是没有这么多内存的,所以必须借助外部 SDRAM,而 SDRAM 是挂在AHB 总线上的,LTDC 的 AHB 接口,就是用来将显存数据,从 SDRAM 存储器传输到 FIFO 里面。0 Z5 D& p8 a( ]9 I9 T# ]: T' ]6 r

) r+ @) v) y3 @" E4.LTDC相关寄存器及使用方法
, q1 U+ v0 s6 }' N/ q- z
LTDC 的各种配置寄存器以及状态寄存器,用于控制整个 LTDC 的工作参数,
: V# O# t0 O) P2 j3 b主要有:各信号的有效电平、垂直/水平同步时间参数、像素格式、数据使能等等。7 V' Y8 z- C1 w8 T, v, {
如果 RGBLCD 使用的是 DE 模式,需要设置如下参数,然后 LTDC会根据这些设置,自动控制 DE 信号。
  x* I6 S8 F0 k/ m. R5 C1 |$ e
$ i! P* e% j) h/ {LTCD全局控制寄存器 LTCD_GCR
  E9 d( p9 G# d- L8 H  F
2 M! g; s. n8 r! C
20210720104228854.png
7 z' j9 s4 t' I9 ]! S
6 w, x# w( T9 q1 A
]V@HJS%I_Y[%1XLYT61%0@2.png
8 `) t% R2 h+ G' t1 k/ ^+ g1 u0 o
% d) L6 F9 `6 i9 _( C$ y7 p
LTCD同步大小寄存器 LTDC_SSCR
$ K8 N, S8 Y) U0 y0 x该寄存器用于设置垂直同步高度(VSH)和水平同步宽度(HSW)0 n4 L  y9 ~/ `/ O" D- v4 C
% _" M0 N9 Z: S* q0 G$ B, r
20210720104959506.png

0 `) q, S, Y7 a2 z( z$ w7 P2 Z
& J- J) i3 u6 x8 g# V* |
0PRMT7%Y[QF2O{1W`AQ82~7.png

3 Y6 K* R5 X* }3 x: J' A8 C- N- s3 e1 @" v/ R3 X* {' V! D/ J

; B% A& d, S" oLTDC有效宽度配置寄存器 LTDC_AWCR
! [% q1 N7 q' E( J% g这里所说的有效高度和有效宽度,是指 LCD 面板的宽度和高度,构成分辨率
2 c9 H" d* H+ ?1 Z
/ A# t' [+ Y8 n6 X  }% _
20210720110024135.png
" a* W8 w# K- ~8 K( F
$ d" {' |# f: x7 t8 c
[AREI`HGZ@RRR{J@MJC8W]8.png

4 e3 o9 _. |' b! t3 U& V3 y; s
% r  S! e+ S% U5 U# `0 D6 O+ p     * z: I5 k* a! H) b! d
LTDC 总宽度配置寄存器 LTDC_TWCR
) l4 H3 t9 ]" E
! O& u) C. p% X% J$ S& `/ X
20210720110931326.png
9 j9 k* ?; v8 f
. p# l& q9 a0 i$ _
O6G8SGZNHK4ZYO{)JN[]USW.png

+ B% m/ W+ D# X% C( i" j' S; N
3 H& o; l. y" z% u      
  v+ z# `, ?" k) I# {0 eLTDC 背景色配置寄存器 LTDC_BCCR* m/ J  P. f& r2 w- ^1 n7 J
该寄存器定义背景层的颜色(RGB888),通过低 24 位配置,我们一般设置为全 0 即可。
: G0 B6 ~8 s" M  B' s' R; P( _2 O  S7 S3 \; k* D

! k. A1 _& y2 L4 |2 l" C8 g3 n6 Y
20210720111141846.png

; ?+ q: k6 _6 }: _. O7 O* v- h& d7 z) {7 c) P
LTDC当前位置状态寄存器 LTDC_CPSR7 t5 r8 e- J/ R1 G

0 t1 Y2 o/ z3 |! J: D- R
a3355e745c2c73657ef826bf1a8f42f5.png

) C5 v* _$ M% X2 ~) n9 @+ x0 A4 g( P9 }6 }/ U" U
CXPOS[31~16]:返回当前X坐标位置" f' h+ ?, C( d0 B  P9 E
CYPOS[15~0]:返回当前Y坐标位置; X9 ?2 z  L( k: o

1 t, S6 T5 w7 S* n  i7 s* CLTDC当前显示状态寄存器 LTDC_CDSR6 C. ^9 _7 U( g/ v: R- G! C: Q) I
此寄存器返回由 HSYNC、VSYNC 和水平/垂直 DE 信号控制的当前显示阶段的状态7 E/ A9 h. r) C9 K; j- y
# D! q* H3 b, R+ E' c* ]  w" f  V
c1e72a8f7ff1155cd5391d05ba83e42d.png
! b) J; `7 x! p7 L4 F8 n( z, V8 [
  v2 J1 z! d& N9 }; F" g) s
位 31:24 保留,必须保持复位值
6 P7 q  |5 |' r位 3 HSYNCS:水平同步显示状态 (Horizontal Synchronization display Status)8 {" }1 R1 B6 M4 {4 Q
0:低电平有效  P7 c1 E& K& t; b
1:高电平有效
1 n0 M' J! h( E* H" }位 2 VSYNCS:垂直同步显示状态 (Vertical Synchronization display Status)
( I4 L6 \6 z: S9 G, l* N0:低电平有效
2 q3 k( ~* {, k2 b6 q# W3 O% `1:高电平有效$ A" u0 `5 _! a6 |+ j0 t/ \
位 1 HDES:水平数据使能显示状态 (Horizontal Data Enable display Status)$ |1 t" M! V& R
0:低电平有效
3 w8 g4 X: V$ t: e1 B+ t1 [" [1:高电平有效
* U* d: X+ o* Q0 u% P6 X位 0 VDES:垂直数据使能显示状态 (Vertical Data Enable display Status)
3 u$ W& a. O% d0 _+ h0:低电平有效
0 I3 L$ D; C0 a7 i( U, H# d: m1:高电平有效
% ~) R; o  @# b0 v5 @; b' u) Z' [  O* O- m1 D: Q2 J; q: ?
LTDC 的层颜色帧缓冲区地址寄存器 LTDC_LxCFBAR(x=1/2)
$ D% D; I4 \9 T该寄存器用来定义一层显存的起始地址。STM32F767 的 LTDC 支持 2 个层,所以总共有两个寄存器,分别设置层 1 和层 2 的显存起始地址。
% e4 E2 j3 p$ V& W# e: u* z
$ e$ i1 L" R/ `1 ~+ q3 e' d( l
20210720111336311.png

1 }) ~& P/ q, \* K
5 |) r7 [$ l+ wLTDC 的层像素格式配置寄存器 LTDC_LxPFCR(x=1/2)
+ _7 c' U2 U$ G: O9 N该寄存器只有最低 3 位有效,用于设置层颜色的像素格式,一般使用 RGB565 格式,即该寄存器设置为:010 即可。# l+ @( a8 D  ^& j; n0 @4 i1 z

* e; }2 W- N" g1 q
STQ}OUE_D7Z(33OZ_E@73.png

  H8 E: T8 L' H$ w
5 [& l3 }$ [' ~. e6 K# F' w
/ L2 r( i: g$ [! h       ' `' d" V& O5 E, U. S( c" a
LTDC 的层恒定 Alpha 配置寄存器 LTDC_LxCACR(x=1/2)
3 Y! F4 V6 Y3 ~& D5 ]2 d& a该寄存器低 8 位(CONSTA)有效,这些位配置混合时使用的恒定 Alpha。恒定 Alpha 由硬件实现 255 分频。
/ ]7 Y: g8 H# E' \6 p
$ e6 j# e  ?4 u6 _- o* o
20210720112235516.png
: M7 |. K. w! b* d2 n6 l6 [
% @' e9 z' s7 d
LTDC 的层默认颜色配置寄存器 LTDC_LxDCCR(x=1/2)
+ m- G; H, k( t
该寄存器定义采用 ARGB8888 格式的层的默认颜色。默认颜色在定义的层窗口外使用或在层禁止时使用。一般情况下,用不到,所以该寄存器一般设置为 0 即可。
3 @: E. b+ \( V! s
6 W+ t# a9 v; o/ t  `$ ^& D1 a
20210720112604555.png
8 y4 d! [/ ^9 E

- [$ T9 V( e0 J+ b+ f/ GLTDC 层混合系数配置寄存器:LTDC_LxBFCR(x=1/2)
4 ^: O2 ^: P' F# H. L3 ?! H! {该寄存器用于定义混合系数: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即可。
' b6 h9 x4 S' r; E; @+ _通用的混合公式为:BC=BF1C+BF2Cs% {% k7 {+ O3 `. U6 m. k+ h
其中:BC=混合后的颜色;BF1=混合系数 1;C=当前层颜色,即我们写入层显存的颜色值;BF2=混合系数 2;Cs=底层混合后的颜色,对于层 1 来说,Cs=背景层的颜色,对于层 2 来说,Cs=背景层和层 1 混合后的颜色。. H' E( @8 d9 H8 o, Y

2 a: }' \* h+ O  g2 D
2021072011293763.png

$ i4 ?: Z- p! j+ E! V4 E* c) t
. ]2 D" C% T, v5 v% Q  zLTDC 的层窗口水平位置配置寄存器 LTDC_LxWHPCR(x=1/2)
8 E2 }4 Z" D7 e( E3 s' ?
该寄存器定义第 1 层或第 2 层窗口的水平位置,第一个和最后一个像素) L7 {8 q7 Y8 ]" O8 d' Z2 T

6 N2 x' s( a; R% j  _9 c3 Q
20210720113448290.png

( x0 g* Z7 o/ R# a' o( b* {: p' T# i4 c, I& v' i& i
WHSTPOS:窗口水平起始位置,定义层窗口的一行的第一个可见像素,3 ]8 H! E) W) P  |
WHSPPOS:窗口水平停止位置,定义层窗口的一行的最后一个可见像素
4 `8 {2 v1 L/ m) ?3 d+ s( {$ A# e2 Y( v( z5 p; j
LTDC 的层窗口垂直位置配置寄存器 LTDC_LxWVPCR(x=1/2)

. p9 R6 a5 }: ~# H4 I该寄存器定义第 1 层或第 2 层窗口的垂直位置(第一行或最后一行)  Q' s. J8 c/ `( w; a! a# P
. D2 T% `# N5 Q/ @/ |* x" }
20210720133247145.png

3 ]0 U& \0 R- I2 ?' d. l( ~: R; R1 B% l- {+ W% N9 h, t4 L1 ~
WVSTPOS:窗口垂直起始位置,定义层窗口的第一个可见行。2 A5 m1 N- t' A6 D
WVSPPOS:窗口垂直停止位置,定义层窗口的最后一个可见行。
- x. X, m/ q( I: B) w4 F6 f! U: k' l, T( ?+ e8 q$ P
LTDC 的层颜色帧缓冲区长度寄存器 LTDC_LxCFBLR(x=1/2)
. [/ N. c6 r2 Z- S- S+ {8 A该寄存器定义颜色帧缓冲区的行长和行间距。5 L) K% D6 q' N+ |5 z9 H( x

3 p! o6 |  E8 l6 f% Y
20210720133802157.png
* a. A& a3 T3 a. P) s  e

) z! N- |; q' @' DCFBLL:这些位定义一行像素的长度(以字节为单位)+3。4 f' c! d- C. y' T: d
行长的计算方法为:有效宽度 * 每像素的字节数 + 3。
! G' n" W# z$ S/ @+ a( _$ ~比如,LCD 面板的分辨率为 800480,有效宽度为 800,采用 RGB565 格式,那么 CFBLL 需要设置为:8002+3=1603。
$ ~4 N- l- n' H4 [( \4 v: }/ PCFBP:这些位定义从像素某行的起始处到下一行的起始处的增量(以字节为单位)。
1 H4 z6 J9 P4 b这个设置,其实同样是一行像素的长度,对于 800480 的 LCD 面板,RGB565 格式,设置 CFBP 为:8002=1600 即可。7 r3 r4 s/ W  \# B' R3 l; I* S6 [

" W8 d: t5 H! h- S5 `LTDC 的层颜色帧缓冲区行数寄存器 LTDC_LxCFBLNR(x=1/2)' Z0 L  g% a  K6 [6 C
该寄存器定义颜色帧缓冲区中的行数。
+ j( m6 C, ]" R9 i: K比如,LCD 面板的分辨率为 800*480,那么帧缓冲区的行数为 480 行,则设置 CFBLNBR=480 即可# ]+ G2 C+ y# H4 O

  C/ R  e% D, _5 i5 N1 q3 U, P! D
20210720133424485.png

+ ?8 n$ H3 X% G& m- P! m" Y) H; b. L" N( A- |9 f
5.时钟域+ h$ F9 d8 R  V
LTDC 有三个时钟域:AHB 时钟域(HCLK)、APB2 时钟域(PCLK2)和像素时钟域(LCD_CLK),/ v, X% n4 ]; z  `
AHB 时钟域用于驱动 AHB 接口,读取存储器的数据到 FIFO 里面;
' z) R+ Q- b! L- N( x+ e8 ZAPB2 时钟域用于配置寄存器;- D3 T  E9 e- n9 ?7 r9 _
LCD_CLK像素时钟域则用于生成 LCD 接口信号,LCD_CLK 的输出应按照 LCD 面板要求进行配置。  e" [5 j' M5 P/ j! y, ~

# _8 j/ c* n; I! B: ADMA2D# m; i+ B* Y5 I7 f+ g
为了提高STM32F767的图像处理能力,ST公司设计了一个专用于图像处理的专业 DMA,通过 DMA2D 对图像进行填充和搬运,可以完全不用CPU 干预,从而提高效率,减轻 CPU 负担。
& ^6 Q7 o; S) X$ I3 C& g* @* F
它可以执行下列操作:
/ e# |! K0 P" u1 E  I0 Y用特定颜色填充目标图像的一部分或全部(可用于快速单色填充)
* D# p( T; b% d: T4 w9 e将源图像的一部分(或全部)复制到目标图像的一部分(或全部)中(可用于快速图像填充)
5 J; B! r8 Q( Y  F' ~- v通过像素格式转换将源图像的一部分(或全部)复制到目标图像的一部分(或全部)中/ J0 v' Q1 ^  x8 ]
将像素格式不同的两个源图像部分和/ 或全部混合,再将结果复制到颜色格式不同的部分或整个目标图像中- p! Q# H7 Z; w( }# q- u, ^; {5 P# ]
9 Q9 {/ y  h9 S, q$ j7 X/ r) ]! p
' ]2 _  A6 G, N  E7 Y! {% {. r, H& S
DMA2D 有四种工作模式,通过 DMA2D_CR 寄存器的 MODE[1:0]位选择工作模式:5 }; ]" Q) f- O2 c' z+ y
1, 寄存器到存储器
# U. Y8 ]% ]' P2, 存储器到存储器6 D+ H9 ~! E$ k* r8 [' ^
3, 存储器到存储器并执行 PFC
) T: A# z! l& A3 ]( {4, 存储器到存储器并执行 PFC 和混合
9 y- _, P$ `1 m. b: ^4 h* U: C

8 t9 I/ e, w$ _, E4 d寄存器到储存器
. M1 r% N. k$ I# \寄存器到存储器模式用于以预定义颜色填充用户自定义区域,也就是可以实现快速的单色* J$ j8 r' \# A3 ]9 M9 {8 r
填充显示,比如清屏操作。
' W  H+ x- ]% R6 }  o在该模式下:颜色格式在 DMA2D_OPFCCR 中设置,DMA2D 不从任何源获取数据,它只/ K  h; U3 B5 ?2 j1 T  ^
是将 DMA2D_OCOLR 寄存器中定义的颜色写入通过 DMA2D_OMA 寻址以及 DMA2D_NLR 和- z" H$ M( g1 N+ v2 o2 z
DMA2D_OOR 定义的区域
7 t9 l+ x# W( z+ r( O5 s& I( g8 A
5 e8 W7 R  J1 G- i" i( G. Q) x
储存器到储存器  [2 ^( t! G. T. W3 B' u6 D
该模式下,DMA2D 不执行任何图形数据转换。前景层输入 FIFO 充当缓冲区,数据从
8 i7 c% R0 ]. u  x0 KDMA2D_FGMAR 中定义的源存储单元传输到 DMA2D_OMAR 寻址的目标存储单元,可用于快! Q6 M5 X. Q: ]) J$ f" a
速图像填充。DMA2D_FGPFCCR 寄存器的 CM[3:0]位中编程的颜色模式决定输入和输出的每像. u7 ^0 q8 y$ F2 j; h4 E
素位数。对于要传输的区域大小,源区域大小由 DMA2D_NLR 和 DMA2D_FGOR 寄存器定义,
" ^* q1 e( \* b目标区域大小则由 DMA2D_NLR 和 DMA2D_OOR 寄存器定义。
: l- [* P" W5 C/ k
' V/ |3 s5 {% |" |( Z7 F7 s+ U1 i! s4 b' ?
以上两个工作模式,LTDC 在层帧缓存里面的开窗关系都一样的,经过如下三个寄存器的配置,就可以确定窗口的显示位置和大小。
8 W2 x: K/ {+ h" a8 U$ U(1). 窗口显示区域的显存首地址由 DMA2D_OMAR 寄存器指定,! K4 s! \) F( E- ^4 [
(2).窗口宽度和高度由DMA2D_NRL 寄存器的 PL 和 NL 指定
' c- c6 L0 @3 j; o$ O(3).行偏移(确定下一行的起始地址)由 DMA2D_OOR寄存器指定,, |5 W9 z5 Z/ u8 [8 a1 R0 L4 @

, n+ ]$ k3 Q; h: p" _
20210720170136697.png

6 o. H3 G* M5 Y9 {( a
. L* R  Y2 f1 t5 f% z0 w3 _# z: M0 }5 s, K! ]
在寄存器到存储器模式下,在开窗完成后,DMA2D 可以将 DMA2D_OCOLR 指定的颜色,- [: |6 f. j& V5 a. P* `9 R3 a( w- z, ~* n
自动填充到开窗区域,完成单色填充。
$ n! r; {$ U6 Z% j
/ |3 j. j: D3 P9 w( j7 Y3 A4 [9 V. Q( R5 C
在存储器到存储器模式下,需要完成两个开窗:前景层和显示层,完成配置后,图像数据从前景层拷贝到显示层(仅限窗口范围内),从而显示到 LCD 上面。显示层的开窗如上图所示,前景层也和上图类似,只是 DMA2D_OMAR 寄存器变成了DMA2D_FGMAR,DMA2D_OOR寄存器变成了DMA2D_FGOR,DMA2D_NRL则两个层共用,然后就可以完成对前景层的开窗,确定好两个窗口后,DMA2D 就将前景层窗口内的数据,拷贝到显示层窗口,完成快速图像填充。
! e& `) ?2 X1 {- ^" S. k# j; Y, y9 U; z2 P+ i2 _" c7 u& S  \' P

8 x9 T: @# G# a6 _" N* gDMA2D相关寄存器; Y! i% g4 M, U- C$ A
DMA2D控制寄存器 DMA2D_CR4 y! p. i* v/ j4 Z
该寄存器,主要是MODE 和 START 这两个设置( }! L" j6 q6 k6 ^
6 \" }# b+ h' P8 u: ?% P& Z
20210720172154901.png

0 J# l4 n) E: q: F( @* B) J% m0 D! X7 {  T; E% N3 R
MODE:表示 DMA2D 的工作模式,
7 _2 h! ^# C# ?( L" c00:存储器到存储器模式;01:存储器到存储器模式并执行 PFC;# u0 V+ q6 u- f! |0 f
10:存储器到存储器并执行混合;11,寄存器到存储器模式;
& z0 S$ }4 U5 u$ N* V: S: OSTART:该位控制 DMA2D 的启动,在配置完成后,设置该位为 1,启动 DMA2D 传输。
3 K0 ?2 _; x4 t: d- X5 i$ ^( K/ g5 O7 w6 A: p& ^/ |
DMA2D输出 PFC 控制寄存器 DMA2D_OPFCCR: t3 A. Q; Q/ H5 }" o
该寄存器用于设置寄存器到存储器模式下的颜色格式0 ?6 g: {5 A  v
& s9 n2 m+ ]- I" z* Y/ P
20210720172538112.png

$ e6 o3 c% s( Y  G( y& ]$ Q1 \  P! S: Q9 p5 S) o# H4 e! f
只有最低 3 位有效(CM[2:0]),表示的颜色格式有:
8 I8 g/ x( O8 a5 L- `9 O7 Y000,ARGB8888;001:RGB888;010:RGB565;1 L0 G9 Y' w3 Q' d# a* D
011:ARGB1555;100:ARGB1444。
/ `$ G: S. x* O" f& J; q. Q; W  c我们一般使用的是 RGB565 格式,所以设置 CM[2:0]=010 即可。
6 {: L4 F- g& G- }/ ^/ }5 c. ~7 v, e9 n" L
DMA2D前景层 PFC 控制寄存器:DMA2D_FGPFCCR- ^- U/ n* \, i" |

( ?$ Z3 d- C+ f6 H9 Q' }
20210720173213773.png
7 G% G; b% }8 x5 L3 d+ b6 h

( ^' o! t4 h# n* \该寄存器,低 4 位:CM[3:0],用于设置存储器到存储器模式下的颜色格式,这四个位表示的颜色格式为:
3 K! T1 x$ \4 r0 l! c! s3 B0000:ARGB8888;0001:RGB888;0010:RGB565;- F( D7 p/ [& r8 Y" i, _
0011:ARGB1555;0100:ARGB4444;0101:L8;$ a0 ]% M) p1 j& `, X# \6 c
0110:AL44;0111:AL88;1000:L4;1001:A8;1010:A4;
- L7 q3 n" }! p4 ~我们一般使用 RGB565 格式,所以设置 CM[3:0]=0010 即可。/ p" J5 {6 v/ M6 R
% t5 [/ A3 l7 Z! k1 @7 H2 s, _
DMA2D输出偏移寄存器 DMA2D_OOR
5 P8 a8 t5 L  I2 Y5 H0 b) k/ R& z
20210720174740982.png
  h* S) B; u- |: y) m
该寄存器仅最低 14 位有效(LO[13:0]),用于设置输出行偏移,作用于显示层,以像素为
- t* \" E6 J) s6 y# ?1 @单位表示。此值用于生成地址。行偏移将添加到各行末尾,用于确定下一行的起始地址。, u. l" l, D/ x, A; A' M4 N+ n
同样的,还有前景层偏移寄存器:DMA2D_FGOR,该寄存器同 DMA2D_OOR 一样,也是& }$ h# ~* G$ X3 {, F! v1 R
低 14 位有效,用于控制前景层的行偏移,也是用于生成地址,添加到各行末尾,从而确定下一5 b$ k7 z# p  q
行的起始地址。. g! ?4 r% a- [& O( \( L1 G+ g  k9 e
5 f1 |0 _6 S& A' J+ \
DMA2D输出存储器地址寄存器 DMA2D_OMAR
3 y3 w$ |* e2 w+ R9 E
5 X8 N: C" B( |7 |
20210720175051288.png
0 O2 w+ ?, J0 z  Y# @" g

: I- M- }0 R$ ~3 {该寄存器设置由 MA[31:0]设置输出存储器地址,也就是输出 FIFO 所存储的数据地址,该地址需要根据开窗的起始坐标来进行设置。以 800480 的 LCD 屏为例,行长度为 800 像素,假定帧缓存数组为:ltdc_framebuf,我们设置窗口的起始地址为:sx(<800),sy(<480),颜色格式为 RGB565,每个像素 2 个字节,那么 MA 的设置值应该为:' b1 }3 a, B2 k- D/ q
*MA[31:0]= framebuf+2(800sy+sx)**3 i- b% }6 M# z
同样的,还有前景层偏移寄存器:DMA2D_ FGMAR,该寄存器同 DMA2D_OMAR 一样,6 w6 V2 [2 o7 P( E
不过是用于控制前景层的存储器地址,计算方法同 DMA2D_OMAR。1 Q4 H2 [* C8 Z# R' R6 a& Q

2 N9 q( P, `) PDMA2D行数寄存器 DMA2D_NLR
% R% l& F6 |  I5 i5 n, U9 c) X; a; a
20210720180044872.png
' G+ e' E2 k" R/ r
该寄存器用于控制每行的像素和行数,该寄存器的设置对前景层和显示层均有效,通过该寄存器的配置,就可以设置开窗的大小。其中:1 ~5 V$ y$ m; m  v, P0 |" h- W
NL[15: 0]:设置待传输区域的行数,用于确定窗口的高度。
  h+ d, i7 t: V1 `  d2 zPL[13: 0]:设置待传输区域的每行像素数,用于确定窗口的宽度8 E# e3 l& }5 R) {; N
8 J' H) L& c9 \2 U- V6 m1 w1 ?
DMA2D输出颜色寄存器 DMA2D_OCOLR" S2 F- X5 }0 x* Z
! [- \( b1 S; F, u
20210720180520678.png

! |+ m8 K8 u, d该寄存器用于配置在寄存器到存储器模式下,填充时所用的颜色值,该寄存器是一个 32位寄存器,可以支持 ARGB8888 格式,也可以支持 RGB565 格式。我们一般使用 RGB565 格式,比如要填充红色,那么直接设置 DMA2D_OCOLR=0XF800 就可以了。
& u6 g8 L  j( H2 e9 v% [9 c% l# K, J
' Q' r6 g: g: P, w  [; q) s' [; GDMA2D中断状态寄存器 DMA2D_ISR+ o8 R3 r/ a2 ?0 ?3 |8 a9 c% T

  ^+ {$ y9 c5 y* Q& {
2021072018063162.png

3 q7 w" M3 v+ P5 H6 q
, k, B; H2 o! A$ ?# \/ ~该寄存器表示了 DMA2D 的各种状态标识
! U2 v# }. n, b7 d, V# G7 g# }TCIF 位,表示 DMA2D 的传输完成中断标志。当 DMA2D 传输操作完成(仅限数据传输)时此位置 1,表示可以开始下一次 DMA2D 传输了
& G- j7 p* [4 ~1 p8 `8 hDMA2D 中断标志清零寄存器:DMA2D_IFCR,用于清除 DMA2D_ISR 寄存器对应位的标志。通过向该寄存器的第 1 位(CTCIF)写 1,可以用于清除 DMA2D_ISR 寄存器的 TCIF 位标志。
& S& ~, {1 Z% |# J' t- r- O1 r0 J) e
4 o' z8 `$ T2 I; w
" f7 Q7 s  g& q5 J, l- W* _) ZLTDC具体使用步骤: ~3 U' a! D  r
1.使能 LTDC 时钟,并配置 LTDC 相关的 IO 及其时钟使能。
3 M0 D3 r8 `2 U9 g使用 LTDC,当然首先得开启其时钟。: z8 T' r% J4 v
然后需要把 LCD_R/G/B 数据线、LCD_HSYNC和 LCD_VSYNC 等相关 IO 口,全部配置为复用输出,并使能各 IO 组的时钟。
( z0 n2 O* q) \. @( l# K
. t9 G2 ^9 Z. s7 i" f
  1. //LTDC底层IO初始化和时钟使能( h5 r- b( }& ~( D! S, \0 }
  2. //此函数会被HAL_LTDC_Init()调用
    . r8 l5 y6 V& Q4 ~1 Y& q* S+ U3 ?
  3. //hltdc:LTDC句柄
    4 U. C- _$ L% P4 Q" [# s
  4. void HAL_LTDC_MspInit(LTDC_HandleTypeDef* hltdc)
    - D8 m5 T+ y+ r
  5. {5 h3 U. \5 ?4 l1 ?) W" h
  6.     GPIO_InitTypeDef GPIO_Initure;" S/ f2 y0 J5 k  j# ?, F

  7. / V3 i4 Y. e) X$ @# y( n$ d
  8.     __HAL_RCC_LTDC_CLK_ENABLE();                //使能LTDC时钟
    9 O2 A' z8 \, p: Q# v
  9.     __HAL_RCC_DMA2D_CLK_ENABLE();               //使能DMA2D时钟
    + }2 R; A0 j4 _0 d, ]! _4 s7 L
  10.     __HAL_RCC_GPIOB_CLK_ENABLE();               //使能GPIOB时钟! }; P' d7 {' S% a
  11.     __HAL_RCC_GPIOF_CLK_ENABLE();               //使能GPIOF时钟/ H6 F7 ~1 m% c' j$ T0 M5 V
  12.     __HAL_RCC_GPIOG_CLK_ENABLE();               //使能GPIOG时钟
    7 X$ M. f. I) n# e( Y( u9 @" `
  13.     __HAL_RCC_GPIOH_CLK_ENABLE();               //使能GPIOH时钟5 a! ~- B2 S6 x9 V9 q1 j$ u
  14.     __HAL_RCC_GPIOI_CLK_ENABLE();               //使能GPIOI时钟
    + O, f. g0 O  u' K0 f+ A$ V
  15. / Z0 @. G9 s. [% y$ m
  16.     //初始化PB5,背光引脚
    7 h& e. e4 @% D0 N, j/ z1 _0 y8 T
  17.     GPIO_Initure.Pin=GPIO_PIN_5;                //PB5推挽输出,控制背光
    " F% [9 q4 U0 q0 g$ u
  18.     GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;      //推挽输出' s/ Z- n% o$ m) H
  19.     GPIO_Initure.Pull=GPIO_PULLUP;              //上拉' X, u& _" T( M# b) L
  20.     GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速
    1 f/ @+ E4 H1 v& \5 z$ A& g! t
  21.     HAL_GPIO_Init(GPIOB,&GPIO_Initure);8 |3 ~0 Q- a  ?, j6 {/ X

  22. , c' X: `) u$ [& |& S8 a5 u
  23.     //初始化PF10
    + z: I( D( N6 P. c/ m8 b
  24.     GPIO_Initure.Pin=GPIO_PIN_10; . _3 ]- q* y% X  m
  25.     GPIO_Initure.Mode=GPIO_MODE_AF_PP;          //复用
    2 C, v" c% @, |2 X1 N9 ^, z, a' d2 c
  26.     GPIO_Initure.Pull=GPIO_NOPULL;8 s( C, {7 O( j2 R4 L% \1 K
  27.     GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速
    . F) e6 {# Z% O0 D
  28.     GPIO_Initure.Alternate=GPIO_AF14_LTDC;      //复用为LTDC1 x0 o: X/ v. _/ o9 P1 w
  29.     HAL_GPIO_Init(GPIOF,&GPIO_Initure);# ]8 c0 Y+ J' x  d
  30. 2 f6 ~9 A$ L  ]
  31.     //初始化PG6,7,111 i: w+ i# u# _1 k+ i
  32.     GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_11;3 Y/ ?6 Q" E* Q& E& X
  33.     HAL_GPIO_Init(GPIOG,&GPIO_Initure);
    ! X. i' d, U. t) Z6 ?( |$ R; Y

  34. 2 R; B! X6 k, e6 J* K  ?4 K4 Z
  35.     //初始化PH9,10,11,12,13,14,15! f2 B6 v8 V0 O8 e/ `. T
  36.     GPIO_Initure.Pin=GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|\4 ^/ W4 h$ ~, n+ r) j2 L) r
  37.                      GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
    + N) x# ]5 `) `! q0 o7 i  j3 m
  38.     HAL_GPIO_Init(GPIOH,&GPIO_Initure);! h, w! R3 p& f( D5 S" }* U  R

  39. ' x1 Z# Z/ C7 _3 z3 V5 {
  40.     //初始化PI0,1,2,4,5,6,7,9,10
    3 l, I+ V# x( ]: F6 ?
  41.     GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|\
    & S8 H4 S* E3 d% @
  42.                      GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_9|GPIO_PIN_10;
    7 n+ {( [6 i5 X/ k: N. Q$ D6 W( c- b' L
  43.     HAL_GPIO_Init(GPIOI,&GPIO_Initure);
    , t- Y9 ~: |4 D8 F& B8 l( i) n, {
  44. }
复制代码

' h9 n9 o, F9 s' z) s+ u$ u, I2.设置LCD_CLK时钟
% G5 Y1 u" t3 `# {6 k$ Q配置 LCD 的像素时钟,根据 LCD 的面板参数进行设置,LCD_CLK 由 PLLSAI进行配置,配置使用到的 HAL 库函数为:& P+ R8 U, L$ j* c6 u/ C
! ?  P+ y5 Z' p
  1.         //pllsain:SAI时钟倍频系数N,取值范围:50~432.  
    9 V7 \7 B5 l) l
  2.         //pllsair:SAI时钟的分频系数R,取值范围:2~71 I( o* \  E+ w- e
  3.         //pllsaidivr:LCD时钟分频系数,取值范围:0~3,对应分频2~16
    / T5 M* I& M4 ?# H( I
  4.         //假设:外部晶振为25M,pllm=25的时候,Fin=1Mhz.
    4 c4 R. n" p% T1 u  M! }
  5.         //例如:要得到20M的LTDC时钟,则可以设置:pllsain=400,pllsair=5,pllsaidivr=1
    5 I; ^/ j' T) F8 F) X+ z# ~
  6.         //Fdclk=1*396/3/2*2^1=396/12=33Mhz
    4 T) ]! B+ R! [/ a
  7.     RCC_PeriphCLKInitTypeDef PeriphClkIniture;$ p7 e4 v: i/ `, G

  8. ; t+ e' ^# H3 [8 C( o% |! v4 p
  9.     //LTDC输出像素时钟,需要根据自己所使用的LCD数据手册来配置!
    % B, K$ Z6 W! \
  10.     PeriphClkIniture.PeriphClockSelection=RCC_PERIPHCLK_LTDC;       //LTDC时钟
    / K7 c) s6 _4 V( C1 b/ t
  11.     PeriphClkIniture.PLLSAI.PLLSAIN=pllsain;8 t6 q! C5 v8 `" Q6 E- v; b' U
  12.     PeriphClkIniture.PLLSAI.PLLSAIR=pllsair;
    2 y- Q% \0 S/ u, m# }
  13.     PeriphClkIniture.PLLSAIDivR=pllsaidivr;
    2 z6 ~0 s! }2 E4 Q/ v* ]* |8 X$ V! x& }
  14.         HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef *PeriphClkInit)
复制代码

6 Z5 G9 W  V3 b: G' c% H0 H3.设置RGBLCD相关参数,并使能LTDC4 t# ~- w& ~  a* m$ D! p& Q0 V
  1. typedef struct: m7 E/ v* A6 |8 r9 Q$ p
  2. {8 b2 i! U, ~+ ~! s# f: q+ X
  3. uint32_t HSPolarity;                         //水平同步极性9 v* v0 g# g; M
  4. uint32_t VSPolarity;                         //垂直同步极性 ! }" b3 I& y* [7 C$ B7 D4 @- D3 r
  5. uint32_t DEPolarity;                         //数据使能极性  i+ v& L3 m+ S* W9 B" ]9 y; D
  6. uint32_t PCPolarity;                         //像素时钟极性
    1 x- w' Z$ u2 j' L
  7. uint32_t HorizontalSync;                 //水平同步宽度
    ; _8 c4 n! f9 w: |- e9 D2 r8 u) k
  8. uint32_t VerticalSync;                 //垂直同步高度
    7 [/ }" J, m+ \
  9. uint32_t AccumulatedHBP;                 //水平同步后沿宽度
    , F( p( z/ ~+ p/ v7 r8 t6 Q2 ~
  10. uint32_t AccumulatedVBP;                 //垂直同步后沿高度 : t; ]9 n# F' X9 y
  11. uint32_t AccumulatedActiveW;         //累加有效宽度
    6 n1 t% W0 S) F; Z/ _7 [4 K
  12. uint32_t AccumulatedActiveH;         //累加有效高度
    : @' I, y7 t3 V" w" t2 [/ {8 F9 K
  13. uint32_t TotalWidth;                         //总宽度
    9 T9 u3 B9 h9 n. w" h
  14. uint32_t TotalHeigh;                         //总高度
    # [! t# ^5 _$ a3 L
  15. LTDC_ColorTypeDef Backcolor;         //屏幕背景层颜色 4 ~: z% k2 E3 K& z7 s) M& v
  16. } LTDC_InitTypeDef;
    7 s8 T( P* @0 s( M! _1 l

  17.   i. M' H; Q; i- Z; b  L
  18. typedef struct' e$ X/ x" M% J" s5 B
  19. {
    # c: e( h9 l- n! ?
  20.   LTDC_TypeDef                *Instance;                /*Instance变量是LTDC_TypeDef结构体指针类型*/
    - E" d" ^& W: E+ S  r% P
  21.   LTDC_InitTypeDef            Init;                     /*用来初始化LTDC的结构体变量*/
    , L  u+ Q8 g/ X" A
  22.   LTDC_LayerCfgTypeDef        LayerCfg[MAX_LAYER];      /*保存LTDC层配置参数*/
    ' ~+ o5 r: s: t5 ~7 I- A
  23.   HAL_LockTypeDef             Lock;                     /*锁状态*/
    - j; i: ]0 K) `) @. D
  24.   __IO HAL_LTDC_StateTypeDef  State;                    /*LTDC的状态*/* ~& c5 }8 H5 h4 y, C9 h. g
  25.   __IO uint32_t               ErrorCode;                /*错误处理*/
    * V' x$ \. Z3 p# o
  26. } LTDC_HandleTypeDef;* l  I" `4 M9 |9 G
  27. + C! Z$ C( {$ u
  28. LTDC_HandleTypeDef  LTDC_Handler;                                   //LTDC句柄
    ! U& {2 @  Y0 ]/ I! y2 q
  29. * w" I* I+ I5 V8 N+ T
  30. LTDC_Handler.Instance=LTDC;" V# R  l9 k  r, E* M8 X! i* A; X2 k
  31. LTDC_Handler.Init.HSPolarity=LTDC_HSPOLARITY_AL;                 //水平同步极性  c9 O' l0 ?, g
  32. LTDC_Handler.Init.VSPolarity=LTDC_VSPOLARITY_AL;                 //垂直同步极性
    $ `( d  Y  Q  A
  33. LTDC_Handler.Init.DEPolarity=LTDC_DEPOLARITY_AL;                 //数据使能极性5 C8 |5 B& L1 N$ @: P3 h
  34. LTDC_Handler.Init.PCPolarity=LTDC_PCPOLARITY_IPC;                 //像素时钟极性9 `6 p: n& o9 A# T. {& \4 ]
  35. LTDC_Handler.Init.HorizontalSync=10-1;                                         //水平同步宽度
    # ?4 Z) D3 ^4 {2 Y' _. ]
  36. LTDC_Handler.Init.VerticalSync=2-1;                                         //垂直同步宽度7 N& j$ I/ W6 K& L! E
  37. LTDC_Handler.Init.AccumulatedHBP=10+20-1;                                 //水平同步后沿宽度# Y; V% r# f! {/ D
  38. LTDC_Handler.Init.AccumulatedVBP=2+2-1;                                 //垂直同步后沿高度
    & _; ?: Z( i2 C, V/ G% l, S3 n, y
  39. LTDC_Handler.Init.AccumulatedActiveW=10+20+480-1;                 //有效宽度4 R2 z- ~: ~" y$ y
  40. LTDC_Handler.Init.AccumulatedActiveH=2+2+272-1;                 //有效高度
    * A) f/ I3 C* I9 u$ c
  41. LTDC_Handler.Init.TotalWidth=10+20+480+10-1;                         //总宽度7 L) d% }% G. X) x1 D8 K  e
  42. LTDC_Handler.Init.TotalHeigh=2+2+272+4-1;                                 //总高度
    0 S9 y) T- M9 u6 P5 t6 {
  43. LTDC_Handler.Init.Backcolor.Red=0;                                                 //屏幕背景层红色部分
    ! I, k4 U6 d+ Z/ O6 U* V
  44. LTDC_Handler.Init.Backcolor.Green=0;                                         //屏幕背景层绿色部分: G1 ^& T) e  f3 e$ H, b
  45. LTDC_Handler.Init.Backcolor.Blue=0;                                         //屏幕背景色蓝色部分" u- }, u" d/ x# r- V4 F
  46. HAL_LTDC_Init(<DC_Handler);                                                         //设置 RGBLCD 的相关参数,并使能 LTDC,会调用HAL_LTDC_MspInit
复制代码
$ [. w( K' `4 V; k* Y: K
4.设置 LTDC层参数) _' [  n( J* F& R2 \6 ], U% R: N
  1. //layerx:层值,0/1.
    2 E2 w# v+ R4 w6 y4 b: D* s
  2. //bufaddr:层颜色帧缓存起始地址  N) j2 l# Q; v: L' I3 g
  3. //pixformat:颜色格式.0,ARGB8888;1,RGB888;2,RGB565;3,ARGB1555;4,ARGB4444;5,L8;6;AL44;7;AL88
    ' Q/ S2 z, e7 B8 K  m
  4. //alpha:层颜色Alpha值,0,全透明;255,不透明
    ; V8 ]" |9 a$ [; M) a
  5. //alpha0:默认颜色Alpha值,0,全透明;255,不透明  m/ x* Q- V1 x  I
  6. //bfac1:混合系数1,4(100),恒定的Alpha;6(101),像素Alpha*恒定Alpha+ e7 u  x: J$ n; O4 O+ B: v% P
  7. //bfac2:混合系数2,5(101),恒定的Alpha;7(111),像素Alpha*恒定Alpha
    5 G* N: u$ t  o
  8. //bkcolor:层默认颜色,32位,低24位有效,RGB888格式' a. {6 N1 `  s# ]* l
  9. void LTDC_Layer_Parameter_Config(u8 layerx,u32 bufaddr,u8 pixformat,u8 alpha,u8 alpha0,u8 bfac1,u8 bfac2,u32 bkcolor)# z" Q+ N5 q) m1 s. t7 v5 w3 n  I2 A8 B
  10. {
    1 K! s- C+ a. p: a: d
  11.     LTDC_LayerCfgTypeDef pLayerCfg;
    - e4 ?, @3 X" M* g1 Q9 k. c
  12. 7 m3 y0 A9 T& W, f) k- w1 J/ q# O
  13.     pLayerCfg.WindowX0=0;                                   //窗口起始X坐标
    8 |& r4 V# }( }% n0 ]
  14.     pLayerCfg.WindowY0=0;                                   //窗口起始Y坐标: l( X5 J& ]; N& ~7 e) t& H
  15.     pLayerCfg.WindowX1=lcdltdc.pwidth;                      //窗口终止X坐标" \* U4 y7 i/ d
  16.     pLayerCfg.WindowY1=lcdltdc.pheight;                     //窗口终止Y坐标2 K& Q4 }* N" i
  17.     pLayerCfg.PixelFormat=pixformat;                        //像素格式
    ' |' m$ j; u: G
  18.     pLayerCfg.Alpha=alpha;                                  //Alpha值设置,0~255,255为完全不透明
    8 q, N3 N. E" c$ T
  19.     pLayerCfg.Alpha0=alpha0;                                //默认Alpha值( c$ U" V, `5 @' @% ?: y) }
  20.     pLayerCfg.BlendingFactor1=(u32)bfac1<<8;                //设置层混合系数8 h' X$ L2 k( N. v  J4 X
  21.     pLayerCfg.BlendingFactor2=(u32)bfac2<<8;                //设置层混合系数
    * G; P* Z2 o' n1 ^6 A
  22.     pLayerCfg.FBStartAdress=bufaddr;                        //设置层颜色帧缓存起始地址6 D/ J. }0 w- ?7 Y$ L
  23.     pLayerCfg.ImageWidth=lcdltdc.pwidth;                    //设置颜色帧缓冲区的宽度   
    " ]8 A5 D7 j% O$ Q
  24.     pLayerCfg.ImageHeight=lcdltdc.pheight;                  //设置颜色帧缓冲区的高度
    * q" K, J: p( t* ~- y. B
  25.     pLayerCfg.Backcolor.Red=(u8)(bkcolor&0X00FF0000)>>16;   //背景颜色红色部分. i, @4 c5 e, P4 {3 J
  26.     pLayerCfg.Backcolor.Green=(u8)(bkcolor&0X0000FF00)>>8;  //背景颜色绿色部分
    ) Y. O' D: o; ?; K+ }  U
  27.     pLayerCfg.Backcolor.Blue=(u8)bkcolor&0X000000FF;        //背景颜色蓝色部分6 K& f4 D+ z: T3 A$ V/ y% E, \' ?
  28.     HAL_LTDC_ConfigLayer(<DC_Handler,&pLayerCfg,layerx);  //设置所选中的层1 @! ]- ]5 o! x1 Q& }
  29. }* O. g/ W: ]. S0 N! h2 ]* m) t( c

  30. . `& T5 I, f5 X7 v6 a
  31. //在init时调用$ P4 e# Y( P7 w0 M
  32. LTDC_Layer_Parameter_Config(0(u32)ltdc_framebuf[0],LCD_PIXFORMAT,255,0,6,7,0X000000);  //层参数配置
复制代码

. e& `" [9 P' T2 }* j9 |5.设置LTDC层窗口
6 D# o/ X( M/ ^! i, V+ I
  1. //layerx:层值,0/1.  B) I# D4 }" v$ Z8 r0 S- ?
  2. //sx,sy:起始坐标$ \1 @* k; ^, b6 [3 d
  3. //width,height:宽度和高度5 `, v4 \; a' a2 I0 P# }3 L8 f& z
  4. void LTDC_Layer_Window_Config(u8 layerx,u16 sx,u16 sy,u16 width,u16 height)  W# m0 N" R& W) R* C; Z3 l( {
  5. {
    ; P- U4 k' ^: V$ F) d
  6.     HAL_LTDC_SetWindowPosition(<DC_Handler,sx,sy,layerx);                                  //设置窗口的位置1 S: l' A" f- j* W6 k3 p
  7.     HAL_LTDC_SetWindowSize(<DC_Handler,width,height,layerx);                                //设置窗口大小   
    ( w. G- S+ U- @; U/ R% P
  8. }, ?) p* B: Y7 K3 H

  9. : J3 U- p- J" n
  10. //在init时调用3 G) b3 {9 S) |+ p* O/ d5 y
  11. LTDC_Layer_Window_Config(0,0,0,lcdltdc.pwidth,lcdltdc.pheight);             //层窗口配置,以LCD面板坐标系为基准
复制代码

% R& i  C: E/ z完成了 LTDC 的配置,可以控制 RGBLCD 显示了。
% Y9 t" u+ \1 k1 ^  `+ ^0 \1 r% @% C2 O% v8 K( r2 t
使用DMA2D完成颜色填充
% B8 V. t; W  H2 I/ ]8 J# b- ^. ^使用官方提供的 HAL 库 DMA2D 相关库函数进行颜色填充效率极为低下,大量时间浪费在函数的入栈出栈以及过程处理,所以在项目开发中一般都不会使用 DMA2D 库函数进行颜色填充
9 \; P0 w* [. h6 C% U$ j# B% d7 l7 H
1)使能 DMA2D 时钟,并先停止 DMA2D。. c& Z8 s. ?/ J3 W$ E8 v2 d- m
要使用 DMA2D,先得开启其时钟。然后 DMA2D 在配置其相关参数的时候,需要先停止DMA2D 传输。 使能 DMA2D 时钟和停止 DMA2D 方法为:, [0 Z2 p6 ]& i
  1. __HAL_RCC_DMA2D_CLK_ENABLE(); //使能 DM2D 时钟
    & ^# e9 g7 i( H# q
  2. DMA2D->CR&=~DMA2D_CR_START; //停止 DMA2D
复制代码
9 p) H- w3 D1 \/ x5 ?0 P
2)设置 DMA2D 工作模式。
* ]- @' j1 t6 g通过 DMA2D_CR 寄存器,配置 DMA2D 的工作模式。我们用了寄存器到存储器模式和存储器到存储器这两个模式。
, J& }, d; D: C9 o$ C; Q$ D寄存器到存储器模式设置:
. e6 c- j2 [9 y' J5 L
  1. DMA2D->CR=DMA2D_R2M; //寄存器到存储器模式
复制代码

/ s3 k. H& R. S* ?$ u' F存储器到存储器模式设置:
% X& z8 J2 w' p! U$ i) J, R# X
  1. DMA2D->CR= DMA2D_M2M; //存储器到存储器模式
复制代码
0 L, x. P* G( h1 s' N% Q
3)设置 DMA2D 的相关参数。" n' A  a* P0 J2 r4 v4 [3 j
这一步,我们需要设置:颜色格式、输出窗口、输出存储器地址、前景层地址(仅存储器到存储器模式需要设置)、颜色寄存器(仅寄存器到存储器模式需要设置)等,由:DMA2D_OPFCCR、DMA2D_FGPFCCR、DMA2D_OOR、DMA2D_FGOR 、DMA2D_OMAR、DMA2D_FGMAR 和 DMA2D_NLR 等寄存器进行配置。具体配置过程请参考实验源码。
. d% @2 h" O. N8 `1 ~+ T+ a! E, g7 D! f* z/ a
4)启动 DMA2D 传输。
' ]& u, t/ p# \1 T通过 DMA2D_CR 寄存器配置开启 DMA2D 传输,实现图像数据的拷贝填充,方法为:) x. m: [9 ^( z4 W2 x- R
/ n3 E, s/ K3 Q7 q8 e
DMA2D->CR|=DMA2D_CR_START; //启动 DMA2D8 d8 m1 O$ f* I/ ?; S. N
1
$ K% O* _3 P1 W  j5)等待 DMA2D 传输完成,清除相关标识。
' X% M2 T" D& n/ ]* f最后,在传输过程中,不要再次设置 DMA2D,否则会打乱显示,所以一般在启动 DMA2D后,需要等待 DMA2D 传输完成(判断 DMA2D_ISR),在传输完成后,清除传输完成标识(设置 DMA2D_IFCR),以便启动下一次 DMA2D 传输。9 C. p2 j* M! X5 v! l5 e' C
, K  Z0 O! Z% }( X" i. F
  1. while((DMA2D->ISR&DMA2D_FLAG_TC)==0) ; //等待传输完成, A7 p2 C4 i9 B/ N: d9 A0 J6 c7 A
  2. DMA2D->IFCR|=DMA2D_FLAG_TC; //清除传输完成标志
复制代码
2 i" s8 O/ _$ [* o  i8 Z1 G
通过以上几个步骤,我们就完成了 DMA2D 填充
, B- m( N8 N0 G% [. t# d% G
8 A! t9 ^& S' N4 t6 a/ P" P' ~使用示例' n' W' t2 t2 {7 L9 Y! e# g( |
  1. //LCD LTDC重要参数集
    4 f: }" d! l- q( E  M  b
  2. typedef struct  9 ?4 w8 c5 ^+ ^- x0 k
  3. {
    + H! M4 U& H; z; A- w% g+ H1 L; k. r
  4.     u32 pwidth;         //LCD面板的宽度,固定参数,不随显示方向改变,如果为0,说明没有任何RGB屏接入; V; }5 N) a2 |# a& G. N( w; l5 |& a
  5.     u32 pheight;        //LCD面板的高度,固定参数,不随显示方向改变
    3 M$ e& Y/ j! N7 C6 ^
  6.     u16 hsw;            //水平同步宽度 Horizontal synchronization width
    ; j" \( A) m* E3 C2 |
  7.     u16 vsw;            //垂直同步宽度 Vertical synchronization width
    0 Y/ i/ q4 V* \( P# H. Q$ i! l/ C
  8.     u16 hbp;            //水平后廊  t( P9 r: K5 ^- Y( O
  9.     u16 vbp;            //垂直后廊& {- W$ P: ?8 `3 _. b
  10.     u16 hfp;            //水平前廊
    ; K+ @8 k6 ~- P2 N, g% K5 r; @
  11.     u16 vfp;            //垂直前廊
    & j- \. ^3 ~+ _1 W5 T6 p
  12.     u8 activelayer;     //当前层编号:0/1+ j  X; P4 I4 B1 o- _# w
  13.     u8 dir;             //0,竖屏;1,横屏;# b/ L! X# J. |" W  G; K
  14.     u16 width;          //LCD宽度6 N# Z  z2 r  t! _9 |. h
  15.     u16 height;         //LCD高度5 z; z+ ]' V( V$ w- S. I
  16.     u32 pixsize;        //每个像素所占字节数9 i0 h- u  e* k8 U) _
  17. }_ltdc_dev;' h+ S) j, a) y  x" V! t9 J+ B
  18. 8 n  u# P  U8 Y$ Y
  19. _ltdc_dev lcdltdc;                //管理LCD LTDC的重要参数& W" T! k: _0 V6 w
  20. 1 a) L+ W% U0 t- O, T
  21. //LTDC填充矩形,DMA2D填充, S/ d# M5 ^! v: e
  22. //(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)   + F% c5 i1 b5 X1 v* g  H( E
  23. //注意:sx,ex,不能大于lcddev.width-1;sy,ey,不能大于lcddev.height-1!!!
    3 |- Y. g; a& _/ _7 s4 |+ G
  24. //color:要填充的颜色
    3 h) G% i6 e  W. @3 a/ o8 r
  25. void LTDC_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u32 color)6 N& x& W+ a  G  c" h4 f
  26. { 4 w1 j4 o" A' d3 k4 e4 e
  27.     u32 psx,psy,pex,pey;                        //以LCD面板为基准的坐标系,不随横竖屏变化而变化6 C* J' c; }9 ?6 \% {
  28.     u32 timeout=0;   Y* C1 u/ Y& U% a: T( ^( |
  29.     u16 offline;
    8 p: y) j' s, V  b" j! f0 a! z
  30.     u32 addr; ) ?" O3 \/ C0 {. p7 E
  31.     //坐标系转换
    / _  _$ h9 O' m( h5 s
  32.     if(lcdltdc.dir)                             //横屏8 z9 Y) ~* q: K
  33.     {
    ( R) P' Y# M1 d3 |
  34.         psx=sx;psy=sy;" b; Q4 }* d- h" _
  35.         pex=ex;pey=ey;, a' T9 k- L( j) m: j" \; _
  36.     }else                                       //竖屏
    + u6 E. y: S0 b9 F) x
  37.     {3 A  c; _( E  A$ t
  38.         psx=sy;psy=lcdltdc.pheight-ex-1;
    7 h0 ~- Y6 a2 {7 [/ M6 j$ |3 D
  39.         pex=ey;pey=lcdltdc.pheight-sx-1;$ Q- H  F- q. _: f/ v  h: ]5 Q
  40.     } - S! t" t0 O# [' M  @  @
  41.     offline=lcdltdc.pwidth-(pex-psx+1);
    ! o3 c$ O5 f: B8 x0 d- W
  42.     addr=((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*psy+psx));
    : n9 K4 K. u/ @
  43.     RCC->AHB1ENR|=1<<23;                        //使能DM2D时钟: E! b( g2 Q& c/ X
  44.     DMA2D->CR=3<<16;                            //寄存器到存储器模式% J4 L% S+ E5 g5 M" e$ f. H; ?  @
  45.     DMA2D->OPFCCR=LCD_PIXFORMAT;                //设置颜色格式6 x) X" j+ O8 P# n# N
  46.     DMA2D->OOR=offline;                         //设置行偏移 + k  Q5 ?  }/ N5 ?  ~" m
  47.     DMA2D->CR&=~(1<<0);                         //先停止DMA2D
    ; Q$ T2 I5 O7 r9 l; C4 U
  48.     DMA2D->OMAR=addr;                           //输出存储器地址
    6 ^) ^" o# u' r
  49.     DMA2D->NLR=(pey-psy+1)|((pex-psx+1)<<16);   //设定行数寄存器7 o/ L( L  n8 |2 x
  50.     DMA2D->OCOLR=color;                         //设定输出颜色寄存器
    8 P* T& c3 ~1 O! r3 w5 w
  51.     DMA2D->CR|=1<<0;                            //启动DMA2D
    2 W, m  E) O6 g. S
  52.     while((DMA2D->ISR&(1<<1))==0)               //等待传输完成. B0 \' h' j, t4 Y9 F: ?; l, P
  53.     {9 z9 M6 U  T2 t7 [
  54.         timeout++;
    * g+ T0 B( y2 P+ d
  55.         if(timeout>0X1FFFFF)break;              //超时退出
    1 E& W7 U6 Q3 ^! O
  56.     }  
      N4 P  i0 q" m' s- f' B
  57.     DMA2D->IFCR|=1<<1;                          //清除传输完成标志& `, }. Y- ]; b8 ?5 Q2 [
  58. }
    ' x( E. o$ i& P6 `; `
  59. ( f( T. B/ K% c/ q
  60. //LCD清屏
    ! l- \8 D' j2 o# U3 u" w. V" s
  61. //color:颜色值
    2 g3 e# Q. t. }
  62. void LTDC_Clear(u32 color)8 `, Y5 o" J. K- g
  63. {
    : \# I) W* z- w7 I3 S% N
  64.     LTDC_Fill(0,0,lcdltdc.width-1,lcdltdc.height-1,color);! U5 ^4 o% `' Y* u
  65. }( \  T! A0 p5 ~2 T9 d

  66. 4 Y! a* T* ?. U* }8 i& K3 S3 r( m

  67. $ G9 C: s3 D3 K8 W* W
复制代码
; t6 F' ^$ b& r3 c/ i

* Z; I+ K) D5 I
)0J3WVNZQ8DQ6O089(M6FJW.png
收藏 评论0 发布时间:2021-12-13 08:50

举报

0个回答

所属标签

相似技术帖

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