AnsweredAssumed Answered

STM32F091 SPI1, RXNE never asserted

Question asked by twc_st on Oct 6, 2016
Latest reply on Oct 7, 2016 by waclawek.jan
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.).

001.#include "stm32f0xx.h"                                                             
002.                                                                                     
003./* set up to run at 48MHz with HSE 16MHz crystal */                                
004.void                                                                               
005.SystemInit(void)                                                                   
006.{                                                                                  
007.        /* start HSE, wait until ready */                                          
008.        RCC->CR |= RCC_CR_HSEON;                                                   
009.        while (!(RCC->CR & RCC_CR_HSERDY))                                         
010.                ;                                                                  
011.                                                                                     
012.        /* set up PLL */                                                           
013.        RCC->CR &= ~RCC_CR_PLLON;       // disable PLL                             
014.        while (RCC->CR & RCC_CR_PLLRDY) // wait until it has disabled              
015.                ;                                                                  
016.                                                                                     
017.        RCC->CFGR2 = RCC_CFGR2_PREDIV_DIV1;                                        
018.        RCC->CFGR |= RCC_CFGR_PLLMUL3 | RCC_CFGR_PLLSRC_HSE_PREDIV;                
019.                                                                                     
020.        RCC->CR |= RCC_CR_PLLON;           // enable PLL                           
021.        while (!(RCC->CR & RCC_CR_PLLRDY)) // wait until it has locked             
022.                ;                                                                  
023.                                                                                     
024.        /* set up flash latency */                                                 
025.        FLASH->ACR |= 1; // one wait state, we're over 24MHz                       
026.        // FLASH->ACR |= FLASH_ACR_PRFTBE; // enable prefetch buffer               
027.                                                                                     
028.        /* switch to PLL main clock and wait until it's switched over */           
029.        RCC->CFGR |= RCC_CFGR_SW_PLL;                                              
030.        while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL)                     
031.                ;                                                                  
032.}                                                                                  
033.                                                                                     
034.int                                                                                
035.main(void)                                                                         
036.{                                                                                  
037.        volatile uint32_t tmpreg;                                                  
038.                                                                                     
039.        /* delay to allow us to have a hope of stopping it in debugger after       
040.         * reset                                                                   
041.         */                                                                        
042.        for (uint32_t i = 0; i < 10000000; i++)                                    
043.                __NOP();                                                           
044.                                                                                     
045.        /* start GPIOA and GPIOB clocks (SPI1 on PA4-7, LED on PB2) */             
046.        RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN;                    
047.        tmpreg = RCC->AHBENR;                                                      
048.                                                                                     
049.        /* start SPI1 clock */                                                     
050.        RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;                                        
051.        tmpreg = RCC->APB2ENR;                                                     
052.                                                                                     
053.        (void)tmpreg;                                                              
054.                                                                                     
055.        /* configure GPIO for LED */                                               
056.        GPIOB->MODER |= GPIO_MODER_MODER2_0; // PB2 = output                       
057.                                                                                     
058.        /* configure GPIO for SPI1 on PA4-7 */                                     
059.        GPIOA->MODER |= GPIO_MODER_MODER7_1 | // PA7 = alt function mode           
060.                        GPIO_MODER_MODER6_1 | // PA6 = alt function mode           
061.                        GPIO_MODER_MODER5_1 | // PA5 = alt function mode           
062.                        GPIO_MODER_MODER4_1;  // PA4 = alt function mode           
063.                                                                                     
064.        GPIOA->OSPEEDR |=                                                          
065.          GPIO_OSPEEDR_OSPEEDR7_1 | GPIO_OSPEEDR_OSPEEDR7_0 | // PA7 highspeed  
066.          GPIO_OSPEEDR_OSPEEDR6_1 | GPIO_OSPEEDR_OSPEEDR6_0 | // PA6 highspeed  
067.          GPIO_OSPEEDR_OSPEEDR5_1 | GPIO_OSPEEDR_OSPEEDR5_0 | // PA5 highspeed  
068.          GPIO_OSPEEDR_OSPEEDR4_1 | GPIO_OSPEEDR_OSPEEDR4_0;  // PA4 highspeed  
069.                                                                                     
070.        GPIOA->AFR[0] = 0; // will already be zero; use AF0 for PA4-7 for SPI      
071.                                                                                     
072.        /* configure SPI1 */                                                       
073.        SPI1->CR1 |= SPI_CR1_BR_2 | // SPI clock divide by 32, or 1.5MHz           
074.                     SPI_CR1_MSTR | // use SPI as master                           
075.                     SPI_CR1_CPOL | // CPOL=1                                      
076.                     SPI_CR1_CPHA;  // CPHA=1                                      
077.                                                                                     
078.        /* should already have DS[3:0] set up for 8-bit */                         
079.        SPI1->CR2 |= SPI_CR2_FRXTH | // assert RXNE after 8 bits                   
080.                     SPI_CR2_DS_2 | SPI_CR2_DS_1 | SPI_CR2_DS_0 | // 8-bit         
081.                     SPI_CR2_SSOE; // automatically control slave select line      
082.                                                                                     
083.        /* enable SPI1 */                                                          
084.        SPI1->CR1 |= SPI_CR1_SPE;                                                  
085.                                                                                     
086.        /* turn on LED */                                                          
087.        GPIOB->BSRR = GPIO_BSRR_BS_2;                                              
088.                                                                                     
089.        /* ...transfer some data... */                                             
090.                                                                                     
091.        unsigned char tx_buf[8] = {                                                
092.          0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55};                         
093.        unsigned char rx_buf[8];                                                   
094.        unsigned char tmpbyte;                                                     
095.                                                                                     
096.        /* clear receive fifo, just in case */                                     
097.        while (SPI1->SR & SPI_SR_RXNE)                                             
098.                tmpbyte = *(volatile uint8_t *)&SPI1->DR;                          
099.        (void)tmpbyte;                                                             
100.                                                                                     
101.        int n        = sizeof(tx_buf);                                             
102.        int tx_count = 0;                                                          
103.        int rx_count = 0;                                                          
104.        while (tx_count < n || rx_count < n) {                                     
105.                if (SPI1->SR & SPI_SR_TXE)                                         
106.                        *(volatile uint8_t *)&SPI1->DR = tx_buf[tx_count++];       
107.                                                                                     
108.                if (SPI1->SR & SPI_SR_RXNE)                                        
109.                        rx_buf[rx_count++] = *(volatile uint8_t *)&SPI1->DR;       
110.        }                                                                          
111.        (void)rx_buf;                                                              
112.                                                                                     
113.        /* should get here and flash LED mindlessly */                             
114.        for (;;) {                                                                 
115.                GPIOB->BRR = GPIO_BRR_BR_2;                                        
116.                for (uint32_t i = 0; i < 500000; i++)                              
117.                        __NOP();                                                   
118.                                                                                     
119.                GPIOB->BSRR = GPIO_BSRR_BS_2;                                      
120.                for (uint32_t i = 0; i < 500000; i++)                              
121.                        __NOP();                                                   
122.        }                                                                          
123.                                                                                     
124.        return 0;                                                                  
125.}

Outcomes