cancel
Showing results for 
Search instead for 
Did you mean: 

LIS2DH 6D mode not working properly

vcaia.1
Associate II

Hello,

I am trying to implement 6D mode. I am following 1:1 the code documented in the design tip DT0097.

I have been trying for a while: I2C interface is working and other modes of LIS2DH work properly.

As a safety measure, during the init I reset all registers back to their default value.

I read IRQ_SRC as soon as the INT1 line is raised.

However, the behavior is not as expected:

I do get interrupts when I move the board, but:

  • If I move the board, I usually have 2 consecutive very near interrupts. The second is always with all the flags "low" set.
  • The value in the flags is wrong: even with horizontal position I never get neutral X an Y, or even Z if I put the board in vertical
  • The threshold, duration and registers seems to have no effect whatsoever
  • If I rotate very slowly the board, I can succeed to flip it without triggering any interrupt

In the interrupt, I simply read INT1_SRC, that should be enough, right?

This is an example of events I get while flipping the Z axis of the board. Val is the (hex) value of INT1_SRC, while the rest is the string is my decoding of it.

Do you have any hint or fully-fledged example?

val:66 XU YD ZU

val:15 XD YD ZD

val:65 XD YD ZU

val:15 XD YD ZD

val:66 XU YD ZU

val:15 XD YD ZD

val:56 XU YD ZD

val:15 XD YD ZD

val:69 XD YU ZU

val:15 XD YD ZD

val:59 XD YU ZD

val:15 XD YD ZD

6 REPLIES 6
Eleon BORLINI
ST Employee

Hi @vcaia.1​ , you can refer to the LIS3DH application note for a further description of the 6D/4D orientation detection, even if the device is not exactly your LIS2DH (AN3308 p.28, LINK).

0693W000000Uhi6QAC.png

Can you please check if your are following the described steps in your code? Regards

Thank you Eleon.

Yes, I read also that one document, it is not of any help.

This is my initalization code

void accel_flip_detection(void)
{
	uint8_t i2cdata[2];
	twi_master_init();
 
	ADDR = 0x30;
 
	i2cdata[0] = CTRL_REG5;
	i2cdata[1] = BOOT; 			//reset memory
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
		
	i2cdata[0] = CTRL_REG1;
	i2cdata[1] = 0x00;			//Stop
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
		
	i2cdata[0] = CTRL_REG2;
	i2cdata[1] = 0x00;			//default
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
		
	//CTRL_REG3
	i2cdata[0] = CTRL_REG3;
	i2cdata[1] = I1_AOI1;									// AOI1 interrupt generation is	routed to INT1 pin.
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);	
 
	//CTRL_REG4
	i2cdata[0] = CTRL_REG4;
	i2cdata[1] = 0; //+-2g
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);	
 
	i2cdata[0] = CTRL_REG5;
	i2cdata[1] = 0x00;			
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
 
	i2cdata[0] = CTRL_REG6;
	i2cdata[1] = 0x00;			//default
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
 
	//INT1_CFG -> interrupts on INT1
	i2cdata[0] = INT1_CFG;
	i2cdata[1] = AOI | d6D | ZHIE | ZLIE | YHIE | YLIE | XHIE | XLIE;
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
 
	uint8_t ths = 0x21;
	i2cdata[0] = INT1_THS;
	i2cdata[1] = ths;
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
 
	uint8_t duration = 0x20;
	i2cdata[0] = INT1_DURATION;
	i2cdata[1] = duration;
  twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
		
  //not needed, added as safety measure
	i2cdata[0] = REFERENCE;
	i2cdata[1] = 0x00;
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);						//write address to read
 
	i2cdata[0] = FIFO_CTRL_REG;
	i2cdata[1] = 0x00;
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
 
	i2cdata[0] = 0x34;
	i2cdata[1] = 0x00;
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
	i2cdata[0] = 0x35;
	i2cdata[1] = 0x00;
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
	i2cdata[0] = 0x36;
	i2cdata[1] = 0x00;
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
	i2cdata[0] = 0x37;
	i2cdata[1] = 0x00;
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
	i2cdata[0] = 0x38;
	i2cdata[1] = 0x00;
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
	i2cdata[0] = 0x3a;
	i2cdata[1] = 0x00;
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
	i2cdata[0] = 0x3b;
	i2cdata[1] = 0x00;
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
	i2cdata[0] = 0x3c;
	i2cdata[1] = 0x00;
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
	i2cdata[0] = 0x3d;
	i2cdata[1] = 0x00;
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
	i2cdata[0] = 0x3e;
	i2cdata[1] = 0x00;
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
	i2cdata[0] = 0x3f;
	i2cdata[1] = 0x00;
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
 
 
	//CTRL_REG1 start Low power
	i2cdata[0] = CTRL_REG1;
	i2cdata[1] = ODR_25 | LPen | Zen | Yen | Xen;			// Set LIS3DH to low power mode with ODR = 25Hz.
	twi_master_transfer(ADDR | WRITE, i2cdata, 2, true);
 
	delay_ms(1);
}

And this is the ISR routine

void ACCEL_releaseInt1(void)
{
	static uint8_t last_orientation = 0x00;
	uint8_t i2cdata[2];
	ADDR = 0x30;
	twi_master_init();
 
	i2cdata[0] = INT1_SRC;
	twi_master_transfer(ADDR | WRITE, i2cdata, 1, false);
	twi_master_transfer(ADDR | READ, i2cdata, 1, true);
	uint8_t ir = (i2cdata[0] & 0b00111111); //current orientation
 
//	0b000100, //a
//	0b000010, //b
//	0b000001, //c
//	0b001000, //d
//	0b100000, //e
//	0b010000 //f
 
	char str[10];
	if (ir != last_orientation)
	{
		PRu8hex(str, i2cdata[0]);
		uart_putstring_buf((uint8_t*)"val:");
		uart_putstring_buf((uint8_t*)str);
 
		if (ir & 0b000010)
			uart_putstring_buf((uint8_t*)" XU");
		else if (ir & 0b000001)
			uart_putstring_buf((uint8_t*)" XD");
		else
			uart_putstring_buf((uint8_t*)" X-");
 
		if (ir & 0b0001000)
			uart_putstring_buf((uint8_t*)" YU");
		else if (ir & 0b000100)
			uart_putstring_buf((uint8_t*)" YD");
		else
			uart_putstring_buf((uint8_t*)" Y-");
 
		if (ir & 0b100000)
			uart_putstring_buf((uint8_t*)" ZU");
		else if (ir & 0b10000)
			uart_putstring_buf((uint8_t*)" ZD");
		else
			uart_putstring_buf((uint8_t*)" Z-");
 
		uart_putstring_buf((uint8_t*)"\n");
	}
 
	last_orientation = ir;
}

But I tried dozen of different combinations with no better outcome...

vcaia.1
Associate II

Good morning,

I tried to achieve the same result doing a simple inertial wake up on axis z, as per the application note you posted. So, I expect an interrupt when axis Z value is above a certain value (so the board is laying on one of the two faces).

The results are the same: I get 2 IRQs every time, and the INT1_SRC doesn't show the real condition. It's almost like hp filter is active, because I always end up with lower poart of INT1_SRC = 0x15 (all the "low" IRQs).

Hi @vcaia.1​ , thank you for the detailed analysis. Can you try with modifying the interrupt duration? You can do it either latching the interrupt, i.e. setting to '1' the LIR_INT1 of the CTRL_REG5 (24h) register or directly changing the duration of the interrupt itself, by modifying the register content in the INT1_DURATION (33h) register. Regards

I tried that, but I tried again now based on my code posted above.

LIR_INT1 has no effect, I see no difference.

Duration is already 0x20. (that should be 1280ms @25hz). Even if I put that one to 0x7f (5s!)I see no increased delay between events.

I understand the duration register as the time the event has to last in order to trigger the interrupt (e.g. the Z axis must be > the threshold for 5s) is it correct?

Or is it just the duration of the pulse on INT1 and it's enough to have one sample over the threshold?

So one problem looks to be that ISR routine was called both on rising and falling edge. This has been solved now, but I still get some unwanted results, when moving the board really slow.