cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with setting up LIS3DH SPI with STM32F0x ??!!

MGolm.2
Associate II

Hi Everyone. I have encountered a problem in using LIS3DH SPI with STM32F0x MCU. I used to configure and set LIS3DH accelerometer with ATXMEGA families without any issues but this time I really can not understand the origin of my fault. I'm using bare-metal codes for SPI and LIS3DH with 8-bits data long. The main problem is, I can not read Who_Am_I register properly that should be 51. Instead I read 255 or 0 all the time. I attached the SPI and LIS3DH libraries that I have made before.

Will be greatly appreciated if anyone can help me to solve this frustrating problem.

////////////// SPI.C /////////////////////////

#include "spi.h"

/**

 * @brief SPI GPIO Pins Config

 */

void spi_GPIO_config(void)

{

 //Enable PORTA Clock

 RCC->AHBENR |= RCC_AHBENR_GPIOAEN;

 //Re-mapping Alternate functions all belong to AF0 as SPI1

 //PA4:CS output , PA5:SCK , PA6:MISO , PA7:MOSI

 GPIOA->MODER &= ~(GPIO_MODER_MODER4 | GPIO_MODER_MODER5 | GPIO_MODER_MODER6 | GPIO_MODER_MODER7); // Reset SPI Pins MODE

 GPIOA->MODER |= ( GPIO_MODER_MODER5_1 | GPIO_MODER_MODER6_1 | GPIO_MODER_MODER7_1); //Setting SPI pins as Alternate functions

 GPIOA->MODER |= GPIO_MODER_MODER4_0; //PA4 as general output

 GPIOA->OTYPER &= ~(GPIO_OTYPER_OT_4 | GPIO_OTYPER_OT_5 | GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_7);//PA4 Push pull output

// GPIOA->PUPDR |= GPIO_PUPDR_PUPDR4_0;//Enable Pull-up resistor in PA4

 GPIOA->AFR[0] &= ~(GPIO_AFRL_AFRL5 |GPIO_AFRL_AFRL6 |GPIO_AFRL_AFRL7); // Alternate function AF0 Select for PA5,6,7

 //Output max medium speed

 GPIOA->OSPEEDR &= ~(GPIO_OSPEEDR_OSPEEDR4 | GPIO_OSPEEDR_OSPEEDR5 |GPIO_OSPEEDR_OSPEEDR6 | GPIO_OSPEEDR_OSPEEDR7); //clear the PA2 Output speed bit fields

 GPIOA->OSPEEDR |= (GPIO_OSPEEDR_OSPEEDR4_1 | GPIO_OSPEEDR_OSPEEDR5_1 |GPIO_OSPEEDR_OSPEEDR6_1 | GPIO_OSPEEDR_OSPEEDR7_1); //Set the PA2 Output speed as medium speed

 GPIOA->BSRR = (GPIO_BSRR_BS_4); //Set PA4 High as default

}

/**

 * @brief SPI Peripheral configuration

 */

void spi_config(void)

{

 //Reset SPI

// RCC->APB2RSTR |= RCC_APB2RSTR_SPI1RST;

// RCC->APB2RSTR &= ~RCC_APB2RSTR_SPI1RST;

 //Enable SPI Clock

 RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;

 //Setting SPI Mode to mode3(CPOL=CPHA=1)

 SPI1->CR1 |= (SPI_CR1_CPHA | SPI_CR1_CPOL);

 //Baud rate selection for SPI = 3MHZ

 SPI1->CR1 &= ~SPI_CR1_BR;

 SPI1->CR1 |= (SPI_CR1_BR_1 | SPI_CR1_BR_0);

 //MSB First

 SPI1->CR1 &= ~SPI_CR1_LSBFIRST;

 //Full Duplex mode

 SPI1->CR1 &= ~SPI_CR1_RXONLY;

 //SPI in Master mode

 SPI1->CR1 |= SPI_CR1_MSTR;

 //Setting Data length to 8bits

 SPI1->CR2 |= (SPI_CR2_DS_0 |SPI_CR2_DS_1 |SPI_CR2_DS_2 );

 //Setting Frame format

 SPI1->CR2 &= ~ SPI_CR2_FRF;

 //software SS enable

 SPI1->CR1 |= (SPI_CR1_SSI | SPI_CR1_SSM) ;

 //SPI Enable

 SPI1->CR1 |= SPI_CR1_SPE;

 // Clear All flags

 __IO uint32_t tempRd= (uint8_t)SPI1->SR;

}

/**

 * @brief SPI Transmit

 */

 bool spi_transmit(uint8_t *pData, uint8_t len, uint32_t timeout)

 {

  //Enable SPI,if not

  SPI1->CR1 |= SPI_CR1_SPE;

  //Timeout initial Ticks

  uint8_t dataIdx=0;

  uint32_t startTick=rcc_msGetTicks();

  //while loop, transferring data, managing timeout

  while(dataIdx<len)

  {

   //TXE flag check

   if(SPI1->SR & SPI_SR_TXE)

   {

    *((__IO uint8_t *)&SPI1->DR) = pData[dataIdx];

//    *(uint8_t *)&SPI1->DR = pData[dataIdx];

//    SPI1->DR = pData[dataIdx];

    dataIdx++;

   }

   else // Timeout

   {

    if((rcc_msGetTicks()-startTick)>=timeout) return false;

   }

  }

//  while(!(SPI1->SR & SPI_SR_TXE));

  //wait for busy flag

  while(SPI1->SR & SPI_SR_BSY)

  {

   if((rcc_msGetTicks()-startTick)>=timeout) return false;

  }

  //Clear overrun -->reading DR and then SR

  __IO uint32_t tempRd= (uint8_t)SPI1->DR ;

  __IO uint32_t tempRd= *(__IO uint8_t *)&SPI1->DR ;

  tempRd= (uint8_t)SPI1->SR;

  return 1;

 }

/**

 * @brief SPI Receive

 */

 bool spi_receive(uint8_t *pData, uint8_t len, uint32_t timeout)

 {

  //Enable SPI,if not

  SPI1->CR1 |= SPI_CR1_SPE;

  //Timeout initial Ticks

  uint8_t dataIdx=0;

  uint32_t startTick=rcc_msGetTicks();

//  bool isTransmit=true;

  bool dummyTx = true;

  //while loop , Transmit , Receive , Timeout

  while(dataIdx<len)

  {

   //Transmit

   if((SPI1->SR & SPI_SR_TXE) && dummyTx)

   {

    *((__IO uint8_t *)&SPI1->DR) = 0xFF; //Sending Dummy data before read

    dummyTx=false;

   }

   //Receive

   if(SPI1->SR & SPI_SR_RXNE)

   {

    pData[dataIdx] = *((__IO uint8_t *)&SPI1->DR);

//    pData[dataIdx] = (uint8_t)SPI1->DR;

    dataIdx++;

    dummyTx=true;

   }

   else // Timeout management

   {

    if((rcc_msGetTicks()-startTick)>=timeout) return false;

   }

  }

  //busy flag

  while(SPI1->SR & SPI_SR_BSY)

  {

   if((rcc_msGetTicks()-startTick)>=timeout) return false;

  }

  //Clear overrun -->reading DR and then SR

  __IO uint32_t tempRd= *(__IO uint8_t *)&SPI1->DR ;

  tempRd= (uint8_t)SPI1->SR;

  return 1;

 }

 /**

 * @brief CS Enable

 */

void spi_cs_enable(void)

{

 GPIOA->BSRR = (GPIO_BSRR_BR_4); // Reset PA4

}

/**

 * @brief CS disable

 */

void spi_cs_disable(void)

{

 GPIOA->BSRR = (GPIO_BSRR_BS_4); //Set PA4

}

////////////////////////// LIS3DH.c ////////////////////////

#include "lis3dh.h"

/**

 * @brief lis3dh Enable Pull-up on SDO pin

 */

void lis3dh_init(void)

{

 lis3dh_write(LIS3DH_CTRL_REG0 , 0x90); //Enable pull-up on sdo pin

 lis3dh_write(LIS3DH_CTRL_REG1 , 0x97);//ODR:1.34K , X,Y and Z Axis Enable

 lis3dh_write(LIS3DH_CTRL_REG4 , 0x88); //Enable Block Data Update , Full-scale range +-2G,high Resolution enable

 lis3dh_write(LIS3DH_CTRL_REG5 , 0x40); //Enable FIFO

 lis3dh_write(LIS3DH_FIFO_CTRL_REG , 0x9F); //FIFO in Stream Mode

}

/**

 * @brief lis3dh Write

 */

void lis3dh_write(uint8_t address , uint8_t Data)

{

 uint8_t val[2]={(address | 0x00) , Data};

 spi_cs_enable();

 spi_transmit(val, 2, 100);

 spi_cs_disable();

}

/**

 * @brief lis3dh Read

 */

uint8_t lis3dh_read(uint8_t address)

{

// address|=0x40;

 address|=0x80;

 spi_cs_enable();

 spi_transmit(&address, 1, 100);

 uint8_t dataRd=0;

 spi_receive(&dataRd, 1, 100);

 spi_cs_disable();

 return dataRd;

}

4 REPLIES 4
MGolm.2
Associate II

I'm still waiting for a useful help to get ride of this problem.

Code looks good.

What's on the wires, observed using oscilloscope?

JW​

MGolm.2
Associate II

Thanks for your response @Community member​ . Yes , I monitored all the lines of SPI and encountered some issues. first , my UART in program was putting some delay in SPI routine and cause the CS line tied to zero long time than normal that i solved that by disabling UART at that period of time and then enable it again. And the second one is related to routine of clearing overrun flag in spi_transmit function. when i follow the routine of clearing overrun flag in transmit function, program hangs at that point and when i comment these line, it gets back to normal operation. I should mention that , the same routine in spi_receive function for clearing overrun flag has not effect on normal operation.

MGolm.2
Associate II

my routine for clearing overrun flag is these following codes:

  //Clear overrun -->reading DR and then SR

  __IO uint32_t tempRd= 0U;

  tempRd= SPI1->DR ;

  tempRd= SPI1->SR;

  (void)tempRd;