今天准备移植STM32F030R8T6的程序到STM32G030C8T6上,程序中用到了硬件SPI外设,因为STM32G0用的HAL+LL库而不是不是标准库,所以我用STM32Cube MX生成了SPI的LL库代码,但是使能SPI后发现硬件怎么都不能触发RXNE接收标志,生成代码如下:
7 l, J' j/ d* F) R3 N% a& `9 x& s+ Y
- void MX_SPI1_Init(void)
6 j9 W5 h3 _/ {" h - {5 }+ ^" A, z0 B! p; I
6 m! J5 G( Z, O( i, P- /* USER CODE BEGIN SPI1_Init 0 */5 D O, K! A; A% O9 Q4 g
" A$ ^8 J: m7 u7 p- /* USER CODE END SPI1_Init 0 */
2 e4 F( C9 P5 _3 O' Z" U& z3 ^ - : q( F0 D7 L8 }. W& s7 {
- LL_SPI_InitTypeDef SPI_InitStruct = {0};2 J0 Q* a$ s7 ^' c7 R
6 e! d2 w- x T r- LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
O" ^$ V( B8 h% f4 |* \ Q
6 ^% D) B+ Z$ Y- X& k3 r/ J9 m- /* Peripheral clock enable */3 S) X0 u/ T* t
- LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
- i7 ~5 e6 a: P9 b+ V# H" l( K* {$ C
& R/ k: R$ }5 y& c- LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
9 M& L) p6 }( [4 a& `# l% \- G - /**SPI1 GPIO Configuration
$ i3 ?* Y0 L! P& q% ~' T, X - PA5 ------> SPI1_SCK, I& Z& [" G8 I
- PA6 ------> SPI1_MISO) K3 b- ]& m4 k1 z' G2 W
- PA7 ------> SPI1_MOSI, X$ D5 R+ q4 Y
- */ d* y2 G8 I# {3 s5 j
- GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
+ `: b& q9 e0 S# Q& Z - GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
q- v% k; ~" x - GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;1 U" z- G0 Q8 B. u$ p& v5 v
- GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;9 ~/ v Z: M2 ^
- GPIO_InitStruct.Alternate = LL_GPIO_AF_0;4 B' L9 ?2 y% ]2 B( _/ e) i) ?
& q0 M& C+ g5 d. h7 _; R& ]) v# `- GPIO_InitStruct.Pin = SPI_SCK_PIN;
& u% \8 |# F* B& U$ Z) A - LL_GPIO_Init(SPI_SCK_PORT, &GPIO_InitStruct);$ D4 W: \. P5 j6 e+ z$ Y) [
- , Y* B, a* [, @) g1 o% U8 V( T
- GPIO_InitStruct.Pin = SPI_MISO_PIN;
; P5 S" }3 a, {: S+ E5 n1 Y - LL_GPIO_Init(SPI_MISO_PORT, &GPIO_InitStruct);4 Q$ l' e. l2 P" P
0 t# T0 t1 B) U) t# _5 \+ T: [' M- GPIO_InitStruct.Pin = SPI_MOSI_PIN;1 D+ y, ?2 s( I
- LL_GPIO_Init(SPI_MOSI_PORT, &GPIO_InitStruct);
; n1 N0 r$ w+ `' J+ Y - A( c% n' d/ Z" ?. L
- /* USER CODE BEGIN SPI1_Init 1 *// A' f3 n& y/ {* J( q+ O
- : a4 |2 b9 O. H* w8 y& i
- /* USER CODE END SPI1_Init 1 */
: O! D: L% l: f1 U% B1 v$ s; J" a9 v - SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
3 M3 v/ c" r$ c- y5 ~ - SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
5 c5 @) A' ~2 Y/ a5 `! o; T F7 o - SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;9 S: Z: X; X* _# e2 z8 |
- SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_HIGH;
/ g1 [& A1 M6 ^6 H# K9 z0 S8 Y - SPI_InitStruct.ClockPhase = LL_SPI_PHASE_2EDGE;2 `# [- [8 S6 i
- SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
, S, r& x2 {5 b3 } W - SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV4;: _/ R" c( L. G
- SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;& g0 I( R" C; B/ {* \$ H, _! _( I
- SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
( ]# K$ C" o) j) p' r# K& B, f - SPI_InitStruct.CRCPoly = 7;
0 L2 b6 y2 t( ~% R/ T. B! D6 C - LL_SPI_Init(SPI1, &SPI_InitStruct); P$ S5 O8 q% U( v
- LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA);/ H, ^" E; [2 L @
- LL_SPI_DisableNSSPulseMgt(SPI1);
3 Z5 D9 R$ U- H0 q - /* USER CODE BEGIN SPI1_Init 2 */# ?+ w3 R9 f0 I/ n+ h
- LL_SPI_Enable(SPI1); //用户手动使能SPI. O" V5 F" C3 c8 Q$ g- i% p) Q
- /* USER CODE END SPI1_Init 2 */* z& L7 D; Q0 F ~* X' k
- + M' e) _+ i( T; }. H9 l8 x
- }6 y* Y& i6 S2 n w. J8 R
复制代码 / M5 d$ a4 N l9 C# Z
程序正常运行后,通过在线DEBUG并调出SPI外设后,查看相关寄存器,可以看出SPI能正常发送,但是因为CR2寄存器的RXNE标志一直不能被触发,导致接收不到数据,如下图所示:( e4 P6 W0 |1 v4 H& S% O
2 l/ \. F1 s, |" w$ _, j8 |' L+ i# O- v
但是相同的设置在STM32F0的标准库上是可以正常运行了,模式配置都一样,但是用LL库的STM32G0上就不能运行,后来查看STM32G031K LL库的使用 - SPI这篇文章,发现代码中额外添加了以下语句:3 `+ A# p9 V9 u* ^: }4 a
% ~& z( e9 ^4 @" ^6 p0 K9 W! b8 V/ O- /* Configure the SPI2 FIFO Threshold */
. M- y4 t9 e: f4 ^. K; S6 K. J4 _ - LL_SPI_SetRxFIFOThreshold(SPI2, LL_SPI_RX_FIFO_TH_QUARTER);//设置RX非空事件产生的FIFO阈值,根据通信时最<span style="background-color: rgb(255, 255, 255);">小数据的大小设置,我这边最小为8位,所以设置为四分之一</span>
复制代码 / x' c9 h0 C1 o& g
通过查看STM32G0x0官方数据手册的24.6.2 SPI control register 2 (SPIx_CR2)小节,可以看到设置外设接收8位数据,RX FIFO阈值要设置为1/4,但因为Cube MX生成的代码没有设置FIFO阈值,并且LL_SPI_Init()函数也并没有直接对CR2寄存器的FRXTH位进行设置,导致了代码中虽然设置的是接收8位数据,但寄存器为默认16位的阈值,所以RXNE标志就一直不能触发,也就接收不到任何数据。
" j) i/ B/ a2 G6 q5 x# j% P+ W6 i* T0 c
9 U' E7 r( C. t5 u
. ^ s3 X D2 S5 d+ I9 `* N' G2 G
反观用了标准库函数的STM32F0,同样的设置为什么就可以正常运行呢???通过查看标准库函数SPI_Init(),可以发现函数中对CR2进行了赋值操作,而对应值正是SPI_DataSize_8b这个宏,该宏的值为0x0700,Bit12 FRXTH=1,该值对应FRXTH接收阈值为1/4,所以程序能正常运行,RXNE可以正常触发,这也就解释了为什么同样的配置在标准库上SPI能正常运行,但是在LL库上却不能正常运行的问题所在。, A( R; m# }7 J
/ I- Z N M! \, C' K
- void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct)
* k0 o2 g- }, j: u - {6 E4 Q, L. @2 [- K& Q9 q
- .......
$ E# f& }! n* E# y. c: { - /* Configure SPIx: Data Size */
0 F" f" g. M0 f5 T3 Z8 E; v - tmpreg |= (uint16_t)(SPI_InitStruct->SPI_DataSize); //SPI发送接收的数据为8位 e6 i" v; @, m4 X* }! `
- /* Write to SPIx CR2 */& q, [$ E+ @& I
- SPIx->CR2 = tmpreg; & \* s0 s' m' A; I, q- r+ x, v
- ......
复制代码 * o3 O9 [% ^: h! ]+ V. f
9 u5 B r, M: N/ R" O: c3 D+ Y, Z
* D( a# ~ J8 \' E! r) R* x3 \ |