/* * Copyright (C) 2017 OTA keys S.A. * 2018 Matthew Blue * * 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_ads101x * @{ * * @file * @brief ADS101x/111x ADC device driver * * @author Vincent Dupont * @author Matthew Blue * @} */ #include "assert.h" #include "periph/i2c.h" #include "periph/gpio.h" #include "xtimer.h" #include "ads101x.h" #include "ads101x_params.h" #include "ads101x_regs.h" #define ENABLE_DEBUG (0) #include "debug.h" #ifndef ADS101X_READ_DELAY #define ADS101X_READ_DELAY (8 * US_PER_MS) /* Compatible with 128SPS */ #endif #define I2C_SPEED I2C_SPEED_FAST #define I2C (dev->params.i2c) #define ADDR (dev->params.addr) static int _ads101x_init_test(i2c_t i2c, uint8_t addr); int ads101x_init(ads101x_t *dev, const ads101x_params_t *params) { assert(dev && params); dev->params = *params; return _ads101x_init_test(I2C, ADDR); } int ads101x_alert_init(ads101x_alert_t *dev, const ads101x_alert_params_t *params) { assert(dev && params); dev->params = *params; dev->cb = NULL; dev->arg = NULL; /* Set up alerts */ ads101x_set_alert_parameters(dev, dev->params.low_limit, dev->params.high_limit); return _ads101x_init_test(I2C, ADDR); } int _ads101x_init_test(i2c_t i2c, uint8_t addr) { uint8_t regs[2]; /* Acquire test */ i2c_acquire(i2c); if (i2c_init_master(i2c, I2C_SPEED) < 0) { i2c_release(i2c); DEBUG("[ads101x] init - error: unable to initialize I2C bus\n"); return ADS101X_NOI2C; } /* Register read/write test */ i2c_read_regs(i2c, addr, ADS101X_CONF_ADDR, ®s, 2); regs[1] = (regs[1] & ~ADS101X_DATAR_MASK) | ADS101X_DATAR_3300; i2c_write_regs(i2c, addr, ADS101X_CONF_ADDR, ®s, 2); i2c_read_regs(i2c, addr, ADS101X_CONF_ADDR, ®s, 2); i2c_release(i2c); /* Write should have actually written the register */ if ((regs[1] & ADS101X_DATAR_MASK) != ADS101X_DATAR_3300) { DEBUG("[ads101x] init - error: unable to set reg (reg=%x)\n", regs[1]); return ADS101X_NODEV; } return ADS101X_OK; } int ads101x_set_mux_gain(const ads101x_t *dev, uint8_t mux_gain) { uint8_t regs[2]; i2c_acquire(I2C); i2c_read_regs(I2C, ADDR, ADS101X_CONF_ADDR, ®s, 2); /* Zero mux and gain */ regs[0] &= ~ADS101X_MUX_MASK; regs[0] &= ~ADS101X_PGA_MASK; /* Write mux and gain */ regs[0] |= mux_gain; i2c_write_regs(I2C, ADDR, ADS101X_CONF_ADDR, ®s, 2); i2c_release(I2C); return ADS101X_OK; } int ads101x_read_raw(const ads101x_t *dev, int16_t *raw) { uint8_t regs[2]; int status; i2c_acquire(I2C); /* Read control register */ i2c_read_regs(I2C, ADDR, ADS101X_CONF_ADDR, ®s, 2); /* Tell the ADC to aquire a single-shot sample */ regs[0] |= ADS101X_CONF_OS_CONV; i2c_write_regs(I2C, ADDR, ADS101X_CONF_ADDR, ®s, 2); /* Wait for the sample to be aquired */ xtimer_usleep(ADS101X_READ_DELAY); /* Read the sample */ status = i2c_read_regs(I2C, ADDR, ADS101X_CONV_RES_ADDR, ®s, 2); i2c_release(I2C); /* Status should equal bytes asked for (2) */ if (status != 2) { return ADS101X_NODATA; } /* If all okay, change raw value */ *raw = (int16_t)(regs[0] << 8) | (int16_t)(regs[1]); return ADS101X_OK; } int ads101x_enable_alert(ads101x_alert_t *dev, ads101x_alert_cb_t cb, void *arg) { uint8_t regs[2]; if (dev->params.alert_pin == GPIO_UNDEF) { return ADS101X_OK; } /* Read control register */ i2c_acquire(I2C); i2c_read_regs(I2C, ADDR, ADS101X_CONF_ADDR, ®s, 2); /* Enable alert comparator */ regs[1] &= ~ADS101X_CONF_COMP_DIS; i2c_write_regs(I2C, ADDR, ADS101X_CONF_ADDR, ®s, 2); i2c_release(I2C); /* Enable interrupt */ dev->arg = arg; dev->cb = cb; gpio_init_int(dev->params.alert_pin, GPIO_IN, GPIO_FALLING, cb, arg); return ADS101X_OK; } int ads101x_set_alert_parameters(const ads101x_alert_t *dev, int16_t low_limit, int16_t high_limit) { uint8_t regs[2]; i2c_acquire(I2C); /* Set up low_limit */ regs[0] = (uint8_t)(low_limit >> 8); regs[1] = (uint8_t)low_limit; i2c_write_regs(I2C, ADDR, ADS101X_LOW_LIMIT_ADDR, ®s, 2); /* Set up high_limit */ regs[0] = (uint8_t)(high_limit >> 8); regs[1] = (uint8_t)high_limit; i2c_write_regs(I2C, ADDR, ADS101X_HIGH_LIMIT_ADDR, ®s, 2); /* Read control register */ i2c_read_regs(I2C, ADDR, ADS101X_CONF_ADDR, ®s, 2); /* Set up window mode */ if (low_limit != 0) { /* Enable window mode */ regs[1] |= ADS101X_CONF_COMP_MODE_WIND; } else { /* Disable window mode */ regs[1] &= ~ADS101X_CONF_COMP_MODE_WIND; } i2c_write_regs(I2C, ADDR, ADS101X_CONF_ADDR, ®s, 2); i2c_release(I2C); return ADS101X_OK; }