2019-02-05 08:54 AM
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.
Enjoy!
2019-07-21 04:27 PM
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
}
2019-07-22 07:28 AM
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.
Attached the Unico FSM example.
Regards