2022-06-15 12:31 AM
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;
}
2022-06-18 12:07 AM
I'm still waiting for a useful help to get ride of this problem.
2022-06-18 01:10 AM
Code looks good.
What's on the wires, observed using oscilloscope?
JW
2022-06-18 04:58 AM
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.
2022-06-18 04:59 AM
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;