2016-10-05 06:35 PM
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
2016-10-07 02:15 AM
Do you use a debugger to display the registers in the loop?
JW