STM32发现F3 SPI环回RXFIFO收不到数据

Posted

技术标签:

【中文标题】STM32发现F3 SPI环回RXFIFO收不到数据【英文标题】:STM32 discovery F3 SPI loopback RXFIFO receives no data 【发布时间】:2017-07-03 00:30:04 【问题描述】:

我正在使用 STM32 F3 discovery 套件并开始使用 SPI 外围设备。我从一个简单的环回系统开始:我检查 TXFIFOLVL 状态,如果未满,我将数据发送到 DR 寄存器,然后它应该循环回我的RxBuffer(我从 DR 读取数据,而 RXFIFOLVL 不为空),但我遇到了问题 - 我没有得到任何回复在我的接收缓冲区上,我似乎不明白为什么。我不使用 HAL标准外设库,所以我配置 SPI 并通过如下寄存器值使用它:

SPI 代码的头文件:

#define GPIOA_ENABLE                    0b1<<17             // Enable GPIO port A clock in AHBENR register
#define SPI1_CLOCK_ENABLE               0b1<<12             // Enable SPI1 clock in APB2ENR register
#define SPI1_PIN_ALT_FNC                0b1010<<4           // Sets PA5,PA6 & PA7 to Alternative function
#define SPI1_OUTPUT_TYPE                ~(0b111<<5)         // Sets PA5, PA6 & PA7 to push-pull
#define SPI1_PIN_SPEED                  0b1111<<4           // Sets pins from 4 to 7 to work on 50 MHz output speed
#define SPI1_PIN_ALT_FNC_LOW            0b0101<<4           // Sets the Alternative function to AF5 in alternative function low register
#define SPI1_PIN_ALT_FNC_HIGH           0b0101<<4           // Sets the Alternative function to AF5 in alternative function high register
#define SPI1_BAUDRATE_PRESCALER_2       0b000<<3            // F_PCLK/2
#define SPI1_BAUDRATE_PRESCALER_128     0b110<<3            // F_PCLK/128
#define SPI1_MASTER_MODE                0b1<<2              // Sets the SPI1 to master mode
#define SPI1_PERI_ENABLE                0b1<<6              // Enable the SPI peripheral
#define SPI1_SSM_ENABLE                 0b1<<9              // Enable SPI software slave management
#define SPI1_SSI_ENABLE                 0b1<<8              // SPI1 internal slave select
#define SPI1_NSSP_ENABLE                0b1<<3              // Enable NSS pulse management
#define SPI1_FRXTH_8BIT                 0b1<<12             //Set the FIFO reception threshold to 8 bits
#define SPI1_DATA_SIZE                  0b0111<<8           // SPI1 DATA size
#define SPI1_TXFIFO_FULL_FLAG           0b11<<11            // SPI1 Tx FIFO transmission flag
#define SPI1_RXFIFO_EMPTY_FLAG          0b00<<9             // SPI1 Rx FIFO reception flag

#include "main.h"
#include "stm32f3xx_hal.h"

void spi_init();
void spi_WriteRead(uint8_t *rxBuffer, uint8_t *txBuffer, uint8_t bufferSize);

SPI 代码的代码文件:

#include "SPI_toSD.h"

/* SPI1 configuration
 * PA5 - SCK
 * PA6 - MISO
 * PA7 - MOSI
 */
void spi_init()

// Start the GPIO and peripheral clocks in Reset and Clock Control register
RCC->AHBENR |= GPIOA_ENABLE;
RCC->APB2ENR |= SPI1_CLOCK_ENABLE;

// Configure the GPios for SPI communication
GPIOA->MODER |= SPI1_PIN_ALT_FNC;
GPIOA->OTYPER &= SPI1_OUTPUT_TYPE;
GPIOA->OSPEEDR |= SPI1_PIN_SPEED;
GPIOA->AFR[0] |= SPI1_PIN_ALT_FNC_LOW;
GPIOA->AFR[1] |= SPI1_PIN_ALT_FNC_HIGH;

// Configure the SPI peripheral
SPI1->CR1 |= SPI1_BAUDRATE_PRESCALER_2;
SPI1->CR1 |= SPI1_SSM_ENABLE;
SPI1->CR1 |= SPI1_MASTER_MODE;
SPI1->CR1 |= SPI1_SSI_ENABLE;
SPI1->CR2 |= SPI1_DATA_SIZE;
SPI1->CR2 |= SPI1_FRXTH_8BIT;
SPI1->CR2 |= SPI1_NSSP_ENABLE;
SPI1->CR1 |= SPI1_PERI_ENABLE;
SPI1->CR1 &= ~SPI1_SSI_ENABLE;



void spi_WriteRead(uint8_t *rxBuffer, uint8_t *txBuffer, uint8_t bufferSize)
int i;
while((SPI1->SR & 0b11<<11)==SPI1_TXFIFO_FULL_FLAG);
for(i=0;i<bufferSize;i++)
        SPI1->DR |= *txBuffer;  // send *txBuffer++
        txBuffer++;


    while((SPI1->SR & 0b11<<9)!=SPI1_RXFIFO_EMPTY_FLAG)
        *rxBuffer = SPI1->DR;
        rxBuffer++;
    



在 main 中,我只是简单地定义我的缓冲区并像这样初始化它们:

uint8_t rx_buff[SIZE] = 0,0,0,0,0,0,0,0,0,0;
uint8_t tx_buff[SIZE] = 1,2,3,4,5,6,7,8,9,10;

因此,在调用我的 spi_WriteRead() 函数之后,我自然希望这些缓冲区具有相同的值。

我调用我的 spi_init() 函数并在我的 while 循环中调用 spi_WriteRead() 函数:

  spi_WriteRead(rx_buff,tx_buff,SIZE);

SIZE 在我的 main.c 中定义为:

#define SIZE  10

我使用 SW4STM32 环境进行编码和调试,因此在我的调试器中我可以看到所有的寄存器值。我的 SPI 已按照我的定义进行初始化,并且我的数据正在发送到 TXFIFO 缓冲区,但 RXFIFO 缓冲区没有任何内容。如果我检查 SPI SR 寄存器,我可以看到我的 TXFIFO 已填满,但 RXFIFO 标志说它是空的。

有没有人知道我做错了什么?我是否严重误解了 SPI 的一些简单内容?感谢您的输入!

【问题讨论】:

您是否使用示波器/逻辑分析仪验证了 SPI 的物理线路? 是的,我刚刚用 PicoScope 检查了它,它似乎发送了乱码,这可以解释 TXFIFO 填充并保持满,而 RXFIFO 保持为空。 如果有什么理由不使用好的库?不过,这里有来自 keil keil.com/dd2/pack 的非常方便的 io 驱动程序。 【参考方案1】:

编辑:

好好看看这里:

#define SPI1_SSI_ENABLE                 0b1<<8
...
SPI1->CR1 |= SPI1_PERI_ENABLE;
SPI1->CR1 &= ~SPI1_SSI_ENABLE;

现在您可能知道为什么 #define 宏通常被认为是一个坏主意。如果您使用来自stm32f3xxx.h 标头的#define 值,则不会有这个问题,因为所有带有操作的值都在那里有括号。你没有它们。这就是为什么您的代码在编译器中看起来像这样:

SPI1->CR1 |= SPI1_PERI_ENABLE;
SPI1->CR1 &= ~0b1<<8;

相当于:

SPI1->CR1 |= SPI1_PERI_ENABLE;
SPI1->CR1 &= (~0b1)<<8;

更进一步:

SPI1->CR1 |= SPI1_PERI_ENABLE;
SPI1->CR1 &= 0xffffff00;

可能不是你想要的。

您还应该知道,如果您的设备是主设备,则应同时设置 SSI 和 SSM 位。 https://***.com/a/42169600/157344

原文:

请注意,在这些设备中,当您直接访问 SPI1-&gt;DR 时,您会一次发送/接收两个字节。那是因为这个寄存器被定义为uint16_t 并且 SPI 支持所谓的“数据打包”(在参考手册中搜索它)。如果您想一次发送/接收一个字节,那么您需要将寄存器转换为写入和读取:

readByte = (volatile uint8_t*)SPI1->DR;
(volatile uint8_t*)SPI1->DR = writeByte;

顺便说一句 - 为什么不使用 CMSIS 标头提供的#defines?你不必定义像SPI1_MASTER_MODE...

【讨论】:

感谢您的提示,我不知道。必须在参考手册中浏览过它。因此,如果我真的不关心数据是作为 WORD 还是作为 BYTE 发送的,我也可以将指针增加 2 而不是 1,对吗?同样在调试器中,我注意到 CR1 中的 SPI 启用字段在 spi_init() 完成后设置为 0,这是正常行为还是应该调查它? @saukijan - 您可以一次发送 8 位或 16 位数据,但要增加指针,您还必须从缓冲区读取/写入 2 个字节。当前,您读取一个字节并将其作为 16 位 0x00?? 写入 DR 寄存器。一般来说,新的 STM32 设备中的 SPI 可能会很棘手...... @saukijan - 看看编辑后的答案。它现在应该可以解决您的(主要)问题。 谢谢你的详细解释,现在说得通了。我会测试它并稍后报告结果。 是的,括号是问题所在。下次我会知道使用 CMSIS 定义。感谢您的帮助!

以上是关于STM32发现F3 SPI环回RXFIFO收不到数据的主要内容,如果未能解决你的问题,请参考以下文章

stm32的两个spi互相通信,从spi正确接收主spi数据,但主spi收不到从spi数据(MISO一直为低),是何原因?

是否可以在 STM32F3 上使用 DMA 通过 SPI 传输无限数据?

STM32 SPI数据打包

STM32的SPI从机接收数据错误是怎么回事

STM32:简单的 SPI 传输

stm32f3发现usart没有发送