Post Go back to editing

odd resolution Z axis for ADXL355 - missing histograms bins

Hello

I ploted some statistics from raw data of ADXL355 and I noticed that histogram for Z axis look like missing some bins that might mean it might be somehow upsampled instead of default 20bit.

Any explanation why this happen?

  • I see negative numbers on z axis. So check your 2s complement conversion. Check this code :

    acc32 = ((uint32_t)acc3 << 12) | ((uint16_t)acc2 << 4) | (acc1>> 4);

    if (acc32 & (1UL << 19)) acc32-= 1UL << 20;

  • what is wrong with negative number? Its negative because of sensor orientation

    Anyway, here is my download sample code

    void _ADXL355::downloadSample(uint8_t *sampleRaw){
        uint8_t data[11] = {reg.readAddr(0x06),0,0,0,0,0,0,0,0,0,0};
        reg.transferBytes(data,data,11);
        memcpy(sampleRaw,&data[1],11);
    }


    template <class T>
    void _ADXL355::getSampleRaw(ADXL355_sample_t<T> *sample){
        static uint8_t sampleRaw[11];
        downloadSample(sampleRaw);
        sample->temp = (sampleRaw[0]&0b00001111)<<8 | sampleRaw[1];
        sample->ax = (int8_t)sampleRaw[2]<<12 | sampleRaw[3]<<4 | sampleRaw[4]>>4;
        sample->ay = (int8_t)sampleRaw[5]<<12 | sampleRaw[6]<<4 | sampleRaw[7]>>4;
        sample->az = (int8_t)sampleRaw[8]<<12 | sampleRaw[9]<<4 | sampleRaw[10]>>4;
    }
  • I mean that the error appears only on the z-axis because it is negative. The 2s complement conversion is missing in your code.

    are ax, ay, az signed 32-bit integers (int32_t) ?

    why are you casting sampleRaw to int8_t ? should be int32_t

    if (ax & (1UL << 19)) ax -= 1UL << 20;

    if (ay & (1UL << 19)) ay -= 1UL << 20;

    if (az & (1UL << 19)) az -= 1UL << 20;

  • ax,ay,az are float, Particular byte are casted as integer to properly shift left and fill '1' so compiler decide when to use arithmetic or logical bit shift so any further if statement are unecessary to correct negative value. It is little bit tricky but i believe its fastest implementation.

    sample->ax = (int32_t)(((int8_t)sampleRaw[2])<<12 | ((uint8_t)sampleRaw[3])<<4 | ((uint8_t)sampleRaw[4])>>4));

    if sampleRaw[2] is treated in uint then left bits always will be filled by 0, if sampleRaw[2] is treat as integer and its negative then shifted value is filled by 1 to keep it as negative and result value also is int32_t by this operation

    My device work perfectly as expectation, excluding metioned statistical nuance.

    I checked it on 3 different sensors with same result. Also it is always Z axis no matter of orientation (negative, positive or near zero)

    I also try your conversion with same result

    int32_t ax = sampleRaw[2]<<12 | sampleRaw[3]<<4 | sampleRaw[4]>>4;
    int32_t ay = sampleRaw[5]<<12 | sampleRaw[6]<<4 | sampleRaw[7]>>4;
    int32_t az = sampleRaw[8]<<12 | sampleRaw[9]<<4 | sampleRaw[10]>>4;
    
    if (ax & (1UL << 19)) ax -= 1UL << 20;
    if (ay & (1UL << 19)) ay -= 1UL << 20;
    if (az & (1UL << 19)) az -= 1UL << 20;
    
    sample->ax = ax;
    sample->ay = ay;
    sample->az = az;

  • I eventually catch where the probliem lie. Described issue at code also match my observation where Z axis always was multiply of 16 where it watch missing last 4 bits ( sampleRaw[10]>>4 )

    Thanks for participate.

    void _ADXL355::downloadSampleOld(uint8_t *sampleRaw){
        uint8_t data[11] = {reg.readAddr(0x06),0,0,0,0,0,0,0,0,0,0}; // not large enough array to store data
        reg.transferBytes(data,data,11); // <--- transferr not enough bytes
        memcpy(sampleRaw,&data[1],11); // memcpy copy one byte out of data range so sampleRaw[10] was undefined
    }
    
    void _ADXL355::downloadSample(uint8_t *sampleRaw){
        uint8_t data[12] = {reg.readAddr(0x06),0,0,0,0,0,0,0,0,0,0,0};
        reg.transferBytes(data,data,12);
        memcpy(sampleRaw,&data[1],11);
    }