2021-04-09 04:21 AM
Hi,
I can't find any examples of using commands in the statemachines.
I want to create a tilt sensor, by using 2 statemachines, 1 is monitoring x axis, the other z axis.
To keep it simple i will add the code for the x axis only .
This statemachine setup should do the same as this equivalent in c :
If ((x<THRS1) || (x>THRS1)) -> trigger the interrupt pin
This does not seem to work, what do i overlook?
Triggerlevel goes from 1 to 255, i use this to set the sensitivity of the detection
// 1 get the current x, y , z values to determine how the PCB is fixed in the cabinet
lis3dsh_update_xyz();
triggerlevel = MAX_SENSITIVITY/sensitivity;
buf[0] = CTRL_REG3;
buf[1] = 0x48; // INT1 pin active '1'
if(! lis3dsh_write(buf,2)) return false;
buf[0] = THRS2_1;
buf[1] = (lis3dsh.xyz.raw.x/256) + triggerlevel; //threshold to identify angle
if(! lis3dsh_write(buf,2)) return false;
buf[0] = THRS1_1;
buf[1] = (lis3dsh.xyz.raw.x/256) - triggerlevel; //threshold to identify angle in the other direction
if(! lis3dsh_write(buf,2)) return false;
buf[0] = MASK1_A;
buf[1] = 0xC0; //positive and negative axis enabled X as only
if(! lis3dsh_write(buf,2)) return false;
buf[0] = SETT1;
buf[1] = 0x21; //CONT can generate interrupt
if(! lis3dsh_write(buf,2)) return false;
// state machine
buf[0] = ST1_1;
buf[1] = JMP;
if(! lis3dsh_write(buf,2)) return false;
buf[0] = ST1_2;
buf[1] = RESET(GNTH2)|NEXT(LNTH1); // RESET = Shift left 4, NEXT = AND low nibble
if(! lis3dsh_write(buf,2)) return false; // if x greater then THRS2, jump to state4 - if x smaller then THRS1, jump to state4 , if none of the conditions are met -> retry next sample
buf[0] = ST1_3;
buf[1] = 0x44; // one of the conditions where fine , jump to ST1_4
if(! lis3dsh_write(buf,2)) return false;
buf[0] = ST1_4;
buf[1] = CONT;
if(! lis3dsh_write(buf,2)) return false;
buf[0] = CTRL_REG1; // Status machine 1 enabled
buf[1] = 0x01;
if(! lis3dsh_write(buf,2)) return false;
Solved! Go to Solution.
2021-04-16 03:46 AM
I managed to get it working while keeping it short and simple.
It does what it needs to : detecting when a PCB angle change for at least 300ms .
The PCB can be mounted in any orientation but all axis need to be 0,90,180 or 270° orientated. A slight offset (2000) is alowed.
Sensitivity can be set from 0 to 100% .
I hope this code can contribute.
#define SET_SENSITIVITY(PERCENT) (1+((101-PERCENT)*12000/256/100)) // 12000 = digital value for a manually decided maximum angle
bool lis3dsh_tiltdetect_init(void *pshock_tiltback, uint8_t sensitivity)
{
uint16_t timer2_val;
uint8_t triggerlevel;
lis3dsh.callback = pshock_tiltback;
lis3dsh.sensitivity = sensitivity;
uint8_t AxisMask=0;
uint8_t Thrs2_val;
if(sensitivity>100) sensitivity = 100;
triggerlevel = SET_SENSITIVITY(sensitivity);
lis3dsh_update_xyz();
timer2_val = TIMX(300); //time in which the angle must be validated
buf[0] = TIM2_1_L;
buf[1] = (uint8_t)timer2_val;
if(! lis3dsh_write(buf,2)) return false;
buf[0] = TIM2_1_H;
buf[1] = (uint8_t)(timer2_val>>8);
if(! lis3dsh_write(buf,2)) return false;
buf[0] = CTRL_REG3;
buf[1] = 0x48; // INT1 pin active '1'
if(! lis3dsh_write(buf,2)) return false;
if((lis3dsh.xyz.raw.x < 2000) && (lis3dsh.xyz.raw.x > -2000) && (lis3dsh.xyz.raw.y < 2000) && (lis3dsh.xyz.raw.y > -2000)){
AxisMask |= 0xF0;
if(lis3dsh.xyz.raw.x<0) lis3dsh.xyz.raw.x=-lis3dsh.xyz.raw.x;
Thrs2_val = (lis3dsh.xyz.raw.x/256) + (triggerlevel); //threshold to identify angle
}
if((lis3dsh.xyz.raw.y < 2000) && (lis3dsh.xyz.raw.y > -2000) && (lis3dsh.xyz.raw.z < 2000) && (lis3dsh.xyz.raw.z > -2000)){
AxisMask |= 0x3C;
if(lis3dsh.xyz.raw.y<0) lis3dsh.xyz.raw.y=-lis3dsh.xyz.raw.y;
Thrs2_val = (lis3dsh.xyz.raw.y/256) + (triggerlevel); //threshold to identify angle
}
if((lis3dsh.xyz.raw.x < 2000) && (lis3dsh.xyz.raw.x > -2000) && (lis3dsh.xyz.raw.z < 2000) && (lis3dsh.xyz.raw.z > -2000)){
AxisMask |= 0xCC;
if(lis3dsh.xyz.raw.x<0) lis3dsh.xyz.raw.x=-lis3dsh.xyz.raw.x;
Thrs2_val = (lis3dsh.xyz.raw.x/256) + (triggerlevel); //threshold to identify angle
}
if(AxisMask!=0){
buf[0] = THRS2_1;
buf[1] = Thrs2_val;
if(! lis3dsh_write(buf,2)) return false;
buf[0] = MASK1_A; // P_X N_X P_Y N_Y P_Z N_Z P_V N_V
buf[1] = AxisMask; // enabled AxisMask axis
if(! lis3dsh_write(buf,2)) return false;
buf[0] = SETT1; // P_DET THR3_SA ABS - - THR3_MA R_TAM SITR
buf[1] = 0x21; //ABS enabled, CONT can generate interrupt
if(! lis3dsh_write(buf,2)) return false;
// state machine
buf[0] = ST1_1;
buf[1] = RESET(LLTH2)|NEXT(TI2);
if(! lis3dsh_write(buf,2)) return false;
buf[0] = ST1_2;
buf[1] = CONT;
if(! lis3dsh_write(buf,2)) return false;
buf[0] = CTRL_REG1;
buf[1] = 0x01; //enable statemachine
if(! lis3dsh_write(buf,2)) return false;
}
else{
// no valid mounting position found
buf[0] = CTRL_REG1;
buf[1] = 0x00; //disable statemachine
if(! lis3dsh_write(buf,2)) return false;
return false;
}
return true;
}
2021-04-09 06:22 AM
Hi @sde c.1 ,
I would suggest you first to check the DT0077 Design tip, that describes some examples for the configuration of the FSM in the LIS3DSH.
A way to deal with the tilt example could be the following one:
By the way, there are a lot of more example for the FSM of LSM6DSO(X) sensors' family, that is similar in the core to the one, but has much more literature: for this, I suggest you the AN5226 application note and the C Github examples.
-Eleon
2021-04-12 06:37 AM
thank you ! i will look into the stuff you send me :folded_hands:
2021-04-13 07:32 AM
does not work, and examples doesn't help eather.
Any idea why my inititial code does not work ?
This code i created according the above example. Datarate = 100
buf[0] = CTRL_REG3;
buf[1] = 0x48; // INT1 pin active '1'
if(! lis3dsh_write(buf,2)) return false;
timer_val = TIMX(240); //time between detection in ms
buf[0] = TIM1_1_L;
buf[1] = (uint8_t)timer_val;
if(! lis3dsh_write(buf,2)) return false;
buf[0] = TIM1_1_H;
buf[1] = (uint8_t)(timer_val>>8);
if(! lis3dsh_write(buf,2)) return false;
timer_val = TIMX(600); //time between detection in ms
buf[0] = TIM2_1_L;
buf[1] = (uint8_t)timer_val;
if(! lis3dsh_write(buf,2)) return false;
buf[0] = TIM2_1_H;
buf[1] = (uint8_t)(timer_val>>8);
if(! lis3dsh_write(buf,2)) return false;
buf[0] = THRS1_1;
buf[1] = SHOCK_SENSITIVITY(lis3dsh.interrupt_sensitivity); //threshold to identify the shock
if(! lis3dsh_write(buf,2)) return false;
buf[0] = MASK1_A;
buf[1] = 0x80; //positive and negative axis enabled
if(! lis3dsh_write(buf,2)) return false;
buf[0] = SETT1;
buf[1] = 0x21; //peak detection enabled, CONT can generate interrupt
if(! lis3dsh_write(buf,2)) return false;
// state machine
buf[0] = ST1_1;
buf[1] = RESET(NOP)|NEXT(GNTH1); // peak axis must be below THRS1 for TIM2 time
if(! lis3dsh_write(buf,2)) return false;
buf[0] = ST1_2;
buf[1] = RESET(LNTH1)|NEXT(TI1);
if(! lis3dsh_write(buf,2)) return false; // wait till peak axis higher then THRS2
buf[0] = ST1_3;
buf[1] = SRP;
if(! lis3dsh_write(buf,2)) return false;
buf[0] = ST1_4;
buf[1] = RESET(NOP)|NEXT(LNTH1);
if(! lis3dsh_write(buf,2)) return false;
buf[0] = ST1_5;
buf[1] = RESET(GNTH1)|NEXT(TI2);
if(! lis3dsh_write(buf,2)) return false;
buf[0] = ST1_6;
buf[1] = CRP;
if(! lis3dsh_write(buf,2)) return false;
buf[0] = CTRL_REG1;
buf[1] = 0x01;
if(! lis3dsh_write(buf,2)) return false;
return true;
2021-04-15 05:15 AM
Hi @sde c.1 ,
have you check whether the read/write operation actually correctly configure the registers, right?
And which threshold are you setting in this point of the code? --> SHOCK_SENSITIVITY (Line 26)
-Eleon
2021-04-16 03:46 AM
I managed to get it working while keeping it short and simple.
It does what it needs to : detecting when a PCB angle change for at least 300ms .
The PCB can be mounted in any orientation but all axis need to be 0,90,180 or 270° orientated. A slight offset (2000) is alowed.
Sensitivity can be set from 0 to 100% .
I hope this code can contribute.
#define SET_SENSITIVITY(PERCENT) (1+((101-PERCENT)*12000/256/100)) // 12000 = digital value for a manually decided maximum angle
bool lis3dsh_tiltdetect_init(void *pshock_tiltback, uint8_t sensitivity)
{
uint16_t timer2_val;
uint8_t triggerlevel;
lis3dsh.callback = pshock_tiltback;
lis3dsh.sensitivity = sensitivity;
uint8_t AxisMask=0;
uint8_t Thrs2_val;
if(sensitivity>100) sensitivity = 100;
triggerlevel = SET_SENSITIVITY(sensitivity);
lis3dsh_update_xyz();
timer2_val = TIMX(300); //time in which the angle must be validated
buf[0] = TIM2_1_L;
buf[1] = (uint8_t)timer2_val;
if(! lis3dsh_write(buf,2)) return false;
buf[0] = TIM2_1_H;
buf[1] = (uint8_t)(timer2_val>>8);
if(! lis3dsh_write(buf,2)) return false;
buf[0] = CTRL_REG3;
buf[1] = 0x48; // INT1 pin active '1'
if(! lis3dsh_write(buf,2)) return false;
if((lis3dsh.xyz.raw.x < 2000) && (lis3dsh.xyz.raw.x > -2000) && (lis3dsh.xyz.raw.y < 2000) && (lis3dsh.xyz.raw.y > -2000)){
AxisMask |= 0xF0;
if(lis3dsh.xyz.raw.x<0) lis3dsh.xyz.raw.x=-lis3dsh.xyz.raw.x;
Thrs2_val = (lis3dsh.xyz.raw.x/256) + (triggerlevel); //threshold to identify angle
}
if((lis3dsh.xyz.raw.y < 2000) && (lis3dsh.xyz.raw.y > -2000) && (lis3dsh.xyz.raw.z < 2000) && (lis3dsh.xyz.raw.z > -2000)){
AxisMask |= 0x3C;
if(lis3dsh.xyz.raw.y<0) lis3dsh.xyz.raw.y=-lis3dsh.xyz.raw.y;
Thrs2_val = (lis3dsh.xyz.raw.y/256) + (triggerlevel); //threshold to identify angle
}
if((lis3dsh.xyz.raw.x < 2000) && (lis3dsh.xyz.raw.x > -2000) && (lis3dsh.xyz.raw.z < 2000) && (lis3dsh.xyz.raw.z > -2000)){
AxisMask |= 0xCC;
if(lis3dsh.xyz.raw.x<0) lis3dsh.xyz.raw.x=-lis3dsh.xyz.raw.x;
Thrs2_val = (lis3dsh.xyz.raw.x/256) + (triggerlevel); //threshold to identify angle
}
if(AxisMask!=0){
buf[0] = THRS2_1;
buf[1] = Thrs2_val;
if(! lis3dsh_write(buf,2)) return false;
buf[0] = MASK1_A; // P_X N_X P_Y N_Y P_Z N_Z P_V N_V
buf[1] = AxisMask; // enabled AxisMask axis
if(! lis3dsh_write(buf,2)) return false;
buf[0] = SETT1; // P_DET THR3_SA ABS - - THR3_MA R_TAM SITR
buf[1] = 0x21; //ABS enabled, CONT can generate interrupt
if(! lis3dsh_write(buf,2)) return false;
// state machine
buf[0] = ST1_1;
buf[1] = RESET(LLTH2)|NEXT(TI2);
if(! lis3dsh_write(buf,2)) return false;
buf[0] = ST1_2;
buf[1] = CONT;
if(! lis3dsh_write(buf,2)) return false;
buf[0] = CTRL_REG1;
buf[1] = 0x01; //enable statemachine
if(! lis3dsh_write(buf,2)) return false;
}
else{
// no valid mounting position found
buf[0] = CTRL_REG1;
buf[1] = 0x00; //disable statemachine
if(! lis3dsh_write(buf,2)) return false;
return false;
}
return true;
}
2021-04-20 07:04 AM
Hi @sde c.1 ,
glad to hear you solved at least partially your issue.
You now need to detect a variation of a tilt angle from 0deg, 90deg and multiples on all the 3 axis that lasts more than 300ms, am I right?
In this case, after having compensated the initial offset for each axis, you should check when the single axis senses the 1000mg gravity vector, so you could program a machine that check (also simultaneously) whether an axis has exceeded, for example, the 900mg threshold for more than 300ms (applying a proper mask, and then you can infer if: for example, if the FSM output is '0' '0' '1' (x y z), you'll know that the device is in flat position, with the z axis pointing out of the table.
If you get '0', '0', '0', you'll be in an orientation different from 90° and multiples on each axis.
-Eleon
2021-04-21 02:18 AM
Hi Eleon, i did not have questions anymore, it acts exactly as i want now. Just wanted to share my solution with the world.
2021-04-21 02:25 AM
ah ok :D
I selected your answer as "Best" for the world
-Eleon
2021-04-21 02:26 AM
=)