i2c_transfer() reads all zeros

Hello,

I am trying to read data from LS2DE12 accelerometer MEMS chip via I2C bus and I am seeing only zeros for all 3 axes.
I can write to the various registers successfully and read back their content to check the write was successful using this function.

static int32_t lis2de12_readb(uint8_t add, uint8_t *b)
{
    struct i2c_msg msgs[2];

    /* Send the address to read from */
    msgs[0].buf = &add;
    msgs[0].len = 1U;
    msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP;

    /* Read from device. STOP after this. */
    msgs[1].buf = b;
    msgs[1].len = 1U;
    msgs[1].flags = I2C_MSG_READ | I2C_MSG_STOP;

    return i2c_transfer(accelerometer.handle, &msgs[0], 2, LIS2DE12_I2C_ADD);
}

The above is called at initialisation to configure the various registers as shown in the snippets of code below, and all seems to be working ok...

accelerometer_t *lis2de12_initialise(void *dev)
{
    accelerometer.handle = dev;
    uint8_t b,d[8];

    accelerometer.moved = false;
    lis2de12_readb( LIS2DE12_WHO_AM_I,&d[0] );
    if ( d[0] != LIS2DE12_ID )
    {
        LOG_INF( "Fail LIS2" );
        return( NULL );
    }
    else
    {
        LOG_DBG( "OK LIS2" );
        accelerometer.present = true;

        lis2de12_writeb( LIS2DE12_CTRL_REG1, 0x2f ); //0x1f);
        lis2de12_readb( LIS2DE12_CTRL_REG1, &d[0] );
        if ( d[0] != 0x2f )
        {
            LOG_INF( "Fail LIS2" );
            return( NULL );
        }

        lis2de12_writeb( LIS2DE12_CTRL_REG4, 0x80 );
        lis2de12_readb( LIS2DE12_CTRL_REG4, &d[1] );
        if (d[1] != 0x80)
        {
            LOG_INF( "Fail LIS2" );
            return( NULL );
        }

        //High pass filter enabled
//      lis2de12_writeb(LIS2DE12_CTRL_REG2,0x40);

        // Normal mode + HPF cutoff freq 0.02 Hz @1 Hz ODR + Enable the internal filter
        lis2de12_writeb( LIS2DE12_CTRL_REG2,0xB8 );
        lis2de12_readb( LIS2DE12_CTRL_REG2,&d[2] );
        if ( d[2] != 0xB8 )
        {
            LOG_INF( "Fail LIS2" );
            return( NULL );
        }

        // Enable FIFO operation
        lis2de12_writeb( LIS2DE12_CTRL_REG5, 0x40 );
        lis2de12_readb( LIS2DE12_CTRL_REG5, &d[3] );
        if (d[3] != 0x40)
        {
            LOG_INF( "Fail LIS2" );
            return( NULL );
        }

        // Enable FIFO Mode
        lis2de12_writeb( LIS2DE12_FIFO_CTRL_REG, 0x40 );
        lis2de12_readb( LIS2DE12_FIFO_CTRL_REG, &d[4] );
        if (d[4] != 0x40)
        {
            LOG_INF( "Fail LIS2" );
            return( NULL );
        }

        LOG_DBG( "C1 %x:C4 %x:C2 %x:C5 %x:FIFO %x:",d[0],d[1],d[2],d[3],d[4] );
        k_sleep(K_MSEC(20));

        return( &accelerometer );
    }

}//lis2de12_initialise()

However, when I read the x,y,z data I am getting all zeros.
The function that reads the x,y,z data is shown below,

static int32_t lis2de12_read_fifo(uint8_t add, uint8_t *b)
{
    struct i2c_msg msgs[2];

    /* Send the address to read from */
    msgs[0].buf = &add;
    msgs[0].len = 1U;
    msgs[0].flags = I2C_MSG_WRITE | I2C_MSG_STOP;

    /* Read from device. STOP after this. */
    msgs[1].buf = b;
    msgs[1].len = 6U;
    msgs[1].flags = I2C_MSG_READ | I2C_MSG_STOP;

    return i2c_transfer(accelerometer.handle, &msgs[0], 2, LIS2DE12_I2C_ADD);
}

The above function lis2de12_read_fifo() is called from the function shown below which itself gets called from an executive loop running in a forever loop.

typedef struct accel{
            void        * handle;
            int16_t     x;
            int16_t     y;
            int16_t     z;
            uint32_t    vector;
            uint32_t    oldvector;
            uint8_t     present:1;
            uint8_t     moved:1;
            uint32_t    LastMovementTime;

        } accelerometer_t;

accelerometer_t accelerometer;

boolean_t lis2de12_getxyz(void)
{
    uint8_t     status;
    uint8_t     d[6],i;
    union {
            uint8_t  b[2];
            int16_t  i;
          } iandb;

    accelerometer.vector = accelerometer.oldvector;

    if (accelerometer.present)
    {
        lis2de12_readb( LIS2DE12_STATUS_REG, &status );
        if ( status & ZYX_DATA_READY )
        {
#if 0
            for ( i = 0; i < 6; i++ )
            {
                if ( lis2de12_readb( LIS2DE12_FIFO_READ_START + i, &d[i] ) != 0 )
                {
                    break;
                }
            }
            if ( i == 6 )
#endif //#if 0

            if ( lis2de12_read_fifo( LIS2DE12_FIFO_READ_START, d ) != 0 )
            {
                iandb.b[1] = d[0];
                iandb.b[0] = d[1];
                accelerometer.x = iandb.i;

                iandb.b[1] = d[2];
                iandb.b[0] = d[3];
                accelerometer.y = iandb.i;

                iandb.b[1] = d[4];
                iandb.b[0] = d[5];
                accelerometer.z = iandb.i;

                accelerometer.vector = (uint32_t)accelerometer.x * (uint32_t)accelerometer.x +
                                       (uint32_t)accelerometer.y * (uint32_t)accelerometer.y +
                                       (uint32_t)accelerometer.z * (uint32_t)accelerometer.z;
                
                printf( "[%u s] ", timer_GetOneSecondTime() ); //DBG
                printf( "STATUS_REG = 0x%02x acc_x = 0x%04x acc_y = 0x%04x acc_z = 0x%04x v = %d acc_oldv = %d\n",
                        status,
                        accelerometer.x, accelerometer.y, accelerometer.z,
                        accelerometer.vector,
                        accelerometer.oldvector                             );
            }
        }
        return true;
    }
    else
    {
        return false;
    }

}//lis2de12_getxyz()
 

Here is a sample of the debug output

[14 s] STATUS_REG = 0xff acc_x = 0x0000 acc_y = 0x0000 acc_z = 0x0000 v = 0 acc_oldv = 0
[15 s] STATUS_REG = 0xff acc_x = 0x0000 acc_y = 0x0000 acc_z = 0x0000 v = 0 acc_oldv = 0
[15 s] STATUS_REG = 0xff acc_x = 0x0000 acc_y = 0x0000 acc_z = 0x0000 v = 0 acc_oldv = 0
[15 s] STATUS_REG = 0xff acc_x = 0x0000 acc_y = 0x0000 acc_z = 0x0000 v = 0 acc_oldv = 0
[15 s] STATUS_REG = 0xff acc_x = 0x0000 acc_y = 0x0000 acc_z = 0x0000 v = 0 acc_oldv = 0
[15 s] STATUS_REG = 0xff acc_x = 0x0000 acc_y = 0x0000 acc_z = 0x0000 v = 0 acc_oldv = 0
[15 s] STATUS_REG = 0xff acc_x = 0x0000 acc_y = 0x0000 acc_z = 0x0000 v = 0 acc_oldv = 0

It must be something to do with the way I am reading the FIFO content because when I read individual registers content all seems to be OK.
Please advise.
Kind regards
Mohamed
Parents
  • Hello,

    I'll take a look at this tomorrow.

    Best regards,

    Simon

  • Thank you Simon.

    I am looking forward to read your findings.

    Kind regards

    Mohamed

  • Try setting struct i2c_msg msgs[2] to static, like shown below:

    static int32_t lis2de12_read_fifo(uint8_t add, uint8_t *b)
    {
        static struct i2c_msg msgs[2];
    
        /* Send the address to read from */
        msgs[0].buf = &add;
        msgs[0].len = 1U;
        .
        .

    Do you have a logic analyzer? That is quite useful to see what's actually going on, on the lines. If you have one, could you you attach it to the SDA and SCL lines and upload the trace here?

    Best regards,

    Simon

  • Thank you Simon.

    I tried your suggestion to make the struct declaration static but it did not make any difference.
    Hooking up a logic analyser to SDA and SCL lines was going to be my next move but I was hoping you may be able to find what could be wrong in my code without resorting to a logic analyser. I am not suspecting the hardware, are you?
    The reason I am saying this is because I can read the control and status registers content without any problem. If there was something wrong with the hardware setup it would have affected them too.
    Anyway, I am working from home today and the logic analyser is in the office. So, I will do it on Monday and will give you some feedback.
    Kind regards
    Mohamed
  • Hey, did you capture a trace?

    I'll take a closer look at this tomorrow.

    What happens if you try to read the data in the same way it's done in the lis2ds12 driver, by using i2c_burst_read()?

    https://github.com/nrfconnect/sdk-zephyr/blob/v2.6.99-ncs1/drivers/sensor/lis2ds12/lis2ds12_i2c.c#L28-L29

  • Good Morning Simon,
    Thank you for sharing the link about i2c_burst_read().
    I did not have to use the logic analyser because when I disabled the sensor internal filter (cleared FDS bit) I could read the sensor data.
    lis2de12_writeb( LIS2DE12_CTRL_REG2,0xB8 );
    changed to
    lis2de12_writeb( LIS2DE12_CTRL_REG2,0x80 );
    However, I still cannot read the content of the FIFO. I tried both FIFO and stream modes and neither worked. When in stream mode the FIFO seemed to always be empty (EMPTY bit always set).
    I have not had a chance to try the i2c_burst_read() but I will do tomorrow.
    ------------------
    Updated post
    ------------------
    I have now tried to read the fifo using i2c_burst_read() but I am still finding that when I read register  LIS2DE12_FIFO_SRC_REG (address 0x2F) I get 0x20 meaning the fifo is always empty. I am enabling fifo (FIFO_EN) and selecting stream mode by writing 0x80 to register LIS2DE12_FIFO_CTRL_REG.
    Below is the code used to read the content of the fifo.
    static int32_t lis2de12_read_fifo(uint8_t add, uint8_t *data)
    {
        return i2c_burst_read( accelerometer.handle,    // i - Pointer to the device structure for an I2C controller
                               LIS2DE12_I2C_ADD,        // i - Address of the I2C device to read from
                               add,                     // i - Internal address from which the data is read
                               data,                    // o - Buffer to read the data into
                               6                    );  // i - Number of bytes to read
    }
    
    
    boolean_t lis2de12_getxyz_fifo(void)
    {
        boolean_t   result = false;
        uint8_t     fifo_status;
        uint8_t     d[6],i;
        union {
                uint8_t  b[2];
                int16_t  i;
        } iandb;
    
        accelerometer.vector = accelerometer.oldvector;
    
        if (accelerometer.present)
        {
            lis2de12_readb( LIS2DE12_FIFO_SRC_REG, &fifo_status );
            if ( fifo_status & 0x1f )
            {
                if ( lis2de12_read_fifo( LIS2DE12_FIFO_READ_START | 0x80, d ) == 0 )
                {
                    iandb.b[1] = d[0];
                    iandb.b[0] = d[1];
                    accelerometer.x = iandb.i;
    
                    iandb.b[1] = d[2];
                    iandb.b[0] = d[3];
                    accelerometer.y = iandb.i;
    
                    iandb.b[1] = d[4];
                    iandb.b[0] = d[5];
                    accelerometer.z = iandb.i;
    
                    accelerometer.vector = (uint32_t)accelerometer.x * (uint32_t)accelerometer.x +
                                           (uint32_t)accelerometer.y * (uint32_t)accelerometer.y +
                                           (uint32_t)accelerometer.z * (uint32_t)accelerometer.z;
                    printf( "[%u s] ", timer_GetOneSecondTime() ); //DBG
                    printf( "STATUS_REG = 0x%02x acc_x = 0x%04x acc_y = 0x%04x acc_z = 0x%04x v = %d acc_oldv = %d\n",
                            fifo_status,
                            accelerometer.x, accelerometer.y, accelerometer.z,
                            accelerometer.vector,
                            accelerometer.oldvector                             );
                    
                    result = true;
                }
            }
        }
    
        return result;
    
    }//lis2de12_getxyz_fifo()
    
    -----------------------
    If I don't bother to read and check the content of the FIFO source register (LIS2DE12_FIFO_SRC_REG) for the existence of data before reading then I can read the sensor data successfully. The two commented out lines are shown below.
    //      lis2de12_readb( LIS2DE12_FIFO_SRC_REG, &fifo_status );
    //      if ( fifo_status & 0x1f )
    
    The data read is shown below, ignore the STATUS_REG values because it is not being read.
    [16 s] STATUS_REG = 0x05 acc_x = 0x00fd acc_y = 0x00ff acc_z = 0x0042 v = 133390 acc_oldv = 133390
    [17 s] STATUS_REG = 0x00 acc_x = 0x00fd acc_y = 0x00ff acc_z = 0x0042 v = 133390 acc_oldv = 133390
    [18 s] STATUS_REG = 0x00 acc_x = 0x00f5 acc_y = 0x0006 acc_z = 0x00c5 v = 98870 acc_oldv = 133390
    [19 s] STATUS_REG = 0x00 acc_x = 0x00f9 acc_y = 0x00f8 acc_z = 0x0042 v = 127861 acc_oldv = 98870
    [20 s] STATUS_REG = 0x00 acc_x = 0x00bf acc_y = 0x00f2 acc_z = 0x00fa v = 157545 acc_oldv = 127861
    [21 s] STATUS_REG = 0x00 acc_x = 0x00c1 acc_y = 0x00f3 acc_z = 0x00f9 v = 158299 acc_oldv = 157545
    [22 s] STATUS_REG = 0x05 acc_x = 0x0006 acc_y = 0x00bc acc_z = 0x0006 v = 35416 acc_oldv = 158299
    [23 s] STATUS_REG = 0x00 acc_x = 0x000a acc_y = 0x00bc acc_z = 0x0000 v = 35444 acc_oldv = 35416
    [24 s] STATUS_REG = 0x00 acc_x = 0x000e acc_y = 0x00bd acc_z = 0x0002 v = 35921 acc_oldv = 35444
    [25 s] STATUS_REG = 0x00 acc_x = 0x0010 acc_y = 0x00be acc_z = 0x0001 v = 36357 acc_oldv = 35921
    [26 s] STATUS_REG = 0x05 acc_x = 0x00ff   acc_y = 0x0040 acc_z = 0x00fd v = 133130 acc_oldv = 36357
    [27 s] STATUS_REG = 0x00 acc_x = 0x0003 acc_y = 0x0040 acc_z = 0x0003 v = 4114 acc_oldv = 133130
    [28 s] STATUS_REG = 0x00 acc_x = 0x0002 acc_y = 0x00bc acc_z = 0x0008 v = 35412 acc_oldv = 4114
    [29 s] STATUS_REG = 0x00 acc_x = 0x0000 acc_y = 0x00bc acc_z = 0x000b v = 35465 acc_oldv = 35412
    [30 s] STATUS_REG = 0x05 acc_x = 0x0000 acc_y = 0x00bc acc_z = 0x000b v = 35465 acc_oldv = 35465
    [30 s] STATUS_REG = 0x00 acc_x = 0x0001 acc_y = 0x00bd acc_z = 0x000b v = 35843 acc_oldv = 35465
    [31 s] STATUS_REG = 0x05 acc_x = 0x00fa  acc_y = 0x0001 acc_z = 0x003f v = 66470 acc_oldv = 35843
    [32 s] STATUS_REG = 0x00 acc_x = 0x00fa  acc_y = 0x0000 acc_z = 0x0041 v = 66725 acc_oldv = 66470
    Kind regards
    Mohamed

Reply
  • Good Morning Simon,
    Thank you for sharing the link about i2c_burst_read().
    I did not have to use the logic analyser because when I disabled the sensor internal filter (cleared FDS bit) I could read the sensor data.
    lis2de12_writeb( LIS2DE12_CTRL_REG2,0xB8 );
    changed to
    lis2de12_writeb( LIS2DE12_CTRL_REG2,0x80 );
    However, I still cannot read the content of the FIFO. I tried both FIFO and stream modes and neither worked. When in stream mode the FIFO seemed to always be empty (EMPTY bit always set).
    I have not had a chance to try the i2c_burst_read() but I will do tomorrow.
    ------------------
    Updated post
    ------------------
    I have now tried to read the fifo using i2c_burst_read() but I am still finding that when I read register  LIS2DE12_FIFO_SRC_REG (address 0x2F) I get 0x20 meaning the fifo is always empty. I am enabling fifo (FIFO_EN) and selecting stream mode by writing 0x80 to register LIS2DE12_FIFO_CTRL_REG.
    Below is the code used to read the content of the fifo.
    static int32_t lis2de12_read_fifo(uint8_t add, uint8_t *data)
    {
        return i2c_burst_read( accelerometer.handle,    // i - Pointer to the device structure for an I2C controller
                               LIS2DE12_I2C_ADD,        // i - Address of the I2C device to read from
                               add,                     // i - Internal address from which the data is read
                               data,                    // o - Buffer to read the data into
                               6                    );  // i - Number of bytes to read
    }
    
    
    boolean_t lis2de12_getxyz_fifo(void)
    {
        boolean_t   result = false;
        uint8_t     fifo_status;
        uint8_t     d[6],i;
        union {
                uint8_t  b[2];
                int16_t  i;
        } iandb;
    
        accelerometer.vector = accelerometer.oldvector;
    
        if (accelerometer.present)
        {
            lis2de12_readb( LIS2DE12_FIFO_SRC_REG, &fifo_status );
            if ( fifo_status & 0x1f )
            {
                if ( lis2de12_read_fifo( LIS2DE12_FIFO_READ_START | 0x80, d ) == 0 )
                {
                    iandb.b[1] = d[0];
                    iandb.b[0] = d[1];
                    accelerometer.x = iandb.i;
    
                    iandb.b[1] = d[2];
                    iandb.b[0] = d[3];
                    accelerometer.y = iandb.i;
    
                    iandb.b[1] = d[4];
                    iandb.b[0] = d[5];
                    accelerometer.z = iandb.i;
    
                    accelerometer.vector = (uint32_t)accelerometer.x * (uint32_t)accelerometer.x +
                                           (uint32_t)accelerometer.y * (uint32_t)accelerometer.y +
                                           (uint32_t)accelerometer.z * (uint32_t)accelerometer.z;
                    printf( "[%u s] ", timer_GetOneSecondTime() ); //DBG
                    printf( "STATUS_REG = 0x%02x acc_x = 0x%04x acc_y = 0x%04x acc_z = 0x%04x v = %d acc_oldv = %d\n",
                            fifo_status,
                            accelerometer.x, accelerometer.y, accelerometer.z,
                            accelerometer.vector,
                            accelerometer.oldvector                             );
                    
                    result = true;
                }
            }
        }
    
        return result;
    
    }//lis2de12_getxyz_fifo()
    
    -----------------------
    If I don't bother to read and check the content of the FIFO source register (LIS2DE12_FIFO_SRC_REG) for the existence of data before reading then I can read the sensor data successfully. The two commented out lines are shown below.
    //      lis2de12_readb( LIS2DE12_FIFO_SRC_REG, &fifo_status );
    //      if ( fifo_status & 0x1f )
    
    The data read is shown below, ignore the STATUS_REG values because it is not being read.
    [16 s] STATUS_REG = 0x05 acc_x = 0x00fd acc_y = 0x00ff acc_z = 0x0042 v = 133390 acc_oldv = 133390
    [17 s] STATUS_REG = 0x00 acc_x = 0x00fd acc_y = 0x00ff acc_z = 0x0042 v = 133390 acc_oldv = 133390
    [18 s] STATUS_REG = 0x00 acc_x = 0x00f5 acc_y = 0x0006 acc_z = 0x00c5 v = 98870 acc_oldv = 133390
    [19 s] STATUS_REG = 0x00 acc_x = 0x00f9 acc_y = 0x00f8 acc_z = 0x0042 v = 127861 acc_oldv = 98870
    [20 s] STATUS_REG = 0x00 acc_x = 0x00bf acc_y = 0x00f2 acc_z = 0x00fa v = 157545 acc_oldv = 127861
    [21 s] STATUS_REG = 0x00 acc_x = 0x00c1 acc_y = 0x00f3 acc_z = 0x00f9 v = 158299 acc_oldv = 157545
    [22 s] STATUS_REG = 0x05 acc_x = 0x0006 acc_y = 0x00bc acc_z = 0x0006 v = 35416 acc_oldv = 158299
    [23 s] STATUS_REG = 0x00 acc_x = 0x000a acc_y = 0x00bc acc_z = 0x0000 v = 35444 acc_oldv = 35416
    [24 s] STATUS_REG = 0x00 acc_x = 0x000e acc_y = 0x00bd acc_z = 0x0002 v = 35921 acc_oldv = 35444
    [25 s] STATUS_REG = 0x00 acc_x = 0x0010 acc_y = 0x00be acc_z = 0x0001 v = 36357 acc_oldv = 35921
    [26 s] STATUS_REG = 0x05 acc_x = 0x00ff   acc_y = 0x0040 acc_z = 0x00fd v = 133130 acc_oldv = 36357
    [27 s] STATUS_REG = 0x00 acc_x = 0x0003 acc_y = 0x0040 acc_z = 0x0003 v = 4114 acc_oldv = 133130
    [28 s] STATUS_REG = 0x00 acc_x = 0x0002 acc_y = 0x00bc acc_z = 0x0008 v = 35412 acc_oldv = 4114
    [29 s] STATUS_REG = 0x00 acc_x = 0x0000 acc_y = 0x00bc acc_z = 0x000b v = 35465 acc_oldv = 35412
    [30 s] STATUS_REG = 0x05 acc_x = 0x0000 acc_y = 0x00bc acc_z = 0x000b v = 35465 acc_oldv = 35465
    [30 s] STATUS_REG = 0x00 acc_x = 0x0001 acc_y = 0x00bd acc_z = 0x000b v = 35843 acc_oldv = 35465
    [31 s] STATUS_REG = 0x05 acc_x = 0x00fa  acc_y = 0x0001 acc_z = 0x003f v = 66470 acc_oldv = 35843
    [32 s] STATUS_REG = 0x00 acc_x = 0x00fa  acc_y = 0x0000 acc_z = 0x0041 v = 66725 acc_oldv = 66470
    Kind regards
    Mohamed

Children
No Data
Related