分析STM32G0 SPI外设不能触发RXNE接收标志的原因

今天准备移植STM32F030R8T6的程序到STM32G030C8T6上,程序中用到了硬件SPI外设,因为STM32G0用的HAL+LL库而不是不是标准库,所以我用STM32Cube MX生成了SPI的LL库代码,但是使能SPI后发现硬件怎么都不能触发RXNE接收标志,生成代码如下:

void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  LL_SPI_InitTypeDef SPI_InitStruct = {0};

  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* Peripheral clock enable */
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);

  LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
  /**SPI1 GPIO Configuration
  PA5   ------> SPI1_SCK
  PA6   ------> SPI1_MISO
  PA7   ------> SPI1_MOSI
  */
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
  
  GPIO_InitStruct.Pin = SPI_SCK_PIN;
  LL_GPIO_Init(SPI_SCK_PORT, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = SPI_MISO_PIN;
  LL_GPIO_Init(SPI_MISO_PORT, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = SPI_MOSI_PIN;
  LL_GPIO_Init(SPI_MOSI_PORT, &GPIO_InitStruct);

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
  SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
  SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
  SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_HIGH;
  SPI_InitStruct.ClockPhase = LL_SPI_PHASE_2EDGE;
  SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
  SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV4;
  SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
  SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
  SPI_InitStruct.CRCPoly = 7;
  LL_SPI_Init(SPI1, &SPI_InitStruct);
  LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA);
  LL_SPI_DisableNSSPulseMgt(SPI1);
  /* USER CODE BEGIN SPI1_Init 2 */
  LL_SPI_Enable(SPI1); //用户手动使能SPI
  /* USER CODE END SPI1_Init 2 */

}

程序正常运行后,通过在线DEBUG并调出SPI外设后,查看相关寄存器,可以看出SPI能正常发送,但是因为CR2寄存器的RXNE标志一直不能被触发,导致接收不到数据,如下图所示:

在这里插入图片描述
但是相同的设置在STM32F0的标准库上是可以正常运行了,模式配置都一样,但是用LL库的STM32G0上就不能运行,后来查看STM32G031K LL库的使用 - SPI这篇文章,发现代码中额外添加了以下语句:

/* Configure the SPI2 FIFO Threshold */
  LL_SPI_SetRxFIFOThreshold(SPI2, LL_SPI_RX_FIFO_TH_QUARTER);//设置RX非空事件产生的FIFO阈值,根据通信时最小数据的大小设置,我这边最小为8位,所以设置为四分之一

通过查看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标志就一直不能触发,也就接收不到任何数据。
在这里插入图片描述

反观用了标准库函数的STM32F0,同样的设置为什么就可以正常运行呢???通过查看标准库函数SPI_Init(),可以发现函数中对CR2进行了赋值操作,而对应值正是SPI_DataSize_8b这个宏,该宏的值为0x0700,Bit12 FRXTH=1,该值对应FRXTH接收阈值为1/4,所以程序能正常运行,RXNE可以正常触发,这也就解释了为什么同样的配置在标准库上SPI能正常运行,但是在LL库上却不能正常运行的问题所在。

void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct)
{
	.......
	 /* Configure SPIx: Data Size */
	tmpreg |= (uint16_t)(SPI_InitStruct->SPI_DataSize); //SPI发送接收的数据为8位
	/* Write to SPIx CR2 */
	SPIx->CR2 = tmpreg; 
	......
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
配置STM32G030的SPI1/SPI2需要遵循以下步骤: 1. 打开SPI时钟使能(RCC_APB2ENR_SPI1EN/RCC_APB1ENR_SPI2EN); 2. 配置SPI的时钟分频、数据大小、传输模式、时钟极性和相位等参数; 3. 配置SPI的NSS片选引脚(如果使用软件片选则可以不用配置); 4. 配置SPI的中断(如果需要使用中断); 5. 使能SPI。 下面是一个简单的例子,演示如何配置SPI1/SPI2,并向外部设备发送数据。 ```c #include "stm32g0xx.h" void SPI1_Init(void) { // 使能SPI1时钟 RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; // 配置SPI1时钟分频、数据大小、传输模式、时钟极性和相位等参数 SPI1->CR1 = SPI_CR1_BR_0 | SPI_CR1_MSTR | SPI_CR1_CPOL | SPI_CR1_CPHA; // 配置SPI1的NSS片选引脚(软件片选) SPI1->CR2 = SPI_CR2_SSOE; // 使能SPI1 SPI1->CR1 |= SPI_CR1_SPE; } void SPI2_Init(void) { // 使能SPI2时钟 RCC->APB1ENR |= RCC_APB1ENR_SPI2EN; // 配置SPI2时钟分频、数据大小、传输模式、时钟极性和相位等参数 SPI2->CR1 = SPI_CR1_BR_0 | SPI_CR1_MSTR | SPI_CR1_CPOL | SPI_CR1_CPHA; // 配置SPI2的NSS片选引脚(软件片选) SPI2->CR2 = SPI_CR2_SSOE; // 使能SPI2 SPI2->CR1 |= SPI_CR1_SPE; } void SPI_SendData(SPI_TypeDef *SPIx, uint8_t *data, uint32_t size) { uint32_t i; for (i = 0; i < size; i++) { // 等待发送缓冲区为空 while ((SPIx->SR & SPI_SR_TXE) == 0); // 发送数据 SPIx->DR = data[i]; // 等待接收缓冲区非空 while ((SPIx->SR & SPI_SR_RXNE) == 0); // 读取接收数据(如果需要) uint8_t dummy = SPIx->DR; } } int main(void) { // 初始化SPI1和SPI2 SPI1_Init(); SPI2_Init(); // 发送数据到外部设备 uint8_t data[4] = {0x01, 0x02, 0x03, 0x04}; SPI_SendData(SPI1, data, sizeof(data)); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值