Skip to content

gesture_proximity_threshold default causes prox value to lock at 51 #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
kattni opened this issue May 4, 2020 · 9 comments
Closed
Labels

Comments

@kattni
Copy link

kattni commented May 4, 2020

From @dastels in #16:
Related: gestures being triggered (prox > gesture_proximity_threshold) freeze the returned proximity value. E.g. if the threshold is at the default 50, the returned proximity value to 'lock in' when it reaches 51. Setting the threshold to 255 allows proximity to work property throughout it's full 0-255 range.

@evaherrada evaherrada added the bug label Jun 17, 2020
@Stalkii
Copy link

Stalkii commented Mar 15, 2021

I do have this bug as well. How do I set the threshold to work around it?

@jerryneedell
Copy link

I tried to look into this, but I don't think I understand was the issue is. Can someone provide an example of what is wrong?

@Stalkii
Copy link

Stalkii commented Mar 17, 2021

The proximity reading is good as long as the detected distance is below the value of 50. Meaning it always returns back to 0 if the object (e.g. hand) is removed from the sensor. Once the value gets above 50 it gets "stuck" there, so does not return to 0. Basically it doesn't change at all (neither higher nor lower values).
It doesn't matter if you only activate proximity reading or have anything else (gesture, color, prox_int) activated as well.

@jerryneedell
Copy link

FYI - I have reproduced this. What I am seeing is that if I only enable proximity, then the setting of gesture_proximity_threshold does not matter. That is, the issue only occurs if I also enable gesture.
If gesture is enabled, then once the gesture_proximity_threshold is exceeded, proximity readings are all at the value of gesture_proximity_threshold + 1. Gesture detection continues to function, but proximity readings are useless.

I have not found a workaround at this time... still looking.

@joeblubaugh
Copy link

joeblubaugh commented Jul 30, 2021

I'm also experiencing this problem on a QT Py RP2040. I took a look at the datasheet: https://cdn.sparkfun.com/assets/learn_tutorials/3/2/1/Avago-APDS-9960-datasheet.pdf

There are a number of relevant registers, I'm going to focus on ENABLE and GCONFIG4

Here's the enable_gesture code. _gesture_enable lives in the ENABLE register and _gesture_mode lives in GCONFIG4.

 ## GESTURE DETECTION
    @property
    def enable_gesture(self):
        """Gesture detection enable flag. True to enable, False to disable.
        Note that when disabled, gesture mode is turned off"""
        return self._gesture_enable

    @enable_gesture.setter
    def enable_gesture(self, enable_flag):
        if not enable_flag:
            self._gesture_mode = False
        self._gesture_enable = enable_flag

If you set _gesture_mode = False (that's GCONFIG4, bit 0), you'll drop out of the gesture state machine. I wonder if we need to clear the _gesture_mode flag after the gesture value is read ...

The gesture state machine is on page 15 of the datasheet, and it implies that if _gesture_mode isn't cleared, the gesture state machine will loop forever

@fivesixzero
Copy link

I've seen this issue as well during my recent tesing.

The use of the GCONFIG4<GMODE> (gesture mode) bit in the current code for gesture_enable is a bit weird here.

Here's the doc describing the GMODE flag from the section covering the GCONF4 (oxAB) register on page 32:

Gesture Mode. Reading this bit reports if the gesture state machine is actively running, 1 = Gesture, 0= ALS, Proximity, Color. Writing a 1 to this bit causes immediate entry in to the gesture state machine (as if GPENTH had been exceeded). Writing a 0 to this bit causes exit of gesture when current analog conversion has finished (as if GEXTH had been exceeded).

This only tells part of the story though. The Gesture Engine description includes a bit more detail on how GMODE is used internally.

During operation, the Gesture engine is entered when its enable bit, GEN, and the operating mode bit, GMODE, are both set. GMODE can be set/reset manually, via I²C, or becomes set when proximity results, PDATA, is greater or equal to the gesture proximity entry threshold, GPENTH. Exit of the gesture engine will not occur until GMODE is reset to zero. During normal operation, GMODE is reset when all 4-bytes of a gesture dataset fall below the exit threshold, GEXTH, for GEXPERS times. This exit condition is also influenced by the gesture exit mask, GEXMSK, which includes all non-masked datum (i.e. singular 1-byte U, D, L, R points). To prevent premature exit, a persistence filter is also included; exit will only occur if a consecutive number of below-threshold results is greater or equal to the persistence value, GEXPERS. Each dataset result that is above-threshold will reset the persistence count. False or incomplete gestures (engine entry and exit without GVALID transitioning high) will not generate a gesture interrupt, GINT, and FIFO data will automatically be purged.

Given how complicated the entry/exit of the gesture machine is it'll take some iterative testing to find the best defaults and how to expose the relevant settings effectively for things like GPENTH, GEXPERS, GEXMSK, and GWTIME. Other things like GINT, GVALID, and GMODE may be useful to read during gesture operations to determine flow in the driver, particularly since it doesn't look like there's any guarantee that every gesture engine run will result in valid data becoming available.

But I don't think we should be writing to GMODE based on this info - GEN being set to true should be enough to enter the gesture state machine. Getting the gesture state machine to reliably return useful data though will depend on making sure that other config registers are configured with values that will work for the majority of use cases.

Once I've worked through quirks in the proximity system (which has some config items that are closely related to gesture) I'm hoping to get this figured out more definitively with some extensive testing.

@fivesixzero
Copy link

Spent a bunch of time today getting my head around the state machines and config registers in the APDS-9960. The datasheet is thorough enough but it takes a lot of reading, re-reading and tinkering to get it all figured out. This definitely not an intuitive sensor to work with, particularly the gesture engine. 😢

The root cause of this issue is the fact that the gesture engine gets stuck in an infinite loop. With this nested state machine looping, the overarching device-wide state machine never progresses to the next steps.

That's why our PDATA looks "frozen" - the device hasn't run another proximity measurement yet. And it won't. Ever. Even after a reset, unless that reset included a power cycle.

This infinite looping happens because we haven't set GPEXTH . When that register has a value of 0, the gesture engine will loop indefinitely until the host de-asserts GMODE or the power gets pulled.

There are a few potential fixes for this, like just setting a GPEXTH on init or de-asserting GMODE at the end of our gesture() call. I've tried a few of these types of things but I'm seeing very random-looking results coming from gesture() though.

Thankfully I've got plenty of time this week to dive in. If all goes well I should have a PR up in a few days. I'm hoping to find an elegant fix but in the end a more substantial rewrite/modernization of gesture() may be in order.

@fivesixzero
Copy link

Managed to get a good fix on options for making gesture() do its thing much more effectively. Going to just link the notes before I get some sleep. 😂

@FoamyGuy
Copy link

FoamyGuy commented Jan 8, 2022

This has been resolved by #39

@FoamyGuy FoamyGuy closed this as completed Jan 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants