cancel
Showing results for 
Search instead for 
Did you mean: 

Crash Detection on lsm6dsl

MSchl.3
Associate II
 
6 REPLIES 6
MSchl.3
Associate II

We are looking for the best way to use the lsm6dsl for a crash detection. Example: Device is belted to the human body. Body crashes while mountainbiking. device should report a crash and the force on the 3 axis.

We have used the TAP detection so far and used the fifo_in_continous_to_fifo mode for the acceleration data that lead to the tap detection, as here we can set the threshold individually from 0.5g up to 16g.

However even with slight taps or putting the device on the table, we get values of up to 10g which is way too much.

These are our settings and code. Please kindly help. Thanks a lot!

 Settings:

{
    uint8_t value;
   
    // No duration
    // 0x00 single-tap | 0x00 wake-up
    lsm6dsl_write(accel, LSM6DSL_WAKE_UP_DUR, 0x00);
    
    // Configure  Activity/Inactivity threshold
    // 0x02 single-tap | 0x00 wake-up
    // 2g
    #ifdef LSM_16G
        lsm6dsl_write(accel, LSM6DSL_WAKE_UP_THS, 0x01);
    #else
        lsm6dsl_write(accel, LSM6DSL_WAKE_UP_THS, 0x08);
    #endif
 
    // Enable interrupts(TAP & WU), tap detection on X, Y, Z axis (TAP), apply slope filter (WU)
    // 0x8E single-tap | 0x90 wake-up
    lsm6dsl_write(accel, LSM6DSL_TAP_CFG, 0x9E);
    
    // Set tap threshold
    // 0x89 single-tap | 0x00 wake-up
    // X * 0.0625 = threshold_in_g
    // e.g 0x10 * 0.0625 = 1g
    // so TAP_THS field of TAP_THS_6D register is 0b10000
 
    #ifdef LSM_16G
        lsm6dsl_write(accel, LSM6DSL_TAP_THS_6D, 0x84);
    #else
        lsm6dsl_write(accel, LSM6DSL_TAP_THS_6D, 0x90);
    #endif
 
    #ifdef LSM_16G
        //BUG_CHECK (-> test avec 0x64 et 0x60 pour 416Hz)
        lsm6dsl_write(accel, LSM6DSL_CTRL1_XL, 0x74);
        //lsm6dsl_write(accel, LSM6DSL_CTRL1_XL, 0x64);
    #else
        lsm6dsl_write(accel, LSM6DSL_CTRL1_XL, 0x70);
        //lsm6dsl_write(accel, LSM6DSL_CTRL1_XL, 0x60);
    #endif
 
    DELAY_MS(10);
    
    lsm6dsl_read(accel, LSM6DSL_CTRL1_XL, &value, 1);
    ////lsm6dsl_write(accel, LSM6DSL_CTRL1_XL, 0x60);
    
    lsm6dsl_write(accel, LSM6DSL_INT_DUR2, 0x06);
 
    lsm6dsl_write(accel, LSM6DSL_MD1_CFG, 0x20) ;
 
    //! NEW FIFO IMU
    // Single tap on INT2
    lsm6dsl_write(accel, LSM6DSL_MD2_CFG, 0x40);
    
    return 0;
}

Code

void lsm6dsl_set_fifo_in_bypass_mode(lsm6dsl_t* accel)
{
    // 0x00 -> FIFO disabled | 0x00 -> Bypass mode. FIFO disabled.
    lsm6dsl_write(accel, LSM6DSL_FIFO_CTRL5, 0x00);
}
 
 
void lsm6dsl_set_fifo_in_continuous_to_fifo_mode(lsm6dsl_t* accel)
{
    // Single tap has to be on INT2 !!!!!
    
    if (FIFO_SIZE <= 255)
    {
        // 0x1E ->  FIFO threshold = FIFO_SIZE (30)
        lsm6dsl_write(accel, LSM6DSL_FIFO_CTRL1, FIFO_SIZE);
    }
    else
    {
        /* code */
    }
    
    // 0x00 -> Gyro not in FIFO | 0x01 -> No decimation
    lsm6dsl_write(accel, LSM6DSL_FIFO_CTRL3, 0x01);
 
    // 0x80 -> Enable FIFO threshold | 
    lsm6dsl_write(accel, LSM6DSL_FIFO_CTRL4, 0x80);
    
    // 0x30 -> ODR 416Hz | 0x03 -> Continuous mode until trigger is deasserted, then FIFO mode
    lsm6dsl_write(accel, LSM6DSL_FIFO_CTRL5, 0x33);
 
    return 0;
}
 
 
void lsm6dsl_read_fifo(lsm6dsl_t* accel, lsm6dsl_fifo_t* fifo)
{
    uint8_t value;
    uint8_t data_L;
    uint8_t data_H;
    uint8_t i;
    uint8_t pattern;
    uint8_t I2C_status = 0;
 
    // 0x40 -> Enable BDU
    lsm6dsl_write(accel, LSM6DSL_CTRL3_C, 0x40);
 
    lsm6dsl_read(accel, LSM6DSL_FIFO_STATUS1, &value, 1);
    fifo->status1 = value;
 
    lsm6dsl_read(accel, LSM6DSL_FIFO_STATUS2, &value, 1);
    fifo->status2 = value;
 
     for (i = 0; i < (FIFO_SIZE/3); i++)
    {
        do
        {
            I2C_status = lsm6dsl_read(accel, LSM6DSL_FIFO_STATUS3, &pattern, 1);
            lsm6dsl_read(accel, LSM6DSL_FIFO_DATA_OUT_L, &data_L, 1);
            lsm6dsl_read(accel, LSM6DSL_FIFO_DATA_OUT_H, &data_H, 1);
 
            if (I2C_status != I2C2_MESSAGE_COMPLETE)
            {
                break;
            }
            
        } while (pattern != 0);
        
        fifo->accel[i].XLx = data_H;
        fifo->accel[i].XLx = fifo->accel[i].XLx << 8;
        fifo->accel[i].XLx |= data_L;
 
        lsm6dsl_read(accel, LSM6DSL_FIFO_STATUS3, &pattern, 1);
        lsm6dsl_read(accel, LSM6DSL_FIFO_DATA_OUT_L, &data_L, 1);
        lsm6dsl_read(accel, LSM6DSL_FIFO_DATA_OUT_H, &data_H, 1);
        
        if (pattern == 1)
        {
            fifo->accel[i].XLy = data_H;
            fifo->accel[i].XLy = fifo->accel[i].XLy << 8;
            fifo->accel[i].XLy |= data_L;
        }
        else
        {
            fifo->accel[i].XLy = 0;
        }
                
        lsm6dsl_read(accel, LSM6DSL_FIFO_STATUS3, &pattern, 1);
        lsm6dsl_read(accel, LSM6DSL_FIFO_DATA_OUT_L, &data_L, 1);
        lsm6dsl_read(accel, LSM6DSL_FIFO_DATA_OUT_H, &data_H, 1);
        
        if (pattern == 2)
        {
            fifo->accel[i].XLz = data_H;
            fifo->accel[i].XLz = fifo->accel[i].XLz << 8;
            fifo->accel[i].XLz |= data_L;
        }
        else
        {
            fifo->accel[i].XLz = 0;
        }
    }
    
    // 0x00 -> disable BDU
    lsm6dsl_write(accel, LSM6DSL_CTRL3_C, 0x00);
}

Eleon BORLINI
ST Employee

Hi @MSchl.3​ ,

I'm not sure this is an issue related to the code itself, but maybe to a limitation in the detection range of the LSM6DSL (max FS = 16g). Do you have a target acceleration value to be detected? I mean do you know how many "g" you would expect b y the shock you would detect?

It's not so difficult to reach up to 10g, if the shock pulse is short enough. You might set some filters (low pass and high pass) on the LSM6DSL, so that you can concentrate the shock you want to detect and reduce the spurious acceleration peaks.

To do this, you can use the Composite filter described in the datasheet, p.67:

0693W00000HraTDQAZ.png 

If you are using the TAP interrupt, you might try to increase the Interrupt duration, so that the shock must be over threshold for a minimum time (to be fine-tuned with the specific application).

Otherwise, you might try changing device using an high-g accelerometer (up to 200g) such as the H3LIS331DL, which is more suitable for the shock detections.

Otherwise,

-Eleon

MSchl.3
Associate II

Hi Eleon,

thanks for your reply.

We have made an improvement by making the settings in this strict order:

lsm6dsl_write(accel, LSM6DSL_CTRL1_XL, 0x74); 
lsm6dsl_write(accel, LSM6DSL_TAP_CFG, 0x8E);
lsm6dsl_write(accel, LSM6DSL_TAP_THS_6D, 0x42);  //previously 0x82 without 6D
lsm6dsl_write(accel, LSM6DSL_CTRL8_XL, 0x01);  //enable Filters 0x09 Extreme: 0xE9
lsm6dsl_write(accel, LSM6DSL_INT_DUR2, 0x06);
lsm6dsl_write(accel, LSM6DSL_WAKE_UP_THS, 0x01);
lsm6dsl_write(accel, LSM6DSL_WAKE_UP_DUR, 0x00);
lsm6dsl_write(accel, LSM6DSL_MD2_CFG, 0x40);
lsm6dsl_write(accel, LSM6DSL_MD1_CFG, 0x20);

However when we try to apply LowPass or HighPassFilters with this settings:

LPF1_BW_SEL = 1 (thus CTRL1_XL = 0x76)

and CTRL8_XL = 0xE9 ((11101001)) the system hangs and cant read out any more data.

Any hints?

What would be the minium setting for a Low Pass Filter with the above basic settings?

Thanks a lot

Hi @MSchl.3​ ,

glad to see you made progressions on your issue.

Not sure it is possible to apply both Low pass and High pass filter, since from the block diagram of the composite filter they are not on in cascade.

You should choose only one of them, maybe only the high pass path, that cuts all the low pass frequency. You will be able to see only shocks faster than ODR/x.

0693W00000JMpUvQAL.png 

-Eleon

MSchl.3
Associate II

Hi Eleon,

thanks for your reply.

We have now set only the HighPass filters. It seems to work, BUT after a random number of detections and interrupts (approx 5-10), the device seems to stall and not send any more informations.

is there a hint if we should soft.reset the IMU after each detection or do anything else to avoid these issues?

Any advise on delays between setting the registers or having to read out EACH of the needed registers before writing into them?

Thanks!

Thanks

Hi @MSchl.3​ ,

maybe a 100ms delay would be a safe delay before and after reading the registers, but if you run the multiple registers SPI/I2C you don't have delays between reg_t and reg_t+1, and this should be a safe condition by design.

Not sure why the device seems to stall at a certain point... but yes, you can try enabling the SW_RESET bit of the CTRL3_C (12h), that performs the software reset. Did you already have the possibility to check this?

-Eleon