Post Go back to editing

ADXL372 sends Garbage Data

Thread Summary

The user is experiencing incorrect data readings from the ADXL372 accelerometer, even after a successful self-test. The issue is resolved by correctly combining the high and low bytes of the acceleration data without erasing the LSBs, and then shifting the entire word 4 bits to the right. The SPI configuration is 8-bit, MSB first, CPOL=0, CPHA=0, and 3.75 Mbit/s.
AI Generated Content
Category: Hardware
Product Number: ADXL372

I can't get the ADXL372 to work. 

Self Test is successful:

uint8_t val;

// SELF TEST
reg_write(0x3F, 0x00);
reg_write(0x41, 0x52);
HAL_Delay(10);
reg_write(0x3F, 0b11);
HAL_Delay(10);
reg_write(0x40, 0b1);
HAL_Delay(1000);
reg_read(0x40, &val);
if (val == 0x6) {
    printf("\r\nADXL372 self-test sucess\r\n");
}



And this is the init and first read out:
HAL_StatusTypeDef ret = HAL_OK;
ret |= reg_write(0x3F, 0x00); // standy mode
ret |= reg_write(0x41, 0x52); // reset
HAL_Delay(10);

ret |= reg_write(0x3D, 0x00); // ODR 400Hz
ret |= reg_write(0x3E, 0b1000); // BW 200Hz, Low Noise
ret |= reg_write(0x3F, 0b1111); // full bandwidth measurment mode, disable HPF and LPF
if (ret != HAL_OK) return ret;

do {
    ret = reg_read(0x04, &val); // check if data is availabe
} while ((val & 0x01) == 0);

// read data
uint8_t buf[6];
ret |= spi_raw_accel_read_reg(0x08, buf, 6);
if (ret != HAL_OK) return ret;

uint16_t x = (((int16_t)((buf[0] << 8) | buf[1])) >> 4)&0x0FFF;
uint16_t y = (((int16_t)((buf[2] << 8) | buf[3])) >> 4)&0x0FFF;
uint16_t z = (((int16_t)((buf[4] << 8) | buf[5])) >> 4)&0x0FFF;

printf("ADXL372 X=%5d Y=%5d Z=%5d\r\n", x, y, z);

After I read out as soon data is available.

Output:

ADXL372 X=    14 Y=     0 Z=  4078
ADXL372 X=     9 Y=  4095 Z=  4079
ADXL372 X=    13 Y=  4093 Z=  4078
ADXL372 X=     6 Y=     1 Z=  4075
ADXL372 X=     9 Y=     2 Z=  4076
ADXL372 X=    11 Y=  4095 Z=  4079
ADXL372 X=    16 Y=     3 Z=  4078
ADXL372 X=    11 Y=     0 Z=  4076
ADXL372 X=    13 Y=  4093 Z=  4083



Whats wrong? I've tested two devices and the FIFO, and different Modes, same behavior.

  • Forgot so say:
    When I tilt or move the device, it doesn't affect the data in any way.

    SPI: 8Bits, MSB First, CPOL=0 CPHA=0, 3.75Mbit/s

  • Grüezi! Thanks for reaching out.

    I believe you're seeing this error as a result of the bit-shifting you do to the low bytes of the acceleration channels. As you shift the bits and then mask each channel with 0xFFF, you're effectively erasing the four LSBs of acceleration data from the program. You should shift the high bytes left 8 bits, and then add the low bytes. In a separate line, you then shift the entire word 4 bits to the right. Could you try the bottom configuration and see if you get a good result?

    uint16_t x = (((int16_t)((buf[0] << 8) | buf[1])));
    uint16_t y = (((int16_t)((buf[2] << 8) | buf[3])));
    uint16_t z = (((int16_t)((buf[4] << 8) | buf[5])));

    x = x >> 4;
    y = y >> 4;
    z = z >> 4;

    printf("ADXL372 X=%5d Y=%5d Z=%5d\r\n", x, y, z);

    I tried a similar setup on my end and the issue was resolved when I changed the order to the one described above. Let me know how it works for you.

    Thanks,

    Nico

  • Thanks for the reply. 


    I've changed it but still no reasonable data. 

    HAL_StatusTypeDef adxl372_simple_init(void)
    {
        uint8_t val;
    
        // SELF TEST
        reg_write(0x3F, 0x00);
        reg_write(0x41, 0x52);
        HAL_Delay(10);
        reg_write(0x3F, 0b11);
        HAL_Delay(10);
        reg_write(0x40, 0b1);
        HAL_Delay(1000);
        reg_read(0x40, &val);
        if (val == 6) {
            printf("ADXL372 self-test sucess\r\n");
        }
    
        HAL_StatusTypeDef ret = HAL_OK;
        ret |= reg_write(0x3F, 0x00); // standy mode
        ret |= reg_write(0x41, 0x52); // reset
        ret |= reg_write(0x3F, 0x00); // standy mode
    
        HAL_Delay(10);
    
        ret |= reg_write(0x3D, 0x00); // ODR 400Hz
        ret |= reg_write(0x3E, 0b1000); // BW 200Hz, Low Noise
        ret |= reg_write(0x3F, 0b1111); // full bandwidth measurment mode, disable HPF and LPF
        if (ret != HAL_OK) return ret;
    
        do {
            ret = reg_read(0x04, &val); // check if data is availabe
        } while ((val & 0x01) == 0);
    
        // read data
        uint8_t buf[6];
        ret |= spi_accel_read_reg(0x08, buf, 6);
        if (ret != HAL_OK) return ret;
    
        uint16_t x = ((int16_t)((buf[0] << 8) | buf[1]));
        uint16_t y = ((int16_t)((buf[2] << 8) | buf[3]));
        uint16_t z = ((int16_t)((buf[4] << 8) | buf[5]));
    
        x = x >> 4;
        y = y >> 4;
        z = z >> 4;
      
        printf("ADXL372 X=%5d Y=%5d Z=%5d\r\n", x, y, z);
    
        return HAL_OK;
    }
    
    HAL_StatusTypeDef adxl372_simple_read(adxl372_sample_t *sample)
    {
        uint8_t val;
        reg_read(0x04, &val);
        if ((val & 0x01) == 0) return HAL_ERROR;
    
        uint8_t buf[6];
        HAL_StatusTypeDef ret = spi_accel_read_reg(0x08, buf, 6);
        if (ret != HAL_OK) return ret;
    
        uint16_t x = ((int16_t)((buf[0] << 8) | buf[1]));
        uint16_t y = ((int16_t)((buf[2] << 8) | buf[3]));
        uint16_t z = ((int16_t)((buf[4] << 8) | buf[5]));
    
        sample->x = x >> 4;
        sample->y = y >> 4;
        sample->z = z >> 4;
    
        return HAL_OK;
    }

    Output:

    ADXL372 X=     1 Y=  4094 Z=  4085
    ADXL372 X=     3 Y=  4095 Z=  4087
    ADXL372 X=     3 Y=     1 Z=  4087
    ADXL372 X=  4095 Y=  4093 Z=  4084
    ADXL372 X=     1 Y=  4091 Z=  4086
    ADXL372 X=  4093 Y=     1 Z=  4089
    ADXL372 X=     1 Y=  4094 Z=  4083
    ADXL372 X=  4095 Y=     1 Z=  4087
    ADXL372 X=  4094 Y=     3 Z=  4085
    ADXL372 X=  4095 Y=  4094 Z=  4083
    ADXL372 X=     2 Y=  4091 Z=  4088
    ADXL372 X=     2 Y=  4095 Z=  4083
    ADXL372 X=     2 Y=  4095 Z=  4087
    ADXL372 X=  4095 Y=  4095 Z=  4089
    ADXL372 X=     3 Y=     3 Z=  4086
    ADXL372 X=  4095 Y=  4095 Z=  4086
    ADXL372 X=     2 Y=  4093 Z=  4087
    ADXL372 X=     1 Y=     1 Z=  4087
    ADXL372 X=  4091 Y=  4093 Z=  4087
    ADXL372 X=  4094 Y=  4095 Z=  4086
    ADXL372 X=  4095 Y=     2 Z=  4084
    ADXL372 X=  4092 Y=  4095 Z=  4085
    ADXL372 X=  4095 Y=     2 Z=  4087



    and moving the device doesn't seem to make a pattern in the data. 

  • Hi there, sorry to hear this initial fix didn't work. Could you share what your "spi_accel_read_reg()" method contains? I am trying to see if this is an error with the way you are setting up the chip, or if it's a problem with register reads. Thank you.

    Nico

  • Sure:

    static inline void accel_cs_low(void) { HAL_GPIO_WritePin(SPI_RAW_ACCEL_CS_PORT, SPI_RAW_ACCEL_CS_PIN, GPIO_PIN_RESET); }
    static inline void accel_cs_high(void){ HAL_GPIO_WritePin(SPI_RAW_ACCEL_CS_PORT, SPI_RAW_ACCEL_CS_PIN, GPIO_PIN_SET);   }
    
    
    static HAL_StatusTypeDef reg_write(uint8_t reg, uint8_t val)
    {
        return spi_accel_write_reg(reg, &val, 1);
    }
    
    static HAL_StatusTypeDef reg_read(uint8_t reg, uint8_t *val)
    {
        return spi_accel_read_reg(reg, val, 1);
    }
    
    
    HAL_StatusTypeDef spi_accel_read_reg(uint8_t reg, uint8_t *buf, uint16_t len)
    {
        uint8_t addr = (uint8_t)(reg << 1) | 0x01;
        HAL_StatusTypeDef ret;
    
        osMutexAcquire(s_bus_mutex, osWaitForever);
        accel_cs_low();
        ret = HAL_SPI_Transmit(&hspi4, &addr, 1, HAL_MAX_DELAY);
        if (ret == HAL_OK)
            ret = HAL_SPI_Receive(&hspi4, buf, len, HAL_MAX_DELAY);
        accel_cs_high();
        osMutexRelease(s_bus_mutex);
        return ret;
    }
    
    HAL_StatusTypeDef spi_accel_write_reg(uint8_t reg, const uint8_t *buf, uint16_t len)
    {
        uint8_t addr = (uint8_t)((reg&0xFF) << 1);
        HAL_StatusTypeDef ret;
    
        osMutexAcquire(s_bus_mutex, osWaitForever);
        accel_cs_low();
        ret = HAL_SPI_Transmit(&hspi4, &addr, 1, HAL_MAX_DELAY);
        if (ret == HAL_OK)
            ret = HAL_SPI_Transmit(&hspi4, (uint8_t *)buf, len, HAL_MAX_DELAY);
        accel_cs_high();
        osMutexRelease(s_bus_mutex);
        return ret;
    }
    
    

  • Have you had a chance to look at the code? The implementation of the read function is the other answer. Thanks

  • I'm reviewing your code and attempting to recreate the error on my end. For now, are you able to read the device info registers (0x00-0x03) correctly using your read method? If not, that may tell us there is something wrong with the way you're reading registers.

  •     uint16_t x = ((int16_t)((buf[0] << 8) | buf[1]));
        uint16_t y = ((int16_t)((buf[2] << 8) | buf[3]));
        uint16_t z = ((int16_t)((buf[4] << 8) | buf[5]));

    x,y,z are signed (16-bit) integers. Try instead:

        int16_t x = ((int16_t)((buf[0] << 8) | buf[1]));
        int16_t y = ((int16_t)((buf[2] << 8) | buf[3]));
        int16_t z = ((int16_t)((buf[4] << 8) | buf[5]));
    

    The units are 200g/2048ticks = ~0.1g/tick, so we expect Z to be about +/-10, which is consistent with the 4086 in your display.

    [Edit: Minor clarification]