STM32 discovery F3 SPI loopback RXFIFO receives no data
我正在使用 STM32 F3 发现套件并开始弄乱 SPI 外围设备。我从一个简单的环回系统开始:我检查 TXFIFOLVL 状态,如果它未满,我将数据发送到 DR 寄存器,然后应该环回我的 RxBuffer(当 RXFIFOLVL 不为空时,我从 DR 读取数据),但我遇到了一个问题——我的接收缓冲区没有得到任何东西,我似乎不明白为什么。我不使用 HAL 或标准外设库,所以我配置 SPI 并通过如下寄存器值使用它:
SPI 代码的头文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #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 代码的代码文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | #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 中,我简单地定义我的缓冲区并像这样初始化它们:
1 2 | 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() 函数:
1 | spi_WriteRead(rx_buff,tx_buff,SIZE); |
SIZE 在我的 main.c 中定义为:
1 | #define SIZE 10 |
我使用 SW4STM32 环境进行编码和调试,所以在我的调试器中我可以看到所有的寄存器值。我的 SPI 就像我定义的那样被初始化,我的数据被发送到 TXFIFO 缓冲区,但没有任何东西进入 RXFIFO 缓冲区。如果我检查 SPI SR 寄存器,我可以看到我的 TXFIFO 已满,但 RXFIFO 标志说它是空的。
有没有人知道我可能做错了什么?我是否严重误解了关于 SPI 的一些简单信息?感谢您的输入!
编辑:
好好看看这里:
1 2 3 4 | #define SPI1_SSI_ENABLE 0b1<<8 ... SPI1->CR1 |= SPI1_PERI_ENABLE; SPI1->CR1 &= ~SPI1_SSI_ENABLE; |
现在您可能知道为什么
1 2 | SPI1->CR1 |= SPI1_PERI_ENABLE; SPI1->CR1 &= ~0b1<<8; |
相当于:
1 2 | SPI1->CR1 |= SPI1_PERI_ENABLE; SPI1->CR1 &= (~0b1)<<8; |
更进一步:
1 2 | SPI1->CR1 |= SPI1_PERI_ENABLE; SPI1->CR1 &= 0xffffff00; |
可能不是你想要的。
您还应该知道,如果您的设备是主设备,那么 SSI 和 SSM 位都应该设置。 https://stackoverflow.com/a/42169600/157344
原件:
请注意,在这些设备中,当您直接访问
1 2 | readByte = (volatile uint8_t*)SPI1->DR; (volatile uint8_t*)SPI1->DR = writeByte; |
顺便说一句 - 为什么不使用 CMSIS 标头提供的#defines?您不必定义诸如
之类的东西