October 24, 2024
Chicago 12, Melborne City, USA
C#

How to write data to the control registers of the accelerometer LIS3LV02DQ?


I am writing a driver to measure acceleration using the accelerometer LIS3LV02DQ. I use STM32F411 and CMSIS. I connected a four-channel SPI and set it to a frequency of about 1 MHz. I am able to read the register values from the accelerometer, but nothing happens when writing the values in them. Using an oscilloscope, I can see that the output signals from the STM32 look exactly like in datasheet, but the accelerometer does not respond to them. Also, SPI2->SR on STM32 does not show that some error occurred during transmission over SPI. What could be the mistake?

The source code of my functions:

void setup_LIS_spi() {
    // set GPIO pins
    // set PB10 as input, PB12 (CS) as output, PB15:13 as AF
    GPIOB->MODER |= (GPIO_MODER_MODER12_0 | GPIO_MODER_MODER13_1 
                        | GPIO_MODER_MODER14_1 | GPIO_MODER_MODER15_1);   
    GPIOB->OSPEEDR |= ((0xFF << 24) | (3 << 20)); // high speed for PB15:PB12 & PB10 pins
        // enable AF05 for PB13 (SCK), PB14 (MISO) and PB15 (MOSI)
    GPIOB->AFR[1] |= ((5 << 20) | (5 << 24) | (5 << 28)); 

    // set SPI2 properties
    SPI2->CR1 |= SPI_CR1_MSTR;  // master mode
    SPI2->CR1 |= SPI_CR1_SSM;   // software slave management
    SPI2->CR1 |= SPI_CR1_SSI;   // internal slave select
    SPI2->CR1 |= SPI_CR1_SPE;   // SPI enable
    
    // transmission of 16 bits
    SPI2->CR1 |= SPI_CR1_DFF;

    // APB2 = 50 MHz
    // Baud rate ~ 1 MHz = (50 / 16) MHz
    SPI2->CR1 |= (3 << 3);

    // LIS3LV02DQ
    SPI2->CR1 |= SPI_CR1_CPOL;
    SPI2->CR1 |= SPI_CR1_CPHA;
}

static inline void transfer_spi2_16bit(const uint16_t byte_send, uint16_t *byte_read) {
    while (SPI2->SR & SPI_SR_BSY);  // wait for when spi is not busy
    SPI2->DR = byte_send;
    while(!(SPI2->SR & SPI_SR_RXNE)); // wait for when rx buffer is not empty
    *byte_read = SPI2->DR & 0xFFFF;
}

// dalay = 10 000 == 1 ms
inline void __attribute__((always_inline)) delay(uint32_t delay) {
   while(delay--) __asm("");
}

void LIS3_write_data(uint8_t address, uint8_t data) {
    // the first 8 bits indicate the address of the register to be communicated with
    // the next 8 bits transmit the value to be written to this register
    // The 16th bit must be equal to 0 in order for a register entry to occur.
    uint16_t tx_data = ((address << 8) | data) & 0x7fff;
    uint16_t trash = 0;
    
    CS_OFF;
    transfer_spi2_16bit(tx_data, &trash);
    // the delay is manually adjusted so that CS becomes 1 when all bits are sent
    delay(105);
    CS_ON;
}

uint8_t LIS3_read_data(uint8_t address) {
    address |= READ_FLAG;
    uint16_t rx_data = 0;
    uint16_t tx_data = (address << 8);

    CS_OFF;
    transfer_spi2_16bit(tx_data, &rx_data);
    delay(105);
    CS_ON;

    // the required data is in the lower 8 bits
    return (uint8_t)(rx_data & 0x00FF);
}

If I just read the WHO_AM_I register, then its correct value is returned to me:

int main() {
    setup_LIS_spi();
    while (1) {
         // value after reset
         LIS3_read_data(0x0F); // return 0x3A
         LIS3_read_data(0x20); // return 0x07
    }
}

if I write a value to a register as initialization, and then read the value of the same register, then I return the unchanged value:

int main() {
    setup_LIS_spi();
    LIS3_write_data(0x20, 0x87)
    while (1) {
         LIS3_read_data(0x20); // return 0x07
    }
}

if I call the register write function in an infinite loop, then 0xff is returned to me when reading

int main() {
    setup_LIS_spi();
    while (1) {
         LIS3_write_data(0x20, 0x87)
         delay(10000);
         LIS3_read_data(0x20); // return 0xFF
    }
}



You need to sign in to view this answers

Leave feedback about this

  • Quality
  • Price
  • Service

PROS

+
Add Field

CONS

+
Add Field
Choose Image
Choose Video