mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
173 lines
4.9 KiB
C
173 lines
4.9 KiB
C
/*
|
|
* Copyright (C) 2017 Inria
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
* directory for more details.
|
|
*/
|
|
|
|
/**
|
|
* @ingroup drivers_vcnl40x0
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief Device driver implementation for VCNL40X0 Proximity and Ambient Light devices.
|
|
*
|
|
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
|
|
*
|
|
* @}
|
|
*/
|
|
|
|
#include "vcnl40x0.h"
|
|
#include "vcnl40x0_internals.h"
|
|
#include "vcnl40x0_params.h"
|
|
#include "periph/i2c.h"
|
|
|
|
#define ENABLE_DEBUG 0
|
|
#include "debug.h"
|
|
|
|
#define DEV_I2C (dev->params.i2c_dev)
|
|
#define DEV_ADDR (dev->params.i2c_addr)
|
|
|
|
/* Internal functions */
|
|
static int _set_command_reg(const vcnl40x0_t *dev, uint8_t reg)
|
|
{
|
|
if (i2c_write_reg(DEV_I2C, DEV_ADDR, VCNL40X0_REG_COMMAND, reg, 0) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _get_command_reg(const vcnl40x0_t *dev, uint8_t *reg)
|
|
{
|
|
if (i2c_read_reg(DEV_I2C, DEV_ADDR, VCNL40X0_REG_COMMAND, reg, 0) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*
|
|
* VCNL40X0 Core API *
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
int vcnl40x0_init(vcnl40x0_t *dev, const vcnl40x0_params_t *params)
|
|
{
|
|
dev->params = *params;
|
|
|
|
/* Acquire exclusive access */
|
|
i2c_acquire(DEV_I2C);
|
|
|
|
/* Check sensor ID */
|
|
uint8_t checkid;
|
|
i2c_read_reg(DEV_I2C, DEV_ADDR, VCNL40X0_REG_PRODUCT_ID,
|
|
&checkid, 0);
|
|
if ((checkid & VCNL40X0_PRODUCT_MASK_PRODUCT_ID) != VCNL40X0_PRODUCT_ID) {
|
|
DEBUG("[vcnl40x0] Error: wrong device ID '0x%02x', expected '0x%02x'\n",
|
|
checkid, VCNL40X0_PRODUCT_ID);
|
|
i2c_release(DEV_I2C);
|
|
return -VCNL40X0_ERR_NODEV;
|
|
}
|
|
|
|
/* LED current cannot be above 20 */
|
|
if (dev->params.led_current > 20) {
|
|
dev->params.led_current = 20;
|
|
}
|
|
|
|
if (i2c_write_reg(DEV_I2C, DEV_ADDR, VCNL40X0_REG_PROXIMITY_CURRENT,
|
|
dev->params.led_current, 0) != 0) {
|
|
DEBUG("[vcnl40x0] Error: failed to set proximity current\n");
|
|
i2c_release(DEV_I2C);
|
|
return -VCNL40X0_ERR_I2C;
|
|
}
|
|
|
|
if (_set_command_reg(dev, VCNL40X0_COMMAND_ALL_DISABLE) < 0) {
|
|
DEBUG("[vcnl40x0] Error: failed to set disable all commands\n");
|
|
i2c_release(DEV_I2C);
|
|
return -VCNL40X0_ERR_I2C;
|
|
}
|
|
|
|
if (i2c_write_reg(DEV_I2C, DEV_ADDR, VCNL40X0_REG_PROXIMITY_RATE,
|
|
dev->params.proximity_rate, 0) != 0) {
|
|
DEBUG("[vcnl40x0] Error: failed to set proximity rate\n");
|
|
i2c_release(DEV_I2C);
|
|
return -VCNL40X0_ERR_I2C;
|
|
}
|
|
|
|
if (i2c_write_reg(DEV_I2C, DEV_ADDR, VCNL40X0_REG_AMBIENT_PARAMETER,
|
|
dev->params.ambient_rate |
|
|
VCNL40X0_AMBIENT_PARA_AUTO_OFFSET_ENABLE |
|
|
dev->params.ambient_avg, 0) != 0) {
|
|
DEBUG("[vcnl40x0] Error: failed to set ambient light rate\n");
|
|
i2c_release(DEV_I2C);
|
|
return -VCNL40X0_ERR_I2C;
|
|
}
|
|
|
|
/* Release I2C device */
|
|
i2c_release(DEV_I2C);
|
|
|
|
DEBUG("[vcnl40x0] info: vcnl40x0 sensor initialized with success\n");
|
|
|
|
return VCNL40X0_OK;
|
|
}
|
|
|
|
uint16_t vcnl40x0_read_proximity(const vcnl40x0_t *dev)
|
|
{
|
|
i2c_acquire(DEV_I2C);
|
|
|
|
_set_command_reg(dev,
|
|
VCNL40X0_COMMAND_PROX_ENABLE |
|
|
VCNL40X0_COMMAND_PROX_ON_DEMAND);
|
|
uint16_t cnt = 0xffff;
|
|
while (cnt--) {
|
|
uint8_t reg;
|
|
_get_command_reg(dev, ®);
|
|
if (reg & VCNL40X0_COMMAND_MASK_PROX_DATA_READY) {
|
|
uint8_t prox_buf[2];
|
|
i2c_read_regs(DEV_I2C, DEV_ADDR, VCNL40X0_REG_PROXIMITY_VALUE,
|
|
&prox_buf, 2, 0);
|
|
uint16_t res = (uint16_t)((prox_buf[0] << 8) | prox_buf[1]);
|
|
DEBUG("[vcnl40x0] Proximity read: %i\n", res);
|
|
i2c_release(DEV_I2C);
|
|
return res;
|
|
}
|
|
}
|
|
|
|
i2c_release(DEV_I2C);
|
|
return 0;
|
|
}
|
|
|
|
uint16_t vcnl40x0_read_ambient_light(const vcnl40x0_t *dev)
|
|
{
|
|
i2c_acquire(DEV_I2C);
|
|
|
|
_set_command_reg(dev,
|
|
VCNL40X0_COMMAND_AMBI_ENABLE |
|
|
VCNL40X0_COMMAND_AMBI_ON_DEMAND);
|
|
|
|
uint16_t cnt = 0xffff;
|
|
while (cnt--) {
|
|
uint8_t reg;
|
|
_get_command_reg(dev, ®);
|
|
if (reg & VCNL40X0_COMMAND_MASK_AMBI_DATA_READY) {
|
|
uint8_t ambient_buf[2];
|
|
i2c_read_regs(DEV_I2C, DEV_ADDR, VCNL40X0_REG_AMBIENT_VALUE,
|
|
&ambient_buf, 2, 0);
|
|
uint16_t res = (uint16_t)((ambient_buf[0] << 8) | ambient_buf[1]);
|
|
DEBUG("[vcnl40x0] Ambient light read: %i\n", res);
|
|
i2c_release(DEV_I2C);
|
|
return res;
|
|
}
|
|
}
|
|
|
|
i2c_release(DEV_I2C);
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint16_t vcnl40x0_read_illuminance(const vcnl40x0_t *dev)
|
|
{
|
|
return vcnl40x0_read_ambient_light(dev) >> 2;
|
|
}
|