Possible incompatible change in behaviour of accelerometers - EV_ABS rather than EV_REL - and other thoughts.

Neil Brown neilb at suse.de
Tue Mar 10 01:00:40 CET 2009


Hello fellow developers.

I have be turning my attention to the accelerometers in the Freerunner
recently, and I would like to make a number of improvements.
I'll give a bit of an overview below for those who are interested, but
the main point of the email is to let you know about a change which
I very much hope will go through and will require most applications
which use the accelerometers to be changed, though it will probably be
a very minor change.

The input event devices (/dev/input/event[23]) which report the status
of the accelerometers currently use EV_REL events (REL_X, REL_Y,
REL_Z).  This is wrong.  They should be using EV_ABS events.

EV_REL should be used when the value reported is a change since last
time.  The classic example is a mouse.  It reports distances.  It is
not a distance from any absolute location, but rather the distance
from where ever the mouse was last time.
Conversely a touchpad reports distances which are absolute.  They are
distances from e.g. the top-right corner.

So a mouse uses EV_REL and a touchpad uses EV_ABS.

The accelerometer reports acceleration relative to free-fall.  So
there is an absolute frame of reference.  So it should use EV_ABS
events.

Apart from this basic "rightness" of use EV_ABS there are some
practical advantages.

- EV_ABS will not report anything when there is no change in the
  values.  It is possible to set a value (absfuzz) to roughly set what
  precision we are interested in and changes below that precision will
  simply not get reported.  So when the device is under constant
  acceleration, the application won't be repeatedly told this.
- EV_REL events never report 0.  So currently if one of the axes is
  not under acceleration (i.e. it is level) that axis isn't reported,
  which could lead to obscure bugs in applications.
- With ABS it is possible to use the EVIOCGABS ioctl to get the
  current (actually 'most recently reported') values.   This means
  that I can open the event device, issue an ioctl and get the
  current orientation of the freerunner without having to wait for
  events to come in.  Normally they wold come fairly fast.  However if
  the 'threshold' has been set fairly high and some other application
  already has the event device open, then you will not get any events
  until the device changes acceleration so you cannot directly measure
  the direction of gravity.
- EV_ABS events can be calibrated using the EVIOCSABS ioctl which can
  set min/max/level.  If someone wants very accurate readings, this
  might be useful.

Those are the benefits.  The cost is that any application which
currently looks for EV_REL events will not see them any more.
However EV_REL and EV_ABS events look very very similar.  The only
difference is the 'type' code which is 0x03 rather than 0x02.
The ABS_X, ABS_Y and ABS_Z code all match REL_X, REL_Y and REL_Z 
(0, 1, and 2) so the same code can be used to match them.

I have submitted a kernel patch to Andy to change the accelerometers
to use EV_ABS events and he has tentatively accepted it so it should
show up in andy-tracking soonish.  If he gets lots of "andy-tracking
broke my accelerometers" email, he might be tempted to revert it.

So I would like to encourage (even beg) anyone who is responsible for
code that reads the accelerometers to change their code to accept
either EV_REL or EV_ABS events.

Thank you very much!

And if you could let me know that you have done this for some
particular user of the accelerometers, I would really appreciate that too.

Other things that I want to do to the accelerometers:

1/  Make "sample_rate" more useful.  I would like values from
    0 up to 400 to all be meaningful, including fractions like 0.01.
    It would mean "minimum rate at which to report samples".

    If the value were above 50, I would have the accelerometer
    interrupt on every data_ready event and report them at the
    requested rate.

    If the value were below 50 I would disable that interrupt and use
    a kernel timer to sample the values at the desired rate.

2/  Make 'threshold' a little more useful by giving it a precise
    meaning.
    That meaning would be "also report samples when any axis differs
    from the previous value by more than the given number".
    Currently it doesn't always do exactly that for various reasons.
    e.g. when 'duration' is zero, the analog threshold detector can
    see spikes that don't get noticed by the A-D converter.  I want to
    synthesise a best-guess at what the peak acceleration probably was
    at that point so that application can see those peaks too.

3/  Enable the tap and double-tap detection circuits, both for
    general use and for wakeup-from-suspend.
    I would like to see these generating EV_KEY events such as
    BTN_X BTN_Y and BTN_Z for single tap and possibly
    BTN_A BTN_B and BTN_C for double tap (though that is a bit ugly)

    It would be best to create new /dev/input/event* devices for these
    so an app that wants them doesn't have to be woken by all the
    noise of ABS_* events.  However creating new event devices would
    renumber some existing one which would break any app which relies
    on hard codes paths (we really should have e.g. /dev/input/AUX and
    /dev/input/accel{0,1}).
    I'm not sure what I'll do about this just yet.

I expect to post patches for some or all of this to the kernel list
some time this month.

NeilBrown




More information about the devel mailing list