cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F417 and LIS3DH SPI1 problem

slal
Associate III
Posted on February 13, 2014 at 22:59

Hi forum!

Here is a very strange problem I'm facing with the SPI1 peripheral of the STM32F417 connected to the LIS3DH. I have to single-step through my code with my debugger in order to get the right data from the LIS3DH, otherwise I end up getting just 0xFF.

Here is my setup:

- PA4 set to OUT and Pull_UP used as CS♯ for LIS3DH, toggled by me through software.

- PA5/6/7 set to AF and PP.

- All pins at 50MHz, portA clock is enabled, SPI1 clock is enabled.

How I read a byte from the STM LIS3DH:

ACCEL_SELECT();

SPI1->DR = (uint8_t)(0x80 | reg); // set bit 7 to read

while( !(SPI1->SR & SPI_I2S_FLAG_TXE) );

SPI1->DR = 0x00; // dummy byte

while( !(SPI1->SR & SPI_I2S_FLAG_TXE) );

while( SPI1->SR & SPI_I2S_FLAG_BSY );

*data = (uint8_t)(SPI1->DR & 0xFF);

ACCEL_DESELECT();

Open to suggestions! Thanks!

#lis3dh #stm32f417
5 REPLIES 5
slal
Associate III
Posted on February 13, 2014 at 23:04

And here's the init code just in case:

/* Accelerometer over SPI */

RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA, ENABLE );

RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE );

SPI_I2S_DeInit(SPI1);

// GPIO setup

// CS#

gpio.GPIO_Pin = GPIO_Pin_4;

gpio.GPIO_Mode = GPIO_Mode_OUT;

gpio.GPIO_Speed = GPIO_Speed_50MHz;

gpio.GPIO_OType = GPIO_OType_PP;

gpio.GPIO_PuPd = GPIO_PuPd_UP;

GPIO_Init( GPIOA, &gpio );

ACCEL_DESELECT();

// Others

GPIO_PinAFConfig( GPIOA, GPIO_PinSource5, GPIO_AF_SPI1 ); // SPI1_SCK

GPIO_PinAFConfig( GPIOA, GPIO_PinSource6, GPIO_AF_SPI1 ); // SPI1_MISO

GPIO_PinAFConfig( GPIOA, GPIO_PinSource7, GPIO_AF_SPI1 ); // SPI1_MOSI

gpio.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;

gpio.GPIO_Mode = GPIO_Mode_AF;

gpio.GPIO_Speed = GPIO_Speed_50MHz;

gpio.GPIO_OType = GPIO_OType_PP;

gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;

GPIO_Init( GPIOA, &gpio );

// Configure SPI

SPI_InitTypeDef spi;

spi.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

spi.SPI_Mode = SPI_Mode_Master;

spi.SPI_DataSize = SPI_DataSize_8b;

spi.SPI_CPOL = SPI_CPOL_Low;

spi.SPI_CPHA = SPI_CPHA_1Edge;

spi.SPI_NSS = SPI_NSS_Soft;

spi.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;

spi.SPI_FirstBit = SPI_FirstBit_MSB;

SPI_Init(SPI1, &spi);

SPI_Cmd(SPI1, ENABLE);

francescatodiego
Associate II
Posted on February 14, 2014 at 00:42

try changing

this

while( SPI1->SR & SPI_I2S_FLAG_BSY );

with

while(!( SPI1->SR & SPI_I2S_FLAG_RXNE ));

and also check  the CS line

behavior

If

the switching of the

CS

line

is ''slow

'' add multiple call to CS selection

ACCEL_SELECT();

ACCEL_SELECT();

ACCEL_SELECT();

so

the start of communication

is

delayed

and CS is active when SPI start

slal
Associate III
Posted on February 14, 2014 at 03:16

Thanks for your suggestions Diego. I've already tried both those approaches - they both don't help. I believe the BSY happens after RXNE anyways, right?

Also, if CS was slow, my writing would fail. But I don't have any issues while writing. It's only the reading that doesn't work - only works when I single step in the debugger.
francescatodiego
Associate II
Posted on February 14, 2014 at 07:55

uint8_t dummy ;

ACCEL_SELECT();

SPI1->DR = (uint8_t)(0x80 | reg); // set bit 7 to read

while( !(SPI1->SR & SPI_I2S_FLAG_TXE) );

while( !(SPI1->SR & SPI_I2S_FLAG_RXNE) );

dummy = (uint8_t)(SPI1->DR & 0xFF); // Dummy read clr RXNE flag  

SPI1->DR = 0x00; // dummy byte

while( !(SPI1->SR & SPI_I2S_FLAG_TXE));

while( !(SPI1->SR & SPI_I2S_FLAG_RXNE) );

*data = (uint8_t)(SPI1->DR & 0xFF);

ACCEL_DESELECT();

You must read the SPI RX register after each TX

The ST manual Note pag. 872

Note: Do not use the BSY flag to handle each data transmission or reception. It is better to use the TXE and RXNE flags instead.

slal
Associate III
Posted on February 14, 2014 at 15:54

Thanks Diego, that helped! I had also tried it before, but thanks to your post I recognized a silly coding mistake on my part - my compiler was optimizing out the 'dummy' byte. This time I coded it again with 'volatile uint8_t dummy' instead, and it worked. Thanks, this is resolved.