Re: lsm303dlhc magnetometer: please help

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



---- Message d'origine ----
> De : Jonathan Cameron <jic23@xxxxxxxxxx>
> À : yarl-baudig@xxxxxxxxxx
> Sujet : Re: lsm303dlhc magnetometer: please help
> Date : 05/04/2020 15:03:56 Europe/Paris
> Copie à : denis.ciocca@xxxxxx;
>       linux-iio@xxxxxxxxxxxxxxx
> 
> On Sat,  4 Apr 2020 14:43:04 +0200 (CEST)
> yarl-baudig@xxxxxxxxxx wrote:
> 
> > Good afternoun,
> > 
> > I have an lsm303dlhc that I'm trying to get to work with a triggered 
> buffer, the magnetometer part of it.
> > The problem with this sensor is that the dataready signal has, I think, a 
> different
> > meaning than the one expected by the ST sensor driver set.
> > On this sensor the signal is always high except when the sensor is writing 
> new values to its data
> > registers. The problem with the driver is that it expects the sensor to 
> have a register
> > to check if new data is available:
> > https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git/tree/drivers/
> iio/common/st_sensors/st_sensors_trigger.c?h=testing#n36
> > the lsm303dlhc magnetometer is not configured with such a register:
> > https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git/tree/drivers/
> iio/magnetometer/st_magn_core.c?h=testing#n183
> > There is one in the sensor but the dataready bit is just the value of the 
> signal, so
> > even if I added the address and mask for this information, the meaning 
> would be
> > wrong from the point of view of  function and the while loop would run 
> endlessly:
> > https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git/tree/drivers/
> iio/common/st_sensors/st_sensors_trigger.c?h=testing#n113
> > 
> Looking at the datasheet, it is a rather dumb device isn't it and the 
> datasheet
> doesn't supply anywhere near enough info..  It says it's a system in 
> package
> so in theory we could find out what the sensor actually is and that might
> have a better datasheet.
> 
> Then we have the data ready bit as you say and a lock bit that fires when 
> we
> successfully start reading (ensuring we get a full set from the same 
> 'scan')
> The dataready bit description says:
> "Data-ready bit. This bit is when a new set of measurements is available."
> I admit I'm reading between the lines, but that sounds like it will clear 
> when
> the data has been read.  If it clears on it's own then there isn't much
> we can do reliably.
> 
> We could just treat the irq as a iio-trigger-interrupt trigger as long as we 
> definitely don't
> need to do anything to clear it.  That will not hit any of the paths you 
> are
> looking at as will directly call st_sensors_trigger_handler.
> 
> Unfortunately that doesn't seem to have a device tree binding yet 
> (obviously
> not much used except on very old platforms). I don't have a handy platform 
> to
> test it on at the moment unfortunately but should just be a case of adding
> a device tree id table to the driver.  Then the dt entry will simply 
> contain
> the interrupt line.
> 
> Denis, any more info on this part and whether the using a dumb interrupt 
> trigger
> is the way to go or if we can do anything more clever?
> 
> It may be a case where the best bet is to ignore that line and use a high
> resolution time trigger running at half the raw sampling frequency of the 
> device
> (to avoid repeated values)
> 
> Thanks,
> 
> Jonathan
> 

Thank you for answering. I will probably try as you say, use an hrtimer.

Anyway I want to precise one thing I just saw using the patch I showed you.
The lsm303dlhc contains an accelerometer and a magnetometer.
When the buffer for the accelerometer is disabled, the magnetometer "works"
the way I described in my last mail: one out of two times.
When the buffer for the accelerometer is enabled: the magnetometer works,
every time...
> 
> > I then modified a bit, patch below.
> > 
> > Let me first tell you that it work one out of two time:
> > I boot, load this device-tree:
> > ---
> > /dts-v1/;
> > /plugin/;
> > 
> > / {
> >   compatible = "brcm,bcm2708";
> > 
> >   fragment@0 {
> >     target = <&gpio>;
> >     __overlay__ {
> >       magn_pins: nine_dof_pins {
> >         brcm,pins = <27>;
> >         brcm,function = <0>;
> >         brcm,pull = <1>;
> >         status = "okay";
> >       };
> >     };
> >   };
> > 
> >   fragment@1 {
> >     target = <&i2c_arm>;
> >     __overlay__ {
> >       status = "okay";
> >       #address-cells = <1>;
> >       #size-cells = <0>;
> >       magn@1e {
> >         compatible = "st,lsm303dlhc-magn";
> >         reg = <0x1e>;
> >         status = "okay";
> >         interrupt-parent = <&gpio>;
> >         interrupts = <27 1>;
> >       };
> >     };
> >   };
> > };
> > ---
> > I then enable scan_elements, enable buffer (echo 1 > buffer/enable)
> > interrupts are coming regularly at sampling_frequency. It works fine.
> > If I now disable the buffer then re-enable it, one and only interrupt,
> > doesn't work fine..
> > re-disable, re-re-enable: works fine!
> > and it seem to be always that, it works modulo 2.
> > 
> > On my first try I didn't change st_magn_buffer_preenable and 
> st_magn_buffer_postenable
> > But I thought that maybe, the problem was some sort of bad writting, 
> reading timing
> > because 
> > (1) request_threaded_irq is called for a rising signal while it is already 
> high.
> > 
> > I make a break here and ask you a question:
> > As you read, I am a kernel newbie: is doing (1) bad?
> Interesting question.  There is so little info in the datasheet that it is 
> hard
> to tell. It might be a level_high interrupt.
> 
> > end of break.
> > 
> > So I added st_magn_buffer_preenable and modified st_magn_buffer_postenable 
> to
> > try to mask the irq during the arppropriate interval.
> > 
> > No visible change.
> > I never almost never wrote kernel code before.
> > I tried to get closer to what was happening using gdb/kgdb, first time I 
> used this.
> > I am now pretty discouraged and any suggestions are welcome.
> > 
> > Thank you.
> > 
> > ---
> >  drivers/iio/common/st_sensors/st_sensors_core.c | 11 +++++++++++
> >  .../iio/common/st_sensors/st_sensors_trigger.c  |  9 +++++++++
> >  drivers/iio/magnetometer/st_magn_buffer.c       | 17 ++++++++++++++++-
> >  drivers/iio/magnetometer/st_magn_core.c         |  3 +++
> >  include/linux/iio/common/st_sensors.h           |  2 ++
> >  5 files changed, 41 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c 
> b/drivers/iio/common/st_sensors/st_sensors_core.c
> > index 09279e40c55c..fef6b70976b4 100644
> > --- a/drivers/iio/common/st_sensors/st_sensors_core.c
> > +++ b/drivers/iio/common/st_sensors/st_sensors_core.c
> > @@ -480,6 +480,17 @@ int st_sensors_set_dataready_irq(struct iio_dev 
> *indio_dev, bool enable)
> >  	u8 drdy_addr, drdy_mask;
> >  	struct st_sensor_data *sdata = iio_priv(indio_dev);
> >  
> > +	if (sdata->sensor_settings->drdy_irq.simple) {
> > +		/*
> > +		 * some devices very simple. No register to enable, disable
> > +		 * or configure the signal. Actually, when it is low it means that
> > +		 * sensor is writing data to its register, when it is high it
> > +		 * means that data can be read. i.e when rising new data is available.
> > +		 */
> > +		sdata->hw_irq_trigger = enable;
> > +		return 0;
> > +	}
> > +
> >  	if (!sdata->sensor_settings->drdy_irq.int1.addr &&
> >  	    !sdata->sensor_settings->drdy_irq.int2.addr) {
> >  		/*
> > diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c 
> b/drivers/iio/common/st_sensors/st_sensors_trigger.c
> > index fdcc5a891958..146aaae0a85c 100644
> > --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c
> > +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c
> > @@ -30,6 +30,13 @@ static int st_sensors_new_samples_available(struct 
> iio_dev *indio_dev,
> >  	u8 status;
> >  	int ret;
> >  
> > +	/* We simply trust the signal */
> > +	if (sdata->sensor_settings->drdy_irq.simple) {
> > +		if (indio_dev->active_scan_mask)
> > +			return 1;
> > +		return 0;
> > +	}
> > +
> >  	/* How would I know if I can't check it? */
> >  	if (!sdata->sensor_settings->drdy_irq.stat_drdy.addr)
> >  		return -EINVAL;
> > @@ -90,6 +97,8 @@ static irqreturn_t st_sensors_irq_thread(int irq, void 
> *p)
> >  	if (sdata->hw_irq_trigger &&
> >  	    st_sensors_new_samples_available(indio_dev, sdata)) {
> >  		iio_trigger_poll_chained(p);
> > +		if (sdata->sensor_settings->drdy_irq.simple)
> > +			return IRQ_HANDLED;
> >  	} else {
> >  		dev_dbg(sdata->dev, "spurious IRQ\n");
> >  		return IRQ_NONE;
> > diff --git a/drivers/iio/magnetometer/st_magn_buffer.c 
> b/drivers/iio/magnetometer/st_magn_buffer.c
> > index 37ab30566464..ae13e4339127 100644
> > --- a/drivers/iio/magnetometer/st_magn_buffer.c
> > +++ b/drivers/iio/magnetometer/st_magn_buffer.c
> > @@ -30,6 +30,16 @@ int st_magn_trig_set_state(struct iio_trigger *trig, 
> bool state)
> >  	return st_sensors_set_dataready_irq(indio_dev, state);
> >  }
> >  
> > +static int st_magn_buffer_preenable(struct iio_dev *indio_dev)
> > +{
> > +	struct st_sensor_data *mdata = iio_priv(indio_dev);
> > +
> > +	if (mdata->sensor_settings->drdy_irq.simple) {
> > +		disable_irq(mdata->get_irq_data_ready(indio_dev));
> > +	}
> > +	return 0;
> > +}
> > +
> >  static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
> >  {
> >  	int err;
> > @@ -45,7 +55,11 @@ static int st_magn_buffer_postenable(struct iio_dev 
> *indio_dev)
> >  	if (err < 0)
> >  		goto st_magn_buffer_postenable_error;
> >  
> > -	return st_sensors_set_enable(indio_dev, true);
> > +	err = st_sensors_set_enable(indio_dev, true);
> > +
> > +	enable_irq(mdata->get_irq_data_ready(indio_dev));
> > +
> > +	return err;
> >  
> >  st_magn_buffer_postenable_error:
> >  	kfree(mdata->buffer_data);
> > @@ -70,6 +84,7 @@ static int st_magn_buffer_predisable(struct iio_dev 
> *indio_dev)
> >  }
> >  
> >  static const struct iio_buffer_setup_ops st_magn_buffer_setup_ops = {
> > +	.preenable = &st_magn_buffer_preenable,
> >  	.postenable = &st_magn_buffer_postenable,
> >  	.predisable = &st_magn_buffer_predisable,
> >  };
> > diff --git a/drivers/iio/magnetometer/st_magn_core.c 
> b/drivers/iio/magnetometer/st_magn_core.c
> > index 72f6d1335a04..0fb0915529e9 100644
> > --- a/drivers/iio/magnetometer/st_magn_core.c
> > +++ b/drivers/iio/magnetometer/st_magn_core.c
> > @@ -259,6 +259,9 @@ static const struct st_sensor_settings 
> st_magn_sensors_settings[] = {
> >  				},
> >  			},
> >  		},
> > +    .drdy_irq = {
> > +      .simple = true,
> > +    },
> >  		.multi_read_bit = false,
> >  		.bootime = 2,
> >  	},
> > diff --git a/include/linux/iio/common/st_sensors.h 
> b/include/linux/iio/common/st_sensors.h
> > index f9bd6e8ab138..e25b5f033557 100644
> > --- a/include/linux/iio/common/st_sensors.h
> > +++ b/include/linux/iio/common/st_sensors.h
> > @@ -154,6 +154,7 @@ struct st_sensor_int_drdy {
> >   * struct ig1 - represents the Interrupt Generator 1 of sensors.
> >   * @en_addr: address of the enable ig1 register.
> >   * @en_mask: mask to write the on/off value for enable.
> > + * @simple: the data-ready is a "very simple implementation".
> >   */
> >  struct st_sensor_data_ready_irq {
> >  	struct st_sensor_int_drdy int1;
> > @@ -168,6 +169,7 @@ struct st_sensor_data_ready_irq {
> >  		u8 en_addr;
> >  		u8 en_mask;
> >  	} ig1;
> > +	bool simple;
> >  };
> > 
> > 
> 
> 





[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux