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

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

[复制链接]
STMCU小助手 发布时间:2021-12-13 08:50
基础知识简介
  ~' z3 `9 c! u; BRGBLCD
4 |* P( h5 X, @! I! Z- n
1.RGBLCD的信号2 K2 D/ E; B6 l# ^
20210720093227878.png
% ?; f7 o, ?& {0 @

8 z5 _" B' u1 q4 `% t$ h一般的 RGB 屏有 24 根颜色数据线(RGB 各站 8 根,即RGB888 格式),这样可以表示最多 1600W 色,DE、VS、HS 和 DCLK,用于控制数据传输。/ y" Q( R# Z+ v

, w' n% Z: E# J! z- {9 `% d6 T2.RGBLCD驱动模式

; n9 t; ^8 E; W其驱动模式主要分为两种
. o& q' _; z5 c9 F' b. v/ ~6 F# B+ l5 U
      DE模式
$ B% ], h* e8 Z! s  }2 S      DE 模式使用 DE 信号来确定有效数据,DE 为高/低时,数据有效7 l& r* j0 X6 g4 n% f
      HV模式
5 R& I% Z8 h: N0 p/ p/ @; E      HV模式需要行同步和列同步,来表示扫描的行和列4 t3 T7 `+ j: u/ N; w

& N3 V; M" \( X' x8 YLTDC9 G4 ]9 M, y" F. w5 w
STM32F767xx 系列芯片都带有 TFT LCD 控制器,即 LTDC,通过这个 LTDC,STM32F767可以直接外接 RGBLCD 屏,实现液晶驱动。5 |( |: }! S4 ~  E6 o% @4 \$ b
) X( }- Y9 }' u) I6 C! E
1.信号线) l! `7 O3 r1 c+ [' }- c
STM32F767 核心板板载的 LCD 接口引出为了,节省 IO,并提高图片显示速度,使用 RGB565 颜色格式,这样只需要 16 个 IO 口,当使用 RGB565 格式的时候,LCD 面板的数据线,必须连接到 LTDC 数据线的 MSB
9 l  }; r' ?% e7 q: L, q
) A7 x3 F3 ?) h! d
20210720100712790.png

( m7 Y$ i( |$ U/ f; Q( m, p( Y& h) e* C1 q4 A
2.图像处理单元) p- N& i- p$ ?
 先从 AHB 接口获取显存中的图像数据,然后经过层 FIFO(有 2 个,对应 2 个层)缓存,每个层 FIFO 具有 64*32 位存储深度,然后经过像素格式转换器(PFC),把从层的所选输入像素格式转换为 ARGB8888 格式,再通过混合单元,把两层数据合并,混合得到单层要显示的数据,最后经过抖动单元处理(可选)后,输出给 LCD 显示。
& q/ p* i+ E) ^& u2 j* o8 e 混合单元首先将第一层与背景层进行混合,随后,第二层与第一层和第二层的混合颜色结果再次混合,完成混合后,送给 LCD显示。
5 F; Z' W* `. M5 _) r' c5 Z- ~! L% E* n0 d$ F9 j, y, n
20210720102457112.png
5 ?2 G" U$ [! B: m) |7 u
' [3 F- t# k  N) ^- H' N
3.AHB 接口) _1 p" b7 o+ v/ Q
 由于 LTDC 驱动 RGBLCD 的时候,需要有很多内存来做显存,比如一个 800480 的屏幕,按一般的 16 位 RGB565 模式,一个像素需要 2 个字节的内存,总共需要:800480*2=768K 字节内存,STM32 内部是没有这么多内存的,所以必须借助外部 SDRAM,而 SDRAM 是挂在AHB 总线上的,LTDC 的 AHB 接口,就是用来将显存数据,从 SDRAM 存储器传输到 FIFO 里面。
+ n0 k) j5 f& E$ g, E6 e7 A- Q! Y7 s, x# s; o" p
4.LTDC相关寄存器及使用方法
' v4 e5 g9 S1 B, N) j
LTDC 的各种配置寄存器以及状态寄存器,用于控制整个 LTDC 的工作参数,
, D4 `/ Y/ t" {, Q' ~主要有:各信号的有效电平、垂直/水平同步时间参数、像素格式、数据使能等等。
/ M9 i1 W8 H/ u, h0 M- I如果 RGBLCD 使用的是 DE 模式,需要设置如下参数,然后 LTDC会根据这些设置,自动控制 DE 信号。
9 f# ~' x; ]5 r0 l$ x
. b7 J, K9 F4 W+ C; n+ |LTCD全局控制寄存器 LTCD_GCR
1 X$ n) ]2 j& g3 f6 u
7 V/ E3 A, d3 P' R/ ~% w. v5 w
20210720104228854.png
' l) c8 o; O- M5 S
# ~. I8 C) Q0 j; R* {* a( N
]V@HJS%I_Y[%1XLYT61%0@2.png
3 p1 b" p% {( ]! p. T1 |

8 C0 [9 K6 P6 U/ ELTCD同步大小寄存器 LTDC_SSCR0 E, W1 |1 Q5 a
该寄存器用于设置垂直同步高度(VSH)和水平同步宽度(HSW)
% S7 U. l( D6 f- M3 W% K: N7 m( Q5 ~( u
20210720104959506.png
3 I; M7 o# k# T- m

2 r& Y4 h5 \; \6 X  [
0PRMT7%Y[QF2O{1W`AQ82~7.png
9 n% ~8 C/ Q* B/ y; K

  K4 l" h# L0 H) v: j/ X$ C* w) A; q0 |$ ]
LTDC有效宽度配置寄存器 LTDC_AWCR  `, m$ @  A1 `8 R4 a& f
这里所说的有效高度和有效宽度,是指 LCD 面板的宽度和高度,构成分辨率
" J' }. L9 o! w1 i# i( j  f/ M. ~6 ^: P
20210720110024135.png

5 |7 @; C( @( v4 Q% W  P* T- U: v, u1 I  u9 k
[AREI`HGZ@RRR{J@MJC8W]8.png

! e6 z; C+ d9 T/ m& }& w6 R- v: e+ Y  ~
     8 ]/ k( N. J9 Y: L5 y( p
LTDC 总宽度配置寄存器 LTDC_TWCR

- u3 d, G; b) M4 n$ K$ B6 {
- j& x7 r9 c# _+ o
20210720110931326.png
  h' U& G6 ^2 K! g
" n/ s. P% ^6 |) B! M8 q/ p
O6G8SGZNHK4ZYO{)JN[]USW.png
! g5 _) R9 g8 Q* W" e7 M' [
# t" `. \3 O" u& d3 |1 ]
      
' E$ |0 j+ c" }; G( P; BLTDC 背景色配置寄存器 LTDC_BCCR
: Q5 E0 g% e5 \2 a0 M该寄存器定义背景层的颜色(RGB888),通过低 24 位配置,我们一般设置为全 0 即可。6 t( e# N4 N. n- L

, ?5 ]* }: r9 ?1 S4 \, i+ X  `; Z- A3 ]& f- {, G" `0 U/ M; O
20210720111141846.png

7 X* W# o1 X- L$ B; x" V; Z" A0 {
LTDC当前位置状态寄存器 LTDC_CPSR
* u, m+ P4 ?- ~  L5 \8 L7 o
6 L/ f0 H5 J: F. b% `
a3355e745c2c73657ef826bf1a8f42f5.png

  S+ d" s: a$ h$ H9 r. L* I
5 y1 A: k& E+ w/ W7 d6 N! CCXPOS[31~16]:返回当前X坐标位置
% r0 |) y0 |* g/ J* m8 A% f, pCYPOS[15~0]:返回当前Y坐标位置
/ e4 l! S+ d  e* {7 S* @7 T
0 t; h0 `' ^6 x! C! }LTDC当前显示状态寄存器 LTDC_CDSR! C" C$ l4 }. }! T3 L
此寄存器返回由 HSYNC、VSYNC 和水平/垂直 DE 信号控制的当前显示阶段的状态+ ~, `8 o* n5 D& L' f) r
4 R% |' b0 J" F3 F5 F
c1e72a8f7ff1155cd5391d05ba83e42d.png

0 B1 d3 u) F8 Y4 T* ^; S$ A0 b
2 l: F" L, _! t* Y位 31:24 保留,必须保持复位值
: |4 n5 {4 Q& l5 n位 3 HSYNCS:水平同步显示状态 (Horizontal Synchronization display Status)
) \0 R$ `( F/ r0:低电平有效3 r8 n. R/ G+ i/ @) Y: x
1:高电平有效
' ]3 l! ^( ]' m- u# m+ h位 2 VSYNCS:垂直同步显示状态 (Vertical Synchronization display Status)) y) q( W4 e# Y1 I* D4 E9 S
0:低电平有效
3 i9 G" v5 M  p" g- N$ Y6 Z( W  q1:高电平有效
. l+ p/ N( S) a# _  {2 b6 y位 1 HDES:水平数据使能显示状态 (Horizontal Data Enable display Status)
9 K7 b6 |* {! V+ ^" \' Z0:低电平有效
* k) _4 b: p# Z1:高电平有效
9 h2 e/ _0 q- A" k) C: {位 0 VDES:垂直数据使能显示状态 (Vertical Data Enable display Status)
4 l) r2 g3 q5 R- L7 S3 C8 C0:低电平有效
/ z+ x! o! l! H$ j( J1:高电平有效" E$ @' g7 \9 ~' A
9 u) Z, O. W8 u+ v! N. |# K
LTDC 的层颜色帧缓冲区地址寄存器 LTDC_LxCFBAR(x=1/2); r5 E; h: F5 T1 x$ Y: L" H
该寄存器用来定义一层显存的起始地址。STM32F767 的 LTDC 支持 2 个层,所以总共有两个寄存器,分别设置层 1 和层 2 的显存起始地址。
  }. _. |4 J5 M0 O
7 _! x4 p: {1 l, `& S5 v; A$ b/ [0 g
20210720111336311.png

* @3 o/ w  Q/ ]" g
1 @. D: U) b: Z; G- ULTDC 的层像素格式配置寄存器 LTDC_LxPFCR(x=1/2)
# w: v& F4 i# w" B" m9 Q9 e+ O' F该寄存器只有最低 3 位有效,用于设置层颜色的像素格式,一般使用 RGB565 格式,即该寄存器设置为:010 即可。
; e( b. I; E/ w, [# f" d7 a8 q3 F" Z5 L) Q9 I1 z2 ?( C$ X1 r% k
STQ}OUE_D7Z(33OZ_E@73.png
$ l; u; l  M, V4 D3 w
6 E0 w+ _* K- j2 n; x5 i

- S1 u0 {1 Q. o% y+ O- I$ }      
0 Y  {& K8 H2 Y9 @0 u7 `7 ULTDC 的层恒定 Alpha 配置寄存器 LTDC_LxCACR(x=1/2)9 C0 H- h( O+ z( p2 X( U
该寄存器低 8 位(CONSTA)有效,这些位配置混合时使用的恒定 Alpha。恒定 Alpha 由硬件实现 255 分频。7 D# B* s8 C5 P7 |+ X/ c4 J: P
. _+ _/ `1 F: ]$ I/ T; d
20210720112235516.png
6 q. G! A3 I" g: i/ v
% a/ O8 [9 {: f  o7 _1 k2 R4 D
LTDC 的层默认颜色配置寄存器 LTDC_LxDCCR(x=1/2)

: F7 W6 M; p9 @( S0 _  a  I该寄存器定义采用 ARGB8888 格式的层的默认颜色。默认颜色在定义的层窗口外使用或在层禁止时使用。一般情况下,用不到,所以该寄存器一般设置为 0 即可。
" R( I! B1 `2 d  ]. L
7 w! L8 ^: \" w  X! T! t# x' U
20210720112604555.png

; }2 o; X0 C" n  d* B- i* p3 l+ D
1 J4 B+ p# x  }LTDC 层混合系数配置寄存器:LTDC_LxBFCR(x=1/2)
# ]# S5 @( U* T+ D该寄存器用于定义混合系数: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即可。
& i6 J" B# ?; \- p; j通用的混合公式为:BC=BF1C+BF2Cs- T2 q2 |$ ?- Z0 _3 Z1 Z5 _
其中:BC=混合后的颜色;BF1=混合系数 1;C=当前层颜色,即我们写入层显存的颜色值;BF2=混合系数 2;Cs=底层混合后的颜色,对于层 1 来说,Cs=背景层的颜色,对于层 2 来说,Cs=背景层和层 1 混合后的颜色。! \" q3 a( F5 A, v! ^
5 W  R" P3 R# L5 n  [
2021072011293763.png

% x5 Q! F! S. l: F8 K. h; H9 R$ }8 ^1 O2 J! |1 W, Z- J9 T) i& u
LTDC 的层窗口水平位置配置寄存器 LTDC_LxWHPCR(x=1/2)
& O8 c0 e2 p" b6 R# u+ G
该寄存器定义第 1 层或第 2 层窗口的水平位置,第一个和最后一个像素' C& T5 y; j0 m+ y+ m
9 G/ h" |+ T3 B' b' [! d
20210720113448290.png
9 M  J; J! R5 |# L6 F+ k
. J) Q$ ~# O- E
WHSTPOS:窗口水平起始位置,定义层窗口的一行的第一个可见像素,& G: ~6 g5 ^+ P2 R. q
WHSPPOS:窗口水平停止位置,定义层窗口的一行的最后一个可见像素( w: b) W3 K+ I% X/ A. b
; w6 R$ m% S0 [, z  z# r/ e
LTDC 的层窗口垂直位置配置寄存器 LTDC_LxWVPCR(x=1/2)

3 ]  x1 O0 T( t! w; ]/ h该寄存器定义第 1 层或第 2 层窗口的垂直位置(第一行或最后一行)
2 g3 u' f. c( f9 c+ s1 F* u7 q1 N, x; W7 A% X1 K! q& W0 @8 X
20210720133247145.png

# W& X  J/ Y& F, K5 V' z% Z5 @1 I9 l' Y5 @* S$ w. e
WVSTPOS:窗口垂直起始位置,定义层窗口的第一个可见行。% [' Y( d' N7 r0 S& w( y' y% c7 ~
WVSPPOS:窗口垂直停止位置,定义层窗口的最后一个可见行。
+ A; k3 X  Z; P. D( Q$ L; P* U9 B9 I. w5 t, o, o; B
LTDC 的层颜色帧缓冲区长度寄存器 LTDC_LxCFBLR(x=1/2)$ K: R+ r, L3 S
该寄存器定义颜色帧缓冲区的行长和行间距。1 p$ _0 T- P/ Y2 {  q4 L

  ]$ v0 E6 f: ?$ S2 l9 ?  H
20210720133802157.png
6 e- _( }+ B) [+ q5 R
+ u; c7 r, p0 A; H$ D9 @0 f# [/ U' {
CFBLL:这些位定义一行像素的长度(以字节为单位)+3。+ H& `& G( t! h0 Q  [" S" s# [9 ]
行长的计算方法为:有效宽度 * 每像素的字节数 + 3。. g, V4 `  A* S% P5 \0 \
比如,LCD 面板的分辨率为 800480,有效宽度为 800,采用 RGB565 格式,那么 CFBLL 需要设置为:8002+3=1603。
% o2 p9 q) G1 Z' W. w# B! l2 y; sCFBP:这些位定义从像素某行的起始处到下一行的起始处的增量(以字节为单位)。
7 R9 L1 ?7 B2 e4 a  W8 B这个设置,其实同样是一行像素的长度,对于 800480 的 LCD 面板,RGB565 格式,设置 CFBP 为:8002=1600 即可。/ ~7 H$ b/ s, Q" g! {0 S8 e
3 K9 C4 ?8 k8 b3 ~
LTDC 的层颜色帧缓冲区行数寄存器 LTDC_LxCFBLNR(x=1/2)
# B9 K$ }0 D+ \% |* e该寄存器定义颜色帧缓冲区中的行数。* `% Y1 s4 f! \) G
比如,LCD 面板的分辨率为 800*480,那么帧缓冲区的行数为 480 行,则设置 CFBLNBR=480 即可
8 A2 f0 X7 D& Y8 [8 }& e# p9 v. c$ K1 T* l# w/ o
20210720133424485.png

! ?" i* Q2 Y  H- o) x0 l; W
: h  A: e* Z' X5.时钟域
. C* F# m6 ?6 f$ b+ m) gLTDC 有三个时钟域:AHB 时钟域(HCLK)、APB2 时钟域(PCLK2)和像素时钟域(LCD_CLK),) ^! D+ m- @* m
AHB 时钟域用于驱动 AHB 接口,读取存储器的数据到 FIFO 里面;
. F' J9 a# z# ]1 OAPB2 时钟域用于配置寄存器;
! U2 n- E& m) ^% [0 U0 nLCD_CLK像素时钟域则用于生成 LCD 接口信号,LCD_CLK 的输出应按照 LCD 面板要求进行配置。
/ {1 t: b# c9 B; ~
2 G; J) p0 x$ F4 k, T+ zDMA2D
6 m! A. k) k+ L为了提高STM32F767的图像处理能力,ST公司设计了一个专用于图像处理的专业 DMA,通过 DMA2D 对图像进行填充和搬运,可以完全不用CPU 干预,从而提高效率,减轻 CPU 负担。3 r7 ]1 L) S9 p1 Y; g

) {0 K$ M6 \/ p( \, O它可以执行下列操作:
" C" j9 }0 Y( T4 B: c/ e7 K6 V9 y7 v用特定颜色填充目标图像的一部分或全部(可用于快速单色填充)
  v6 F, _' _0 m) T9 L将源图像的一部分(或全部)复制到目标图像的一部分(或全部)中(可用于快速图像填充)- s' P$ [  K5 T. B; O
通过像素格式转换将源图像的一部分(或全部)复制到目标图像的一部分(或全部)中0 m7 p) u; f# S
将像素格式不同的两个源图像部分和/ 或全部混合,再将结果复制到颜色格式不同的部分或整个目标图像中( e. X+ s! S, y2 h- S( B
) d9 w! H) `/ E4 {/ q& v% f( g

1 ^. N5 N( s  n- i& M8 s! @) EDMA2D 有四种工作模式,通过 DMA2D_CR 寄存器的 MODE[1:0]位选择工作模式:
( }+ W9 ?7 z9 A6 ]; z% y5 Y1 O1, 寄存器到存储器
( m7 G1 u4 M0 E2 ~; V% v, F) h2, 存储器到存储器7 I5 T+ Q' S: M6 Q7 z
3, 存储器到存储器并执行 PFC
7 I$ l! y" Y  Y1 Q& b. y4, 存储器到存储器并执行 PFC 和混合" Y0 M$ [+ u) ~- y! K" L* i3 r
8 y7 I+ Y9 j7 C
6 N4 X$ p+ G% e" S2 n, x
寄存器到储存器( ?+ g: l/ G: H3 {6 m! y9 V8 }
寄存器到存储器模式用于以预定义颜色填充用户自定义区域,也就是可以实现快速的单色
; V( o1 Y- m( r0 k! D! ~" ~1 C填充显示,比如清屏操作。
7 Q3 g6 o" V  {% M在该模式下:颜色格式在 DMA2D_OPFCCR 中设置,DMA2D 不从任何源获取数据,它只
; _# Q$ Q6 v' U+ D' M4 q是将 DMA2D_OCOLR 寄存器中定义的颜色写入通过 DMA2D_OMA 寻址以及 DMA2D_NLR 和& X- D* b7 o. i% |
DMA2D_OOR 定义的区域% }8 j. D) j# s- ?" S' Q
! F; f9 ]% O. K' B. c# a
9 k' r( m' L2 d5 z
储存器到储存器, K& q/ _- u/ W7 O8 L; j
该模式下,DMA2D 不执行任何图形数据转换。前景层输入 FIFO 充当缓冲区,数据从
* z* h# p$ P3 v. T' gDMA2D_FGMAR 中定义的源存储单元传输到 DMA2D_OMAR 寻址的目标存储单元,可用于快$ W5 p7 V8 }4 D2 O; j2 b
速图像填充。DMA2D_FGPFCCR 寄存器的 CM[3:0]位中编程的颜色模式决定输入和输出的每像
$ F1 q7 o( I  _' Q! x. A素位数。对于要传输的区域大小,源区域大小由 DMA2D_NLR 和 DMA2D_FGOR 寄存器定义,
/ w0 l3 N( k9 X/ Q' a- C7 d5 p目标区域大小则由 DMA2D_NLR 和 DMA2D_OOR 寄存器定义。/ c! m. f8 v% h3 i
8 G" }- }2 a" o9 A

# l6 \9 d. S) `, m% |以上两个工作模式,LTDC 在层帧缓存里面的开窗关系都一样的,经过如下三个寄存器的配置,就可以确定窗口的显示位置和大小。
; |( D" h6 H( }- a+ ~. D(1). 窗口显示区域的显存首地址由 DMA2D_OMAR 寄存器指定,5 C0 s3 ?5 n" C1 `2 q
(2).窗口宽度和高度由DMA2D_NRL 寄存器的 PL 和 NL 指定; J( e( k: J' K# d) A" s
(3).行偏移(确定下一行的起始地址)由 DMA2D_OOR寄存器指定,
( d! ]6 O7 s' e5 S6 V( u" h, H. \/ y% P4 R/ T) }  Y3 B
20210720170136697.png

8 ^! r; U0 Z% y# i* r6 V
# K! D0 r+ H$ V: \7 P* g" ], f+ J) E9 F2 S4 X
在寄存器到存储器模式下,在开窗完成后,DMA2D 可以将 DMA2D_OCOLR 指定的颜色,
- [! Z8 i2 K5 X4 I自动填充到开窗区域,完成单色填充。8 e& N! x/ Q7 r* ^

" h4 Z3 e- A8 i9 E% X0 m. }/ X5 _7 U" u* m9 a" m
在存储器到存储器模式下,需要完成两个开窗:前景层和显示层,完成配置后,图像数据从前景层拷贝到显示层(仅限窗口范围内),从而显示到 LCD 上面。显示层的开窗如上图所示,前景层也和上图类似,只是 DMA2D_OMAR 寄存器变成了DMA2D_FGMAR,DMA2D_OOR寄存器变成了DMA2D_FGOR,DMA2D_NRL则两个层共用,然后就可以完成对前景层的开窗,确定好两个窗口后,DMA2D 就将前景层窗口内的数据,拷贝到显示层窗口,完成快速图像填充。5 S1 L1 d- ~8 p4 k1 ]1 T% X

1 f1 O  W( O& W$ C- H6 A( e
1 G7 `3 z" g3 Y3 l' l7 ]- ~DMA2D相关寄存器
/ l( `; s- f: e' l* Y" ?$ oDMA2D控制寄存器 DMA2D_CR! j7 h  y3 F$ U1 \1 X7 a1 o
该寄存器,主要是MODE 和 START 这两个设置- f+ i/ v* F& i3 I/ e* ?" Q
! E2 r8 W! G" s) T* S( g. {( X) ]
20210720172154901.png

% y- {) t5 C$ R. |/ a% s4 x* N2 B/ s8 h$ T! n
MODE:表示 DMA2D 的工作模式,6 }! E1 B' u1 L: ]  m2 Z
00:存储器到存储器模式;01:存储器到存储器模式并执行 PFC;
) N- k; a8 e3 v4 ?10:存储器到存储器并执行混合;11,寄存器到存储器模式;
: g& Y2 l; i; R  D& \START:该位控制 DMA2D 的启动,在配置完成后,设置该位为 1,启动 DMA2D 传输。
2 K( C% T+ r! _1 A+ E6 e0 T* u/ G4 ^* ^2 m/ C4 G
DMA2D输出 PFC 控制寄存器 DMA2D_OPFCCR
( S3 k1 \9 ]4 [3 Y  b+ D7 ^该寄存器用于设置寄存器到存储器模式下的颜色格式
, M9 o7 K, N1 S6 t/ d  ^
4 z# I; L* F1 E: a3 `* G1 B
20210720172538112.png
, j6 ^. s" @1 d; I4 W! x* R1 q

( ?, ]9 m$ u6 H4 \- C只有最低 3 位有效(CM[2:0]),表示的颜色格式有:
5 r8 Q8 S$ O# H0 }+ B000,ARGB8888;001:RGB888;010:RGB565;
6 e* z$ p  \5 f( N5 u011:ARGB1555;100:ARGB1444。' p% w+ {, e, ^) Y' N8 t
我们一般使用的是 RGB565 格式,所以设置 CM[2:0]=010 即可。4 r) d4 _  ^; Y( R3 h
- m4 d7 J& Z: d  }
DMA2D前景层 PFC 控制寄存器:DMA2D_FGPFCCR
: c, j7 U3 U7 }. e- F9 ^4 I% _$ T
20210720173213773.png

2 ]% @6 C1 w/ k4 w
( i! C+ ^  ]6 t2 u该寄存器,低 4 位:CM[3:0],用于设置存储器到存储器模式下的颜色格式,这四个位表示的颜色格式为:
+ s/ G+ r' z+ T5 h- L+ l0000:ARGB8888;0001:RGB888;0010:RGB565;' g% b" F4 J8 x6 I7 M+ R' H
0011:ARGB1555;0100:ARGB4444;0101:L8;7 a; \3 t, p: K  |7 D- E" k, I
0110:AL44;0111:AL88;1000:L4;1001:A8;1010:A4;
- c! E3 m/ c4 u, \我们一般使用 RGB565 格式,所以设置 CM[3:0]=0010 即可。; A; z2 ?" `7 M# {3 R2 o. K3 Z- @
, F$ Y# i; \5 c. S
DMA2D输出偏移寄存器 DMA2D_OOR
3 ]6 D' q. k1 [1 q
( R& Q4 H9 l2 y6 p9 k& P
20210720174740982.png
, J; [& K( t5 D: Q# W$ D9 l) ?
该寄存器仅最低 14 位有效(LO[13:0]),用于设置输出行偏移,作用于显示层,以像素为$ A6 d- G/ Q, y. c  v0 R. k
单位表示。此值用于生成地址。行偏移将添加到各行末尾,用于确定下一行的起始地址。- z( m& J8 L0 A9 b1 g
同样的,还有前景层偏移寄存器:DMA2D_FGOR,该寄存器同 DMA2D_OOR 一样,也是
9 Q$ J" z2 i0 Z& z8 |" ?1 m0 f0 w低 14 位有效,用于控制前景层的行偏移,也是用于生成地址,添加到各行末尾,从而确定下一
1 x- F/ e1 w8 T9 S$ s4 S行的起始地址。. r# ]) U- l* m- f3 u; d  `' T; y
% h1 N# U8 r9 }5 ^2 B
DMA2D输出存储器地址寄存器 DMA2D_OMAR
. ]' e0 P; o# O  ~+ b) D9 _- z3 [6 v! F
# U: `5 t4 Q* q& t
20210720175051288.png
: d3 z. j4 t" I3 n( h) Z& T1 e. b

3 |( {& y0 g; P) O该寄存器设置由 MA[31:0]设置输出存储器地址,也就是输出 FIFO 所存储的数据地址,该地址需要根据开窗的起始坐标来进行设置。以 800480 的 LCD 屏为例,行长度为 800 像素,假定帧缓存数组为:ltdc_framebuf,我们设置窗口的起始地址为:sx(<800),sy(<480),颜色格式为 RGB565,每个像素 2 个字节,那么 MA 的设置值应该为:
( p! R, }& i$ K/ h*MA[31:0]= framebuf+2(800sy+sx)**1 a" @2 }* c9 I8 C. C4 g6 Z
同样的,还有前景层偏移寄存器:DMA2D_ FGMAR,该寄存器同 DMA2D_OMAR 一样,
9 e$ f  ^% u) h% R4 s不过是用于控制前景层的存储器地址,计算方法同 DMA2D_OMAR。( ?& S+ F: x6 F' B! R: X
! {' m4 G6 m4 d. R  _
DMA2D行数寄存器 DMA2D_NLR, j6 X9 X7 ]" M9 c- X

8 Y; J8 d) p  G7 {2 e
20210720180044872.png

/ R/ R, w9 L1 N! ?+ s% |该寄存器用于控制每行的像素和行数,该寄存器的设置对前景层和显示层均有效,通过该寄存器的配置,就可以设置开窗的大小。其中:
# ~( I7 \* N" U1 ~  FNL[15: 0]:设置待传输区域的行数,用于确定窗口的高度。" K0 x+ v( |/ m0 F& j) O/ }
PL[13: 0]:设置待传输区域的每行像素数,用于确定窗口的宽度
' i8 f2 U) {2 A" m) r8 |5 x: A
" L( k( A/ L; D, ]DMA2D输出颜色寄存器 DMA2D_OCOLR
/ A0 Q; e+ m# _/ [; y5 F# V- {3 k- D" {
20210720180520678.png
  S9 K. v! i! H, {# e' h
该寄存器用于配置在寄存器到存储器模式下,填充时所用的颜色值,该寄存器是一个 32位寄存器,可以支持 ARGB8888 格式,也可以支持 RGB565 格式。我们一般使用 RGB565 格式,比如要填充红色,那么直接设置 DMA2D_OCOLR=0XF800 就可以了。
/ N' g. y' g+ E& {
6 r% p, ~* \4 wDMA2D中断状态寄存器 DMA2D_ISR
3 h* S- t" b$ G- [% j8 h4 k* G# M! {8 p
2021072018063162.png

$ c% V8 ]1 ?' F& @/ j; v! }9 k* l$ u/ H; l  \/ X1 G# u# i
该寄存器表示了 DMA2D 的各种状态标识2 H2 l: m6 V( {, }, O6 i) z
TCIF 位,表示 DMA2D 的传输完成中断标志。当 DMA2D 传输操作完成(仅限数据传输)时此位置 1,表示可以开始下一次 DMA2D 传输了4 \; O/ v, M9 d7 S
DMA2D 中断标志清零寄存器:DMA2D_IFCR,用于清除 DMA2D_ISR 寄存器对应位的标志。通过向该寄存器的第 1 位(CTCIF)写 1,可以用于清除 DMA2D_ISR 寄存器的 TCIF 位标志。
4 m1 x& ^. T  @+ Y8 S2 h
- w4 a/ j# d' B5 r) t2 @3 k
% G7 N1 I  f. w* U4 E# L! G1 ?* F; _LTDC具体使用步骤
5 r9 F+ F% i9 }/ ?+ I) G. O1.使能 LTDC 时钟,并配置 LTDC 相关的 IO 及其时钟使能。
+ q4 G" x4 e& J8 I. i使用 LTDC,当然首先得开启其时钟。
1 F" o3 ?' O' H/ Y7 e7 ?+ q然后需要把 LCD_R/G/B 数据线、LCD_HSYNC和 LCD_VSYNC 等相关 IO 口,全部配置为复用输出,并使能各 IO 组的时钟。
  D3 n# H9 q1 B1 R9 x; O! i
. |- d* O" H1 V7 v" @3 T. e5 \
  1. //LTDC底层IO初始化和时钟使能
    ' ~/ J+ p/ B( Q* q2 P) v0 {# P# h5 }  A
  2. //此函数会被HAL_LTDC_Init()调用
    % r: l2 g3 Y2 a! f
  3. //hltdc:LTDC句柄
    * e; {! r! K' L  n
  4. void HAL_LTDC_MspInit(LTDC_HandleTypeDef* hltdc)
    * h* ?; ~1 K% m# E1 Z5 C! T
  5. {, u5 e& W$ I# p1 A: Z0 \
  6.     GPIO_InitTypeDef GPIO_Initure;
    3 X% B% c& k: z& x  ~, l7 z

  7.   v  t, V9 K, U% p* r/ ]
  8.     __HAL_RCC_LTDC_CLK_ENABLE();                //使能LTDC时钟
    + `0 r  C& l( J: E/ ]3 k
  9.     __HAL_RCC_DMA2D_CLK_ENABLE();               //使能DMA2D时钟9 T, U* v1 q2 ], I
  10.     __HAL_RCC_GPIOB_CLK_ENABLE();               //使能GPIOB时钟' [. e. `  v. |' H0 S& S1 n
  11.     __HAL_RCC_GPIOF_CLK_ENABLE();               //使能GPIOF时钟: _% a' U' f6 f: |( K/ l8 g9 V
  12.     __HAL_RCC_GPIOG_CLK_ENABLE();               //使能GPIOG时钟
    9 ?+ K4 Z4 _. K/ N
  13.     __HAL_RCC_GPIOH_CLK_ENABLE();               //使能GPIOH时钟
    , Q7 k0 ~" d8 t7 Y( w
  14.     __HAL_RCC_GPIOI_CLK_ENABLE();               //使能GPIOI时钟3 H7 ]  N0 `# ^: `. S

  15. 9 l$ Z  ^- r3 e6 P" t
  16.     //初始化PB5,背光引脚- x( s# B5 J6 |' M3 |) ?
  17.     GPIO_Initure.Pin=GPIO_PIN_5;                //PB5推挽输出,控制背光8 @3 R% d' {3 f
  18.     GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;      //推挽输出/ Z; g2 k$ C$ u# t: y
  19.     GPIO_Initure.Pull=GPIO_PULLUP;              //上拉! |0 }: C  R$ a5 _7 P3 y7 S. }
  20.     GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速
    ' ~( R8 A0 H" c& c* @
  21.     HAL_GPIO_Init(GPIOB,&GPIO_Initure);
    , f$ p1 u# ?+ t- Q/ M
  22. ) ~: s: R$ A, B4 L
  23.     //初始化PF10
    5 s& o6 c* E; T' D
  24.     GPIO_Initure.Pin=GPIO_PIN_10; : N# m; O9 h9 k( o. {% ]1 Q
  25.     GPIO_Initure.Mode=GPIO_MODE_AF_PP;          //复用
    9 ~* q; G% |1 W7 N6 I
  26.     GPIO_Initure.Pull=GPIO_NOPULL;
    ; w7 f9 ~& U- C1 j- R6 s
  27.     GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速0 c: t; t# d, K: B# ^) X7 N5 a
  28.     GPIO_Initure.Alternate=GPIO_AF14_LTDC;      //复用为LTDC5 S- d# A! U# R+ \. i/ C
  29.     HAL_GPIO_Init(GPIOF,&GPIO_Initure);* U0 M$ p# O0 C/ ?! f
  30. 8 _0 c8 A9 T9 I
  31.     //初始化PG6,7,11
    8 \* I, Z  W& [' y0 J; g  @
  32.     GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_11;( D6 Z" c  w7 f4 ~2 t: u
  33.     HAL_GPIO_Init(GPIOG,&GPIO_Initure);! |5 R- o* u9 f& O
  34. % f3 Y! H/ s6 w( `
  35.     //初始化PH9,10,11,12,13,14,15/ n$ d8 I7 V8 ~% Q
  36.     GPIO_Initure.Pin=GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|\
    & `" _0 ?4 e) x, R. [% J
  37.                      GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
    9 P' V; P; s  B) M, W
  38.     HAL_GPIO_Init(GPIOH,&GPIO_Initure);
    ' Z0 w$ h% E( Q& h# D' ~" F" M& I
  39. ! S/ |% H- K5 m+ E) j2 ?6 c$ I
  40.     //初始化PI0,1,2,4,5,6,7,9,10
    # o( K6 ^3 s1 P) G3 y8 Q( J
  41.     GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|\
    0 L! _4 J) \9 F4 f0 D: Y% b
  42.                      GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_9|GPIO_PIN_10;! I( O3 J7 w3 Z% h6 h+ O. m
  43.     HAL_GPIO_Init(GPIOI,&GPIO_Initure);
    % R) o) o2 X4 T
  44. }
复制代码
8 w6 |" G' z. L: w# |1 ]4 W
2.设置LCD_CLK时钟
+ _. k, O) c) z( s配置 LCD 的像素时钟,根据 LCD 的面板参数进行设置,LCD_CLK 由 PLLSAI进行配置,配置使用到的 HAL 库函数为:
: Y5 K: Z' S$ k5 [0 j( f  d, k0 w% q" [4 T
  1.         //pllsain:SAI时钟倍频系数N,取值范围:50~432.  
    " \. I  Q( J  H# ~
  2.         //pllsair:SAI时钟的分频系数R,取值范围:2~70 B2 M/ a  Y7 |4 I3 j) ?( {
  3.         //pllsaidivr:LCD时钟分频系数,取值范围:0~3,对应分频2~16
    2 O( a1 B! w  s- Z/ s
  4.         //假设:外部晶振为25M,pllm=25的时候,Fin=1Mhz.& U6 A# h- Q9 u
  5.         //例如:要得到20M的LTDC时钟,则可以设置:pllsain=400,pllsair=5,pllsaidivr=1
    # K( K; ?: F+ S3 V* }1 A
  6.         //Fdclk=1*396/3/2*2^1=396/12=33Mhz
    ( w4 o8 c' w6 W
  7.     RCC_PeriphCLKInitTypeDef PeriphClkIniture;
    5 B- C4 N& P+ U# o# j% m  R

  8. 0 Z2 V5 _4 G/ `% k
  9.     //LTDC输出像素时钟,需要根据自己所使用的LCD数据手册来配置!- T7 u: ]* {, D) X  ^4 ^! ~5 r+ y
  10.     PeriphClkIniture.PeriphClockSelection=RCC_PERIPHCLK_LTDC;       //LTDC时钟) I4 S) T7 \) \6 Y
  11.     PeriphClkIniture.PLLSAI.PLLSAIN=pllsain;% |! X4 @0 A. O+ X6 q: F$ r
  12.     PeriphClkIniture.PLLSAI.PLLSAIR=pllsair;
    ) b. W. g( |, l; U8 A
  13.     PeriphClkIniture.PLLSAIDivR=pllsaidivr;1 K- U& ]8 i% o, c
  14.         HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef *PeriphClkInit)
复制代码
" ?) e& P, t2 K. E9 O1 S
3.设置RGBLCD相关参数,并使能LTDC
2 e. a( A- w1 p+ z
  1. typedef struct5 Q0 ?3 H; r/ {/ a+ @
  2. {7 v! _5 l  i% B1 B0 y/ d
  3. uint32_t HSPolarity;                         //水平同步极性
    ; \/ z. |" k/ M
  4. uint32_t VSPolarity;                         //垂直同步极性 6 A& B5 w  f6 h. l1 C+ H, |: v; R
  5. uint32_t DEPolarity;                         //数据使能极性6 _+ E! v2 ?' ]1 K) S! m
  6. uint32_t PCPolarity;                         //像素时钟极性; ?% M1 L2 B' c) i+ [
  7. uint32_t HorizontalSync;                 //水平同步宽度 $ B" D; g5 R/ k3 Q  H
  8. uint32_t VerticalSync;                 //垂直同步高度: q; U; ~7 J. @  K( m
  9. uint32_t AccumulatedHBP;                 //水平同步后沿宽度  A' m9 ^1 s& G: y) b
  10. uint32_t AccumulatedVBP;                 //垂直同步后沿高度
    + A( M6 `2 U* g6 C/ H0 \+ |
  11. uint32_t AccumulatedActiveW;         //累加有效宽度 # E3 S+ b. i) g/ ?# h! O3 N, U3 Z
  12. uint32_t AccumulatedActiveH;         //累加有效高度
    ! O( Q2 \( Y% o8 W* o9 |
  13. uint32_t TotalWidth;                         //总宽度
    / _# y! q4 a: {* [" q- R
  14. uint32_t TotalHeigh;                         //总高度3 b  `! l7 _+ j& G# j( k7 V$ A( ?
  15. LTDC_ColorTypeDef Backcolor;         //屏幕背景层颜色 " Z. ^5 Q+ W6 I3 v6 I
  16. } LTDC_InitTypeDef;1 C4 I7 \4 A& {' `) i% Z+ ^
  17. ( ?! R' O; S) t6 W
  18. typedef struct
    1 o, N& h8 K: x4 \1 \% }
  19. {
    & O- d* q4 Y0 i; K# o' q
  20.   LTDC_TypeDef                *Instance;                /*Instance变量是LTDC_TypeDef结构体指针类型*/# k. o) |0 P- z. X: v  R5 i- K
  21.   LTDC_InitTypeDef            Init;                     /*用来初始化LTDC的结构体变量*/
    4 z- v: v7 c1 R: D$ v
  22.   LTDC_LayerCfgTypeDef        LayerCfg[MAX_LAYER];      /*保存LTDC层配置参数*/
    2 n2 d7 o+ n  ^$ }: k
  23.   HAL_LockTypeDef             Lock;                     /*锁状态*/
    : J' [( A9 H* f) ~
  24.   __IO HAL_LTDC_StateTypeDef  State;                    /*LTDC的状态*/
    0 {5 p1 h; r: W5 u; G
  25.   __IO uint32_t               ErrorCode;                /*错误处理*/# R2 n- C9 g% h6 l' y
  26. } LTDC_HandleTypeDef;
    ! r5 d: M  v  V1 k8 x/ V2 y; q6 J" }

  27. & I5 C4 l0 t* k. P: i$ o
  28. LTDC_HandleTypeDef  LTDC_Handler;                                   //LTDC句柄
    6 U  _5 B1 m6 R

  29. 2 U) T" }- \" m' H/ \
  30. LTDC_Handler.Instance=LTDC;
    % r9 W; x) T! u8 c4 D8 g
  31. LTDC_Handler.Init.HSPolarity=LTDC_HSPOLARITY_AL;                 //水平同步极性! N; [* ]6 G' e3 v
  32. LTDC_Handler.Init.VSPolarity=LTDC_VSPOLARITY_AL;                 //垂直同步极性
    7 i# A, W' `8 X" _  U/ T
  33. LTDC_Handler.Init.DEPolarity=LTDC_DEPOLARITY_AL;                 //数据使能极性
    3 ^5 m2 {- r# x
  34. LTDC_Handler.Init.PCPolarity=LTDC_PCPOLARITY_IPC;                 //像素时钟极性
    ! V& _  g  t; E. A' K5 \( h4 q
  35. LTDC_Handler.Init.HorizontalSync=10-1;                                         //水平同步宽度
    & J0 ?6 Z. f1 j+ H( N2 _! m8 ]
  36. LTDC_Handler.Init.VerticalSync=2-1;                                         //垂直同步宽度  l+ F2 g+ i2 x7 W, B7 ~7 R
  37. LTDC_Handler.Init.AccumulatedHBP=10+20-1;                                 //水平同步后沿宽度
    # e1 V1 \. Z! u4 [+ R9 S; _
  38. LTDC_Handler.Init.AccumulatedVBP=2+2-1;                                 //垂直同步后沿高度
    1 w8 m  F( a* w3 M3 H( z4 g; G4 J
  39. LTDC_Handler.Init.AccumulatedActiveW=10+20+480-1;                 //有效宽度, p% _3 [6 ]- K! g' s6 D; e- [
  40. LTDC_Handler.Init.AccumulatedActiveH=2+2+272-1;                 //有效高度7 P  L8 n. u1 ]% W0 l* ~0 j7 O. @
  41. LTDC_Handler.Init.TotalWidth=10+20+480+10-1;                         //总宽度
    ) I  N" k+ J' p+ |5 a
  42. LTDC_Handler.Init.TotalHeigh=2+2+272+4-1;                                 //总高度% e9 J/ c4 c6 q" G" `
  43. LTDC_Handler.Init.Backcolor.Red=0;                                                 //屏幕背景层红色部分
    ( G9 k3 L8 O/ g: q0 g
  44. LTDC_Handler.Init.Backcolor.Green=0;                                         //屏幕背景层绿色部分
    . M% ~& `$ q, G( I0 q8 U  Y
  45. LTDC_Handler.Init.Backcolor.Blue=0;                                         //屏幕背景色蓝色部分3 V% l/ Z: o- p  a* T2 R" s% \
  46. HAL_LTDC_Init(<DC_Handler);                                                         //设置 RGBLCD 的相关参数,并使能 LTDC,会调用HAL_LTDC_MspInit
复制代码

. }1 X' s+ _) k, c1 @, T4 V4.设置 LTDC层参数
6 t/ @- z9 C& b% |$ A
  1. //layerx:层值,0/1.8 C8 X0 q- q" u" G& ], ^. A
  2. //bufaddr:层颜色帧缓存起始地址
    $ I" q* ?6 ^2 t* s( r0 ?: X* _, @
  3. //pixformat:颜色格式.0,ARGB8888;1,RGB888;2,RGB565;3,ARGB1555;4,ARGB4444;5,L8;6;AL44;7;AL88" P) ~' ^, o" {
  4. //alpha:层颜色Alpha值,0,全透明;255,不透明! f1 }9 w; F4 ?1 R' p; j
  5. //alpha0:默认颜色Alpha值,0,全透明;255,不透明, @6 }# e% p9 S
  6. //bfac1:混合系数1,4(100),恒定的Alpha;6(101),像素Alpha*恒定Alpha2 Y' L# {. j% Y  h
  7. //bfac2:混合系数2,5(101),恒定的Alpha;7(111),像素Alpha*恒定Alpha
      d+ y1 Y2 V# @" P6 ?# |- ^# J
  8. //bkcolor:层默认颜色,32位,低24位有效,RGB888格式  u5 O8 K: s$ }# L6 a. @; T
  9. void LTDC_Layer_Parameter_Config(u8 layerx,u32 bufaddr,u8 pixformat,u8 alpha,u8 alpha0,u8 bfac1,u8 bfac2,u32 bkcolor)& A2 S  x# z( G: g" l. [4 F' \9 r- L: |# d
  10. {9 S- ]$ X7 f$ W0 x
  11.     LTDC_LayerCfgTypeDef pLayerCfg;
    8 c9 c8 J5 h/ K) g

  12. # {9 \- X$ C  ]: p4 X$ T0 k
  13.     pLayerCfg.WindowX0=0;                                   //窗口起始X坐标8 C/ s. h5 r. C% X, i* v/ C
  14.     pLayerCfg.WindowY0=0;                                   //窗口起始Y坐标
      Q7 |! [& f5 b3 ^/ K: G
  15.     pLayerCfg.WindowX1=lcdltdc.pwidth;                      //窗口终止X坐标
    5 z# A. P0 u7 }
  16.     pLayerCfg.WindowY1=lcdltdc.pheight;                     //窗口终止Y坐标
    8 p) A6 D2 P: q( ?2 B" f
  17.     pLayerCfg.PixelFormat=pixformat;                        //像素格式- Z8 ~8 B" ^6 A0 p: N( U
  18.     pLayerCfg.Alpha=alpha;                                  //Alpha值设置,0~255,255为完全不透明% [9 Y8 ?. b# d+ i) b
  19.     pLayerCfg.Alpha0=alpha0;                                //默认Alpha值0 N! c7 L" g: J; A2 L: P, j
  20.     pLayerCfg.BlendingFactor1=(u32)bfac1<<8;                //设置层混合系数9 B6 M4 b, K1 y* }# m4 x- v# G
  21.     pLayerCfg.BlendingFactor2=(u32)bfac2<<8;                //设置层混合系数
    ) o& g2 U9 t. u! E
  22.     pLayerCfg.FBStartAdress=bufaddr;                        //设置层颜色帧缓存起始地址6 W0 G, K1 n) ~' r, G
  23.     pLayerCfg.ImageWidth=lcdltdc.pwidth;                    //设置颜色帧缓冲区的宽度   
    , }' C9 r; v; n) G9 S: Y( ^
  24.     pLayerCfg.ImageHeight=lcdltdc.pheight;                  //设置颜色帧缓冲区的高度
    + C6 q6 ~- ~# r1 B* V+ c
  25.     pLayerCfg.Backcolor.Red=(u8)(bkcolor&0X00FF0000)>>16;   //背景颜色红色部分
    $ d/ n! X* F7 _
  26.     pLayerCfg.Backcolor.Green=(u8)(bkcolor&0X0000FF00)>>8;  //背景颜色绿色部分
    ' d9 x9 u# A* |4 p: ]" h
  27.     pLayerCfg.Backcolor.Blue=(u8)bkcolor&0X000000FF;        //背景颜色蓝色部分9 r# `3 C1 P6 ~0 ?, c6 |. ~
  28.     HAL_LTDC_ConfigLayer(<DC_Handler,&pLayerCfg,layerx);  //设置所选中的层
    " R5 U. D* [  I6 [4 K9 x# e8 u
  29. }
    2 i! H. |. R5 U6 o- K9 K
  30. 7 _  e, Q5 s& k- Y8 l! ~
  31. //在init时调用
    9 N/ Q$ l# V8 \3 m- h1 V
  32. LTDC_Layer_Parameter_Config(0(u32)ltdc_framebuf[0],LCD_PIXFORMAT,255,0,6,7,0X000000);  //层参数配置
复制代码
2 i$ R; c! N; A4 a
5.设置LTDC层窗口% }+ V7 ?5 D0 c' V8 ]3 ]
  1. //layerx:层值,0/1.4 _( Q# o" i8 @6 C
  2. //sx,sy:起始坐标; v( L) h4 {+ q6 e
  3. //width,height:宽度和高度
    ; F2 O# _4 y* j3 `5 |
  4. void LTDC_Layer_Window_Config(u8 layerx,u16 sx,u16 sy,u16 width,u16 height)
    & y3 }. P: P1 e3 j
  5. {" s$ m8 q8 i5 O* V+ X& |  ?
  6.     HAL_LTDC_SetWindowPosition(<DC_Handler,sx,sy,layerx);                                  //设置窗口的位置3 Y+ Q$ }9 K( E" x% ~/ a
  7.     HAL_LTDC_SetWindowSize(<DC_Handler,width,height,layerx);                                //设置窗口大小   
    ; r. {' B9 i- \2 b3 }; b
  8. }  f" L) D. e2 {( d
  9. 6 \8 H) \0 n& s) ^9 R2 N
  10. //在init时调用* |' |% a9 q* N" F
  11. LTDC_Layer_Window_Config(0,0,0,lcdltdc.pwidth,lcdltdc.pheight);             //层窗口配置,以LCD面板坐标系为基准
复制代码

% ?/ Y/ A8 X" v& C* b9 p8 B完成了 LTDC 的配置,可以控制 RGBLCD 显示了。
% `0 ]5 Q( r) w0 z9 n8 q% w& {* v7 r6 R5 ~" ]2 V1 Q
使用DMA2D完成颜色填充3 Z% Y; y* W5 e( q7 l$ R2 @
使用官方提供的 HAL 库 DMA2D 相关库函数进行颜色填充效率极为低下,大量时间浪费在函数的入栈出栈以及过程处理,所以在项目开发中一般都不会使用 DMA2D 库函数进行颜色填充2 [$ v1 ~( r/ u7 j1 w
: v  N: {3 L7 Y) t! N1 n. @
1)使能 DMA2D 时钟,并先停止 DMA2D。
0 P. v0 {- M! a+ B要使用 DMA2D,先得开启其时钟。然后 DMA2D 在配置其相关参数的时候,需要先停止DMA2D 传输。 使能 DMA2D 时钟和停止 DMA2D 方法为:
" w$ p7 J( J* x9 d
  1. __HAL_RCC_DMA2D_CLK_ENABLE(); //使能 DM2D 时钟
    : b& v' g7 D1 B; E4 m% d
  2. DMA2D->CR&=~DMA2D_CR_START; //停止 DMA2D
复制代码
- b- u2 U" o' g+ i0 [1 r' g
2)设置 DMA2D 工作模式。
# m( N' U+ t9 g通过 DMA2D_CR 寄存器,配置 DMA2D 的工作模式。我们用了寄存器到存储器模式和存储器到存储器这两个模式。
' g* P7 ?! m  I: D+ F5 `! K: D: }寄存器到存储器模式设置:
9 T7 t( _/ `, ]" O; s
  1. DMA2D->CR=DMA2D_R2M; //寄存器到存储器模式
复制代码
/ l+ u* Y( o- H" }) K
存储器到存储器模式设置:
- k9 U) `- n" m, w  d. n
  1. DMA2D->CR= DMA2D_M2M; //存储器到存储器模式
复制代码

; [' a) b3 v- w& w0 h9 Z# J; O3)设置 DMA2D 的相关参数。% X& `  J# {2 A+ N% i/ t' o
这一步,我们需要设置:颜色格式、输出窗口、输出存储器地址、前景层地址(仅存储器到存储器模式需要设置)、颜色寄存器(仅寄存器到存储器模式需要设置)等,由:DMA2D_OPFCCR、DMA2D_FGPFCCR、DMA2D_OOR、DMA2D_FGOR 、DMA2D_OMAR、DMA2D_FGMAR 和 DMA2D_NLR 等寄存器进行配置。具体配置过程请参考实验源码。
/ E1 n5 m; \9 W! U! `
; M3 V' Q$ D$ }' A8 F& t4)启动 DMA2D 传输。
1 S7 N9 }# f) e  l& d通过 DMA2D_CR 寄存器配置开启 DMA2D 传输,实现图像数据的拷贝填充,方法为:
3 F) c3 _# I1 c0 R& y
- M$ W9 J5 w/ z! e2 d  ]$ F6 B( GDMA2D->CR|=DMA2D_CR_START; //启动 DMA2D9 L$ g7 o  J( w
1
6 Y( s/ G. F4 R. u. p6 z$ d6 p8 q5)等待 DMA2D 传输完成,清除相关标识。
" `/ ^7 J( [2 n. ]& B' n- z' R最后,在传输过程中,不要再次设置 DMA2D,否则会打乱显示,所以一般在启动 DMA2D后,需要等待 DMA2D 传输完成(判断 DMA2D_ISR),在传输完成后,清除传输完成标识(设置 DMA2D_IFCR),以便启动下一次 DMA2D 传输。4 ?3 h" H: t7 \

# ?4 \, O* v/ Q/ B% x" d
  1. while((DMA2D->ISR&DMA2D_FLAG_TC)==0) ; //等待传输完成
    1 _: p7 ~- U' X3 B# Z, f  i
  2. DMA2D->IFCR|=DMA2D_FLAG_TC; //清除传输完成标志
复制代码
2 ?& q& {6 U, B4 g3 ^: N/ S
通过以上几个步骤,我们就完成了 DMA2D 填充
% W9 a: _1 j! \; ~! U# G% t
) R. \8 W; W4 w0 k& }使用示例
0 n6 Z7 a' K! P6 r3 ]) r( c
  1. //LCD LTDC重要参数集
    1 L2 `! H: M* s
  2. typedef struct  
    ; w. F0 r) |4 Y* x* Z
  3. {
    ; @7 @& I5 b8 f- n
  4.     u32 pwidth;         //LCD面板的宽度,固定参数,不随显示方向改变,如果为0,说明没有任何RGB屏接入( H( R# o; f+ W
  5.     u32 pheight;        //LCD面板的高度,固定参数,不随显示方向改变6 e+ [6 m9 ^% }3 z
  6.     u16 hsw;            //水平同步宽度 Horizontal synchronization width
    ; `: _7 @' {4 X; L  Q$ L- _
  7.     u16 vsw;            //垂直同步宽度 Vertical synchronization width
    9 |2 g; L$ o2 z$ D. r7 g
  8.     u16 hbp;            //水平后廊" j0 f( m4 v7 B4 `  \4 \
  9.     u16 vbp;            //垂直后廊
    ; C; I: o/ T  ?
  10.     u16 hfp;            //水平前廊
    & j4 [( q" l, i. [& I0 {" s
  11.     u16 vfp;            //垂直前廊
    - B0 X  Z3 N# u- ?- i
  12.     u8 activelayer;     //当前层编号:0/1
    ' s* Q& B2 F' h: m
  13.     u8 dir;             //0,竖屏;1,横屏;3 a: g+ o0 L7 \) r$ e
  14.     u16 width;          //LCD宽度
    2 C9 G0 P7 r: k5 N5 i
  15.     u16 height;         //LCD高度
    2 [' y+ r# ^8 ~# m6 t" k
  16.     u32 pixsize;        //每个像素所占字节数
    / D/ Q0 k1 C$ P+ d) k1 Y
  17. }_ltdc_dev;
    7 n  m) s# L* p; ?, ?/ i

  18. 1 f6 @9 o0 k' o2 g: ?
  19. _ltdc_dev lcdltdc;                //管理LCD LTDC的重要参数' Y) f! ?9 x9 v" ~- W

  20. 6 M  ?5 _2 f* a6 F
  21. //LTDC填充矩形,DMA2D填充
    & P  }& C; ]# H7 c
  22. //(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)   
    " G. ?* J) }1 i- V. ]$ Y; |
  23. //注意:sx,ex,不能大于lcddev.width-1;sy,ey,不能大于lcddev.height-1!!!4 a% w. @8 p) n  o
  24. //color:要填充的颜色
    ( q6 p5 F# W7 k! z( I9 W
  25. void LTDC_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u32 color)+ ]  J/ k. }6 f6 ]" t
  26. { " g7 s: o7 |( J
  27.     u32 psx,psy,pex,pey;                        //以LCD面板为基准的坐标系,不随横竖屏变化而变化! q/ `5 |5 K/ M$ F9 L) k
  28.     u32 timeout=0; : U' T, T5 X4 p4 e8 W
  29.     u16 offline;9 X* i7 S! ]7 m$ d# O0 @  U
  30.     u32 addr;
    $ M/ |- V) \, ^% Z
  31.     //坐标系转换* ~4 @* e2 a* \* |9 S
  32.     if(lcdltdc.dir)                             //横屏% w; N1 @' I3 w
  33.     {2 M% T0 _: ?2 ~' V* c0 f: D
  34.         psx=sx;psy=sy;
    # ~7 S* L, Z  O6 a& c
  35.         pex=ex;pey=ey;# |2 y- K5 U6 @
  36.     }else                                       //竖屏
    ! G- `7 z+ P3 a. f1 X1 R3 f' ]
  37.     {
    9 n6 d* Q+ H* s% a' u6 W4 W
  38.         psx=sy;psy=lcdltdc.pheight-ex-1;
    1 Z5 L' G, P- f% o7 M  r+ T% ?, @
  39.         pex=ey;pey=lcdltdc.pheight-sx-1;
    # W, v# _+ [2 P: ]' J* Z1 G( ~
  40.     }
    " a* Q6 T8 x+ a
  41.     offline=lcdltdc.pwidth-(pex-psx+1);
    1 v/ l- @* M) a* g
  42.     addr=((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*psy+psx));. J9 H( Q- D- P! Y  d
  43.     RCC->AHB1ENR|=1<<23;                        //使能DM2D时钟8 H: B2 u0 i" @$ K: b" N( T. ?
  44.     DMA2D->CR=3<<16;                            //寄存器到存储器模式4 w! u" g! E) P" i3 P$ v3 e- |7 |
  45.     DMA2D->OPFCCR=LCD_PIXFORMAT;                //设置颜色格式
    - R1 [  [/ u# E- Z
  46.     DMA2D->OOR=offline;                         //设置行偏移
    $ z& ]' ]% B( t0 g  K. p1 t6 |
  47.     DMA2D->CR&=~(1<<0);                         //先停止DMA2D! p' u1 [' r' M) }# t) Q& p
  48.     DMA2D->OMAR=addr;                           //输出存储器地址( U; P" D$ s/ A6 g7 U0 w8 L
  49.     DMA2D->NLR=(pey-psy+1)|((pex-psx+1)<<16);   //设定行数寄存器+ [6 k% f# V( l; i8 J
  50.     DMA2D->OCOLR=color;                         //设定输出颜色寄存器
    4 j  h% O+ I' @& t
  51.     DMA2D->CR|=1<<0;                            //启动DMA2D& H5 Z( g3 L$ e
  52.     while((DMA2D->ISR&(1<<1))==0)               //等待传输完成
    . q1 x; l. ]) q
  53.     {
    0 U' g# w# L4 S. }) G  ~# y6 a
  54.         timeout++;
    7 O9 K5 k6 A) ]/ G) |, z
  55.         if(timeout>0X1FFFFF)break;              //超时退出/ |) m) l  p( ^5 A+ K* {9 x
  56.     }  
    * G; L9 W& Z8 ?6 G. j7 M2 M
  57.     DMA2D->IFCR|=1<<1;                          //清除传输完成标志& C& R+ ?4 V* o3 [/ N* I" v
  58. }
    5 M8 g0 x# c9 p
  59. 0 \$ I4 q$ ~7 a# i
  60. //LCD清屏
    9 R  S+ m+ x- `
  61. //color:颜色值) L' u5 d3 Z8 S- }; f5 w& b
  62. void LTDC_Clear(u32 color)- L/ `3 ]7 j" t1 F( O$ \$ ]) T
  63. {6 F7 K# Z8 E2 |2 A. J9 j
  64.     LTDC_Fill(0,0,lcdltdc.width-1,lcdltdc.height-1,color);5 B/ @: P3 P) C2 {- C9 z- g
  65. }; t$ o* U2 h& J5 _4 w0 L5 s9 |
  66. 8 _: `" q0 U, r. L* f  }

  67. 1 W0 @9 A! D5 l( Y+ y' b
复制代码
- T' C! q* d* Z: O

6 ~( L& ]( m5 Z
)0J3WVNZQ8DQ6O089(M6FJW.png
赞 收藏 评论0 发布时间:2021-12-13 08:50

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版