cancel
Showing results for 
Search instead for 
Did you mean: 

Examples Operation codes for commands for LS3DSH

sde c.1
Senior II

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;

1 ACCEPTED SOLUTION

Accepted Solutions
sde c.1
Senior II

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;
}

View solution in original post

9 REPLIES 9
Eleon BORLINI
ST Employee

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:

0693W000008z7NuQAI.png0693W000008z7O9QAI.png 

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

sde c.1
Senior II

thank you ! i will look into the stuff you send me :folded_hands:

sde c.1
Senior II

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;

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

sde c.1
Senior II

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;
}

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

sde c.1
Senior II

Hi Eleon, i did not have questions anymore, it acts exactly as i want now. Just wanted to share my solution with the world.

ah ok :D

I selected your answer as "Best" for the world

-Eleon

sde c.1
Senior II

=)