cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F091 SPI1, RXNE never asserted

stefanzimmer9178
Associate
Posted on October 06, 2016 at 03:35

Hello, I'm trying to use an STM32F091xC's SPI1 peripheral in master mode (8-bit), but am having issues with the reception of data. While I can fill the transmit FIFO via SPI1->DR readily (the TXE bit gets asserted), RXNE is never asserted.

When I change the code (and GPIO) to use SPI2, everything works perfectly. I'm pretty sure I've got all the right clocks, and my configuration of 16MHz HSE crystal feeding the PLL for 48MHz seems correct, as USART1 is operating perfectly. I think I missed the usual pitfall with 8-bit data access, by setting FRXTH in CR2. I've pared down my code to the following, using just CMSIS. I've stripped out the libraries I was using to avoid bugs and have followed the datasheet with direct register access. In the code below, tx_count is successfully incremented as each data byte goes in, but rx_count never increases as the RXNE bit is never set in SPI1->SR (line 108). I really hope this is something dumb and embarrassing. I do have a few extra boards I can assemble, but I can't see it being a problem with the chip, as it otherwise operates perfectly (SPI2, UART1, DMA etc.).


#include ''stm32f0xx.h'' 


/* set up to run at 48MHz with HSE 16MHz crystal */

void

SystemInit(
void
) 

{ 

/* start HSE, wait until ready */

RCC->CR |= RCC_CR_HSEON; 

while
(!(RCC->CR & RCC_CR_HSERDY)) 

; 


/* set up PLL */

RCC->CR &= ~RCC_CR_PLLON; 
// disable PLL 

while
(RCC->CR & RCC_CR_PLLRDY) 
// wait until it has disabled 

; 


RCC->CFGR2 = RCC_CFGR2_PREDIV_DIV1; 

RCC->CFGR |= RCC_CFGR_PLLMUL3 | RCC_CFGR_PLLSRC_HSE_PREDIV; 


RCC->CR |= RCC_CR_PLLON; 
// enable PLL 

while
(!(RCC->CR & RCC_CR_PLLRDY)) 
// wait until it has locked 

; 


/* set up flash latency */

FLASH->ACR |= 1; 
// one wait state, we're over 24MHz 

// FLASH->ACR |= FLASH_ACR_PRFTBE; // enable prefetch buffer 


/* switch to PLL main clock and wait until it's switched over */

RCC->CFGR |= RCC_CFGR_SW_PLL; 

while
((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) 

; 

} 


int

main(
void
) 

{ 

volatile
uint32_t tmpreg; 


/* delay to allow us to have a hope of stopping it in debugger after 

* reset 

*/

for
(uint32_t i = 0; i < 10000000; i++) 

__NOP(); 


/* start GPIOA and GPIOB clocks (SPI1 on PA4-7, LED on PB2) */

RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; 

tmpreg = RCC->AHBENR; 


/* start SPI1 clock */

RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; 

tmpreg = RCC->APB2ENR; 


(
void
)tmpreg; 


/* configure GPIO for LED */

GPIOB->MODER |= GPIO_MODER_MODER2_0; 
// PB2 = output 


/* configure GPIO for SPI1 on PA4-7 */

GPIOA->MODER |= GPIO_MODER_MODER7_1 | 
// PA7 = alt function mode 

GPIO_MODER_MODER6_1 | 
// PA6 = alt function mode 

GPIO_MODER_MODER5_1 | 
// PA5 = alt function mode 

GPIO_MODER_MODER4_1; 
// PA4 = alt function mode 


GPIOA->OSPEEDR |= 

GPIO_OSPEEDR_OSPEEDR7_1 | GPIO_OSPEEDR_OSPEEDR7_0 | 
// PA7 highspeed 

GPIO_OSPEEDR_OSPEEDR6_1 | GPIO_OSPEEDR_OSPEEDR6_0 | 
// PA6 highspeed 

GPIO_OSPEEDR_OSPEEDR5_1 | GPIO_OSPEEDR_OSPEEDR5_0 | 
// PA5 highspeed 

GPIO_OSPEEDR_OSPEEDR4_1 | GPIO_OSPEEDR_OSPEEDR4_0; 
// PA4 highspeed 


GPIOA->AFR[0] = 0; 
// will already be zero; use AF0 for PA4-7 for SPI 


/* configure SPI1 */

SPI1->CR1 |= SPI_CR1_BR_2 | 
// SPI clock divide by 32, or 1.5MHz 

SPI_CR1_MSTR | 
// use SPI as master 

SPI_CR1_CPOL | 
// CPOL=1 

SPI_CR1_CPHA; 
// CPHA=1 


/* should already have DS[3:0] set up for 8-bit */

SPI1->CR2 |= SPI_CR2_FRXTH | 
// assert RXNE after 8 bits 

SPI_CR2_DS_2 | SPI_CR2_DS_1 | SPI_CR2_DS_0 | 
// 8-bit 

SPI_CR2_SSOE; 
// automatically control slave select line 


/* enable SPI1 */

SPI1->CR1 |= SPI_CR1_SPE; 


/* turn on LED */

GPIOB->BSRR = GPIO_BSRR_BS_2; 


/* ...transfer some data... */


unsigned 
char
tx_buf[8] = { 

0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55}; 

unsigned 
char
rx_buf[8]; 

unsigned 
char
tmpbyte; 


/* clear receive fifo, just in case */

while
(SPI1->SR & SPI_SR_RXNE) 

tmpbyte = *(
volatile
uint8_t *)&SPI1->DR; 

(
void
)tmpbyte; 


int
n = 
sizeof
(tx_buf); 

int
tx_count = 0; 

int
rx_count = 0; 

while
(tx_count < n || rx_count < n) { 

if
(SPI1->SR & SPI_SR_TXE) 

*(
volatile
uint8_t *)&SPI1->DR = tx_buf[tx_count++]; 


if
(SPI1->SR & SPI_SR_RXNE) 

rx_buf[rx_count++] = *(
volatile
uint8_t *)&SPI1->DR; 

} 

(
void
)rx_buf; 


/* should get here and flash LED mindlessly */

for
(;;) { 

GPIOB->BRR = GPIO_BRR_BR_2; 

for
(uint32_t i = 0; i < 500000; i++) 

__NOP(); 


GPIOB->BSRR = GPIO_BSRR_BS_2; 

for
(uint32_t i = 0; i < 500000; i++) 

__NOP(); 

} 


return
0; 

}

#stm32f0-stm32f091-spi1-spi-rxne
1 REPLY 1
Posted on October 07, 2016 at 11:15

Do you use a debugger to display the registers in the loop?

JW