cancel
Showing results for 
Search instead for 
Did you mean: 

FSM#12: How to… test your FSM: GLANCE detection (both axl and gyro), further algorithm examples

Eleon BORLINI
ST Employee

This example describes how to set up a finite state machine to enable the built-in detection of a GLANCE action along x-axis. The picture here below shows the steps of the dedicated FSM. This code shows you also how to use the gyro data for a complete and more accurate pattern recognition. GLANCE FSM allows you to check when a glance event occurs. The code is quite longer than the previous examples because the glance gesture is more complex than e.g. a simple motion or a free fall action. In attachment you can find the state machine code to upload on your Unico tool.

Input data are both the axl and the gyro output streams (select ODR >= 26Hz)

Masks selects as interesting orientation the x axis value on positive direction (MASK_A=0x80), the y axis value on positive direction (MASK_B=0x20), and the z axis value on positive direction (MASK_C=0x08),

Thresholds are set to 0.5g (TH1) and 0.1g (TH2)

Timeout have been selected and tuned as 400ms and 120ms (T3 and T4)

Output is an interrupt when a glance gesture is detected.

0690X000006DOPvQAO.png

Enjoy!

Link: https://www.st.com/content/ccc/resource/technical/document/application_note/group0/56/95/d6/a1/34/4c/49/6d/DM00517282/files/DM00517282.pdf/jcr:content/translations/en.DM00517282.pdf

2 REPLIES 2
KWine
Senior

I must be missing something. I got your other examples including motion detect and wrist tilt and shake to work, but the glance detect is not doing anything. Not sure why. Mind taking a look at my function? I am sure I am doing something dumb...

void LSM6DSO::FSMGlanceDetect() {
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_FUNC_CFG_ACCESS, 0x80);                        // enable embedded function access
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_EMB_FUNC_EN_B, 0x01);                          // enable FSM
    uint8_t temp = _i2c_bus->readByte(LSM6DSO_ADDRESS, LSM6DSO_EMB_FUNC_ODR_CFG_B);             // preserve default register contants
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_EMB_FUNC_ODR_CFG_B, temp | 0x01 << 3);         // select 26 Hz FSM ODR
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_FSM_ENABLE_A, 0x01);                           // Enable FSM engine 1
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_FSM_INT1_A,  0x01);                            // Route FSM 1 interrupt to INT1
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_RW, 0x40);                                // Enable page write
 
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_SEL, 0x11);                               // Select page 1 (bit 0 must always be 1)
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_ADDR, 0x7A);                              // Select FSM_LC_TIMEOUT_L register on page 1
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             // write 0 to FSM_LONG_COUNTER_L (register auto increments)
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             // write 0 to FSM_LONG_COUNTER_H
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x01);                             // write 1 to FSM_PROGRAMS
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x01);                             // dummy write to skip to FSM_START_ADD_L register
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             // write to FSM_START_ADDRESS_L
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x04);                             // write to FSM_START_ADDRESS_H
 
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_SEL,   0x41);                             // Select page 4 (bit 0 must always be 1)
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_ADDR,  0x00);                             // Select first address on program page 4
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x80 | 0x30 | 0x08 | 0x02);        // write to CONFIG_A (two thresholds, three masks, two long timers and two short timers)
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             // write to CONFIG_B
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x28);                             // write to SIZE (40 byte program)
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             // write to SETTINGS
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             // write to RESET POINTER
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             // write to PROGRAM POINTER
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             // write to THRESH1 LSB
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x38);                             // write to THRESH1 MSB  (set to + 0.5 g)
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x66);                             // write to THRESH2 LSB
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x2E);                             // write to THRESH2 MSB  (set to + 0.1 g)
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x80);                             // write to MASKA (+X)
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             // write to TMASKA
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x20);                             // write to MASKB (+Y)
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             // write to TMASKB
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x08);                             // write to MASKC (+Z)
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             // write to TMASKC
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             // write to TC
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             // write to TC
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x02);                             // write to TIMER1 ( 2 samples at 26 Hz = 0.0772 seconds) LSB
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             //  MSB
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x20);                             // write to TIMER2 (32 samples at 26 Hz = 1.23 seconds) LSB
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             //  MSB
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x0A);                             // write to TIMER3 (16 samples at 26 Hz = 0.39 seconds)
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x03);                             // write to TIMER4 ( 3 samples at 26 Hz = 0.10 seconds)
 
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x23);                             // write to SINMUX Set input multiplexer
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x01);                             // select gyroscope
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x66);                             // write to SELMA Select MASKA and TMASKA as current mask
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x16);                             // write to TI1 ! GNTH2   look for >thresh2 in TI1 seconds
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x23);                             // write to SINMUX Set input multiplexer
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x07);                             // select integrated gyroscope
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x25);                             // write to TI2 ! GNTH1   look for >thresh1 in TI2 seconds
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x23);                             // write to SINMUX Set input multiplexer
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             // select accelerometer
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x03);                             // write to NOP | TI3
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x77);                             // write to SELMB Select MASKB and TMASKB as current mask
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x84);                             // write to LNTH2 | TI4
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x88);                             // write to SELMC Select MASKC and TMASKC as current mask
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x84);                             // write to LNTH2 | TI4
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x22);                             // write to CONTREL Continues execution from reset pointer, resetting temporary mask
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_VALUE, 0x00);                             // write to STOP
  
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_SEL, 0x01);                               // Disable access to embedded advanced features
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_PAGE_RW, 0x00);                                // Disable page write
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_FUNC_CFG_ACCESS, 0x00);                        // disable embedded function access
 
    temp = _i2c_bus->readByte(LSM6DSO_ADDRESS, LSM6DSO_MD1_CFG);                                // preserve interrupt existing routing
    _i2c_bus->writeByte(LSM6DSO_ADDRESS, LSM6DSO_MD1_CFG, temp | 0x02);                         // add embedded functions interrupt routing to INT1
}

HI @KWine​ , does it means that you are not receiving any interrupt after Glance gesture?

I see you are using the FSM with axl and gyro for the Glance gesture recognition. As a starting point, to simplify the code, I suggest you to use the axl-only FSM, especially if the motion detect and wrist tilt FSM are working. In this case, glance interrupt requires that the movement is performed in a maximum time-window.

0690X000009YywsQAC.png

Attached the Unico FSM example.

Regards