Skip to main content
Visitor II
September 12, 2020
Solved

ISM330DLC: Interrupt on Linux

  • September 12, 2020
  • 3 replies
  • 6078 views

Hello,

I'm try using ISM330DLC connect to Linux OS on board IMX8MP via I2C

Linux supported driver for this device (iio/imu/st_lsm6dsx); I added to dts file as below:

&i2c5 {
	clock-frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c5>;
	pinctrl-assert-gpios = <&pca6416 2 GPIO_ACTIVE_HIGH>; /* i2c5 pin conflict with can1: default gpio low select can1, gpio high select i2c5 */
	status = "okay";
 
	ism330dlc@6b {
		compatible = "st,ism330dlc";
		reg = <0x6b>;
		st,drdy-int-pin = <1>;
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_ioexp_int>;
		interrupt-parent = <&gpio1>;
		interrupts = <12 IRQ_TYPE_EDGE_RISING>;
	};
};

But I didn't see any interrupt signal to Linux

# cat /proc/interrupts | grep 12
 6: 12073 10115 14187 8714 GPCv2 i.MX8MQ 47 Level timer@306a0000
 38: 127 0 0 0 GPCv2 i.MX8MQ 76 Level 30ad0000.i2c
 46: 6787 0 0 0 GPCv2 i.MX8MQ 120 Level 30be0000.ethernet
 50: 0 0 0 0 GPCv2 i.MX8MQ 122 Level 30c90000.easrc
 56: 0 0 0 0 GPCv2 i.MX8MQ 128 Level 30cc0000.xcvr
 57: 0 0 0 0 GPCv2 i.MX8MQ 129 Level 30cc0000.xcvr
 95: 0 0 0 0 gpio-mxc 12 Edge lsm6dsx
127: 0 0 0 0 gpio-mxc 12 Edge 30b50000.mmc cd

could you give some recommend to resolve this issue ?

Thanks in advance !

tam do

    This topic has been closed for replies.
    Best answer by Tdo.1

    Resolved:

    In my case, I have to do more steps with this driver to resolve issue:

    • Enable pulsed data-ready mode instead of Latch mode
    • Enable master DRDY on INT1
    • Change interrupt type flag from IRQF_TRIGGER_HIGH to IRQF_TRIGGER_RISING (modification in device tree is not effect)
    diff --git a/drivers/iio/imu/st_ism330dlc/st_ism330dlc_core.c b/drivers/iio/imu/st_ism330dlc/st_ism330dlc_core.c
    index 998d234..d326d74 100644
    --- a/drivers/iio/imu/st_ism330dlc/st_ism330dlc_core.c
    +++ b/drivers/iio/imu/st_ism330dlc/st_ism330dlc_core.c
    @@ -117,6 +117,14 @@
     #define ST_ISM330DLC_SELFTEST_FAIL_MS			"fail"
     #define ST_ISM330DLC_SELFTEST_PASS_MS			"pass"
     
    +
    +#define ST_ISM330DLC_DRDY_PULSED_ADDR		0x0b
    +#define ST_ISM330DLC_DRDY_PULSED_MASK		0x80
    +
    +#define ST_ISM330DLC_DRDY_ON_INT1_ADDR		0x1a
    +#define ST_ISM330DLC_DRDY_ON_INT1_MASK		0x80
    +
    +
     /* CUSTOM VALUES FOR ACCEL SENSOR */
     #define ST_ISM330DLC_ACCEL_ODR_ADDR			0x10
     #define ST_ISM330DLC_ACCEL_ODR_MASK			0xf0
    @@ -1723,10 +1731,10 @@ static int st_ism330dlc_init_sensor(struct ism330dlc_data *cdata)
     	msleep(200);
     
     	/* Latch interrupts */
    -	err = st_ism330dlc_write_data_with_mask(cdata, ST_ISM330DLC_LIR_ADDR,
    -				ST_ISM330DLC_LIR_MASK, ST_ISM330DLC_EN_BIT, true);
    -	if (err < 0)
    -		return err;
    +//	err = st_ism330dlc_write_data_with_mask(cdata, ST_ISM330DLC_LIR_ADDR,
    +//				ST_ISM330DLC_LIR_MASK, ST_ISM330DLC_EN_BIT, true);
    +//	if (err < 0)
    +//		return err;
     
     	/* Enable BDU for sensors data */
     	err = st_ism330dlc_write_data_with_mask(cdata, ST_ISM330DLC_BDU_ADDR,
    @@ -1741,6 +1749,15 @@ static int st_ism330dlc_init_sensor(struct ism330dlc_data *cdata)
     	if (err < 0)
     		return err;
     
    +	/* Enable pulsed data-ready mode */
    +	err = st_ism330dlc_write_data_with_mask(cdata,
    +					ST_ISM330DLC_DRDY_PULSED_ADDR,
    +					ST_ISM330DLC_DRDY_PULSED_MASK,
    +					ST_ISM330DLC_EN_BIT, true);
    +	if (err < 0)
    +		return err;
    +
    +
     	/* Redirect INT2 on INT1, all interrupt will be available on INT1 */
     	err = st_ism330dlc_write_data_with_mask(cdata,
     					ST_ISM330DLC_INT2_ON_INT1_ADDR,
    @@ -1749,6 +1766,14 @@ static int st_ism330dlc_init_sensor(struct ism330dlc_data *cdata)
     	if (err < 0)
     		return err;
     
    +	/* Enable master DRDY on INT1 */
    +	err = st_ism330dlc_write_data_with_mask(cdata,
    +					ST_ISM330DLC_DRDY_ON_INT1_ADDR,
    +					ST_ISM330DLC_DRDY_ON_INT1_MASK,
    +					ST_ISM330DLC_EN_BIT, true);
    +	if (err < 0)
    +		return err;
    +
     	return st_ism330dlc_get_drdy_reg(cdata, &cdata->drdy_reg);
     }
     
    diff --git a/drivers/iio/imu/st_ism330dlc/st_ism330dlc_trigger.c b/drivers/iio/imu/st_ism330dlc/st_ism330dlc_trigger.c
    index 98038b5..07e887f 100644
    --- a/drivers/iio/imu/st_ism330dlc/st_ism330dlc_trigger.c
    +++ b/drivers/iio/imu/st_ism330dlc/st_ism330dlc_trigger.c
    @@ -132,7 +132,7 @@ int st_ism330dlc_allocate_triggers(struct ism330dlc_data *cdata,
     	}
     
     	err = request_threaded_irq(cdata->irq, NULL, ism330dlc_irq_management,
    -				 IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
    +				 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
     				 cdata->name, cdata);
     	if (err)
     		goto deallocate_trigger;
     

    Note: When integrating to new version of kernel as 5.x, need to change api 'get_monotonic_boottime' to 'ktime_get_ts' in a few code statements.

    3 replies

    ST Employee
    September 16, 2020

    Hi @Tdo.1​ ,

    I'm not an expert of Linux environment, so I'm waiting for internal expert feedback.

    You wrote:

    >> Linux supported driver for this device (iio/imu/st_lsm6dsx); I added to dts file

    Please note however that there are official linux driver at THIS link for the ISM330DLC, especially the st_ism330dlc_i2c.c and st_ism330dlc_i2c_master.c files for the I2C peripheral configuration.

    Let me know if they can help you for your purpose.

    -Eleon

    Tdo.1Author
    Visitor II
    September 17, 2020

    Hi @Eleon BORLINI​ 

    Thank you for reply

    I integrated driver from your link to my current Linux (5.4.24), it's same result as before. I only can ONESHOT conversions by reading `/sys/bus/iio/devices/iio:device0/in_accel_y_raw`

    my dts for ISM330DLC:

    ism330dlc@6b {
    		compatible = "st,ism330dlc";
    		reg = <0x6b>;
    		pinctrl-names = "default";
    		pinctrl-0 = <&pinctrl_ioexp_int>;
    		interrupt-parent = <&gpio1>;
    		interrupts = <12 IRQ_TYPE_LEVEL_HIGH>;
    		st,drdy-int-pin = <1>;
    	};

    I also tested with other IMU as a reference (MPU6050). I connected MPU6050 same as ISM330DLC to board (same I2C, GPIO pin on IMX board) and MPU6050 was worked.

    DTS for MPU6050:

    inv-mpu6050@68 {
    		compatible = "invensense,mpu6050";
    		reg = <0x68>;
    		pinctrl-names = "default";
    		pinctrl-0 = <&pinctrl_ioexp_int>;
    		interrupt-parent = <&gpio1>;
    		interrupts = <12 IRQ_TYPE_EDGE_RISING>;
    		mount-matrix = "-0.984807753012208", /* x0 */
    				"0", /* y0 */
    				"-0.173648177666930", /* z0 */
    				"0", /* x1 */
    				"-1", /* y1 */
    				"0", /* z1 */
    				"-0.173648177666930", /* x2 */
    				"0", /* y2 */
    				"0.984807753012208"; /* z2 */
    	};

    I'm not sure connector between ISM330DLC and board maybe a problem or no :(

    ST Employee
    September 17, 2020

    Hi @Tdo.1​ ,

    can you check if the ISM330DLC INT1 or INT2 pins have been routed out on the IMX8MP?

    The data ready (DRDY) signal can be for example routed on INT1 physical pin enabling the data ready setting to 1 the INT1_DRDY_XL of INT1_CTRL (0Dh) and writing the DRDY_ON_INT1 bit of MASTER_CONFIG (1Ah) register.

    Just to check if it is not an hardware problem...

    -Eleon

    Tdo.1Author
    Visitor II
    September 18, 2020

    Hi @Eleon BORLINI​ ,

    I connected INT1 pin to a GPIO pin on the IMX8MP.

    • After insmode module, I use oscilloscope to check signal on INT1 pin, value is always LOW (0).
    • After I enable IIO trigger mode by writing 1 to `/sys/bus/iio/devices/iio:device0/buffer/enable​`, out of INT1 almost in HIGH level (..1111110111111101111111111...) when checking value of gpio (gpio503 on Linux) that connecting to INT1 pin , and value is almost 1, sometime it's 0;
    echo 503 > /sys/class/gpio/export
    watch -n 1 cat /sys/class/gpio/gpio503/value
    1

    • The same when reading iio buffer by: `xxd /dev/iio:device0`, value is almost HIGH.
    Tdo.1AuthorAnswer
    Visitor II
    September 21, 2020

    Resolved:

    In my case, I have to do more steps with this driver to resolve issue:

    • Enable pulsed data-ready mode instead of Latch mode
    • Enable master DRDY on INT1
    • Change interrupt type flag from IRQF_TRIGGER_HIGH to IRQF_TRIGGER_RISING (modification in device tree is not effect)
    diff --git a/drivers/iio/imu/st_ism330dlc/st_ism330dlc_core.c b/drivers/iio/imu/st_ism330dlc/st_ism330dlc_core.c
    index 998d234..d326d74 100644
    --- a/drivers/iio/imu/st_ism330dlc/st_ism330dlc_core.c
    +++ b/drivers/iio/imu/st_ism330dlc/st_ism330dlc_core.c
    @@ -117,6 +117,14 @@
     #define ST_ISM330DLC_SELFTEST_FAIL_MS			"fail"
     #define ST_ISM330DLC_SELFTEST_PASS_MS			"pass"
     
    +
    +#define ST_ISM330DLC_DRDY_PULSED_ADDR		0x0b
    +#define ST_ISM330DLC_DRDY_PULSED_MASK		0x80
    +
    +#define ST_ISM330DLC_DRDY_ON_INT1_ADDR		0x1a
    +#define ST_ISM330DLC_DRDY_ON_INT1_MASK		0x80
    +
    +
     /* CUSTOM VALUES FOR ACCEL SENSOR */
     #define ST_ISM330DLC_ACCEL_ODR_ADDR			0x10
     #define ST_ISM330DLC_ACCEL_ODR_MASK			0xf0
    @@ -1723,10 +1731,10 @@ static int st_ism330dlc_init_sensor(struct ism330dlc_data *cdata)
     	msleep(200);
     
     	/* Latch interrupts */
    -	err = st_ism330dlc_write_data_with_mask(cdata, ST_ISM330DLC_LIR_ADDR,
    -				ST_ISM330DLC_LIR_MASK, ST_ISM330DLC_EN_BIT, true);
    -	if (err < 0)
    -		return err;
    +//	err = st_ism330dlc_write_data_with_mask(cdata, ST_ISM330DLC_LIR_ADDR,
    +//				ST_ISM330DLC_LIR_MASK, ST_ISM330DLC_EN_BIT, true);
    +//	if (err < 0)
    +//		return err;
     
     	/* Enable BDU for sensors data */
     	err = st_ism330dlc_write_data_with_mask(cdata, ST_ISM330DLC_BDU_ADDR,
    @@ -1741,6 +1749,15 @@ static int st_ism330dlc_init_sensor(struct ism330dlc_data *cdata)
     	if (err < 0)
     		return err;
     
    +	/* Enable pulsed data-ready mode */
    +	err = st_ism330dlc_write_data_with_mask(cdata,
    +					ST_ISM330DLC_DRDY_PULSED_ADDR,
    +					ST_ISM330DLC_DRDY_PULSED_MASK,
    +					ST_ISM330DLC_EN_BIT, true);
    +	if (err < 0)
    +		return err;
    +
    +
     	/* Redirect INT2 on INT1, all interrupt will be available on INT1 */
     	err = st_ism330dlc_write_data_with_mask(cdata,
     					ST_ISM330DLC_INT2_ON_INT1_ADDR,
    @@ -1749,6 +1766,14 @@ static int st_ism330dlc_init_sensor(struct ism330dlc_data *cdata)
     	if (err < 0)
     		return err;
     
    +	/* Enable master DRDY on INT1 */
    +	err = st_ism330dlc_write_data_with_mask(cdata,
    +					ST_ISM330DLC_DRDY_ON_INT1_ADDR,
    +					ST_ISM330DLC_DRDY_ON_INT1_MASK,
    +					ST_ISM330DLC_EN_BIT, true);
    +	if (err < 0)
    +		return err;
    +
     	return st_ism330dlc_get_drdy_reg(cdata, &cdata->drdy_reg);
     }
     
    diff --git a/drivers/iio/imu/st_ism330dlc/st_ism330dlc_trigger.c b/drivers/iio/imu/st_ism330dlc/st_ism330dlc_trigger.c
    index 98038b5..07e887f 100644
    --- a/drivers/iio/imu/st_ism330dlc/st_ism330dlc_trigger.c
    +++ b/drivers/iio/imu/st_ism330dlc/st_ism330dlc_trigger.c
    @@ -132,7 +132,7 @@ int st_ism330dlc_allocate_triggers(struct ism330dlc_data *cdata,
     	}
     
     	err = request_threaded_irq(cdata->irq, NULL, ism330dlc_irq_management,
    -				 IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
    +				 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
     				 cdata->name, cdata);
     	if (err)
     		goto deallocate_trigger;
     

    Note: When integrating to new version of kernel as 5.x, need to change api 'get_monotonic_boottime' to 'ktime_get_ts' in a few code statements.

    ST Employee
    September 22, 2020

    Hi @Tdo.1​ ,

    thank you very much for your follow up on resolved case :smiling_face_with_smiling_eyes:

    ...and sorry for coming back to you late.

    -Eleon