STM32 SPI RXNE 标志不会改变

问题描述 投票:0回答:2

我在 Nucleo 板上使用 STM32F303RE 微控制器。

数据表

参考手册

在尝试编写一个与 SPI 设备通信的程序后,我发现它不起作用,因此我将代码简化为最小的实现,除了接收单个字节之外什么也不做。这是我所拥有的:

volatile char data = 'A';

int main(void) {
  HAL_Init();
  SystemClock_Config();

  RCC->AHBENR |= RCC_AHBENR_GPIOBEN;    // Enable GPIOB clock
  RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;   // Enable SPI2 clock

  // PB12 Alternate Function mode [10]
  GPIOB->MODER &= ~GPIO_MODER_MODER12_0;
  GPIOB->MODER |= GPIO_MODER_MODER12_1;

  // PB13 Alternate Function mode [10]
  GPIOB->MODER &= ~GPIO_MODER_MODER13_0;
  GPIOB->MODER |= GPIO_MODER_MODER13_1;

  // PB14 Alternate Function mode [10]
  GPIOB->MODER &= ~GPIO_MODER_MODER14_0;
  GPIOB->MODER |= GPIO_MODER_MODER14_1;

  // PB15 Alternate Function mode [10]
  GPIOB->MODER &= ~GPIO_MODER_MODER15_0;
  GPIOB->MODER |= GPIO_MODER_MODER15_1;

  // PB12 High Speed [11]
  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR12_0;
  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR12_1;

  // PB13 High Speed [11]
  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR13_0;
  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR13_1;

  // PB14 High Speed [11]
  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR14_0;
  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR14_1;

  // PB15 High Speed [11]
  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR15_0;
  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR15_1;

  // Alternate function 5 [0101]
  GPIOB->AFR[1] = 0;                                // Reset register
  GPIOB->AFR[1] = 0b0101 << GPIO_AFRH_AFRH4_Pos;    // PB12
  GPIOB->AFR[1] = 0b0101 << GPIO_AFRH_AFRH5_Pos;    // PB13
  GPIOB->AFR[1] = 0b0101 << GPIO_AFRH_AFRH6_Pos;    // PB14
  GPIOB->AFR[1] = 0b0101 << GPIO_AFRH_AFRH7_Pos;    // PB15

  SPI2->CR1 |= SPI_CR1_MSTR;    // Master Mode
  SPI2->CR2 |= SPI_CR2_FRXTH;   // 8-bit reception threshold

  // 8-bit data length [0111]
  SPI2->CR2 &= ~SPI_CR2_DS_Msk;
  SPI2->CR2 |= 0b0111 << SPI_CR2_DS_Pos;

  SPI2->CR2 |= SPI_CR2_SSOE;  // SS output enable
  SPI2->CR1 |= SPI_CR1_SPE;   // SPI enable

  while (!(SPI2->SR & SPI_SR_TXE));   // Wait for TX

  SPI2->DR = 'T';                     // Send some byte

  while (!(SPI2->SR & SPI_SR_RXNE));  // Wait for RX (Hangs)

  data = SPI2->DR;                    // Receive byte

  while (1) {

  }
}

结果是线路

while (!(SPI2->SR & SPI_SR_RXNE));
挂起,因为 RXNE 从未设置过。

请注意,我不是在问重复的this问题,因为我已经尝试实现给定的解决方案,即通过设置

SPI_CR2_FRXTH
SPI_CR2_SSOE
位,确保启用正确的时钟,并确保SPI2 在所有其他寄存器设置后启用。

stm32 spi
2个回答
3
投票
  // Alternate function 5 [0101]
  GPIOB->AFR[1] = 0;                                // Reset register
  GPIOB->AFR[1] = 0b0101 << GPIO_AFRH_AFRH4_Pos;    // PB12
  GPIOB->AFR[1] = 0b0101 << GPIO_AFRH_AFRH5_Pos;    // PB13
  GPIOB->AFR[1] = 0b0101 << GPIO_AFRH_AFRH6_Pos;    // PB14
  GPIOB->AFR[1] = 0b0101 << GPIO_AFRH_AFRH7_Pos;    // PB15

这肯定是错误的:每个后续分配都会覆盖所有先前的分配,因此仅设置 PB15 的值。

一般:

  • 您从哪里获得这种编程风格,逐渐将位/位域添加到单个寄存器?一次性计算整个寄存器的值并写入,例如

     GPIOB->AFR[1] = 0
       | (0b0101 << GPIO_AFRH_AFRH4_Pos) // PB12
       | (0b0101 << GPIO_AFRH_AFRH5_Pos) // PB13      
       | (0b0101 << GPIO_AFRH_AFRH6_Pos) // PB14
       | (0b0101 << GPIO_AFRH_AFRH7_Pos) // PB15
    ;
    
  • 每当您遇到问题时,请根据RM中这些寄存器的描述读出并检查相关外设的寄存器(此处:GPIO、SPI)

  • 读取 SPI 和类似外设寄存器时请小心使用调试器,调试具有侵入性并且可能会清除 RXNE 等标志


0
投票

GPIO 配置:

看起来您为

PB12-PB15
配置备用功能的代码行可能会单独覆盖每个引脚的
AFR[1]
寄存器。为了确保所有引脚都正确设置,您应该将这些设置合并到一行中,如下所示:

GPIOB->AFR[1] |= (0b0101 << GPIO_AFRH_AFRH4_Pos) |
                 (0b0101 << GPIO_AFRH_AFRH5_Pos) |
                 (0b0101 << GPIO_AFRH_AFRH6_Pos) |
                 (0b0101 << GPIO_AFRH_AFRH7_Pos);
© www.soinside.com 2019 - 2024. All rights reserved.