Home > Mobile >  SPI Communication between STM32 and ADXL345
SPI Communication between STM32 and ADXL345

Time:10-26

I am trying to use the SPI communication to read data from the ADXL345 accelerometer. I configured the different pins and SPI in master mode, and tried reading the x, y and z axis accelerations.

My issue is that the SPI readings are always 0. I tried debugging to find the issue and I realized that RXNE is never set even though I'm transmitting data and I don't really get why.

I'm using STM32F103 Board.

Here's my code:

#include "Driver_GPIO.h"

#include "stm32f10x.h"

uint8_t RxData[6];
int x,y,z;
float   x_acc,y_acc,z_acc;

void GPIO_Config (void)
{

    
    MyGPIO_Struct_TypeDef NSS={GPIOA,4,Out_OD}; // Output Open Drain
    MyGPIO_Struct_TypeDef SCK={GPIOA,5,AltOut_Ppull}; // Alternate Output Push-Pull
    MyGPIO_Struct_TypeDef MISO={GPIOA,6,In_Floating}; // Input Floating
    MyGPIO_Struct_TypeDef MOSI={GPIOA,7,AltOut_Ppull}; // Alternate Output Push-Pull

    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //enable GPIOA clk
    
    MyGPIO_Init(&NSS);
    MyGPIO_Init(&SCK);
    MyGPIO_Init(&MISO);
    MyGPIO_Init(&MOSI);
}
    

void SPI_Enable (void)
{
    SPI1->CR1 |= (SPI_CR1_SPE);   // SPE=1, Peripheral enabled
}

void SPI_Disable (void)
{
    SPI1->CR1 &= ~(SPI_CR1_SPE);   // SPE=0, Peripheral Disabled
}

void CS_Enable (void)
{
    GPIOA->BSRR |= GPIO_BSRR_BR9;
}

void CS_Disable (void)
{
    GPIOA->BSRR |= GPIO_BSRR_BS9;
}

void SPI_Config(void){
  RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;  // Enable SPI1 CLock
    
  SPI1->CR1 |= SPI_CR1_CPOL| SPI_CR1_CPHA;   // CPOL=1, CPHA=1
    
  SPI1->CR1 |= SPI_CR1_MSTR;  // Master Mode
    
  SPI1->CR1 |= (SPI_CR1_BR_0)| (SPI_CR1_BR_1);  // BR[2:0] = 400: fPCLK/16, PCLK2 = 72MHz, SPI clk = 3.375MHz
    
  SPI1->CR1 &= ~SPI_CR1_LSBFIRST;  // LSBFIRST = 0, MSB first
    
  SPI1->CR1 |= (SPI_CR1_SSM) | (SPI_CR1_SSI);  // SSM=1, SSI=1 -> Software Slave Management
    
  SPI1->CR1 &= ~SPI_CR1_RXONLY;  // RXONLY = 0, full-duplex
    
  SPI1->CR1 &= ~SPI_CR1_DFF;  // DFF=0, 8 bit data
    
  SPI1->CR2 = 0;

}

void SPI_Transmission(uint8_t *data, int size){
    uint8_t clear;
    //check flag TxE //
    int i=0;
    while (i<size)
    {
        while (!((SPI1->SR)&(SPI_SR_TXE))){};  // buffer is empty
        *(volatile uint8_t *)&SPI1->DR = data[i];
        i  ;
    }
    
    while (!((SPI1->SR)&(SPI_SR_TXE))){};  // buffer is empty

    while (((SPI1->SR)&(SPI_SR_BSY))){}; // buffer not communicating

    
    clear= SPI1->DR; // empty Overrun flag
    clear= SPI1->SR;
}

void SPI_Receive (uint8_t *data,int size)
{
    while (size)
    {
        while (((SPI1->SR)&(SPI_SR_BSY))) {};  // buffer not communicating
        *(volatile uint8_t *)&SPI1->DR = 0;  // dummy data
        while (!((SPI1->SR) &(SPI_SR_RXNE))){};
        // buffer is not empty
        *data  = *(volatile uint8_t *)&SPI1->DR;
        size--;
    }
}

void adxl345_write (uint8_t address, uint8_t value)
{
    uint8_t data[2];
    data[0] = address|0x40;  // multibyte write
    data[1] = value;
    CS_Enable ();  // pull the cs pin low
    SPI_Transmission (data,2);  // write data to register
    CS_Disable ();  // pull the cs pin high
}
    

void adxl345_read (uint8_t address, uint8_t *RxData)
{
    address |= 0x80;  // read operation
    address |= 0x40;  // multibyte read
    CS_Enable ();  // pull the pin low
    SPI_Transmission (&address,1);  // send address
    SPI_Receive (RxData,6);  // receive 6 bytes data
    CS_Disable ();;  // pull the pin high
}

void adxl345_init (void)
{
    adxl345_write (0x31, 0x01);  // data_format range=  - 4g
    adxl345_write (0x2d, 0x00);  // reset all bits
    adxl345_write (0x2d, 0x08);  // power_cntl measure and wake up 8hz
}
int main(void)
    
{ 
    GPIO_Config();
    SPI_Config();
    SPI_Enable();
    adxl345_init();

    do{
        adxl345_read(0x32,RxData);
        x = ((RxData[1]<<8)|RxData[0]); // DATA X0, X1
        y = ((RxData[3]<<8)|RxData[2]); // DATA Y0, Y1
        z = ((RxData[5]<<8)|RxData[4]); // DATA Z0, Z1
        
        // Scale Factor for Xout, Yout and Zout is 7.8 mg/LSB for a  -4g, 10-bit resolution
        // ==> multiply by 0.0078 to get real acceleration values
        
        x_acc= x * 0.0078; 
        y_acc= y * 0.0078;
        z_acc= z * 0.0078;
        
    }while(1);
    

}

CodePudding user response:

I will not analyze magic numbers as I do not have time check every number in the RM. But you have many obvious issues.

  1. Deley or readback is required after enabling the peripheral clock. You instantly set the registers which is wrong. Add __DSB(); or readback (for example (void)RCC->APB2ENR;). Same for all peripherals

CodePudding user response:

As already stated you have a lot of issues here

  1. Why NSS pin is configured open-drain? Typically CS lines are push-pull. I don't know the schematics, but this is the first time I see an open-drain CS
  2. In GPIO_Config NSS is pin 4, yet pin 9 is toggled from CS_Enable
  3. If F1 series there is separate clocking bit for the alternate functions, it's not enabled

It is also weird that you are telling that RXNE is always zero and the readings returns zero. Your code should stuck in while loops if RXNE stays zero

  • Related