APDS-9960 gesture sensor

Broadcom's APDS-9960 on the GY-9960 breakout: ambient light, red, green and blue, proximity, and hand swipes, all from one chip.

It is the gesture sensor in the Arduino Nano 33 BLE Sense. Aliases: gesture sensor, color sensor, proximity sensor, GY-9960.

Pins

Pin What it does
VL The IR LED's supply. The board's jumper ties it to VCC; leave it open.
GND Ground.
VCC Supply, 2.4 to 3.6 V. It is a 3.3 V part: use the Uno's 3.3 V pin.
SDA, SCL The I2C bus, address 0x39. The board has the pull-ups, to VCC.
INT Interrupt output, open drain: low while an enabled interrupt is set.

While it runs

The sliders are the light, in lux, and how near a hand is. The arrows swipe a hand across the sensor, and C steps the light's color through white, red, green, blue and yellow.

Reading it on an Arduino

With SparkFun's library, which Mokxi ships as SparkFun_APDS9960.h:

#include <Wire.h>
#include <SparkFun_APDS9960.h>
SparkFun_APDS9960 apds;

void setup() {
  Serial.begin(9600);
  apds.init();
  apds.enableGestureSensor(true);
}

void loop() {
  if (apds.isGestureAvailable()) {
    switch (apds.readGesture()) {
      case DIR_UP: Serial.println("UP"); break;
      case DIR_DOWN: Serial.println("DOWN"); break;
      case DIR_LEFT: Serial.println("LEFT"); break;
      case DIR_RIGHT: Serial.println("RIGHT"); break;
    }
  }
}

Adafruit's library (Adafruit_APDS9960.h) reads it too; turn proximity on before gestures, as its examples do.

What the model gets right

From the APDS-9960 datasheet:

Nothing until it is powered: no reading lands until PON is set in ENABLE, and each engine runs only while its own bit is on.

Color: the integration time from ATIME, 2.78 ms a step, the gain from 1x to 64x, the most a channel can count, and the four little-endian words with AVALID.

Proximity scales with its gain and LED drive, with thresholds that raise an interrupt.

Gestures: a 32-set FIFO of up, down, left and right readings, its level, the valid and overflow flags, and the engine that runs while a hand is over it and exits when it leaves. A swipe lights the near side's photodiode first and the far side's last, which is what the libraries look for.

What it does not model

The light is a level in lux and a color, counted at a round 2.5 a lux for each 100 ms at 1x; Broadcom gives each channel's response per microwatt a square centimeter, with spectral curves and infrared leakage this leaves out. Gesture gain, wait time and thresholds hold what is written but any swipe passes, and the interrupts have no persistence filter.

Common mistakes

Powering it from 5 V: it is a 3.3 V chip, and most boards have no regulator.

Asking for gestures with proximity off: the engine is entered when a hand comes close, which proximity sees.

See it in action

Swipe lamp dims an LED with your swipes. Open it at /templates.