在上新建工程的基础上添加使用SPI功能(新建工程见STM32使用LL库建立工程)
8 p8 C) N0 o! J; o6 h2 }( c7 _0 L! R- d3 H2 v* @. a
一、CubeMX的配置
?5 J0 P# ?# d, N1、非SPI的LCD控制IO口的配置
/ `$ z6 `1 T- l) \4 b' ? Z查看原理图可以看到,有5个引脚接在了MCU上,其中有两个SPI引脚,三个LCD控制引脚) v( v5 B( @1 J- E! R- j- i
, V" w i! p4 \8 @/ w2 b& A7 ~' B8 C7 Y
其引脚对照表如下,所以我们先将PC6、PC7、PB15配置为通用IO推挽输出6 w5 A3 l, b4 i# r/ b8 b
+ s. q" _4 [0 }( d
2 I4 ~; r+ z. K! \! n. G, s( [! }6 A# u1 S2 b0 I( X& ]7 M, _
' }# q# h5 H* U1 B
[" v$ q, }* S% f* v2、SPI的的配置
8 R4 C! ^; M4 A, `! p- r2 rMCU只需要通过SPI向LCD控制器发送命令/数据即可,所以只使用 SPI2 的 SCK 和 MOSI 引脚,将SPI2配置为主设备只发送模式,接下来开始配置SPI2接口:' s5 T- C7 W+ U* n# n4 ^
' v( l& ]* p! u: D! y
首先将SPI2配置为只发送主设备模式
0 R. D3 m) M8 R5 I; b; ?3 Z8 U, |2 z7 p. ?: g. g; W5 W
4 W% _6 g' d" J
! w' h1 _6 A+ J( l1 f8 V- R! h可以看到,SPI2_SCK引脚默认为PB10,我们需要将其修改为PB134 u9 ?' y9 i7 l) |& q/ ^: D. K, {+ ^
' O4 X; F/ Q% L% h& n3 ~: }% N8 _" j O0 Y
9 U9 q9 _6 i7 v' b
* U9 h# |. w: S/ ~0 r- i7 c
然后对SPI的参数进行配置
8 c8 ~' F$ v% \! O$ G7 ~
3 I- N$ ?* b0 U5 U
( G3 U0 D( v% X4 g/ [5 d. K# C# {; M; C- J% P7 f7 c% h
然后重要的是工程设置里,将HAL改成LL# G; }- n. q# x$ s9 U) A. {1 U* f
, A- s+ Y* c' Q0 ?4 z) f( Z' a1 u% @
# l2 _9 P1 M) d
" @+ g7 f# L+ d* V* j9 q5 x然后便可以生成代码
W; T! @1 D! V" E4 L9 q- f2 A; m5 [( y
: F+ e+ k+ |7 @) h
6 Y% Y0 T* a4 l4 m9 R3 M, i二、用户代码修改7 @! m; A* N( d1 N6 J
将SPI初始化代码修改为如下,放入新建的spi.c文件% E1 A6 s3 @' h4 a4 }
9 m: R- a0 x9 H! V- //SPI2初始化代码,配置成主设备只发送模式$ y% |4 Q& I3 D) i
- void SPI2_Init(void) c+ w/ v8 ~: E2 n; [
- {/ F0 m+ U) d6 R Y9 u
- LL_SPI_InitTypeDef SPI_InitStruct;7 r; r1 ^- M1 A! N# W3 u
- LL_GPIO_InitTypeDef GPIO_InitStruct;
/ h, C8 { [3 V
9 ^- ]3 B$ j0 e) `- LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);//使能GPIOB时钟
. p9 |" M% Y) l - LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC);//使能GPIOC时钟% `- x9 d2 k9 N2 n) O& |
- LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); //使能SPI2时钟
% F5 x; ^( o' g) I J* v - * n ~( h f# h. t: T8 m
- // **LCD控制GPIO配置 LCD_PWR->PB15 LCD_WR_RS PC6 LCD_RST->PC7 */
+ ~9 \1 r$ V' a* E2 p# ~ - GPIO_InitStruct.Pin = LL_GPIO_PIN_15;
1 V& P' ]) m9 d - GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;5 a. b7 a# S# g8 G( {
- GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
2 e* B l; U, s6 u3 @ - GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;' B8 R+ _1 p( r4 g7 n, _5 w) s
- GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
: S9 e0 T: H* d. U - LL_GPIO_Init(GPIOB, &GPIO_InitStruct);' S: F: a) h( Y1 d- d0 Q! e
- LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_15);8 X! N# T1 ~& Y9 |& o% g6 E
\! U* Y0 b8 K- S3 f- GPIO_InitStruct.Pin = LL_GPIO_PIN_6|LL_GPIO_PIN_7;: D0 C' ?( ^" B
- LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
7 K6 k4 L+ o( h - LL_GPIO_ResetOutputPin(GPIOC, LL_GPIO_PIN_6|LL_GPIO_PIN_7); v4 a/ [0 f4 ?# O+ j
-
8 t; U% g" t4 V, x( Y9 R1 v. k - // **SPI2 GPIO Configuration PC3-> SPI2_MOSI PB13-> SPI2_SCK */3 U5 o8 @* [4 U* @0 A
- GPIO_InitStruct.Pin = LL_GPIO_PIN_13; \4 ~/ w* A! U: ]3 O
- GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;* K! n! G V% i5 o
- GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH; H7 }$ J- z$ j. r, K w
- GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;1 {/ H+ v' ]% k7 J* g
- GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;- F9 c9 j% b7 {
- GPIO_InitStruct.Alternate = LL_GPIO_AF_5;& h: [! `6 w5 e8 I: O
- LL_GPIO_Init(GPIOB, &GPIO_InitStruct); w, ?( w7 z+ z0 l+ W7 T
-
. D: u2 a% {* ^4 @- S* Q$ f. d - GPIO_InitStruct.Pin = LL_GPIO_PIN_3;2 M }6 b( H: |* `) Q/ @
- LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
~* h! T- k9 C) w- y8 T& v
1 {, T8 M) Z1 i6 j! v3 `' s- /* SPI2 parameter configuration*/
; w ]: j/ o( z* ]1 h - SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX; //全双工/ x' H" k" l, O2 S( _
- SPI_InitStruct.Mode = LL_SPI_MODE_MASTER; //主设备模式
g* N1 O6 O* U; L( D" a - SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT; //8位数据宽度0 R8 I& A: h" T7 |* O, X
- SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_HIGH; //串行同步时钟的空闲状态为高电平
0 O- @, Z V' j - SPI_InitStruct.ClockPhase = LL_SPI_PHASE_2EDGE; //串行同步时钟的第二个跳变沿数据被采样
$ F9 }9 S. [, g% G/ n1 s - SPI_InitStruct.NSS = LL_SPI_NSS_SOFT; //NSS信号由软件(使用SSI位)管理:内部NSS信号由SSI位控制! @& V/ ?8 H! t7 {: I m
- SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2;//定义波特率预分频的值:波特率预分频值为256* `/ e" P4 P: v: }" x2 }. U
- SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST; //数据传输从MSB位开始
( D+ m! u4 Y, [) y4 t+ i - SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;//关闭硬件CRC校验
7 c! j% r, U: C5 L$ g3 y - SPI_InitStruct.CRCPoly = 7; //CRC值计算的多项式" l I, D8 v$ Q: G( W4 K- E
- LL_SPI_Init(SPI2, &SPI_InitStruct);
3 ?% G7 K: }$ l' ]9 S
4 n; y3 U* [9 K8 j6 G- LL_SPI_SetStandard(SPI2, LL_SPI_PROTOCOL_MOTOROLA); //SPI帧格式 为 SPI Motorola模式
4 k; V0 Z, J& G* \+ a9 Z - LL_SPI_DisableNSSPulseMgt(SPI2); //关闭 NSS脉冲模式. U! w( ]% s% V, k" M
- 0 y6 ?. W6 u7 ~2 I. M
- LL_SPI_Enable(SPI2); //使能SPI2
4 L, J8 w$ `1 I9 v - }& Q# c% a f7 B) \5 w% ^! u0 w
- S: ]7 Y$ z H- ~
复制代码
7 e1 b! U+ c4 U! B! G: I; Y然后编写SPI2_WriteByte(u8 *TxData,u16 size)函数
1 N, J3 x# w3 _3 J9 O
) t; x+ S: m; F# ?3 C) ~& V4 g5 S( k- /**7 D; F2 A& I4 t6 I' D: V Q- o- R
- * @brief SPI3 写入一个字节& g4 y( M0 D6 w5 [. S; V) A9 M, V
- * @param TxData 要写入的字节 b0 S; n& M$ n, l- p }% w
- * @param size 写入字节大小
. g4 c. w- Z& d; T" o6 y Z - * @return u8 0:写入成功,其他:写入失败
" p- e5 R4 r# e - */& q: T2 q* ?5 ^1 J7 A" p8 Q; v' U
- u8 SPI2_WriteByte(u8 *TxData,u16 size)
2 K" r( q0 ]( @* Q - {
; l5 ^; ?4 }5 ~/ l- P - u8 retry=0; ' ?. D3 L+ H- v
- u8 n=0;
: Z1 \! m% i9 ]' V - for(n=0;n<size;n++)
5 r) ^; B6 d8 B( Z6 a9 N - {
7 ^3 `$ Y% h/ y6 C7 _ - while (LL_SPI_IsActiveFlag_TXE(SPI2) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位$ R* ]/ x' c( c- I
- {! j5 e8 D3 T7 [8 v; k$ q! C' D
- retry++;
o# w& A5 }9 e9 E, O - if(retry>200)return retry;7 a# u G- h/ V& ?
- }
+ |- z8 V% X& I - LL_SPI_TransmitData8(SPI2, TxData[n]); //通过外设SPIx发送一个数据6 {" H0 }2 G# W' ~ E
- }3 }* r& E( y" X7 a( d" _' b" [7 Z% X
- D X( |& r+ I
- return 0;
" `9 H6 u/ U- Y. ?7 C; z* c1 Q0 L8 v - }
复制代码 , I8 P+ n' ^3 P i7 U _ j# p- G+ O
三、LCD代码移植+ ~ \. q+ H% w, J
BearPi和正点原子的Pandora开发板使用的LCD是同一款,且模式配置也一样,所以既然有现成的代码,我们不妨copy一下,将lcd.c和lcd.h复制过来( B+ Y U. g `9 T" ~" s
然后修改lcd.h里的LCD控制GPIO代码9 G- D2 b$ r5 C, ~# X
. e d% n. ~5 c: \+ l
- /*
; ?5 g8 F) L8 R- O# ? - LCD_PWR: PB15/ [, u; _+ C( }/ N1 d- q9 X
- LCD_RST: PC7, x2 Y" m( X: }2 ]* X! ~( P% C
- LCD_DC: PC6
! \7 [& I) H) Y5 @, q - */8 E* l( N( P- v* Q! i
- #define LCD_PWR(n) (n?LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_15):LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_15))
2 u+ X( \$ H/ c3 [5 o - #define LCD_RST(n) (n?LL_GPIO_SetOutputPin(GPIOC, LL_GPIO_PIN_7 ):LL_GPIO_ResetOutputPin(GPIOC, LL_GPIO_PIN_7))
5 n3 E5 z/ g3 z( h* H - #define LCD_DC(n) (n?LL_GPIO_SetOutputPin(GPIOC, LL_GPIO_PIN_6 ):LL_GPIO_ResetOutputPin(GPIOC, LL_GPIO_PIN_6))4 ]+ g4 w+ C+ N: W1 p
复制代码
8 n: h* ]4 U( L将lcd.c里的LCD_Gpio_Init()代码删去,然后在LCD_Init()开头添加如下代码:3 D* Z4 v7 v' ~3 h% {. i
; D% J0 k* j' x- SPI2_Init();2 R1 s3 R& J9 k- ^9 z
-
( L7 K" A! _) e( @* P9 h - LCD_PWR(0); //关闭显示
5 B6 [2 Z- y$ b( m- p$ U
% p2 Z( D, C- l# t7 U' d- LCD_RST(0);
0 G; {7 Z0 F+ a; b, ?9 ] - delay_ms(120);
B/ [& N' R9 e - LCD_RST(1); //复位
复制代码
0 c6 z0 \$ f& o在主函数里写入
4 `" }0 Z, z; D) c
) H$ c7 i- Z, t: P9 p8 }- LCD_Init(); //初始化LCD
: @8 R4 W( v* o+ F -
6 p5 }3 L v& o I S' y. k( m" n% _& y - POINT_COLOR = RED;
' H% q# {; @# u/ j4 T - LCD_ShowString(0, 100, 240, 32, 32, "BearPi STM32L4");
复制代码 / @2 i- w( t% B& ]# c$ `
编译链接下载到开发板里,测试结果如下
; O9 r4 |! j9 \- s2 D
+ O' q. I7 ^" a) _
3 o8 l, S/ F; z3 d& L
5 p% W, F5 H& P9 G! P
表明测试成功1 t v/ d8 W/ l. ^
————————————————
( c- a! Y" D; _转载:Willliam_william9 l5 g6 `4 W+ K# n- \
3 n+ L+ A( C& f; X2 g( x0 a. z4 h, v( `( T L
|