Skip to main content
Visitor II
March 25, 2020
Question

LIS2DH 6D mode not working properly

  • March 25, 2020
  • 2 replies
  • 1203 views

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

    This topic has been closed for replies.

    2 replies

    ST Employee
    March 25, 2020

    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

    vcaia.1Author
    Visitor II
    March 25, 2020

    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.1Author
    Visitor II
    March 26, 2020

    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).

    ST Employee
    March 26, 2020

    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

    vcaia.1Author
    Visitor II
    March 26, 2020

    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?