mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-21 15:09:00 +00:00
Add support for APDS-9960, Digital Proximity, Ambient Light, RGB and Gesture Sensor (#308)
apds9960: add support for apds9960
This commit is contained in:
@@ -17,6 +17,8 @@ smoke-test:
|
|||||||
@md5sum ./build/test.hex
|
@md5sum ./build/test.hex
|
||||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/apa102/main.go
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/apa102/main.go
|
||||||
@md5sum ./build/test.hex
|
@md5sum ./build/test.hex
|
||||||
|
tinygo build -size short -o ./build/test.hex -target=nano-33-ble ./examples/apds9960/proximity/main.go
|
||||||
|
@md5sum ./build/test.hex
|
||||||
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/apa102/itsybitsy-m0/main.go
|
tinygo build -size short -o ./build/test.hex -target=itsybitsy-m0 ./examples/apa102/itsybitsy-m0/main.go
|
||||||
@md5sum ./build/test.hex
|
@md5sum ./build/test.hex
|
||||||
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/at24cx/main.go
|
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/at24cx/main.go
|
||||||
@@ -216,7 +218,7 @@ DRIVERS = $(wildcard */)
|
|||||||
NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \
|
NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \
|
||||||
hcsr04 ssd1331 ws2812 thermistor apa102 easystepper ssd1351 ili9341 wifinina shifter hub75 \
|
hcsr04 ssd1331 ws2812 thermistor apa102 easystepper ssd1351 ili9341 wifinina shifter hub75 \
|
||||||
hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht keypad4x4 max72xx p1am tone tm1637 \
|
hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht keypad4x4 max72xx p1am tone tm1637 \
|
||||||
pcf8563 mcp2515 servo sdcard rtl8720dn image cmd i2csoft hts221 lps22hb
|
pcf8563 mcp2515 servo sdcard rtl8720dn image cmd i2csoft hts221 lps22hb apds9960
|
||||||
TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS))
|
TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS))
|
||||||
|
|
||||||
unit-test:
|
unit-test:
|
||||||
|
|||||||
@@ -0,0 +1,461 @@
|
|||||||
|
// Package apds9960 implements a driver for APDS-9960,
|
||||||
|
// a digital proximity, ambient light, RGB and gesture sensor.
|
||||||
|
//
|
||||||
|
// Datasheet: https://cdn.sparkfun.com/assets/learn_tutorials/3/2/1/Avago-APDS-9960-datasheet.pdf
|
||||||
|
//
|
||||||
|
package apds9960
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Device wraps an I2C connection to a APDS-9960 device.
|
||||||
|
type Device struct {
|
||||||
|
bus drivers.I2C
|
||||||
|
Address uint8
|
||||||
|
mode uint8
|
||||||
|
gesture gestureData
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configuration for APDS-9960 device.
|
||||||
|
type Configuration struct {
|
||||||
|
ProximityPulseLength uint8
|
||||||
|
ProximityPulseCount uint8
|
||||||
|
GesturePulseLength uint8
|
||||||
|
GesturePulseCount uint8
|
||||||
|
ProximityGain uint8
|
||||||
|
GestureGain uint8
|
||||||
|
ColorGain uint8
|
||||||
|
ADCIntegrationCycles uint16
|
||||||
|
LEDBoost uint16
|
||||||
|
threshold uint8
|
||||||
|
sensitivity uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
// for gesture-related data
|
||||||
|
type gestureData struct {
|
||||||
|
detected uint8
|
||||||
|
threshold uint8
|
||||||
|
sensitivity uint8
|
||||||
|
gXDelta int16
|
||||||
|
gYDelta int16
|
||||||
|
gXPrevDelta int16
|
||||||
|
gYPrevDelta int16
|
||||||
|
received bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// for enabling various device function
|
||||||
|
type enableConfig struct {
|
||||||
|
GEN bool
|
||||||
|
PIEN bool
|
||||||
|
AIEN bool
|
||||||
|
WEN bool
|
||||||
|
PEN bool
|
||||||
|
AEN bool
|
||||||
|
PON bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connected returns whether APDS-9960 has been found.
|
||||||
|
// It does a "who am I" request and checks the response.
|
||||||
|
func (d *Device) Connected() bool {
|
||||||
|
data := []byte{0}
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_ID_REG, data)
|
||||||
|
return data[0] == 0xAB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure sets up the APDS-9960 device.
|
||||||
|
func (d *Device) Configure(cfg Configuration) {
|
||||||
|
d.DisableAll() // turn off everything
|
||||||
|
|
||||||
|
// "default" settings
|
||||||
|
if cfg.ProximityPulseLength == 0 {
|
||||||
|
cfg.ProximityPulseLength = 16
|
||||||
|
}
|
||||||
|
if cfg.ProximityPulseCount == 0 {
|
||||||
|
cfg.ProximityPulseCount = 64
|
||||||
|
}
|
||||||
|
if cfg.GesturePulseLength == 0 {
|
||||||
|
cfg.GesturePulseLength = 16
|
||||||
|
}
|
||||||
|
if cfg.GesturePulseCount == 0 {
|
||||||
|
cfg.GesturePulseCount = 64
|
||||||
|
}
|
||||||
|
if cfg.ProximityGain == 0 {
|
||||||
|
cfg.ProximityGain = 1
|
||||||
|
}
|
||||||
|
if cfg.GestureGain == 0 {
|
||||||
|
cfg.GestureGain = 1
|
||||||
|
}
|
||||||
|
if cfg.ColorGain == 0 {
|
||||||
|
cfg.ColorGain = 4
|
||||||
|
}
|
||||||
|
if cfg.ADCIntegrationCycles == 0 {
|
||||||
|
cfg.ADCIntegrationCycles = 4
|
||||||
|
}
|
||||||
|
if cfg.threshold == 0 {
|
||||||
|
d.gesture.threshold = 30
|
||||||
|
}
|
||||||
|
if cfg.sensitivity == 0 {
|
||||||
|
d.gesture.sensitivity = 20
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetProximityPulse(cfg.ProximityPulseLength, cfg.ProximityPulseCount)
|
||||||
|
d.SetGesturePulse(cfg.GesturePulseLength, cfg.GesturePulseCount)
|
||||||
|
d.SetGains(cfg.ProximityGain, cfg.GestureGain, cfg.ColorGain)
|
||||||
|
d.SetADCIntegrationCycles(cfg.ADCIntegrationCycles)
|
||||||
|
|
||||||
|
if cfg.LEDBoost > 0 {
|
||||||
|
d.LEDBoost(cfg.LEDBoost)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMode returns current engine mode
|
||||||
|
func (d *Device) GetMode() uint8 {
|
||||||
|
return d.mode
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableAll turns off the device and all functions
|
||||||
|
func (d *Device) DisableAll() {
|
||||||
|
d.enable(enableConfig{})
|
||||||
|
d.bus.WriteRegister(d.Address, APDS9960_GCONF4_REG, []byte{0x00})
|
||||||
|
d.mode = MODE_NONE
|
||||||
|
d.gesture.detected = GESTURE_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetProximityPulse sets proximity pulse length (4, 8, 16, 32) and count (1~64)
|
||||||
|
// default: 16, 64
|
||||||
|
func (d *Device) SetProximityPulse(length, count uint8) {
|
||||||
|
d.bus.WriteRegister(d.Address, APDS9960_PPULSE_REG, []byte{getPulseLength(length)<<6 | getPulseCount(count)})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetGesturePulse sets gesture pulse length (4, 8, 16, 32) and count (1~64)
|
||||||
|
// default: 16, 64
|
||||||
|
func (d *Device) SetGesturePulse(length, count uint8) {
|
||||||
|
d.bus.WriteRegister(d.Address, APDS9960_GPULSE_REG, []byte{getPulseLength(length)<<6 | getPulseCount(count)})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetADCIntegrationCycles sets ALS/color ADC internal integration cycles (1~256, 1 cycle = 2.78 ms)
|
||||||
|
// default: 4 (~10 ms)
|
||||||
|
func (d *Device) SetADCIntegrationCycles(cycles uint16) {
|
||||||
|
if cycles > 256 {
|
||||||
|
cycles = 256
|
||||||
|
}
|
||||||
|
d.bus.WriteRegister(d.Address, APDS9960_ATIME_REG, []byte{uint8(256 - cycles)})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetGains sets proximity/gesture gain (1, 2, 4, 8x) and ALS/color gain (1, 4, 16, 64x)
|
||||||
|
// default: 1, 1, 4
|
||||||
|
func (d *Device) SetGains(proximityGain, gestureGain, colorGain uint8) {
|
||||||
|
d.bus.WriteRegister(d.Address, APDS9960_CONTROL_REG, []byte{getProximityGain(proximityGain)<<2 | getALSGain(colorGain)})
|
||||||
|
d.bus.WriteRegister(d.Address, APDS9960_GCONF2_REG, []byte{getProximityGain(gestureGain) << 5})
|
||||||
|
}
|
||||||
|
|
||||||
|
// LEDBoost sets proximity and gesture LED current level (100, 150, 200, 300 (%))
|
||||||
|
// default: 100
|
||||||
|
func (d *Device) LEDBoost(percent uint16) {
|
||||||
|
var v uint8
|
||||||
|
switch percent {
|
||||||
|
case 100:
|
||||||
|
v = 0
|
||||||
|
case 150:
|
||||||
|
v = 1
|
||||||
|
case 200:
|
||||||
|
v = 2
|
||||||
|
case 300:
|
||||||
|
v = 3
|
||||||
|
}
|
||||||
|
d.bus.WriteRegister(d.Address, APDS9960_CONFIG2_REG, []byte{0x01 | v<<4})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setthreshold sets threshold (0~255) for detecting gestures
|
||||||
|
// default: 30
|
||||||
|
func (d *Device) Setthreshold(t uint8) {
|
||||||
|
d.gesture.threshold = t
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setsensitivity sets sensivity (0~100) for detecting gestures
|
||||||
|
// default: 20
|
||||||
|
func (d *Device) Setsensitivity(s uint8) {
|
||||||
|
if s > 100 {
|
||||||
|
s = 100
|
||||||
|
}
|
||||||
|
d.gesture.sensitivity = 100 - s
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableProximity starts the proximity engine
|
||||||
|
func (d *Device) EnableProximity() {
|
||||||
|
if d.mode != MODE_NONE {
|
||||||
|
d.DisableAll()
|
||||||
|
}
|
||||||
|
d.enable(enableConfig{PON: true, PEN: true, WEN: true})
|
||||||
|
d.mode = MODE_PROXIMITY
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProximityAvailable reports if proximity data is available
|
||||||
|
func (d *Device) ProximityAvailable() bool {
|
||||||
|
if d.mode == MODE_PROXIMITY && d.readStatus("PVALID") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadProximity reads proximity data (0~255)
|
||||||
|
func (d *Device) ReadProximity() (proximity int32) {
|
||||||
|
if d.mode != MODE_PROXIMITY {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
data := []byte{0}
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_PDATA_REG, data)
|
||||||
|
return 255 - int32(data[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableColor starts the color engine
|
||||||
|
func (d *Device) EnableColor() {
|
||||||
|
if d.mode != MODE_NONE {
|
||||||
|
d.DisableAll()
|
||||||
|
}
|
||||||
|
d.enable(enableConfig{PON: true, AEN: true, WEN: true})
|
||||||
|
d.mode = MODE_COLOR
|
||||||
|
}
|
||||||
|
|
||||||
|
// ColorAvailable reports if color data is available
|
||||||
|
func (d *Device) ColorAvailable() bool {
|
||||||
|
if d.mode == MODE_COLOR && d.readStatus("AVALID") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadColor reads color data (red, green, blue, clear color/brightness)
|
||||||
|
func (d *Device) ReadColor() (r int32, g int32, b int32, clear int32) {
|
||||||
|
if d.mode != MODE_COLOR {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := []byte{0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_CDATAL_REG, data[:1])
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_CDATAH_REG, data[1:2])
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_RDATAL_REG, data[2:3])
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_RDATAH_REG, data[3:4])
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_GDATAL_REG, data[4:5])
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_GDATAH_REG, data[5:6])
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_BDATAL_REG, data[6:7])
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_BDATAH_REG, data[7:])
|
||||||
|
clear = int32(uint16(data[1])<<8 | uint16(data[0]))
|
||||||
|
r = int32(uint16(data[3])<<8 | uint16(data[2]))
|
||||||
|
g = int32(uint16(data[5])<<8 | uint16(data[4]))
|
||||||
|
b = int32(uint16(data[7])<<8 | uint16(data[6]))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableGesture starts the gesture engine
|
||||||
|
func (d *Device) EnableGesture() {
|
||||||
|
if d.mode != MODE_NONE {
|
||||||
|
d.DisableAll()
|
||||||
|
}
|
||||||
|
d.enable(enableConfig{PON: true, PEN: true, GEN: true, WEN: true})
|
||||||
|
d.mode = MODE_GESTURE
|
||||||
|
d.gesture.detected = GESTURE_NONE
|
||||||
|
d.gesture.gXDelta = 0
|
||||||
|
d.gesture.gYDelta = 0
|
||||||
|
d.gesture.gXPrevDelta = 0
|
||||||
|
d.gesture.gYPrevDelta = 0
|
||||||
|
d.gesture.received = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GestureAvailable reports if gesture data is available
|
||||||
|
func (d *Device) GestureAvailable() bool {
|
||||||
|
if d.mode != MODE_GESTURE {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
data := []byte{0, 0, 0, 0}
|
||||||
|
|
||||||
|
// check GVALID
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_GSTATUS_REG, data[:1])
|
||||||
|
if data[0]&0x01 == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// get number of data sets available in FIFO
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_GFLVL_REG, data[:1])
|
||||||
|
availableDataSets := data[0]
|
||||||
|
if availableDataSets == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// read up, down, left and right proximity data from FIFO
|
||||||
|
var dataSets [32][4]uint8
|
||||||
|
for i := uint8(0); i < availableDataSets; i++ {
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_U_REG, data[:1])
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_D_REG, data[1:2])
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_L_REG, data[2:3])
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_GFIFO_R_REG, data[3:4])
|
||||||
|
for j := uint8(0); j < 4; j++ {
|
||||||
|
dataSets[i][j] = data[j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// gesture detection process
|
||||||
|
d.gesture.detected = GESTURE_NONE
|
||||||
|
for i := uint8(0); i < availableDataSets; i++ {
|
||||||
|
U := dataSets[i][0]
|
||||||
|
D := dataSets[i][1]
|
||||||
|
L := dataSets[i][2]
|
||||||
|
R := dataSets[i][3]
|
||||||
|
|
||||||
|
// if all readings fall below threshold, it's possible that
|
||||||
|
// a movement's just been made
|
||||||
|
if U < d.gesture.threshold && D < d.gesture.threshold && L < d.gesture.threshold && R < d.gesture.threshold {
|
||||||
|
d.gesture.received = true
|
||||||
|
// if there were movement in the previous step (including the last data sets)
|
||||||
|
if d.gesture.gXPrevDelta != 0 && d.gesture.gYPrevDelta != 0 {
|
||||||
|
totalX := d.gesture.gXPrevDelta - d.gesture.gXDelta
|
||||||
|
totalY := d.gesture.gYPrevDelta - d.gesture.gYDelta
|
||||||
|
// if previous and current movement are in opposite directions (pass through one led then next)
|
||||||
|
// and the difference is big enough, the gesture is recorded
|
||||||
|
switch {
|
||||||
|
case totalX < -int16(d.gesture.sensitivity):
|
||||||
|
d.gesture.detected = GESTURE_LEFT
|
||||||
|
case totalX > int16(d.gesture.sensitivity):
|
||||||
|
d.gesture.detected = GESTURE_RIGHT
|
||||||
|
case totalY > int16(d.gesture.sensitivity):
|
||||||
|
d.gesture.detected = GESTURE_DOWN
|
||||||
|
case totalY < -int16(d.gesture.sensitivity):
|
||||||
|
d.gesture.detected = GESTURE_UP
|
||||||
|
}
|
||||||
|
d.gesture.gXDelta = 0
|
||||||
|
d.gesture.gYDelta = 0
|
||||||
|
d.gesture.gXPrevDelta = 0
|
||||||
|
d.gesture.gYPrevDelta = 0
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// recording current movement
|
||||||
|
d.gesture.gXDelta = int16(R) - int16(L)
|
||||||
|
d.gesture.gYDelta = int16(D) - int16(U)
|
||||||
|
if d.gesture.received {
|
||||||
|
d.gesture.received = false
|
||||||
|
d.gesture.gXPrevDelta = d.gesture.gXDelta
|
||||||
|
d.gesture.gYPrevDelta = d.gesture.gYDelta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.gesture.detected != GESTURE_NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadGesture reads last gesture data
|
||||||
|
func (d *Device) ReadGesture() (gesture int32) {
|
||||||
|
return int32(d.gesture.detected)
|
||||||
|
}
|
||||||
|
|
||||||
|
// private functions
|
||||||
|
|
||||||
|
func (d *Device) enable(cfg enableConfig) {
|
||||||
|
var gen, pien, aien, wen, pen, aen, pon uint8
|
||||||
|
|
||||||
|
if cfg.GEN {
|
||||||
|
gen = 1
|
||||||
|
}
|
||||||
|
if cfg.PIEN {
|
||||||
|
pien = 1
|
||||||
|
}
|
||||||
|
if cfg.AIEN {
|
||||||
|
aien = 1
|
||||||
|
}
|
||||||
|
if cfg.WEN {
|
||||||
|
wen = 1
|
||||||
|
}
|
||||||
|
if cfg.PEN {
|
||||||
|
pen = 1
|
||||||
|
}
|
||||||
|
if cfg.AEN {
|
||||||
|
aen = 1
|
||||||
|
}
|
||||||
|
if cfg.PON {
|
||||||
|
pon = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
data := []byte{gen<<6 | pien<<5 | aien<<4 | wen<<3 | pen<<2 | aen<<1 | pon}
|
||||||
|
d.bus.WriteRegister(d.Address, APDS9960_ENABLE_REG, data)
|
||||||
|
|
||||||
|
if cfg.PON {
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) readStatus(param string) bool {
|
||||||
|
data := []byte{0}
|
||||||
|
d.bus.ReadRegister(d.Address, APDS9960_STATUS_REG, data)
|
||||||
|
|
||||||
|
switch param {
|
||||||
|
case "CPSAT":
|
||||||
|
return data[0]>>7&0x01 == 1
|
||||||
|
case "PGSAT":
|
||||||
|
return data[0]>>6&0x01 == 1
|
||||||
|
case "PINT":
|
||||||
|
return data[0]>>5&0x01 == 1
|
||||||
|
case "AINT":
|
||||||
|
return data[0]>>4&0x01 == 1
|
||||||
|
case "PVALID":
|
||||||
|
return data[0]>>1&0x01 == 1
|
||||||
|
case "AVALID":
|
||||||
|
return data[0]&0x01 == 1
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPulseLength(l uint8) uint8 {
|
||||||
|
switch l {
|
||||||
|
case 4:
|
||||||
|
return 0
|
||||||
|
case 8:
|
||||||
|
return 1
|
||||||
|
case 16:
|
||||||
|
return 2
|
||||||
|
case 32:
|
||||||
|
return 3
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPulseCount(c uint8) uint8 {
|
||||||
|
if c < 1 && c > 64 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return c - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func getProximityGain(g uint8) uint8 {
|
||||||
|
switch g {
|
||||||
|
case 1:
|
||||||
|
return 0
|
||||||
|
case 2:
|
||||||
|
return 1
|
||||||
|
case 4:
|
||||||
|
return 2
|
||||||
|
case 8:
|
||||||
|
return 3
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getALSGain(g uint8) uint8 {
|
||||||
|
switch g {
|
||||||
|
case 1:
|
||||||
|
return 0
|
||||||
|
case 4:
|
||||||
|
return 1
|
||||||
|
case 16:
|
||||||
|
return 2
|
||||||
|
case 64:
|
||||||
|
return 3
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
//go:build !nano_33_ble
|
||||||
|
// +build !nano_33_ble
|
||||||
|
|
||||||
|
package apds9960
|
||||||
|
|
||||||
|
import "tinygo.org/x/drivers"
|
||||||
|
|
||||||
|
// New creates a new APDS-9960 connection. The I2C bus must already be
|
||||||
|
// configured.
|
||||||
|
//
|
||||||
|
// This function only creates the Device object, it does not touch the device.
|
||||||
|
func New(bus drivers.I2C) Device {
|
||||||
|
return Device{bus: bus, Address: ADPS9960_ADDRESS, mode: MODE_NONE}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
//go:build nano_33_ble
|
||||||
|
// +build nano_33_ble
|
||||||
|
|
||||||
|
package apds9960
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// New creates a new APDS-9960 connection. The I2C bus must already be
|
||||||
|
// configured.
|
||||||
|
//
|
||||||
|
// This function only creates the Device object, it does not touch the device.
|
||||||
|
func New(bus drivers.I2C) Device {
|
||||||
|
// turn on internal power pin (machine.P0_22) and I2C1 pullups power pin (machine.P1_00)
|
||||||
|
// and wait a moment.
|
||||||
|
ENV := machine.P0_22
|
||||||
|
ENV.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
ENV.High()
|
||||||
|
R := machine.P1_00
|
||||||
|
R.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
|
R.High()
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
|
||||||
|
return Device{bus: bus, Address: ADPS9960_ADDRESS, mode: MODE_NONE}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package apds9960
|
||||||
|
|
||||||
|
const (
|
||||||
|
|
||||||
|
// I2C address
|
||||||
|
ADPS9960_ADDRESS = 0x39
|
||||||
|
|
||||||
|
// control/status registers
|
||||||
|
APDS9960_RAM_REG = 0x00
|
||||||
|
APDS9960_ENABLE_REG = 0x80
|
||||||
|
APDS9960_ATIME_REG = 0x81
|
||||||
|
APDS9960_WTIME_REG = 0x83
|
||||||
|
APDS9960_AILTIL_REG = 0x84
|
||||||
|
APDS9960_AILTH_REG = 0x85
|
||||||
|
APDS9960_AIHTL_REG = 0x86
|
||||||
|
APDS9960_AIHTH_REG = 0x87
|
||||||
|
APDS9960_PILT_REG = 0x89
|
||||||
|
APDS9960_PIHT_REG = 0x8B
|
||||||
|
APDS9960_PERS_REG = 0x8C
|
||||||
|
APDS9960_CONFIG1_REG = 0x8D
|
||||||
|
APDS9960_PPULSE_REG = 0x8E
|
||||||
|
APDS9960_CONTROL_REG = 0x8F
|
||||||
|
APDS9960_CONFIG2_REG = 0x90
|
||||||
|
APDS9960_ID_REG = 0x92
|
||||||
|
APDS9960_STATUS_REG = 0x93
|
||||||
|
APDS9960_CDATAL_REG = 0x94
|
||||||
|
APDS9960_CDATAH_REG = 0x95
|
||||||
|
APDS9960_RDATAL_REG = 0x96
|
||||||
|
APDS9960_RDATAH_REG = 0x97
|
||||||
|
APDS9960_GDATAL_REG = 0x98
|
||||||
|
APDS9960_GDATAH_REG = 0x99
|
||||||
|
APDS9960_BDATAL_REG = 0x9A
|
||||||
|
APDS9960_BDATAH_REG = 0x9B
|
||||||
|
APDS9960_PDATA_REG = 0x9C
|
||||||
|
APDS9960_POFFSET_UR_REG = 0x9D
|
||||||
|
APDS9960_POFFSET_DL_REG = 0x9E
|
||||||
|
APDS9960_CONFIG3_REG = 0x9F
|
||||||
|
APDS9960_GPENTH_REG = 0xA0
|
||||||
|
APDS9960_GEXTH_REG = 0xA1
|
||||||
|
APDS9960_GCONF1_REG = 0xA2
|
||||||
|
APDS9960_GCONF2_REG = 0xA3
|
||||||
|
APDS9960_GOFFSET_U_REG = 0xA4
|
||||||
|
APDS9960_GOFFSET_D_REG = 0xA5
|
||||||
|
APDS9960_GOFFSET_L_REG = 0xA7
|
||||||
|
APDS9960_GOFFSET_R_REG = 0xA9
|
||||||
|
APDS9960_GPULSE_REG = 0xA6
|
||||||
|
APDS9960_GCONF3_REG = 0xAA
|
||||||
|
APDS9960_GCONF4_REG = 0xAB
|
||||||
|
APDS9960_GFLVL_REG = 0xAE
|
||||||
|
APDS9960_GSTATUS_REG = 0xAF
|
||||||
|
APDS9960_IFORCE_REG = 0xE4
|
||||||
|
APDS9960_PICLEAR_REG = 0xE5
|
||||||
|
APDS9960_CICLEAR_REG = 0xE6
|
||||||
|
APDS9960_AICLEAR_REG = 0xE7
|
||||||
|
APDS9960_GFIFO_U_REG = 0xFC
|
||||||
|
APDS9960_GFIFO_D_REG = 0xFD
|
||||||
|
APDS9960_GFIFO_L_REG = 0xFE
|
||||||
|
APDS9960_GFIFO_R_REG = 0xFF
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
|
||||||
|
// sensor modes
|
||||||
|
MODE_NONE = iota
|
||||||
|
MODE_PROXIMITY
|
||||||
|
MODE_COLOR
|
||||||
|
MODE_GESTURE
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
|
||||||
|
// detected gestures
|
||||||
|
GESTURE_NONE = iota
|
||||||
|
GESTURE_UP
|
||||||
|
GESTURE_DOWN
|
||||||
|
GESTURE_LEFT
|
||||||
|
GESTURE_RIGHT
|
||||||
|
)
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/apds9960"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
machine.I2C1.Configure(machine.I2CConfig{
|
||||||
|
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||||
|
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||||
|
Frequency: machine.TWI_FREQ_400KHZ,
|
||||||
|
})
|
||||||
|
|
||||||
|
sensor := apds9960.New(machine.I2C1)
|
||||||
|
|
||||||
|
if !sensor.Connected() {
|
||||||
|
println("APDS-9960 not connected!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||||
|
|
||||||
|
sensor.EnableColor() // enable color engine
|
||||||
|
|
||||||
|
for {
|
||||||
|
|
||||||
|
if sensor.ColorAvailable() {
|
||||||
|
r, g, b, c := sensor.ReadColor()
|
||||||
|
println("Red =", r, "\tGreen =", g, "\tBlue =", b, "\tClear =", c)
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/apds9960"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
machine.I2C1.Configure(machine.I2CConfig{
|
||||||
|
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||||
|
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||||
|
Frequency: machine.TWI_FREQ_400KHZ,
|
||||||
|
})
|
||||||
|
|
||||||
|
sensor := apds9960.New(machine.I2C1)
|
||||||
|
|
||||||
|
if !sensor.Connected() {
|
||||||
|
println("APDS-9960 not connected!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||||
|
|
||||||
|
sensor.EnableGesture() // enable gesture engine
|
||||||
|
|
||||||
|
for {
|
||||||
|
|
||||||
|
// wave your hand (not too slow) about 10 cm above the sensor
|
||||||
|
if sensor.GestureAvailable() {
|
||||||
|
|
||||||
|
gesture := sensor.ReadGesture()
|
||||||
|
print("Detected gesture: ")
|
||||||
|
switch gesture {
|
||||||
|
case apds9960.GESTURE_UP:
|
||||||
|
println("Up")
|
||||||
|
case apds9960.GESTURE_DOWN:
|
||||||
|
println("Down")
|
||||||
|
case apds9960.GESTURE_LEFT:
|
||||||
|
println("Left")
|
||||||
|
case apds9960.GESTURE_RIGHT:
|
||||||
|
println("Right")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// note: the delay shouldn't be too long, otherwise new gesture data might be lost
|
||||||
|
time.Sleep(time.Millisecond * 250)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"tinygo.org/x/drivers/apds9960"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
machine.I2C1.Configure(machine.I2CConfig{
|
||||||
|
SCL: machine.P0_15, // SCL1 on Nano 33 BLE Sense
|
||||||
|
SDA: machine.P0_14, // SDA1 on Nano 33 BLE Sense
|
||||||
|
Frequency: machine.TWI_FREQ_400KHZ,
|
||||||
|
})
|
||||||
|
|
||||||
|
sensor := apds9960.New(machine.I2C1)
|
||||||
|
|
||||||
|
if !sensor.Connected() {
|
||||||
|
println("APDS-9960 not connected!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sensor.Configure(apds9960.Configuration{}) // use default settings
|
||||||
|
|
||||||
|
sensor.EnableProximity() // enable proximity engine
|
||||||
|
|
||||||
|
for {
|
||||||
|
|
||||||
|
if sensor.ProximityAvailable() {
|
||||||
|
p := sensor.ReadProximity()
|
||||||
|
println("Proximity:", p)
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user