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

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

[复制链接]
STMCU小助手 发布时间:2021-12-13 08:50
基础知识简介
. z) P: `. B  O- pRGBLCD
. |( }% b) ?2 R8 S0 {
1.RGBLCD的信号
2 W1 H/ r1 l* E& a1 u
20210720093227878.png
1 q  Z5 @& ]( o0 x/ Z
  \9 }' C! ]6 t' m! P
一般的 RGB 屏有 24 根颜色数据线(RGB 各站 8 根,即RGB888 格式),这样可以表示最多 1600W 色,DE、VS、HS 和 DCLK,用于控制数据传输。. X0 }8 Z1 S& O: h

8 `4 ~+ n1 ^' l+ y8 p6 Y& E2.RGBLCD驱动模式

$ O+ E5 e( Y5 T: ~  i. x0 x  W: a其驱动模式主要分为两种
2 o( Q2 T) q2 M* d& B5 g; Q" ?% ]( [  O7 n; v  w
      DE模式2 [+ E9 \( W, a2 R& a5 c
      DE 模式使用 DE 信号来确定有效数据,DE 为高/低时,数据有效
  s7 O$ s6 d: `& w0 m      HV模式/ Z  R" q9 V$ \3 _2 M* T
      HV模式需要行同步和列同步,来表示扫描的行和列
7 f0 I# P* F1 _4 A  x/ A  R4 M9 V7 ^6 j$ y6 P( o. s
LTDC
& q# H% c$ ^. J9 E0 j2 J6 cSTM32F767xx 系列芯片都带有 TFT LCD 控制器,即 LTDC,通过这个 LTDC,STM32F767可以直接外接 RGBLCD 屏,实现液晶驱动。2 w+ u6 k5 y; h& a. P

0 f5 u' Y6 v# j1 B& @1.信号线
6 A: F0 I9 U' C) {STM32F767 核心板板载的 LCD 接口引出为了,节省 IO,并提高图片显示速度,使用 RGB565 颜色格式,这样只需要 16 个 IO 口,当使用 RGB565 格式的时候,LCD 面板的数据线,必须连接到 LTDC 数据线的 MSB0 Z! ]) H5 W1 o: C& M
( h0 t3 y6 e, d
20210720100712790.png
* T4 H$ c  f' @6 x
4 Q: k( U/ E5 x- p8 m0 O
2.图像处理单元) q: B  F/ X' m( u
 先从 AHB 接口获取显存中的图像数据,然后经过层 FIFO(有 2 个,对应 2 个层)缓存,每个层 FIFO 具有 64*32 位存储深度,然后经过像素格式转换器(PFC),把从层的所选输入像素格式转换为 ARGB8888 格式,再通过混合单元,把两层数据合并,混合得到单层要显示的数据,最后经过抖动单元处理(可选)后,输出给 LCD 显示。2 q& _$ m1 U. j% j" p
 混合单元首先将第一层与背景层进行混合,随后,第二层与第一层和第二层的混合颜色结果再次混合,完成混合后,送给 LCD显示。$ e) I8 o5 B0 K

6 H2 j5 w! ]- n. G5 W7 V! y
20210720102457112.png
3 g' I0 N; p/ ^, I5 P) E# J' I* |
+ o9 F8 r* t) W6 U4 O
3.AHB 接口
* O( z) B2 `7 f" P 由于 LTDC 驱动 RGBLCD 的时候,需要有很多内存来做显存,比如一个 800480 的屏幕,按一般的 16 位 RGB565 模式,一个像素需要 2 个字节的内存,总共需要:800480*2=768K 字节内存,STM32 内部是没有这么多内存的,所以必须借助外部 SDRAM,而 SDRAM 是挂在AHB 总线上的,LTDC 的 AHB 接口,就是用来将显存数据,从 SDRAM 存储器传输到 FIFO 里面。
3 ]; R- G& B9 a
1 p9 X  p0 D& F5 m+ P4.LTDC相关寄存器及使用方法

6 M9 E7 S  E* B/ ~3 V( X" O- OLTDC 的各种配置寄存器以及状态寄存器,用于控制整个 LTDC 的工作参数,
& _; U/ \* Q; s主要有:各信号的有效电平、垂直/水平同步时间参数、像素格式、数据使能等等。' ]6 f+ \; @& ]) u$ y. N
如果 RGBLCD 使用的是 DE 模式,需要设置如下参数,然后 LTDC会根据这些设置,自动控制 DE 信号。
9 E" E! n- `8 l6 K8 b" l% O
# G% l) r6 n& u4 s2 N% ^4 zLTCD全局控制寄存器 LTCD_GCR

: ?  b) t8 J) k
, D5 b' c' M/ M# ]
20210720104228854.png
4 T: p5 R5 o7 P9 }

# Z4 V( v* g. {1 j% d1 C
]V@HJS%I_Y[%1XLYT61%0@2.png

" y" y" E. Y+ q$ f$ ~% O0 K
0 ?3 p8 \; w& P/ z% VLTCD同步大小寄存器 LTDC_SSCR
+ \* J5 i0 i6 }: t# E+ {9 d; H* v" {该寄存器用于设置垂直同步高度(VSH)和水平同步宽度(HSW)& A! F3 B% l% u: |) n
! z+ n; u9 F. b" U* |4 c
20210720104959506.png

% A5 \; @5 n/ ?! U. [+ {+ e
0 W8 T; L. B8 T$ Z, P' H* r
0PRMT7%Y[QF2O{1W`AQ82~7.png

) N) p) ]5 u" x( e  _4 ]5 B; \2 u
9 }5 X6 F7 f1 J* J; b8 l4 T
LTDC有效宽度配置寄存器 LTDC_AWCR
: f8 g2 o& T. x, Z# n2 W这里所说的有效高度和有效宽度,是指 LCD 面板的宽度和高度,构成分辨率, C$ L5 t6 d* }4 H, }6 B$ d
8 Y: i2 N% }7 D" e0 a. L( {0 |
20210720110024135.png
5 ?0 A9 j7 l4 S" F
7 t0 p" ?# f7 y; S5 Y
[AREI`HGZ@RRR{J@MJC8W]8.png
; ]1 Z, _- X/ s1 c7 p
  ^# J; P' x2 s. g" U  U
     
4 _  d. I: i- Y( B8 gLTDC 总宽度配置寄存器 LTDC_TWCR
. q) X) @$ O- {0 G# R
3 W2 }! c/ D- X5 C" t
20210720110931326.png
- t; c- K2 O6 p; I3 _; Q
- W, N+ S% \! B- n0 Q% e
O6G8SGZNHK4ZYO{)JN[]USW.png
" c2 N- q( p8 _* b/ Y
/ e- u& f" o4 q, u& g: p# Y5 W
      
7 R: [8 [8 O+ D7 P, U. f, x2 }LTDC 背景色配置寄存器 LTDC_BCCR
1 r, g6 B; F) P% D4 ]. ^/ O. s- D7 i该寄存器定义背景层的颜色(RGB888),通过低 24 位配置,我们一般设置为全 0 即可。
% P$ ^6 H1 i1 j# |
0 ?( z3 J4 H  Q# X: C. M+ g/ P6 A" S" F. h8 X( c5 ^
20210720111141846.png

; e& e5 c7 `) y9 @
! T8 L# R; B) w, {LTDC当前位置状态寄存器 LTDC_CPSR
. f+ u5 ]8 i# Z% O2 ?+ j0 _# E9 ^' U/ [5 `$ J- z( u. g' @
a3355e745c2c73657ef826bf1a8f42f5.png

# }8 E6 y. H7 [8 D# O7 m: Y$ b. `' M- C$ ?. `/ g+ f8 @2 P
CXPOS[31~16]:返回当前X坐标位置& c  g3 z, {! z/ q
CYPOS[15~0]:返回当前Y坐标位置/ d$ L0 M7 j, O; [

7 i6 W$ L& e% L/ `6 ?* ]LTDC当前显示状态寄存器 LTDC_CDSR: f$ L2 `& M( M, c- o
此寄存器返回由 HSYNC、VSYNC 和水平/垂直 DE 信号控制的当前显示阶段的状态7 U! u* @4 x2 g2 e2 z2 u
9 T8 b3 O4 M2 D# F& L3 w- N
c1e72a8f7ff1155cd5391d05ba83e42d.png
- y4 E' \$ T8 K! [' ~- X3 C; t' F

1 Y" s* j6 s- j! [位 31:24 保留,必须保持复位值
# W2 g4 T; Y$ Z% o8 {" Y位 3 HSYNCS:水平同步显示状态 (Horizontal Synchronization display Status). Z8 h) M6 n6 o2 y
0:低电平有效6 l/ b6 z' ?5 D) z
1:高电平有效
. l/ q% q9 `' X0 {位 2 VSYNCS:垂直同步显示状态 (Vertical Synchronization display Status)1 J3 @6 h% i" G: z; v
0:低电平有效
1 b* s) D2 a6 M" h) _2 z& Z7 ~1:高电平有效
- f6 o2 J2 o6 w' J3 o% f+ v位 1 HDES:水平数据使能显示状态 (Horizontal Data Enable display Status)
$ m. H$ z% R( {0 |8 Q0:低电平有效
8 ^+ [, y/ K3 }  N1:高电平有效+ X% a' U2 L! z3 O
位 0 VDES:垂直数据使能显示状态 (Vertical Data Enable display Status)
/ k4 N8 Y9 C( [3 N/ H+ G" X0:低电平有效& n/ t0 J) x  e9 v1 Y; W
1:高电平有效
- @( [5 k" @2 I! y* X1 Q
, z/ r2 \3 \! z1 [) D- n0 O) Z% w5 Y: jLTDC 的层颜色帧缓冲区地址寄存器 LTDC_LxCFBAR(x=1/2)+ j9 g9 Y/ z5 g, j5 _; ~
该寄存器用来定义一层显存的起始地址。STM32F767 的 LTDC 支持 2 个层,所以总共有两个寄存器,分别设置层 1 和层 2 的显存起始地址。1 }0 e$ [) i& X. e. j5 ?

6 o2 x  ?. n. {) O' z; a& X
20210720111336311.png

0 p! Q2 z- W' x, ^. U, F: l
4 Z. \9 k7 _9 H" F5 l5 T+ wLTDC 的层像素格式配置寄存器 LTDC_LxPFCR(x=1/2)
, u( n& C" C$ W9 i: Y( r2 e) ~1 E该寄存器只有最低 3 位有效,用于设置层颜色的像素格式,一般使用 RGB565 格式,即该寄存器设置为:010 即可。
2 n" D9 q$ Z' A+ d! y- Z" W! S' |5 p: w7 s/ D$ S
STQ}OUE_D7Z(33OZ_E@73.png

- A0 J1 e1 d9 w" N5 d, }. _. |8 \5 ]% h! z# o
6 W: }7 J8 z' w
       # W2 w% y. P& {* w3 ]' g
LTDC 的层恒定 Alpha 配置寄存器 LTDC_LxCACR(x=1/2)
3 g3 I$ ^4 r9 \% [1 ~该寄存器低 8 位(CONSTA)有效,这些位配置混合时使用的恒定 Alpha。恒定 Alpha 由硬件实现 255 分频。7 P  [4 C+ c* X2 {
; u: a' r9 g$ Q) q0 X# E$ i% S
20210720112235516.png

9 B8 j+ k1 I% L+ f5 t; z2 {6 W$ H/ S, [0 s0 H# d
LTDC 的层默认颜色配置寄存器 LTDC_LxDCCR(x=1/2)

1 U7 {( @+ H+ @4 g+ r( C该寄存器定义采用 ARGB8888 格式的层的默认颜色。默认颜色在定义的层窗口外使用或在层禁止时使用。一般情况下,用不到,所以该寄存器一般设置为 0 即可。
5 b9 ]+ m9 [, b' R' y' U' n
: R$ N5 d; I9 c2 b# q" d
20210720112604555.png

$ e- p/ p4 F3 B" P, I% W
! |( Y( ^6 ?( o3 }( G. Z) QLTDC 层混合系数配置寄存器:LTDC_LxBFCR(x=1/2)& V4 P1 U7 Q. ?' m/ b; \
该寄存器用于定义混合系数: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即可。! d0 O  w8 w9 k% D/ J% X  [+ r9 |! C
通用的混合公式为:BC=BF1C+BF2Cs9 N7 k. L1 g' y9 e% o( Z$ Y
其中:BC=混合后的颜色;BF1=混合系数 1;C=当前层颜色,即我们写入层显存的颜色值;BF2=混合系数 2;Cs=底层混合后的颜色,对于层 1 来说,Cs=背景层的颜色,对于层 2 来说,Cs=背景层和层 1 混合后的颜色。
+ m" r% K9 \6 B* h# n) R+ d9 t, B- G  U6 d% ^
2021072011293763.png

& Q% {, A. y& k1 Q+ N
) w, _% j+ `" y4 xLTDC 的层窗口水平位置配置寄存器 LTDC_LxWHPCR(x=1/2)
5 w5 x  R. S3 ^$ Q
该寄存器定义第 1 层或第 2 层窗口的水平位置,第一个和最后一个像素: x4 G0 D2 H8 i6 ~( W$ e
& d; ^% D! A- W2 Z0 g
20210720113448290.png

# S5 @& N1 B/ G0 M4 r. n
% z. |( K9 ]: E$ C( }- KWHSTPOS:窗口水平起始位置,定义层窗口的一行的第一个可见像素,
2 \: n4 n7 e+ h( i( D; n5 F% gWHSPPOS:窗口水平停止位置,定义层窗口的一行的最后一个可见像素" r  D' E" v9 }, v& {2 ^, q/ y

8 G7 T, a! X1 s- w2 yLTDC 的层窗口垂直位置配置寄存器 LTDC_LxWVPCR(x=1/2)

0 ]% C3 S; h) n% t0 t( c" Q$ ?该寄存器定义第 1 层或第 2 层窗口的垂直位置(第一行或最后一行)
4 o0 s  c3 e$ U& E
& O6 D+ ?( h+ M. H: r1 [
20210720133247145.png
4 E! j8 k( E& X
5 q+ L+ E7 f+ I% u
WVSTPOS:窗口垂直起始位置,定义层窗口的第一个可见行。' w- s8 ^4 x: r) ]% r# A& f/ }
WVSPPOS:窗口垂直停止位置,定义层窗口的最后一个可见行。
2 L# r4 I. H# D7 M1 n# c. Z& F  P2 \
LTDC 的层颜色帧缓冲区长度寄存器 LTDC_LxCFBLR(x=1/2)
( Y2 H, {" J3 o$ y8 R. ?8 j该寄存器定义颜色帧缓冲区的行长和行间距。9 j" v4 v) X* I1 M1 {

% m& j+ n& Z1 j- v: I; z3 I
20210720133802157.png
! X( _  h( x: g. L9 P. j4 i9 \
+ ^6 ~% m, }; y1 u" L
CFBLL:这些位定义一行像素的长度(以字节为单位)+3。
: b  ^5 {7 f% s6 u2 K" R6 T) U行长的计算方法为:有效宽度 * 每像素的字节数 + 3。: |7 z& ]8 c/ y! S3 y% B0 f
比如,LCD 面板的分辨率为 800480,有效宽度为 800,采用 RGB565 格式,那么 CFBLL 需要设置为:8002+3=1603。  S7 W4 Y' N4 v4 G4 y) ?
CFBP:这些位定义从像素某行的起始处到下一行的起始处的增量(以字节为单位)。
$ {( J8 U* `& ?( ]1 e0 Q9 L这个设置,其实同样是一行像素的长度,对于 800480 的 LCD 面板,RGB565 格式,设置 CFBP 为:8002=1600 即可。
+ W7 @2 l8 ~: ~2 [/ D
6 K$ N5 i, |0 w0 S" d* VLTDC 的层颜色帧缓冲区行数寄存器 LTDC_LxCFBLNR(x=1/2)
  V6 ]/ R. T9 {8 Z+ T该寄存器定义颜色帧缓冲区中的行数。
: X/ q/ H* n4 b( ~7 K4 Y# F比如,LCD 面板的分辨率为 800*480,那么帧缓冲区的行数为 480 行,则设置 CFBLNBR=480 即可
1 i: A. w7 P- o
$ l% @; `% U* r( i" R
20210720133424485.png
3 U& G6 C9 w+ r) H% B7 I. }
6 ^0 B' K3 Z0 Y) i
5.时钟域, k$ o7 {5 w* y: B& R) f4 W
LTDC 有三个时钟域:AHB 时钟域(HCLK)、APB2 时钟域(PCLK2)和像素时钟域(LCD_CLK),7 z8 l- E! S/ E' S
AHB 时钟域用于驱动 AHB 接口,读取存储器的数据到 FIFO 里面;) ?/ J, [' P1 m' D- Q
APB2 时钟域用于配置寄存器;) k, k, i1 ]- C+ L8 Z- F) z
LCD_CLK像素时钟域则用于生成 LCD 接口信号,LCD_CLK 的输出应按照 LCD 面板要求进行配置。
! K' D: k& C* N
. k0 m4 U( X: x, V- j$ h+ IDMA2D& B6 n: g+ [( s/ d0 @8 K7 m
为了提高STM32F767的图像处理能力,ST公司设计了一个专用于图像处理的专业 DMA,通过 DMA2D 对图像进行填充和搬运,可以完全不用CPU 干预,从而提高效率,减轻 CPU 负担。. [* D0 `  ?- D/ L2 P* o: K
/ u. c) I# c5 G2 e! O# f; L
它可以执行下列操作:
6 [, n: R  \# z+ e( m用特定颜色填充目标图像的一部分或全部(可用于快速单色填充)4 n' L) e8 Z! \2 k
将源图像的一部分(或全部)复制到目标图像的一部分(或全部)中(可用于快速图像填充)
* b1 J+ p7 m& c" Q* K% j通过像素格式转换将源图像的一部分(或全部)复制到目标图像的一部分(或全部)中  N7 Q# G5 J# `' m3 n) {6 M( E
将像素格式不同的两个源图像部分和/ 或全部混合,再将结果复制到颜色格式不同的部分或整个目标图像中
. p& W, F$ p* G( x6 t. o7 k0 q# ~5 R9 S6 o6 Q, W7 C7 \

2 q( k! s' @: }, L. K' e# M! uDMA2D 有四种工作模式,通过 DMA2D_CR 寄存器的 MODE[1:0]位选择工作模式:, p( w! d5 ^; L. r
1, 寄存器到存储器
, N  e: I4 D. t2, 存储器到存储器
: m4 \& q6 N6 @! A+ ~% a2 _  M& {" U6 f3, 存储器到存储器并执行 PFC
7 ^/ M3 B9 d5 w* \( Q7 u3 [4, 存储器到存储器并执行 PFC 和混合* x4 V* z4 X' C/ J
6 R; n: |5 N" O" @

* T# p) _4 V; x- y寄存器到储存器
3 `# b& h) y/ O& |9 ^7 p0 n寄存器到存储器模式用于以预定义颜色填充用户自定义区域,也就是可以实现快速的单色* s4 g4 M! W. q0 ?, ~
填充显示,比如清屏操作。2 p: x% h* {) h$ Z! S- v0 B5 p% {: m
在该模式下:颜色格式在 DMA2D_OPFCCR 中设置,DMA2D 不从任何源获取数据,它只
7 U7 m4 w8 B( V. s) n+ i是将 DMA2D_OCOLR 寄存器中定义的颜色写入通过 DMA2D_OMA 寻址以及 DMA2D_NLR 和
7 w3 {0 {# f4 k! U. }7 hDMA2D_OOR 定义的区域" ~6 o. _5 t2 @2 ~, c

- n$ j5 ]% H3 q' }$ }2 q4 V7 J( D5 g- r+ g! h  ]
储存器到储存器: R, m4 P: N4 |' w. V+ _# G  y
该模式下,DMA2D 不执行任何图形数据转换。前景层输入 FIFO 充当缓冲区,数据从* N( u1 O: s& u& h
DMA2D_FGMAR 中定义的源存储单元传输到 DMA2D_OMAR 寻址的目标存储单元,可用于快
# h% H0 x2 d0 [# y$ _速图像填充。DMA2D_FGPFCCR 寄存器的 CM[3:0]位中编程的颜色模式决定输入和输出的每像
  s- [- J0 a  @3 b- A& m( F  m素位数。对于要传输的区域大小,源区域大小由 DMA2D_NLR 和 DMA2D_FGOR 寄存器定义,, W+ `! D0 V& l( i) r/ d
目标区域大小则由 DMA2D_NLR 和 DMA2D_OOR 寄存器定义。
: T/ l( f% L+ B: z- q1 I& c; W$ L. _. u+ B; M; h/ z
* U. L0 {" f5 t( V6 _
以上两个工作模式,LTDC 在层帧缓存里面的开窗关系都一样的,经过如下三个寄存器的配置,就可以确定窗口的显示位置和大小。
! L" M! s; l- i' N3 ]( O' A(1). 窗口显示区域的显存首地址由 DMA2D_OMAR 寄存器指定,
3 p0 q- G3 q9 B4 a% [, }/ j; U(2).窗口宽度和高度由DMA2D_NRL 寄存器的 PL 和 NL 指定
6 j# _- v% K% f; o3 D(3).行偏移(确定下一行的起始地址)由 DMA2D_OOR寄存器指定,
5 O- l  }4 s! U& A6 B1 C
  K2 ^$ I! _; c  \' |
20210720170136697.png

  U6 K0 T, A0 A
+ N- V- f# d  x/ l, u5 I$ o- A8 X9 q" S" f0 F' W% K
在寄存器到存储器模式下,在开窗完成后,DMA2D 可以将 DMA2D_OCOLR 指定的颜色,
/ Q* n: Q- N& T( c自动填充到开窗区域,完成单色填充。0 _  v& j) t" q4 N! S- v; ~

; ?4 P: u- Z, D% L) C9 p$ w+ t
在存储器到存储器模式下,需要完成两个开窗:前景层和显示层,完成配置后,图像数据从前景层拷贝到显示层(仅限窗口范围内),从而显示到 LCD 上面。显示层的开窗如上图所示,前景层也和上图类似,只是 DMA2D_OMAR 寄存器变成了DMA2D_FGMAR,DMA2D_OOR寄存器变成了DMA2D_FGOR,DMA2D_NRL则两个层共用,然后就可以完成对前景层的开窗,确定好两个窗口后,DMA2D 就将前景层窗口内的数据,拷贝到显示层窗口,完成快速图像填充。2 z! W% A& p1 x0 q
4 K3 w; e( f5 K% S5 S! b+ O
0 A2 H$ B9 N* l) n6 C- P! g/ `
DMA2D相关寄存器/ F, i& H* t2 o' _+ I5 I9 Z
DMA2D控制寄存器 DMA2D_CR2 z4 x9 w1 \+ ~
该寄存器,主要是MODE 和 START 这两个设置  p& ?- b+ [1 r( Q: T3 N% b
$ v. B& T# x4 L/ ]
20210720172154901.png
! r6 J: ?  j1 T2 v$ L0 _
; q: v4 m3 i0 c0 @4 g+ w" |
MODE:表示 DMA2D 的工作模式,
( c; y3 i7 q: R6 z5 n00:存储器到存储器模式;01:存储器到存储器模式并执行 PFC;9 ^& e1 k" X& O8 |3 J
10:存储器到存储器并执行混合;11,寄存器到存储器模式;( ^# Q/ @2 y) W  _
START:该位控制 DMA2D 的启动,在配置完成后,设置该位为 1,启动 DMA2D 传输。
$ p: i. \* T$ _9 @7 n4 N$ O
; |% b0 ^1 z5 L* z+ |* XDMA2D输出 PFC 控制寄存器 DMA2D_OPFCCR
/ ~+ L6 a. W% [( ^# Q* J该寄存器用于设置寄存器到存储器模式下的颜色格式* Z5 M  }+ V  l. _9 c

/ C2 V0 s) H1 f6 Q5 N
20210720172538112.png
; }) `' ~* j8 D% O% u7 x1 W) Y

( }9 H& y- ~: u/ S. n' ?只有最低 3 位有效(CM[2:0]),表示的颜色格式有:
" F  Z2 M" r! M, t2 Z6 @000,ARGB8888;001:RGB888;010:RGB565;
$ ^+ i1 i. m5 Y4 p7 b( V$ e8 y( J011:ARGB1555;100:ARGB1444。
/ A  G% {5 f1 ]6 c我们一般使用的是 RGB565 格式,所以设置 CM[2:0]=010 即可。
/ [' E7 d; z* z  t& _, Q
5 ^% y7 V9 h! T. h( CDMA2D前景层 PFC 控制寄存器:DMA2D_FGPFCCR
" e/ X- `6 X$ X# l# ~- D2 n
2 {- D, u# s) X! p5 c  w
20210720173213773.png
$ r( [% u- r9 @2 g- M( ?  J
# }, _: l+ r: e( j
该寄存器,低 4 位:CM[3:0],用于设置存储器到存储器模式下的颜色格式,这四个位表示的颜色格式为:( x* t: n( P* b9 b; }- M
0000:ARGB8888;0001:RGB888;0010:RGB565;
% i+ M6 _. x, E+ b7 e' U0011:ARGB1555;0100:ARGB4444;0101:L8;$ j; E3 E) t9 q4 m3 |  I  N3 u2 J
0110:AL44;0111:AL88;1000:L4;1001:A8;1010:A4;
0 Z9 W" @, Q+ k我们一般使用 RGB565 格式,所以设置 CM[3:0]=0010 即可。
! i; N$ p- I4 G6 k$ [
; S* `% K! F+ g/ k8 c3 L% jDMA2D输出偏移寄存器 DMA2D_OOR
+ B- w. g8 A5 k$ b, `* h7 r' x, n6 B$ a5 \5 t: K& W
20210720174740982.png

, Q( {% X( f" C# l0 v7 o该寄存器仅最低 14 位有效(LO[13:0]),用于设置输出行偏移,作用于显示层,以像素为
4 M9 U2 _, A/ O8 T4 K) s/ G" c单位表示。此值用于生成地址。行偏移将添加到各行末尾,用于确定下一行的起始地址。+ I* x. E- z( O2 G% Z
同样的,还有前景层偏移寄存器:DMA2D_FGOR,该寄存器同 DMA2D_OOR 一样,也是$ G* ~* Y2 _  J% K2 `. `# g$ ^$ c$ z
低 14 位有效,用于控制前景层的行偏移,也是用于生成地址,添加到各行末尾,从而确定下一7 \: c& ~2 M* ~) Z* N3 r1 s% j! S( b
行的起始地址。
# `& j6 A  \: d; C8 u4 {0 O- G
' M$ N& J: r% b( z) oDMA2D输出存储器地址寄存器 DMA2D_OMAR
2 H; {. Y/ b! k! ?. {0 z: \$ m7 v( r6 S6 H" P4 z' Q
20210720175051288.png

- a! |; T( [  P0 V5 K3 _* v$ |, U! _* E& i9 R
该寄存器设置由 MA[31:0]设置输出存储器地址,也就是输出 FIFO 所存储的数据地址,该地址需要根据开窗的起始坐标来进行设置。以 800480 的 LCD 屏为例,行长度为 800 像素,假定帧缓存数组为:ltdc_framebuf,我们设置窗口的起始地址为:sx(<800),sy(<480),颜色格式为 RGB565,每个像素 2 个字节,那么 MA 的设置值应该为:
) [3 D; u0 _8 c, E*MA[31:0]= framebuf+2(800sy+sx)**
& T8 v( A1 W3 j, ]/ Y) J同样的,还有前景层偏移寄存器:DMA2D_ FGMAR,该寄存器同 DMA2D_OMAR 一样,
; P8 k0 `2 Q0 T% r, g不过是用于控制前景层的存储器地址,计算方法同 DMA2D_OMAR。- v2 ?+ K% M/ s; s/ X8 y) I

* Z8 |, \0 E7 b, s% }# B6 J3 ?* XDMA2D行数寄存器 DMA2D_NLR
  N3 u* j  z7 }) b/ b. V, k" _: p5 Y
20210720180044872.png
2 u) K8 p/ R" E2 C7 Y
该寄存器用于控制每行的像素和行数,该寄存器的设置对前景层和显示层均有效,通过该寄存器的配置,就可以设置开窗的大小。其中:
4 r; H- R$ b7 ]* u& YNL[15: 0]:设置待传输区域的行数,用于确定窗口的高度。; f, `# c4 ]' C" s% X
PL[13: 0]:设置待传输区域的每行像素数,用于确定窗口的宽度
" I; V" R% z- m0 }) C! U0 i( J/ O0 I9 u& O# X7 m
DMA2D输出颜色寄存器 DMA2D_OCOLR
0 M& L2 [6 E7 j3 |
. u. \4 ^% P, v+ x
20210720180520678.png
! R. y. J5 \# O0 F4 H  _
该寄存器用于配置在寄存器到存储器模式下,填充时所用的颜色值,该寄存器是一个 32位寄存器,可以支持 ARGB8888 格式,也可以支持 RGB565 格式。我们一般使用 RGB565 格式,比如要填充红色,那么直接设置 DMA2D_OCOLR=0XF800 就可以了。+ I3 A. U" _. [1 E7 z7 {% w

9 \& w2 b* l1 v3 y3 h8 QDMA2D中断状态寄存器 DMA2D_ISR3 y0 m. w2 ~( [6 k! B, h
/ ?$ T2 c- _, ~+ i
2021072018063162.png
. y# {: r! `% `0 G: N
0 ?7 b2 E6 J/ X, r5 E
该寄存器表示了 DMA2D 的各种状态标识
: Q! k% @& w/ LTCIF 位,表示 DMA2D 的传输完成中断标志。当 DMA2D 传输操作完成(仅限数据传输)时此位置 1,表示可以开始下一次 DMA2D 传输了" i* Q7 R# M" w& e& N% @' d0 }. K0 B
DMA2D 中断标志清零寄存器:DMA2D_IFCR,用于清除 DMA2D_ISR 寄存器对应位的标志。通过向该寄存器的第 1 位(CTCIF)写 1,可以用于清除 DMA2D_ISR 寄存器的 TCIF 位标志。
. i  a( f0 g% g
3 w9 U! D3 y, M6 p0 V6 s: i" k# i. }. U( |
LTDC具体使用步骤- p* s5 P/ ]/ |5 q% X
1.使能 LTDC 时钟,并配置 LTDC 相关的 IO 及其时钟使能。
: W1 `, Z, e& Q5 s" a$ e3 l, Y% l使用 LTDC,当然首先得开启其时钟。
6 \( c) i% n& w; d- f1 r8 Z( Q然后需要把 LCD_R/G/B 数据线、LCD_HSYNC和 LCD_VSYNC 等相关 IO 口,全部配置为复用输出,并使能各 IO 组的时钟。1 k: s2 I  V: i* @, c

. K/ }6 Y0 T: O: X
  1. //LTDC底层IO初始化和时钟使能
    " H3 W, |, Y3 y( w
  2. //此函数会被HAL_LTDC_Init()调用: N$ i( Z' L- {7 f
  3. //hltdc:LTDC句柄5 I. X3 i) N+ X$ W* A* ?0 Q
  4. void HAL_LTDC_MspInit(LTDC_HandleTypeDef* hltdc)& @! J/ a: T! f+ m  K" ~5 }2 s
  5. {
    # {3 n  T# T9 a+ e1 D
  6.     GPIO_InitTypeDef GPIO_Initure;
    : ~& k' ~. V+ q' U+ L+ Q
  7. ( h- M) ?. T2 \8 C! f" l5 s
  8.     __HAL_RCC_LTDC_CLK_ENABLE();                //使能LTDC时钟- j" K, B( k, R8 S9 [
  9.     __HAL_RCC_DMA2D_CLK_ENABLE();               //使能DMA2D时钟& B0 A- E* M' f& H& m$ l
  10.     __HAL_RCC_GPIOB_CLK_ENABLE();               //使能GPIOB时钟1 k3 g6 J! n6 l$ |
  11.     __HAL_RCC_GPIOF_CLK_ENABLE();               //使能GPIOF时钟6 d$ N. \# z, L4 p! H4 Q- M- v* G
  12.     __HAL_RCC_GPIOG_CLK_ENABLE();               //使能GPIOG时钟1 f* `8 N/ P" W' `. J7 r" \
  13.     __HAL_RCC_GPIOH_CLK_ENABLE();               //使能GPIOH时钟
    , i$ D3 }: h( K, n9 [- o
  14.     __HAL_RCC_GPIOI_CLK_ENABLE();               //使能GPIOI时钟! f" V' P. e7 T  G$ }- J

  15. 4 h" m) k) @. m2 u( R
  16.     //初始化PB5,背光引脚
    + F% N+ H0 P' F, A  p- b0 J
  17.     GPIO_Initure.Pin=GPIO_PIN_5;                //PB5推挽输出,控制背光
    * l' a6 h# u7 V
  18.     GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;      //推挽输出
    0 v' o3 u; C/ W
  19.     GPIO_Initure.Pull=GPIO_PULLUP;              //上拉. @# k+ L8 G) `. \
  20.     GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速
    $ H* d% r7 n) e6 F
  21.     HAL_GPIO_Init(GPIOB,&GPIO_Initure);
    % ~! l# T; c7 x1 |4 W
  22. ! Z8 a3 ^# ~+ D% J& B
  23.     //初始化PF10
    0 o$ d, V8 i+ P+ u/ V% d1 [/ S
  24.     GPIO_Initure.Pin=GPIO_PIN_10;
    ; G0 o0 H( r/ F. |; \  p/ i
  25.     GPIO_Initure.Mode=GPIO_MODE_AF_PP;          //复用
    & k' }& a9 I" q; X9 d' f
  26.     GPIO_Initure.Pull=GPIO_NOPULL;: |* P# g$ W' p' A' j
  27.     GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速
    % A' A" V6 I1 R5 j5 D% b! A+ f& N! P
  28.     GPIO_Initure.Alternate=GPIO_AF14_LTDC;      //复用为LTDC6 l" s' ?- D, g4 ~
  29.     HAL_GPIO_Init(GPIOF,&GPIO_Initure);# b4 Y! U" U5 o; L

  30. , D9 |; H  x0 J
  31.     //初始化PG6,7,11
    3 [7 v+ |9 @; X8 Z% a0 E4 u+ v
  32.     GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_11;
    - s8 U9 E& Q# {6 ^+ }) D1 q
  33.     HAL_GPIO_Init(GPIOG,&GPIO_Initure);
    0 Z: ]& ^# B3 F/ ^, w
  34. " O$ c8 b; C( ~5 d% P6 q7 s
  35.     //初始化PH9,10,11,12,13,14,15% {1 W1 B+ e$ J# l; S9 ~  ^0 W
  36.     GPIO_Initure.Pin=GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|\; g6 T4 y3 d/ C% u( Y8 g* u0 M
  37.                      GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;8 f' v" P) i* K6 g
  38.     HAL_GPIO_Init(GPIOH,&GPIO_Initure);
    ( b* |9 s# D, v9 p$ E; Z5 v

  39. + C3 y' v. E" D& c% o* h
  40.     //初始化PI0,1,2,4,5,6,7,9,108 A& b/ e% t6 d, S" B
  41.     GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|\
    3 G: J; t7 |; e/ N
  42.                      GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_9|GPIO_PIN_10;
    1 A: A' M8 v/ o- q0 f* i9 c
  43.     HAL_GPIO_Init(GPIOI,&GPIO_Initure);
    & b* F; G1 X( s1 B% x; l
  44. }
复制代码

  h" F( v+ G5 H2 k) M+ v2.设置LCD_CLK时钟. X2 }) l* @( k' P4 b
配置 LCD 的像素时钟,根据 LCD 的面板参数进行设置,LCD_CLK 由 PLLSAI进行配置,配置使用到的 HAL 库函数为:8 X9 h4 F; D4 P% C

8 f& n% S, {8 M3 J* H
  1.         //pllsain:SAI时钟倍频系数N,取值范围:50~432.  
    5 h9 y& f' L! I$ M
  2.         //pllsair:SAI时钟的分频系数R,取值范围:2~73 K% w. {8 g3 o9 `$ v" k/ A
  3.         //pllsaidivr:LCD时钟分频系数,取值范围:0~3,对应分频2~16 ) E" L0 Q- I2 m
  4.         //假设:外部晶振为25M,pllm=25的时候,Fin=1Mhz.
    5 u, }* I; @/ w2 v4 J7 K4 O
  5.         //例如:要得到20M的LTDC时钟,则可以设置:pllsain=400,pllsair=5,pllsaidivr=1
    * ?1 {. Q! r% f5 S% S
  6.         //Fdclk=1*396/3/2*2^1=396/12=33Mhz6 [" |' i9 ?: Y0 r
  7.     RCC_PeriphCLKInitTypeDef PeriphClkIniture;
    ! ?8 |0 P% z; C$ D1 H

  8. ) U% M! n! f9 E- v! C( B: U
  9.     //LTDC输出像素时钟,需要根据自己所使用的LCD数据手册来配置!6 j( f9 B' l. D& ^' ]  J
  10.     PeriphClkIniture.PeriphClockSelection=RCC_PERIPHCLK_LTDC;       //LTDC时钟8 f  @* J" c6 b
  11.     PeriphClkIniture.PLLSAI.PLLSAIN=pllsain;
    ( R$ _& w: l2 j# A6 Q1 b$ P  S
  12.     PeriphClkIniture.PLLSAI.PLLSAIR=pllsair;
    7 I: @( k- w, p' l9 ]6 B
  13.     PeriphClkIniture.PLLSAIDivR=pllsaidivr;8 L% e: I. h( E" R- ?8 k, D$ t+ D
  14.         HAL_StatusTypeDef HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef *PeriphClkInit)
复制代码
, U2 w% I- _* ^) U! f: A& a
3.设置RGBLCD相关参数,并使能LTDC
( f# K! w2 U$ `+ f) w
  1. typedef struct
      a% f9 O. v0 W
  2. {
    7 V7 v9 p7 T0 S% c
  3. uint32_t HSPolarity;                         //水平同步极性
      O2 S, T2 k% N
  4. uint32_t VSPolarity;                         //垂直同步极性 % _4 N  M2 @, J& Z5 ^7 s! ]% }
  5. uint32_t DEPolarity;                         //数据使能极性
    " L6 I" a5 J/ [! F. v  C8 R# O
  6. uint32_t PCPolarity;                         //像素时钟极性" N9 B* C# ~0 H, ]- v
  7. uint32_t HorizontalSync;                 //水平同步宽度 * B6 z8 j" i1 j# E* X
  8. uint32_t VerticalSync;                 //垂直同步高度0 a* ?$ v2 Y1 N* L3 G; o6 {
  9. uint32_t AccumulatedHBP;                 //水平同步后沿宽度5 O2 c4 Y! O' x* G& q
  10. uint32_t AccumulatedVBP;                 //垂直同步后沿高度
    - ^' a3 z  W% \" a; `5 e, b( y% \  `
  11. uint32_t AccumulatedActiveW;         //累加有效宽度 2 \! {) Z8 T  I. P: p2 J1 _
  12. uint32_t AccumulatedActiveH;         //累加有效高度
    $ ]/ w0 G  }5 o6 r( ~  Z; V8 L
  13. uint32_t TotalWidth;                         //总宽度
    1 O. }; r' B, b
  14. uint32_t TotalHeigh;                         //总高度
    9 X$ Y1 |0 U% o3 c, w
  15. LTDC_ColorTypeDef Backcolor;         //屏幕背景层颜色
    $ t/ |$ e9 V: U0 ~, C
  16. } LTDC_InitTypeDef;  `9 l- T- p, j4 O( t. Y$ r

  17. . F. `1 S  q/ Z; B; H- n$ @1 Q
  18. typedef struct
    0 ~8 I; ?' w3 s1 U: J4 d' U
  19. {
    7 {8 v& l* L( e; Z$ y0 q1 m
  20.   LTDC_TypeDef                *Instance;                /*Instance变量是LTDC_TypeDef结构体指针类型*/
    ' {* K9 g1 \$ {4 s& j/ C
  21.   LTDC_InitTypeDef            Init;                     /*用来初始化LTDC的结构体变量*/4 \6 |( K* ~7 k# K+ l$ E5 ?
  22.   LTDC_LayerCfgTypeDef        LayerCfg[MAX_LAYER];      /*保存LTDC层配置参数*/) E7 p+ ~0 C' a# t& l& j
  23.   HAL_LockTypeDef             Lock;                     /*锁状态*/: U# C( f1 h: T$ ]7 X- J
  24.   __IO HAL_LTDC_StateTypeDef  State;                    /*LTDC的状态*/- y2 Z3 E! @+ `' w
  25.   __IO uint32_t               ErrorCode;                /*错误处理*/
    : R3 d" [9 j9 N- e; [# N+ G. ^
  26. } LTDC_HandleTypeDef;, G3 [* h4 b$ t: Z6 Z; ?
  27. $ e" c$ N' {8 O( s. L: E% n
  28. LTDC_HandleTypeDef  LTDC_Handler;                                   //LTDC句柄
    , i9 c* L! x: K2 Z. c+ Q

  29. 1 U) h9 n0 _+ g2 b
  30. LTDC_Handler.Instance=LTDC;8 q  C  ~, U9 H
  31. LTDC_Handler.Init.HSPolarity=LTDC_HSPOLARITY_AL;                 //水平同步极性
    / x) z2 [' e! Q+ \# k4 k' C4 d( Y
  32. LTDC_Handler.Init.VSPolarity=LTDC_VSPOLARITY_AL;                 //垂直同步极性
      L& C  J: f# h# u$ f* ~' C
  33. LTDC_Handler.Init.DEPolarity=LTDC_DEPOLARITY_AL;                 //数据使能极性$ S# H% V+ \! V
  34. LTDC_Handler.Init.PCPolarity=LTDC_PCPOLARITY_IPC;                 //像素时钟极性
    ' K1 m/ b0 w5 n9 D$ |9 U! h+ P
  35. LTDC_Handler.Init.HorizontalSync=10-1;                                         //水平同步宽度
    ( L' R" j2 l! R' X$ ?1 P3 `" U6 G
  36. LTDC_Handler.Init.VerticalSync=2-1;                                         //垂直同步宽度
    0 b% ~# w! X, {5 F6 W, `+ r) ~0 N
  37. LTDC_Handler.Init.AccumulatedHBP=10+20-1;                                 //水平同步后沿宽度
    ; [/ G5 V) b5 R8 U
  38. LTDC_Handler.Init.AccumulatedVBP=2+2-1;                                 //垂直同步后沿高度
    7 S2 M% A" h* E7 ^: a4 A9 A' P" Z9 U
  39. LTDC_Handler.Init.AccumulatedActiveW=10+20+480-1;                 //有效宽度; A4 Y+ A' ~3 R
  40. LTDC_Handler.Init.AccumulatedActiveH=2+2+272-1;                 //有效高度  Q$ ]# z4 s5 e5 ?3 z
  41. LTDC_Handler.Init.TotalWidth=10+20+480+10-1;                         //总宽度6 g/ e* A5 n( t. ~' d  X4 o
  42. LTDC_Handler.Init.TotalHeigh=2+2+272+4-1;                                 //总高度0 E; L( K3 F* t4 R: ?( f. l/ m
  43. LTDC_Handler.Init.Backcolor.Red=0;                                                 //屏幕背景层红色部分
    ) a/ G* n1 m, i8 E
  44. LTDC_Handler.Init.Backcolor.Green=0;                                         //屏幕背景层绿色部分% [4 X2 a# m9 t; U- C, R
  45. LTDC_Handler.Init.Backcolor.Blue=0;                                         //屏幕背景色蓝色部分* M* }/ v8 F, W6 Z2 w0 j! z& N
  46. HAL_LTDC_Init(<DC_Handler);                                                         //设置 RGBLCD 的相关参数,并使能 LTDC,会调用HAL_LTDC_MspInit
复制代码

# s8 g+ k/ i2 u' T4.设置 LTDC层参数9 P4 k- ?. W) m+ H
  1. //layerx:层值,0/1.
    : |/ M1 C7 J" A4 d
  2. //bufaddr:层颜色帧缓存起始地址2 W) A% w$ G# C7 E; i: N
  3. //pixformat:颜色格式.0,ARGB8888;1,RGB888;2,RGB565;3,ARGB1555;4,ARGB4444;5,L8;6;AL44;7;AL88
    . L* z. W  H9 M$ f1 r
  4. //alpha:层颜色Alpha值,0,全透明;255,不透明  g) e5 Z9 r$ R- T. c- }/ g
  5. //alpha0:默认颜色Alpha值,0,全透明;255,不透明; Q  _; V& [9 j
  6. //bfac1:混合系数1,4(100),恒定的Alpha;6(101),像素Alpha*恒定Alpha7 ?/ a! T8 m3 R2 \
  7. //bfac2:混合系数2,5(101),恒定的Alpha;7(111),像素Alpha*恒定Alpha
    $ K/ N3 o  n" L) _0 j
  8. //bkcolor:层默认颜色,32位,低24位有效,RGB888格式* ~8 S- |. f- X/ d$ ~* Y, k
  9. void LTDC_Layer_Parameter_Config(u8 layerx,u32 bufaddr,u8 pixformat,u8 alpha,u8 alpha0,u8 bfac1,u8 bfac2,u32 bkcolor)
    . z/ o8 J: |) `/ j& A+ ^
  10. {  w+ w9 x- o# U# e, n' M# k0 \
  11.     LTDC_LayerCfgTypeDef pLayerCfg;' b; \* }& X) `! R' ?

  12. 9 w2 ?$ E1 F8 B4 c) Z1 i
  13.     pLayerCfg.WindowX0=0;                                   //窗口起始X坐标
    9 H7 E/ w6 x1 i  Y1 T5 R
  14.     pLayerCfg.WindowY0=0;                                   //窗口起始Y坐标3 K9 Q0 t' z) F, f: q# h9 F
  15.     pLayerCfg.WindowX1=lcdltdc.pwidth;                      //窗口终止X坐标8 `9 ]# m& C( j# U* s7 z
  16.     pLayerCfg.WindowY1=lcdltdc.pheight;                     //窗口终止Y坐标* y" L- q  I  |& N8 C4 r
  17.     pLayerCfg.PixelFormat=pixformat;                        //像素格式# N$ K8 X+ N/ j6 j
  18.     pLayerCfg.Alpha=alpha;                                  //Alpha值设置,0~255,255为完全不透明  F1 e3 H$ k) L9 F% X1 L4 O
  19.     pLayerCfg.Alpha0=alpha0;                                //默认Alpha值& H" [! s) t& |
  20.     pLayerCfg.BlendingFactor1=(u32)bfac1<<8;                //设置层混合系数
    $ J" Y5 o1 c# w
  21.     pLayerCfg.BlendingFactor2=(u32)bfac2<<8;                //设置层混合系数
    ; {8 N1 c% n8 M9 D5 K2 B1 ?5 j' _
  22.     pLayerCfg.FBStartAdress=bufaddr;                        //设置层颜色帧缓存起始地址; {  F9 W" _% X9 c# |
  23.     pLayerCfg.ImageWidth=lcdltdc.pwidth;                    //设置颜色帧缓冲区的宽度    : [) V6 m: h. c( M: B8 ^4 W5 b
  24.     pLayerCfg.ImageHeight=lcdltdc.pheight;                  //设置颜色帧缓冲区的高度" P* `7 y: {, v4 R5 c* R: p$ @
  25.     pLayerCfg.Backcolor.Red=(u8)(bkcolor&0X00FF0000)>>16;   //背景颜色红色部分
    ; u) P, w3 T* Q- e7 S$ m! J
  26.     pLayerCfg.Backcolor.Green=(u8)(bkcolor&0X0000FF00)>>8;  //背景颜色绿色部分
    % {: V% _7 Y+ s( g" W& d
  27.     pLayerCfg.Backcolor.Blue=(u8)bkcolor&0X000000FF;        //背景颜色蓝色部分
    - m  x; J: p: ]% h! m* ]8 v
  28.     HAL_LTDC_ConfigLayer(<DC_Handler,&pLayerCfg,layerx);  //设置所选中的层; i5 {( P) U; U- \, [
  29. }
    5 M5 _- Y! T; S4 b- Q  y

  30. $ z$ Q8 s8 p. N! y$ V4 V
  31. //在init时调用6 b! n+ F) A+ Q7 \  e
  32. LTDC_Layer_Parameter_Config(0(u32)ltdc_framebuf[0],LCD_PIXFORMAT,255,0,6,7,0X000000);  //层参数配置
复制代码

2 B7 I6 V; Y: A$ w$ Q$ z* P5.设置LTDC层窗口% f3 e( C5 I) s# C# i- }
  1. //layerx:层值,0/1.
    + g: D- H4 Z! C1 T
  2. //sx,sy:起始坐标
    6 b8 I& m' \, v4 C/ i* _
  3. //width,height:宽度和高度. \% N8 s0 k; E
  4. void LTDC_Layer_Window_Config(u8 layerx,u16 sx,u16 sy,u16 width,u16 height)7 b8 X8 S; L6 p. f5 Y
  5. {
    7 v& \7 N) b. i7 M6 U9 C9 x( K
  6.     HAL_LTDC_SetWindowPosition(<DC_Handler,sx,sy,layerx);                                  //设置窗口的位置) N+ }' K3 h" {7 X- w* h; c8 d
  7.     HAL_LTDC_SetWindowSize(<DC_Handler,width,height,layerx);                                //设置窗口大小    , z4 I( \" b9 [* z2 l' i; e5 H
  8. }$ P5 s8 o  j7 r2 E( E& F  g: v# X

  9. 7 v0 D( M- Q8 m# {7 a, b* V% \
  10. //在init时调用
    ' \, b1 t7 K  B+ [' Y0 k, |1 j
  11. LTDC_Layer_Window_Config(0,0,0,lcdltdc.pwidth,lcdltdc.pheight);             //层窗口配置,以LCD面板坐标系为基准
复制代码

) S' U8 Y) L. b完成了 LTDC 的配置,可以控制 RGBLCD 显示了。) V1 M* c5 i1 P+ i$ {* S
% j: |( \7 ^8 `# E+ M
使用DMA2D完成颜色填充4 [" C) w/ M# |) h9 F9 b
使用官方提供的 HAL 库 DMA2D 相关库函数进行颜色填充效率极为低下,大量时间浪费在函数的入栈出栈以及过程处理,所以在项目开发中一般都不会使用 DMA2D 库函数进行颜色填充6 b& J* |4 G1 i5 {2 }
9 c% I. l  Z+ D6 @/ o
1)使能 DMA2D 时钟,并先停止 DMA2D。9 V3 p# g& o2 A8 a+ U
要使用 DMA2D,先得开启其时钟。然后 DMA2D 在配置其相关参数的时候,需要先停止DMA2D 传输。 使能 DMA2D 时钟和停止 DMA2D 方法为:
  I3 O# `" C" O# V
  1. __HAL_RCC_DMA2D_CLK_ENABLE(); //使能 DM2D 时钟
    % W( t+ B6 I" n( v2 g+ H7 H& L
  2. DMA2D->CR&=~DMA2D_CR_START; //停止 DMA2D
复制代码

( E1 U$ {/ P0 _2)设置 DMA2D 工作模式。9 H, c) K# }- V* Z( a% q: d5 I
通过 DMA2D_CR 寄存器,配置 DMA2D 的工作模式。我们用了寄存器到存储器模式和存储器到存储器这两个模式。
$ P9 O7 u1 {' d2 n寄存器到存储器模式设置:
1 J) |* v1 v+ q* j
  1. DMA2D->CR=DMA2D_R2M; //寄存器到存储器模式
复制代码
3 O4 N* V' E7 E+ h
存储器到存储器模式设置:
* b; r: v- f+ |$ _7 K' C% ^, z
  1. DMA2D->CR= DMA2D_M2M; //存储器到存储器模式
复制代码

9 s4 S" X. L- C+ k' t& N3)设置 DMA2D 的相关参数。
2 i, t6 z) y4 k4 v- x2 @3 [! X+ B: Y这一步,我们需要设置:颜色格式、输出窗口、输出存储器地址、前景层地址(仅存储器到存储器模式需要设置)、颜色寄存器(仅寄存器到存储器模式需要设置)等,由:DMA2D_OPFCCR、DMA2D_FGPFCCR、DMA2D_OOR、DMA2D_FGOR 、DMA2D_OMAR、DMA2D_FGMAR 和 DMA2D_NLR 等寄存器进行配置。具体配置过程请参考实验源码。
4 C% f- T" c; I) s9 T8 _7 X, Q' A$ W7 O" S  }7 `
4)启动 DMA2D 传输。1 C3 d0 t+ N3 g9 n1 O( V
通过 DMA2D_CR 寄存器配置开启 DMA2D 传输,实现图像数据的拷贝填充,方法为:; G2 v8 g$ j# G" ?: Z" u4 ]# L
3 V% ^9 d6 d' r* M# ?
DMA2D->CR|=DMA2D_CR_START; //启动 DMA2D
) K: ?# v, B2 L/ s1 T16 G6 F. V4 U. u$ m/ e# G9 m
5)等待 DMA2D 传输完成,清除相关标识。7 H4 L" h* j4 Z3 A5 D3 Y
最后,在传输过程中,不要再次设置 DMA2D,否则会打乱显示,所以一般在启动 DMA2D后,需要等待 DMA2D 传输完成(判断 DMA2D_ISR),在传输完成后,清除传输完成标识(设置 DMA2D_IFCR),以便启动下一次 DMA2D 传输。# \' x& U; H. O! A

: p, q1 V1 Z  z1 F# d
  1. while((DMA2D->ISR&DMA2D_FLAG_TC)==0) ; //等待传输完成, j0 \; t2 _# @. {3 q
  2. DMA2D->IFCR|=DMA2D_FLAG_TC; //清除传输完成标志
复制代码
' d8 `* E9 g! u8 O' {
通过以上几个步骤,我们就完成了 DMA2D 填充/ Y" d/ X# X7 O7 |# P' \

- }9 h9 {- c& O9 _% c使用示例
9 ^- m, ?2 O, _: C
  1. //LCD LTDC重要参数集
    % k+ l5 W0 b/ L% p; b
  2. typedef struct  3 O- a% }$ A) [$ H  B( w" W
  3. {
    * @, G- K* P- P3 u, T0 @, q% r
  4.     u32 pwidth;         //LCD面板的宽度,固定参数,不随显示方向改变,如果为0,说明没有任何RGB屏接入
    * B  p' W4 @) C5 @# t5 e2 g
  5.     u32 pheight;        //LCD面板的高度,固定参数,不随显示方向改变
    7 N  m" ~6 i, m: S) U
  6.     u16 hsw;            //水平同步宽度 Horizontal synchronization width
    " H; s% A7 D  }! S
  7.     u16 vsw;            //垂直同步宽度 Vertical synchronization width1 O& B- ?' O( g: {- |1 o) ]
  8.     u16 hbp;            //水平后廊0 G" @1 z8 Y7 q( ]' O/ ?) B
  9.     u16 vbp;            //垂直后廊
    9 c& C; k% c. X( {- y5 B% K( X
  10.     u16 hfp;            //水平前廊) \1 a8 O% @) v" \7 {
  11.     u16 vfp;            //垂直前廊$ m, e6 V( o0 w- r  k' O
  12.     u8 activelayer;     //当前层编号:0/1
    1 d9 K, Y% t2 k
  13.     u8 dir;             //0,竖屏;1,横屏;; @3 F% Y, Q/ `, Z; G( g* ~
  14.     u16 width;          //LCD宽度
    4 {4 K. D2 j6 _$ j. O3 F+ T# G1 k. r
  15.     u16 height;         //LCD高度
    # V+ @( E6 U' e# s9 o& z
  16.     u32 pixsize;        //每个像素所占字节数
    ! o: b6 M. m+ K) o2 Y
  17. }_ltdc_dev;& d# X% T& ~# j1 r1 T: N7 P/ d

  18. 3 f- T. i* {$ |5 d8 z, Q  [
  19. _ltdc_dev lcdltdc;                //管理LCD LTDC的重要参数0 Y8 N- S+ {1 ~9 d4 b" F2 Y. a
  20. 2 K  f7 X1 m, Y3 L1 L& [: C% T
  21. //LTDC填充矩形,DMA2D填充
    % N" R+ @% e) w
  22. //(sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)   
    1 }1 D' c/ F0 w  Z! k4 P7 J6 ]% j) W
  23. //注意:sx,ex,不能大于lcddev.width-1;sy,ey,不能大于lcddev.height-1!!!
    & Q$ u" c! l/ K) {. {# J' v* p) X
  24. //color:要填充的颜色
    / H4 \* p( b0 @. o+ x
  25. void LTDC_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u32 color)
    - f/ N% j$ Y& w2 v- t
  26. { 2 e% C' h& V  \5 D
  27.     u32 psx,psy,pex,pey;                        //以LCD面板为基准的坐标系,不随横竖屏变化而变化8 d% E# @  u+ [8 M: ~! f
  28.     u32 timeout=0;
    " W: q( ~2 d4 ]
  29.     u16 offline;
    - C9 G' o5 J, T3 C
  30.     u32 addr; $ ^. o! }, B3 B
  31.     //坐标系转换
    % ?; Z9 ?/ r/ C4 z: p1 J
  32.     if(lcdltdc.dir)                             //横屏
    9 M; h3 }' J+ ^$ @) l
  33.     {; ~* o& V% s, k2 G4 w# b: U3 e
  34.         psx=sx;psy=sy;
    ( Z- {# L% p8 M8 m# x$ Y
  35.         pex=ex;pey=ey;* L# o0 L1 u* i+ h: [  y
  36.     }else                                       //竖屏  S' y5 Y2 w3 Z" W0 ?; {0 ^
  37.     {
    / {1 z, J: ^: J7 d7 o
  38.         psx=sy;psy=lcdltdc.pheight-ex-1;8 V# m' Z$ j8 j. D
  39.         pex=ey;pey=lcdltdc.pheight-sx-1;$ ?' n& P( `' B" }
  40.     }
    2 d1 Q) ^: J: E- J
  41.     offline=lcdltdc.pwidth-(pex-psx+1);
    ! ]1 n# j  Y- f( c& |  v6 L
  42.     addr=((u32)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*psy+psx));3 r5 R! X1 D- q- R# ~2 x) P% g/ A
  43.     RCC->AHB1ENR|=1<<23;                        //使能DM2D时钟
    7 o" D6 o! [% L+ n1 L# `, o
  44.     DMA2D->CR=3<<16;                            //寄存器到存储器模式* j2 y7 f- W3 ^% @% }
  45.     DMA2D->OPFCCR=LCD_PIXFORMAT;                //设置颜色格式5 Z* L( T9 j( l) W! Z! @5 P
  46.     DMA2D->OOR=offline;                         //设置行偏移
    6 }/ w4 [7 _7 A3 Y
  47.     DMA2D->CR&=~(1<<0);                         //先停止DMA2D# J- G  i. q/ G$ ]( O. L" m
  48.     DMA2D->OMAR=addr;                           //输出存储器地址# S9 `  P" `) A, t" |+ L
  49.     DMA2D->NLR=(pey-psy+1)|((pex-psx+1)<<16);   //设定行数寄存器" [# N% M8 ?6 O  o- E( z& a( V& \
  50.     DMA2D->OCOLR=color;                         //设定输出颜色寄存器
    ( z, R" \2 F1 d: V# n; s$ W8 T6 {4 a
  51.     DMA2D->CR|=1<<0;                            //启动DMA2D
    ! A2 H+ l* q4 z" q9 p
  52.     while((DMA2D->ISR&(1<<1))==0)               //等待传输完成2 j; M! S  Z! r4 Y; E% s
  53.     {9 F9 g' Z, o5 [, u, J
  54.         timeout++;: \9 t6 c# f/ g0 p
  55.         if(timeout>0X1FFFFF)break;              //超时退出& ^1 ]: e) d4 ^8 X' J
  56.     }  
    - g9 V  v+ K% Y9 ^4 n- E% i
  57.     DMA2D->IFCR|=1<<1;                          //清除传输完成标志( T$ N" h6 X/ m( b
  58. }
    $ h) S4 U* ?, x& g

  59. ; R! h- n1 I: o' D5 {6 |- l
  60. //LCD清屏5 e4 n" N8 ]. c- O
  61. //color:颜色值* M/ L* ]" r' d/ n7 Z0 y* k: A
  62. void LTDC_Clear(u32 color)4 O* Q3 y: y. Q$ C
  63. {. l+ Y! `/ U! U
  64.     LTDC_Fill(0,0,lcdltdc.width-1,lcdltdc.height-1,color);
    : S4 P1 A3 a1 K# s/ `* S
  65. }# n' I6 m, v. x1 }/ c6 f. L

  66. 4 m' W, V! E6 T& l5 }5 z9 ^/ [2 q

  67. 7 a% U0 K8 Q6 i' q7 }& c3 y. T
复制代码
) f; i9 F; P% u* O$ P- ^
, Y8 h+ I( w9 f+ Y2 E1 m: U
)0J3WVNZQ8DQ6O089(M6FJW.png
收藏 评论0 发布时间:2021-12-13 08:50

举报

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