1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/si114x/si114x.c

266 lines
7.7 KiB
C

/*
* Copyright (C) 2016-2018 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_si114x
* @{
*
* @file
* @brief Device driver implementation for the Si114x proximity/UV/Ambient
* light sensor with I2C interface.
*
* @author Alexandre Abadie <alexandre.abadie@inria.fr>
* Bas Stottelaar <basstottelaar@gmail.com>
*
* @}
*/
#include <math.h>
#include <string.h>
#include <stdint.h>
#include "ztimer.h"
#include "periph/i2c.h"
#include "si114x.h"
#include "si114x_internals.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#define DEV_I2C (dev->params.i2c_dev)
/* Internal function prototypes */
static void _reset(si114x_t *dev);
static void _initialize(si114x_t *dev);
static void _set_param(si114x_t *dev, uint8_t param, uint8_t value);
/*---------------------------------------------------------------------------*
* Si114x Core API *
*---------------------------------------------------------------------------*/
int8_t si114x_init(si114x_t *dev, const si114x_params_t *params)
{
dev->params = *params;
/* wait before sensor is ready */
ztimer_sleep(ZTIMER_MSEC, SI114X_STARTUP_TIME_MS);
/* acquire exclusive access */
i2c_acquire(DEV_I2C);
/* check sensor ID */
char checkid = 0;
i2c_read_reg(DEV_I2C, SI114X_ADDR, SI114X_REG_PART_ID, &checkid, 0);
if ((checkid != SI1145_ID) && (checkid != SI1146_ID) && (checkid != SI1147_ID)) {
DEBUG("[Error] The given i2c is not enabled.\n");
i2c_release(DEV_I2C);
return -SI114X_ERR_NODEV;
}
/* reset sensor */
_reset(dev);
/* initialize internals registers */
_initialize(dev);
/* release I2C device */
i2c_release(DEV_I2C);
return SI114X_OK;
}
uint16_t si114x_read_uv(si114x_t *dev)
{
/* acquire exclusive access */
i2c_acquire(DEV_I2C);
uint8_t buffer[2];
i2c_read_regs(DEV_I2C, SI114X_ADDR,
SI114X_REG_UV_INDEX0, &buffer, 2, 0);
/* release I2C device */
i2c_release(DEV_I2C);
return (uint16_t)(((buffer[1] << 8) | buffer[0]) / 100);
}
uint16_t si114x_read_ir(si114x_t *dev)
{
/* acquire exclusive access */
i2c_acquire(DEV_I2C);
uint8_t buffer[2];
i2c_read_regs(DEV_I2C, SI114X_ADDR,
SI114X_REG_ALS_IR_DATA0, &buffer, 2, 0);
/* release I2C device */
i2c_release(DEV_I2C);
return (uint16_t)((buffer[1] << 8) | buffer[0]);
}
uint16_t si114x_read_visible(si114x_t *dev)
{
/* acquire exclusive access */
i2c_acquire(DEV_I2C);
uint8_t buffer[2];
i2c_read_regs(DEV_I2C, SI114X_ADDR,
SI114X_REG_ALS_VIS_DATA0, &buffer, 2, 0);
/* release I2C device */
i2c_release(DEV_I2C);
return (uint16_t)((buffer[1] << 8) | buffer[0]);
}
uint16_t si114x_read_distance(si114x_t *dev)
{
/* acquire exclusive access */
i2c_acquire(DEV_I2C);
uint8_t buffer[2];
i2c_read_regs(DEV_I2C, SI114X_ADDR,
SI114X_REG_PS1_DATA0, &buffer, 2, 0);
/* release I2C device */
i2c_release(DEV_I2C);
return (uint16_t)((buffer[1] << 8) | buffer[0]);
}
uint8_t si114x_read_response(si114x_t *dev)
{
/* acquire exclusive access */
i2c_acquire(DEV_I2C);
uint8_t buffer[1];
i2c_read_regs(DEV_I2C, SI114X_ADDR,
SI114X_REG_RESPONSE, &buffer, 1, 0);
/* release I2C device */
i2c_release(DEV_I2C);
return buffer[0];
}
/*------------------------------------------------------------------------------------*/
/* Internal functions */
/*------------------------------------------------------------------------------------*/
void _reset(si114x_t *dev)
{
DEBUG("Resetting sensor.\n");
/* write configuration values */
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_MEAS_RATE0, 0, 0);
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_MEAS_RATE1, 0, 0);
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_IRQ_ENABLE, 0, 0);
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_IRQ_MODE1, 0, 0);
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_IRQ_MODE2, 0, 0);
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_INT_CFG, 0, 0);
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_IRQ_STATUS, 0xFF, 0);
/* perform RESET command */
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_COMMAND, SI114X_RESET, 0);
ztimer_sleep(ZTIMER_MSEC, SI114X_WAIT_10MS);
/* write HW_KEY for proper operation */
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_HW_KEY, SI114X_INIT_VALUE, 0);
ztimer_sleep(ZTIMER_MSEC, SI114X_WAIT_10MS);
}
void _initialize(si114x_t *dev)
{
DEBUG("Initializing sensor.\n");
/* set default UV measurement coefs */
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_UCOEF0, SI114X_UCOEF0_DEFAULT, 0);
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_UCOEF1, SI114X_UCOEF1_DEFAULT, 0);
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_UCOEF2, SI114X_UCOEF2_DEFAULT, 0);
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_UCOEF3, SI114X_UCOEF3_DEFAULT, 0);
/* enable measures */
_set_param(dev, SI114X_PARAM_CHLIST,
SI114X_PARAM_CHLIST_ENUV | SI114X_PARAM_CHLIST_ENALSIR |
SI114X_PARAM_CHLIST_ENALSVIS | SI114X_PARAM_CHLIST_ENPS1);
/* enable interrupt on every sample */
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_INT_CFG, SI114X_INTCFG_INTOE, 0);
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_IRQ_ENABLE, SI114X_EN_ALS_IE | SI114X_EN_PS1_IE, 0);
/* active LED current */
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_PS_LED21, dev->params.led_current, 0);
_set_param(dev, SI114X_PARAM_PS1ADCMUX, SI114X_PARAM_ADCMUX_LARGEIR);
/* proximity sensor uses LED1 */
_set_param(dev, SI114X_PARAM_PSLED12SEL, SI114X_PARAM_PSLED12SEL_PS1LED1);
/* ADC gain */
_set_param(dev, SI114X_PARAM_PSADCGAIN, 0);
_set_param(dev, SI114X_PARAM_PSADCOUNTER, SI114X_ADC_REC_CLK);
/* proximity range */
_set_param(dev, SI114X_PARAM_PSADCMISC,
SI114X_PARAM_PSADCMISC_RANGE | SI114X_PARAM_PSADCMISC_PSMODE);
_set_param(dev, SI114X_PARAM_ALSIRADCMUX, SI114X_PARAM_ADCMUX_SMALLIR);
/* clocks configuration */
_set_param(dev, SI114X_PARAM_ALSIRADCGAIN, 0);
_set_param(dev, SI114X_PARAM_ALSIRADCOUNTER, SI114X_ADC_REC_CLK);
/* high range mode */
_set_param(dev, SI114X_PARAM_ALSIRADCMISC, SI114X_PARAM_ALSIRADCMISC_RANGE);
/* clocks config */
_set_param(dev, SI114X_PARAM_ALSVISADCGAIN, 0);
_set_param(dev, SI114X_PARAM_ALSVISADCOUNTER, SI114X_ADC_REC_CLK);
_set_param(dev, SI114X_PARAM_ALSVISADCMISC,
SI114X_PARAM_ALSVISADCMISC_VISRANGE);
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_MEAS_RATE0, 0xFF, 0);
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_MEAS_RATE1, 0x00, 0);
/* auto-run */
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_COMMAND, SI114X_PS_ALS_AUTO, 0);
}
void _set_param(si114x_t *dev, uint8_t param, uint8_t value)
{
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_PARAM_WR, value, 0);
i2c_write_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_COMMAND, param | SI114X_PARAM_SET, 0);
uint8_t ret;
i2c_read_reg(DEV_I2C, SI114X_ADDR,
SI114X_REG_PARAM_RD, &ret, 0);
}