From 4338d009bd6620f8fc73d22a40daaccab51540ff Mon Sep 17 00:00:00 2001 From: Pawel Jasinski Date: Mon, 29 Jan 2018 22:21:16 +0100 Subject: [PATCH] added support for ads1015 (#2231) * ads1015 is supported, up to 4 devices can be connected at the same time * removed debug, updated documentation * changed to oop API * added __gc to handle active timer cleanup * reworked argument validation and error reporting * stack is no longer messed up after __del --- app/modules/ads1115.c | 905 +++++++++++++++++++++---------------- docs/en/modules/ads1115.md | 175 ++++--- 2 files changed, 638 insertions(+), 442 deletions(-) diff --git a/app/modules/ads1115.c b/app/modules/ads1115.c index e956fbb323..e814e43002 100644 --- a/app/modules/ads1115.c +++ b/app/modules/ads1115.c @@ -8,441 +8,564 @@ #include "lauxlib.h" #include "platform.h" #include "osapi.h" +#include "c_stdlib.h" + + +//*************************************************************************** +// CHIP +//*************************************************************************** +#define ADS1115_ADS1015 ( 15) +#define ADS1115_ADS1115 (115) //*************************************************************************** // I2C ADDRESS DEFINITON //*************************************************************************** -#define ADS1115_I2C_ADDR_GND (0x48) -#define ADS1115_I2C_ADDR_VDD (0x49) -#define ADS1115_I2C_ADDR_SDA (0x4A) -#define ADS1115_I2C_ADDR_SCL (0x4B) +#define ADS1115_I2C_ADDR_GND (0x48) +#define ADS1115_I2C_ADDR_VDD (0x49) +#define ADS1115_I2C_ADDR_SDA (0x4A) +#define ADS1115_I2C_ADDR_SCL (0x4B) +#define IS_I2C_ADDR_VALID(addr) (((addr) & 0xFC) == 0x48) //*************************************************************************** // POINTER REGISTER //*************************************************************************** -#define ADS1115_POINTER_MASK (0x03) -#define ADS1115_POINTER_CONVERSION (0x00) -#define ADS1115_POINTER_CONFIG (0x01) -#define ADS1115_POINTER_THRESH_LOW (0x02) -#define ADS1115_POINTER_THRESH_HI (0x03) +#define ADS1115_POINTER_MASK (0x03) +#define ADS1115_POINTER_CONVERSION (0x00) +#define ADS1115_POINTER_CONFIG (0x01) +#define ADS1115_POINTER_THRESH_LOW (0x02) +#define ADS1115_POINTER_THRESH_HI (0x03) //*************************************************************************** // CONFIG REGISTER //*************************************************************************** -#define ADS1115_OS_MASK (0x8000) -#define ADS1115_OS_NON (0x0000) -#define ADS1115_OS_SINGLE (0x8000) // Write: Set to start a single-conversion -#define ADS1115_OS_BUSY (0x0000) // Read: Bit = 0 when conversion is in progress -#define ADS1115_OS_NOTBUSY (0x8000) // Read: Bit = 1 when device is not performing a conversion - -#define ADS1115_MUX_MASK (0x7000) -#define ADS1115_MUX_DIFF_0_1 (0x0000) // Differential P = AIN0, N = AIN1 (default) -#define ADS1115_MUX_DIFF_0_3 (0x1000) // Differential P = AIN0, N = AIN3 -#define ADS1115_MUX_DIFF_1_3 (0x2000) // Differential P = AIN1, N = AIN3 -#define ADS1115_MUX_DIFF_2_3 (0x3000) // Differential P = AIN2, N = AIN3 -#define ADS1115_MUX_SINGLE_0 (0x4000) // Single-ended AIN0 -#define ADS1115_MUX_SINGLE_1 (0x5000) // Single-ended AIN1 -#define ADS1115_MUX_SINGLE_2 (0x6000) // Single-ended AIN2 -#define ADS1115_MUX_SINGLE_3 (0x7000) // Single-ended AIN3 - -#define ADS1115_PGA_MASK (0x0E00) -#define ADS1115_PGA_6_144V (0x0000) // +/-6.144V range = Gain 2/3 -#define ADS1115_PGA_4_096V (0x0200) // +/-4.096V range = Gain 1 -#define ADS1115_PGA_2_048V (0x0400) // +/-2.048V range = Gain 2 (default) -#define ADS1115_PGA_1_024V (0x0600) // +/-1.024V range = Gain 4 -#define ADS1115_PGA_0_512V (0x0800) // +/-0.512V range = Gain 8 -#define ADS1115_PGA_0_256V (0x0A00) // +/-0.256V range = Gain 16 - -#define ADS1115_MODE_MASK (0x0100) -#define ADS1115_MODE_CONTIN (0x0000) // Continuous conversion mode -#define ADS1115_MODE_SINGLE (0x0100) // Power-down single-shot mode (default) - -#define ADS1115_DR_MASK (0x00E0) -#define ADS1115_DR_8SPS (0x0000) // 8 samples per second -#define ADS1115_DR_16SPS (0x0020) // 16 samples per second -#define ADS1115_DR_32SPS (0x0040) // 32 samples per second -#define ADS1115_DR_64SPS (0x0060) // 64 samples per second -#define ADS1115_DR_128SPS (0x0080) // 128 samples per second (default) -#define ADS1115_DR_250SPS (0x00A0) // 250 samples per second -#define ADS1115_DR_475SPS (0x00C0) // 475 samples per second -#define ADS1115_DR_860SPS (0x00E0) // 860 samples per second - -#define ADS1115_CMODE_MASK (0x0010) -#define ADS1115_CMODE_TRAD (0x0000) // Traditional comparator with hysteresis (default) -#define ADS1115_CMODE_WINDOW (0x0010) // Window comparator - -#define ADS1115_CPOL_MASK (0x0008) -#define ADS1115_CPOL_ACTVLOW (0x0000) // ALERT/RDY pin is low when active (default) -#define ADS1115_CPOL_ACTVHI (0x0008) // ALERT/RDY pin is high when active - -#define ADS1115_CLAT_MASK (0x0004) // Determines if ALERT/RDY pin latches once asserted -#define ADS1115_CLAT_NONLAT (0x0000) // Non-latching comparator (default) -#define ADS1115_CLAT_LATCH (0x0004) // Latching comparator - -#define ADS1115_CQUE_MASK (0x0003) -#define ADS1115_CQUE_1CONV (0x0000) // Assert ALERT/RDY after one conversions -#define ADS1115_CQUE_2CONV (0x0001) // Assert ALERT/RDY after two conversions -#define ADS1115_CQUE_4CONV (0x0002) // Assert ALERT/RDY after four conversions -#define ADS1115_CQUE_NONE (0x0003) // Disable the comparator and put ALERT/RDY in high state (default) +#define ADS1115_OS_MASK (0x8000) +#define ADS1115_OS_NON (0x0000) +#define ADS1115_OS_SINGLE (0x8000) // Write: Set to start a single-conversion +#define ADS1115_OS_BUSY (0x0000) // Read: Bit = 0 when conversion is in progress +#define ADS1115_OS_NOTBUSY (0x8000) // Read: Bit = 1 when device is not performing a conversion + +#define ADS1115_MUX_MASK (0x7000) +#define ADS1115_MUX_DIFF_0_1 (0x0000) // Differential P = AIN0, N = AIN1 (default) +#define ADS1115_MUX_DIFF_0_3 (0x1000) // Differential P = AIN0, N = AIN3 +#define ADS1115_MUX_DIFF_1_3 (0x2000) // Differential P = AIN1, N = AIN3 +#define ADS1115_MUX_DIFF_2_3 (0x3000) // Differential P = AIN2, N = AIN3 +#define ADS1115_MUX_SINGLE_0 (0x4000) // Single-ended AIN0 +#define ADS1115_MUX_SINGLE_1 (0x5000) // Single-ended AIN1 +#define ADS1115_MUX_SINGLE_2 (0x6000) // Single-ended AIN2 +#define ADS1115_MUX_SINGLE_3 (0x7000) // Single-ended AIN3 +#define IS_CHANNEL_VALID(channel) (((channel) & 0x8FFF) == 0) + +#define ADS1115_PGA_MASK (0x0E00) +#define ADS1115_PGA_6_144V (0x0000) // +/-6.144V range = Gain 2/3 +#define ADS1115_PGA_4_096V (0x0200) // +/-4.096V range = Gain 1 +#define ADS1115_PGA_2_048V (0x0400) // +/-2.048V range = Gain 2 (default) +#define ADS1115_PGA_1_024V (0x0600) // +/-1.024V range = Gain 4 +#define ADS1115_PGA_0_512V (0x0800) // +/-0.512V range = Gain 8 +#define ADS1115_PGA_0_256V (0x0A00) // +/-0.256V range = Gain 16 + +#define ADS1115_MODE_MASK (0x0100) +#define ADS1115_MODE_CONTIN (0x0000) // Continuous conversion mode +#define ADS1115_MODE_SINGLE (0x0100) // Power-down single-shot mode (default) + +#define ADS1115_DR_MASK (0x00E0) +#define ADS1115_DR_8SPS ( 8) +#define ADS1115_DR_16SPS ( 16) +#define ADS1115_DR_32SPS ( 32) +#define ADS1115_DR_64SPS ( 64) +#define ADS1115_DR_128SPS ( 128) +#define ADS1115_DR_250SPS ( 250) +#define ADS1115_DR_475SPS ( 475) +#define ADS1115_DR_490SPS ( 490) +#define ADS1115_DR_860SPS ( 860) +#define ADS1115_DR_920SPS ( 920) +#define ADS1115_DR_1600SPS (1600) +#define ADS1115_DR_2400SPS (2400) +#define ADS1115_DR_3300SPS (3300) + +#define ADS1115_CMODE_MASK (0x0010) +#define ADS1115_CMODE_TRAD (0x0000) // Traditional comparator with hysteresis (default) +#define ADS1115_CMODE_WINDOW (0x0010) // Window comparator + +#define ADS1115_CPOL_MASK (0x0008) +#define ADS1115_CPOL_ACTVLOW (0x0000) // ALERT/RDY pin is low when active (default) +#define ADS1115_CPOL_ACTVHI (0x0008) // ALERT/RDY pin is high when active + +#define ADS1115_CLAT_MASK (0x0004) // Determines if ALERT/RDY pin latches once asserted +#define ADS1115_CLAT_NONLAT (0x0000) // Non-latching comparator (default) +#define ADS1115_CLAT_LATCH (0x0004) // Latching comparator + +#define ADS1115_CQUE_MASK (0x0003) +#define ADS1115_CQUE_1CONV (0x0000) // Assert ALERT/RDY after one conversions +#define ADS1115_CQUE_2CONV (0x0001) // Assert ALERT/RDY after two conversions +#define ADS1115_CQUE_4CONV (0x0002) // Assert ALERT/RDY after four conversions +#define ADS1115_CQUE_NONE (0x0003) // Disable the comparator and put ALERT/RDY in high state (default) + +#define ADS1115_DEFAULT_CONFIG_REG (0x8583) // Config register value after reset //*************************************************************************** static const uint8_t ads1115_i2c_id = 0; static const uint8_t general_i2c_addr = 0x00; static const uint8_t ads1115_i2c_reset = 0x06; -static uint8_t ads1115_i2c_addr = ADS1115_I2C_ADDR_GND; -static uint16_t ads1115_os = ADS1115_OS_SINGLE; -static uint16_t ads1115_gain = ADS1115_PGA_6_144V; -static uint16_t ads1115_samples = ADS1115_DR_128SPS; -static uint16_t ads1115_channel = ADS1115_MUX_SINGLE_0; -static uint16_t ads1115_comp = ADS1115_CQUE_NONE; -static uint16_t ads1115_mode = ADS1115_MODE_SINGLE; -static uint16_t ads1115_threshold_low = 0x8000; -static uint16_t ads1115_threshold_hi = 0x7FFF; -static uint16_t ads1115_config = 0x8583; -static uint16_t ads1115_conversion = 0; -static double ads1115_volt = 0; -os_timer_t ads1115_timer; // timer for conversion delay -int ads1115_timer_ref; // callback when readout is ready - -static int ads1115_lua_readoutdone(void); - -static uint8_t write_reg(uint8_t reg, uint16_t config) { - platform_i2c_send_start(ads1115_i2c_id); - platform_i2c_send_address(ads1115_i2c_id, ads1115_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER); - platform_i2c_send_byte(ads1115_i2c_id, reg); - platform_i2c_send_byte(ads1115_i2c_id, (uint8_t)(config >> 8)); - platform_i2c_send_byte(ads1115_i2c_id, (uint8_t)(config & 0xFF)); - platform_i2c_send_stop(ads1115_i2c_id); +static const char metatable_name[] = "ads1115.device"; +static const char unexpected_value[] = "unexpected value"; + +typedef struct { + uint8_t i2c_addr; + uint8_t chip_id; + uint16_t gain; + uint16_t samples_value; // sample per second + uint16_t samples; // register value + uint16_t comp; + uint16_t mode; + uint16_t threshold_low; + uint16_t threshold_hi; + uint16_t config; + int timer_ref; + os_timer_t timer; +} ads_ctrl_ud_t; + + +static int ads1115_lua_readoutdone(void * param); +static int ads1115_lua_register(lua_State *L, uint8_t chip_id); + +static uint8_t write_reg(uint8_t ads_addr, uint8_t reg, uint16_t config) { + platform_i2c_send_start(ads1115_i2c_id); + platform_i2c_send_address(ads1115_i2c_id, ads_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER); + platform_i2c_send_byte(ads1115_i2c_id, reg); + platform_i2c_send_byte(ads1115_i2c_id, (uint8_t)(config >> 8)); + platform_i2c_send_byte(ads1115_i2c_id, (uint8_t)(config & 0xFF)); + platform_i2c_send_stop(ads1115_i2c_id); } -static uint16_t read_reg(uint8_t reg) { - platform_i2c_send_start(ads1115_i2c_id); - platform_i2c_send_address(ads1115_i2c_id, ads1115_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER); - platform_i2c_send_byte(ads1115_i2c_id, reg); - platform_i2c_send_stop(ads1115_i2c_id); - platform_i2c_send_start(ads1115_i2c_id); - platform_i2c_send_address(ads1115_i2c_id, ads1115_i2c_addr, PLATFORM_I2C_DIRECTION_RECEIVER); - uint16_t buf = (platform_i2c_recv_byte(ads1115_i2c_id, 1) << 8); - buf += platform_i2c_recv_byte(ads1115_i2c_id, 0); - platform_i2c_send_stop(ads1115_i2c_id); - return buf; +static uint16_t read_reg(uint8_t ads_addr, uint8_t reg) { + platform_i2c_send_start(ads1115_i2c_id); + platform_i2c_send_address(ads1115_i2c_id, ads_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER); + platform_i2c_send_byte(ads1115_i2c_id, reg); + platform_i2c_send_stop(ads1115_i2c_id); + platform_i2c_send_start(ads1115_i2c_id); + platform_i2c_send_address(ads1115_i2c_id, ads_addr, PLATFORM_I2C_DIRECTION_RECEIVER); + uint16_t buf = (platform_i2c_recv_byte(ads1115_i2c_id, 1) << 8); + buf += platform_i2c_recv_byte(ads1115_i2c_id, 0); + platform_i2c_send_stop(ads1115_i2c_id); + return buf; } // convert ADC value to voltage corresponding to PGA settings -static double get_volt(uint16_t value) { - - double volt = 0; - - switch (ads1115_gain) { - case (ADS1115_PGA_6_144V): - volt = (int16_t)value * 0.1875; - break; - case (ADS1115_PGA_4_096V): - volt = (int16_t)value * 0.125; - break; - case (ADS1115_PGA_2_048V): - volt = (int16_t)value * 0.0625; - break; - case (ADS1115_PGA_1_024V): - volt = (int16_t)value * 0.03125; - break; - case (ADS1115_PGA_0_512V): - volt = (int16_t)value * 0.015625; - break; - case (ADS1115_PGA_0_256V): - volt = (int16_t)value * 0.0078125; - break; - } - - return volt; +static double get_volt(uint16_t gain, uint16_t value) { + + double volt = 0; + + switch (gain) { + case (ADS1115_PGA_6_144V): + volt = (int16_t)value * 0.1875; + break; + case (ADS1115_PGA_4_096V): + volt = (int16_t)value * 0.125; + break; + case (ADS1115_PGA_2_048V): + volt = (int16_t)value * 0.0625; + break; + case (ADS1115_PGA_1_024V): + volt = (int16_t)value * 0.03125; + break; + case (ADS1115_PGA_0_512V): + volt = (int16_t)value * 0.015625; + break; + case (ADS1115_PGA_0_256V): + volt = (int16_t)value * 0.0078125; + break; + } + + return volt; +} + +// validates and convert threshold in volt to ADC value corresponding to PGA settings +// returns true if valid +static uint8_t get_value(uint16_t gain, uint16_t channel, int16_t *volt) { + switch (gain) { + case (ADS1115_PGA_6_144V): + if ((*volt >= 6144) || (*volt < -6144) || ((*volt < 0) && (channel >> 14))) return 0; + *volt = *volt / 0.1875; + break; + case (ADS1115_PGA_4_096V): + if ((*volt >= 4096) || (*volt < -4096) || ((*volt < 0) && (channel >> 14))) return 0; + *volt = *volt / 0.125; + break; + case (ADS1115_PGA_2_048V): + if ((*volt >= 2048) || (*volt < -2048) || ((*volt < 0) && (channel >> 14))) return 0; + *volt = *volt / 0.0625; + break; + case (ADS1115_PGA_1_024V): + if ((*volt >= 1024) || (*volt < -1024) || ((*volt < 0) && (channel >> 14))) return 0; + *volt = *volt / 0.03125; + break; + case (ADS1115_PGA_0_512V): + if ((*volt >= 512) || (*volt < -512) || ((*volt < 0) && (channel >> 14))) return 0; + *volt = *volt / 0.015625; + break; + case (ADS1115_PGA_0_256V): + if ((*volt >= 256) || (*volt < -256) || ((*volt < 0) && (channel >> 14))) return 0; + *volt = *volt / 0.0078125; + break; + } + return 1; +} + + +// Reset of all devices +// Lua: ads1115.reset() +static int ads1115_lua_reset(lua_State *L) { + platform_i2c_send_start(ads1115_i2c_id); + platform_i2c_send_address(ads1115_i2c_id, general_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER); + platform_i2c_send_byte(ads1115_i2c_id, ads1115_i2c_reset); + platform_i2c_send_stop(ads1115_i2c_id); + return 0; +} + +// Register an ADS device +// Lua: ads1115.ADS1115(I2C_ID, ADDRESS) +static int ads1115_lua_register_1115(lua_State *L) { + return ads1115_lua_register(L, ADS1115_ADS1115); } -// convert threshold in volt to ADC value corresponding to PGA settings -static uint8_t get_value(int16_t *volt) { - - switch (ads1115_gain) { - case (ADS1115_PGA_6_144V): - if ((*volt >= 6144) || (*volt < -6144) || ((*volt < 0) && (ads1115_channel >> 14))) return 1; - *volt = *volt / 0.1875; - break; - case (ADS1115_PGA_4_096V): - if ((*volt >= 4096) || (*volt < -4096) || ((*volt < 0) && (ads1115_channel >> 14))) return 1; - *volt = *volt / 0.125; - break; - case (ADS1115_PGA_2_048V): - if ((*volt >= 2048) || (*volt < -2048) || ((*volt < 0) && (ads1115_channel >> 14))) return 1; - *volt = *volt / 0.0625; - break; - case (ADS1115_PGA_1_024V): - if ((*volt >= 1024) || (*volt < -1024) || ((*volt < 0) && (ads1115_channel >> 14))) return 1; - *volt = *volt / 0.03125; - break; - case (ADS1115_PGA_0_512V): - if ((*volt >= 512) || (*volt < -512) || ((*volt < 0) && (ads1115_channel >> 14))) return 1; - *volt = *volt / 0.015625; - break; - case (ADS1115_PGA_0_256V): - if ((*volt >= 256) || (*volt < -256) || ((*volt < 0) && (ads1115_channel >> 14))) return 1; - *volt = *volt / 0.0078125; - break; - } - - return 0; +static int ads1115_lua_register_1015(lua_State *L) { + return ads1115_lua_register(L, ADS1115_ADS1015); } -// Initializes ADC -// Lua: ads11115.setup(ADDRESS) -static int ads1115_lua_setup(lua_State *L) { - - // check variables - if (!lua_isnumber(L, 1)) { - return luaL_error(L, "wrong arg range"); - } - - ads1115_i2c_addr = luaL_checkinteger(L, 1); - if (!((ads1115_i2c_addr == ADS1115_I2C_ADDR_GND) || (ads1115_i2c_addr == ADS1115_I2C_ADDR_VDD) || (ads1115_i2c_addr == ADS1115_I2C_ADDR_SDA) || (ads1115_i2c_addr == ADS1115_I2C_ADDR_SCL))) { - return luaL_error(L, "Invalid argument: adddress"); - } - - platform_i2c_send_start(ads1115_i2c_id); - platform_i2c_send_address(ads1115_i2c_id, general_i2c_addr, PLATFORM_I2C_DIRECTION_TRANSMITTER); - platform_i2c_send_byte(ads1115_i2c_id, ads1115_i2c_reset); - platform_i2c_send_stop(ads1115_i2c_id); - - // check for device on i2c bus - if (read_reg(ADS1115_POINTER_CONFIG) != 0x8583) { - return luaL_error(L, "found no device"); - } - - return 0; +static int ads1115_lua_register(lua_State *L, uint8_t chip_id) { + uint8_t i2c_id = luaL_checkinteger(L, 1); + luaL_argcheck(L, 0 == i2c_id, 1, "i2c_id must be 0"); + uint8_t i2c_addr = luaL_checkinteger(L, 2); + luaL_argcheck(L, IS_I2C_ADDR_VALID(i2c_addr), 2, unexpected_value); + uint16_t config_read = read_reg(i2c_addr, ADS1115_POINTER_CONFIG); + if (config_read == 0xFFFF) { + return luaL_error(L, "found no device"); + } + if (config_read != ADS1115_DEFAULT_CONFIG_REG) { + return luaL_error(L, "unexpected config value (%p) please reset device before calling this function", config_read); + } + ads_ctrl_ud_t *ads_ctrl = (ads_ctrl_ud_t *)lua_newuserdata(L, sizeof(ads_ctrl_ud_t)); + if (NULL == ads_ctrl) { + return luaL_error(L, "ads1115 malloc: out of memory"); + } + luaL_getmetatable(L, metatable_name); + lua_setmetatable(L, -2); + ads_ctrl->chip_id = chip_id; + ads_ctrl->i2c_addr = i2c_addr; + ads_ctrl->gain = ADS1115_PGA_6_144V; + ads_ctrl->samples = ADS1115_DR_128SPS; + ads_ctrl->samples_value = chip_id == ADS1115_ADS1115 ? 128 : 1600; + ads_ctrl->comp = ADS1115_CQUE_NONE; + ads_ctrl->mode = ADS1115_MODE_SINGLE; + ads_ctrl->threshold_low = 0x8000; + ads_ctrl->threshold_hi = 0x7FFF; + ads_ctrl->config = ADS1115_DEFAULT_CONFIG_REG; + ads_ctrl->timer_ref = LUA_NOREF; + return 1; } -// Change ADC settings -// Lua: ads1115.setting(GAIN,SAMPLES,CHANNEL,MODE[,CONVERSION_RDY][,COMPARATOR,THRESHOLD_LOW,THRESHOLD_HI]) +// Change the ADC device settings +// Lua: ads1115.device:settings(GAIN,SAMPLES,CHANNEL,MODE[,CONVERSION_RDY][,COMPARATOR,THRESHOLD_LOW,THRESHOLD_HI[,COMP_MODE]) static int ads1115_lua_setting(lua_State *L) { - - // check variables - if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4)) { - return luaL_error(L, "wrong arg range"); - } - - ads1115_gain = luaL_checkinteger(L, 1); - if (!((ads1115_gain == ADS1115_PGA_6_144V) || (ads1115_gain == ADS1115_PGA_4_096V) || (ads1115_gain == ADS1115_PGA_2_048V) || (ads1115_gain == ADS1115_PGA_1_024V) || (ads1115_gain == ADS1115_PGA_0_512V) || (ads1115_gain == ADS1115_PGA_0_256V))) { - return luaL_error(L, "Invalid argument: gain"); - } - - ads1115_samples = luaL_checkinteger(L, 2); - if (!((ads1115_samples == ADS1115_DR_8SPS) || (ads1115_samples == ADS1115_DR_16SPS) || (ads1115_samples == ADS1115_DR_32SPS) || (ads1115_samples == ADS1115_DR_64SPS) || (ads1115_samples == ADS1115_DR_128SPS) || (ads1115_samples == ADS1115_DR_250SPS) || (ads1115_samples == ADS1115_DR_475SPS) || (ads1115_samples == ADS1115_DR_860SPS))) { - return luaL_error(L, "Invalid argument: samples"); - } - - ads1115_channel = luaL_checkinteger(L, 3); - if (!((ads1115_channel == ADS1115_MUX_SINGLE_0) || (ads1115_channel == ADS1115_MUX_SINGLE_1) || (ads1115_channel == ADS1115_MUX_SINGLE_2) || (ads1115_channel == ADS1115_MUX_SINGLE_3) || (ads1115_channel == ADS1115_MUX_DIFF_0_1) || (ads1115_channel == ADS1115_MUX_DIFF_0_3) || (ads1115_channel == ADS1115_MUX_DIFF_1_3) || (ads1115_channel == ADS1115_MUX_DIFF_2_3))) { - return luaL_error(L, "Invalid argument: channel"); - } - - ads1115_mode = luaL_checkinteger(L, 4); - if (!((ads1115_mode == ADS1115_MODE_SINGLE) || (ads1115_mode == ADS1115_MODE_CONTIN))) { - return luaL_error(L, "Invalid argument: mode"); - } - - if (ads1115_mode == ADS1115_MODE_SINGLE) { - ads1115_os = ADS1115_OS_SINGLE; - } else { - ads1115_os = ADS1115_OS_NON; - } - - ads1115_comp = ADS1115_CQUE_NONE; - - // Parse optional parameters - if (lua_isnumber(L, 5) && !(lua_isnumber(L, 6) || lua_isnumber(L, 7))) { - - // conversion ready mode - ads1115_comp = luaL_checkinteger(L, 5); - if (!((ads1115_comp == ADS1115_CQUE_1CONV) || (ads1115_comp == ADS1115_CQUE_2CONV) || (ads1115_comp == ADS1115_CQUE_4CONV))) { - return luaL_error(L, "Invalid argument: conversion ready mode"); - } - - ads1115_threshold_low = 0x7FFF; - ads1115_threshold_hi = 0x8000; - - write_reg(ADS1115_POINTER_THRESH_LOW, ads1115_threshold_low); - write_reg(ADS1115_POINTER_THRESH_HI, ads1115_threshold_hi); - - } else if (lua_isnumber(L, 5) && lua_isnumber(L, 6) && lua_isnumber(L, 7)) { - - // comparator mode - ads1115_comp = luaL_checkinteger(L, 5); - if (!((ads1115_comp == ADS1115_CQUE_1CONV) || (ads1115_comp == ADS1115_CQUE_2CONV) || (ads1115_comp == ADS1115_CQUE_4CONV))) { - return luaL_error(L, "Invalid argument: comparator mode"); - } - - ads1115_threshold_low = luaL_checkinteger(L, 5); - ads1115_threshold_hi = luaL_checkinteger(L, 6); - - if ((int16_t)ads1115_threshold_low > (int16_t)ads1115_threshold_hi) { - return luaL_error(L, "Invalid argument: threshold_low > threshold_hi"); - } - - if (get_value(&ads1115_threshold_low)) { - return luaL_error(L, "Invalid argument: threshold_low"); - } - - if (get_value(&ads1115_threshold_hi)) { - return luaL_error(L, "Invalid argument: threshold_hi"); - } - - write_reg(ADS1115_POINTER_THRESH_LOW, ads1115_threshold_low); - write_reg(ADS1115_POINTER_THRESH_HI, ads1115_threshold_hi); - - } - - ads1115_config = (ads1115_os | ads1115_channel | ads1115_gain | ads1115_mode | ads1115_samples | ADS1115_CMODE_TRAD | ADS1115_CPOL_ACTVLOW | ADS1115_CLAT_NONLAT | ads1115_comp); - - write_reg(ADS1115_POINTER_CONFIG, ads1115_config); - - return 0; + int argc = lua_gettop(L); + if (argc != 5 && argc != 6 && argc != 8 && argc != 9) { // user data counts + luaL_error(L, "invalid number of arguments to 'setting'"); + } + ads_ctrl_ud_t *ads_ctrl = luaL_checkudata(L, 1, metatable_name); + // gain + uint16_t gain = luaL_checkinteger(L, 2); + luaL_argcheck(L, (gain == ADS1115_PGA_6_144V) || (gain == ADS1115_PGA_4_096V) || (gain == ADS1115_PGA_2_048V) || + (gain == ADS1115_PGA_1_024V) || (gain == ADS1115_PGA_0_512V) || (gain == ADS1115_PGA_0_256V), + 2, unexpected_value); + ads_ctrl->gain = gain; + // samples + uint16_t samples_value = luaL_checkinteger(L, 3); + uint16_t samples = 0; + if (ads_ctrl->chip_id == ADS1115_ADS1115) { + switch(samples_value) { + case ADS1115_DR_8SPS: + samples = 0; + break; + case ADS1115_DR_16SPS: + samples = 0x20; + break; + case ADS1115_DR_32SPS: + samples = 0x40; + break; + case ADS1115_DR_64SPS: + samples = 0x60; + break; + case ADS1115_DR_128SPS: // default + samples = 0x80; + break; + case ADS1115_DR_250SPS: + samples = 0xA0; + break; + case ADS1115_DR_475SPS: + samples = 0xC0; + break; + case ADS1115_DR_860SPS: + samples = 0xE0; + break; + default: + luaL_argerror(L, 3, unexpected_value); + } + } else { // ADS1115_ADS1015 + switch(samples_value) { + case ADS1115_DR_128SPS: + samples = 0; + break; + case ADS1115_DR_250SPS: + samples = 0x20; + break; + case ADS1115_DR_490SPS: + samples = 0x40; + break; + case ADS1115_DR_920SPS: + samples = 0x60; + break; + case ADS1115_DR_1600SPS: // default + samples = 0x80; + break; + case ADS1115_DR_2400SPS: + samples = 0xA0; + break; + case ADS1115_DR_3300SPS: + samples = 0xC0; + break; + default: + luaL_argerror(L, 3, unexpected_value); + } + } + ads_ctrl->samples = samples; + ads_ctrl->samples_value = samples_value; + // channel + uint16_t channel = luaL_checkinteger(L, 4); + luaL_argcheck(L, IS_CHANNEL_VALID(channel), 4, unexpected_value); + // mode + uint16_t mode = luaL_checkinteger(L, 5); + luaL_argcheck(L, (mode == ADS1115_MODE_SINGLE) || (mode == ADS1115_MODE_CONTIN), 5, unexpected_value); + ads_ctrl->mode = mode; + uint16_t os = mode == ADS1115_MODE_SINGLE ? ADS1115_OS_SINGLE : ADS1115_OS_NON; + + uint16_t comp = ADS1115_CQUE_NONE; + // Parse optional parameters + if (argc > 5) { + // comparator or conversion count + comp = luaL_checkinteger(L, 6); + luaL_argcheck(L, (comp == ADS1115_CQUE_1CONV) || (comp == ADS1115_CQUE_2CONV) || (comp == ADS1115_CQUE_4CONV), + 6, unexpected_value); + uint16_t threshold_low = 0x7FFF; + uint16_t threshold_hi = 0x8000; + if (argc > 6) { + // comparator thresholds + threshold_low = luaL_checkinteger(L, 7); + threshold_hi = luaL_checkinteger(L, 8); + luaL_argcheck(L, (int16_t)threshold_low <= (int16_t)threshold_hi, 7, "threshold_low > threshold_hi"); + luaL_argcheck(L, get_value(gain, channel, &threshold_low), 7, unexpected_value); + luaL_argcheck(L, get_value(gain, channel, &threshold_hi), 8, unexpected_value); + } + ads_ctrl->threshold_low = threshold_low; + ads_ctrl->threshold_hi = threshold_hi; + NODE_DBG("ads1115 low: %04x\n", threshold_low); + NODE_DBG("ads1115 hi : %04x\n", threshold_hi); + write_reg(ads_ctrl->i2c_addr, ADS1115_POINTER_THRESH_LOW, threshold_low); + write_reg(ads_ctrl->i2c_addr, ADS1115_POINTER_THRESH_HI, threshold_hi); + } + ads_ctrl->comp = comp; + + uint16_t comparator_mode = ADS1115_CMODE_TRAD; + if (argc == 9) { + comparator_mode = luaL_checkinteger(L, 9); + luaL_argcheck(L, (comparator_mode == ADS1115_CMODE_WINDOW) || (comparator_mode == ADS1115_CMODE_TRAD), + 9, unexpected_value); + } + + uint16_t config = (os | channel | gain | mode | samples | comparator_mode | ADS1115_CPOL_ACTVLOW | ADS1115_CLAT_NONLAT | comp); + ads_ctrl->config = config; + + NODE_DBG("ads1115 config: %04x\n", ads_ctrl->config); + write_reg(ads_ctrl->i2c_addr, ADS1115_POINTER_CONFIG, config); + return 0; } -// Read the conversion register from the ADC -// Lua: ads1115.startread(function(volt, voltdec, adc) print(volt,voltdec,adc) end) +// Read the conversion register from the ADC device +// Lua: ads1115.device:startread(function(volt, voltdec, adc) print(volt,voltdec,adc) end) static int ads1115_lua_startread(lua_State *L) { - - if (((ads1115_comp == ADS1115_CQUE_1CONV) || (ads1115_comp == ADS1115_CQUE_2CONV) || (ads1115_comp == ADS1115_CQUE_4CONV)) && (ads1115_threshold_low == 0x7FFF) && (ads1115_threshold_hi == 0x8000)) { - - if (ads1115_mode == ADS1115_MODE_SINGLE) { - write_reg(ADS1115_POINTER_CONFIG, ads1115_config); - } - - return 0; - - } else { - - luaL_argcheck(L, (lua_type(L, 1) == LUA_TFUNCTION || lua_type(L, 1) == LUA_TLIGHTFUNCTION), 1, "Must be function"); - lua_pushvalue(L, 1); - ads1115_timer_ref = luaL_ref(L, LUA_REGISTRYINDEX); - - if (ads1115_mode == ADS1115_MODE_SINGLE) { - write_reg(ADS1115_POINTER_CONFIG, ads1115_config); - } - - // Start a timer to wait until ADC conversion is done - os_timer_disarm (&ads1115_timer); - os_timer_setfn (&ads1115_timer, (os_timer_func_t *)ads1115_lua_readoutdone, NULL); - - switch (ads1115_samples) { - case (ADS1115_DR_8SPS): - os_timer_arm (&ads1115_timer, 150, 0); - break; - case (ADS1115_DR_16SPS): - os_timer_arm (&ads1115_timer, 75, 0); - break; - case (ADS1115_DR_32SPS): - os_timer_arm (&ads1115_timer, 35, 0); - break; - case (ADS1115_DR_64SPS): - os_timer_arm (&ads1115_timer, 20, 0); - break; - case (ADS1115_DR_128SPS): - os_timer_arm (&ads1115_timer, 10, 0); - break; - case (ADS1115_DR_250SPS): - os_timer_arm (&ads1115_timer, 5, 0); - break; - case (ADS1115_DR_475SPS): - os_timer_arm (&ads1115_timer, 3, 0); - break; - case (ADS1115_DR_860SPS): - os_timer_arm (&ads1115_timer, 2, 0); - break; - } - - return 0; - } + ads_ctrl_ud_t *ads_ctrl = luaL_checkudata(L, 1, metatable_name); + + if (((ads_ctrl->comp == ADS1115_CQUE_1CONV) || + (ads_ctrl->comp == ADS1115_CQUE_2CONV) || + (ads_ctrl->comp == ADS1115_CQUE_4CONV)) && + (ads_ctrl->threshold_low == 0x7FFF) && + (ads_ctrl->threshold_hi == 0x8000)) { + // conversion ready mode + if (ads_ctrl->mode == ADS1115_MODE_SINGLE) { + NODE_DBG("ads1115 trigger config: %04x", ads_ctrl->config); + write_reg(ads_ctrl->i2c_addr, ADS1115_POINTER_CONFIG, ads_ctrl->config); + } + return 0; + } + + luaL_argcheck(L, (lua_type(L, 2) == LUA_TFUNCTION || lua_type(L, 2) == LUA_TLIGHTFUNCTION), 2, "Must be function"); + lua_pushvalue(L, 2); + ads_ctrl->timer_ref = luaL_ref(L, LUA_REGISTRYINDEX); + + if (ads_ctrl->mode == ADS1115_MODE_SINGLE) { + write_reg(ads_ctrl->i2c_addr, ADS1115_POINTER_CONFIG, ads_ctrl->config); + } + + // Start a timer to wait until ADC conversion is done + os_timer_disarm(&ads_ctrl->timer); + os_timer_setfn(&ads_ctrl->timer, (os_timer_func_t *)ads1115_lua_readoutdone, (void *)ads_ctrl); + + int msec = 1; // ADS1115_DR_1600SPS, ADS1115_DR_2400SPS, ADS1115_DR_3300SPS + switch (ads_ctrl->samples_value) { + case ADS1115_DR_8SPS: + msec = 150; + break; + case ADS1115_DR_16SPS: + msec = 75; + break; + case ADS1115_DR_32SPS: + msec = 35; + break; + case ADS1115_DR_64SPS: + msec = 20; + break; + case ADS1115_DR_128SPS: + msec = 10; + break; + case ADS1115_DR_250SPS: + msec = 5; + break; + case ADS1115_DR_475SPS: + case ADS1115_DR_490SPS: + msec = 3; + break; + case ADS1115_DR_860SPS: + case ADS1115_DR_920SPS: + msec = 2; + } + os_timer_arm(&ads_ctrl->timer, msec, 0); + return 0; } // adc conversion timer callback -static int ads1115_lua_readoutdone(void) { - - ads1115_conversion = read_reg(ADS1115_POINTER_CONVERSION); - ads1115_volt = get_volt(ads1115_conversion); - int ads1115_voltdec = (int)((ads1115_volt - (int)ads1115_volt) * 1000); - ads1115_voltdec = ads1115_voltdec>0?ads1115_voltdec:0-ads1115_voltdec; - - lua_State *L = lua_getstate(); - os_timer_disarm (&ads1115_timer); - - lua_rawgeti (L, LUA_REGISTRYINDEX, ads1115_timer_ref); - luaL_unref (L, LUA_REGISTRYINDEX, ads1115_timer_ref); - ads1115_timer_ref = LUA_NOREF; - - lua_pushnumber(L, ads1115_volt); - lua_pushinteger(L, ads1115_voltdec); - lua_pushinteger(L, ads1115_conversion); - - lua_call (L, 3, 0); +static int ads1115_lua_readoutdone(void * param) { + ads_ctrl_ud_t * ads_ctrl = (ads_ctrl_ud_t *)param; + + uint16_t ads1115_conversion = read_reg(ads_ctrl->i2c_addr, ADS1115_POINTER_CONVERSION); + double ads1115_volt = get_volt(ads_ctrl->gain, ads1115_conversion); + int ads1115_voltdec = (int)((ads1115_volt - (int)ads1115_volt) * 1000); + ads1115_voltdec = ads1115_voltdec > 0 ? ads1115_voltdec : 0 - ads1115_voltdec; + + lua_State *L = lua_getstate(); + os_timer_disarm(&ads_ctrl->timer); + + lua_rawgeti(L, LUA_REGISTRYINDEX, ads_ctrl->timer_ref); + luaL_unref(L, LUA_REGISTRYINDEX, ads_ctrl->timer_ref); + ads_ctrl->timer_ref = LUA_NOREF; + + lua_pushnumber(L, ads1115_volt); + lua_pushinteger(L, ads1115_voltdec); + lua_pushinteger(L, ads1115_conversion); + + lua_call(L, 3, 0); } -// Read the conversion register from the ADC -// Lua: volt,voltdec,adc = ads1115.read() +// Read the conversion register from the ADC device +// Lua: volt,voltdec,adc = ads1115.device:read() static int ads1115_lua_read(lua_State *L) { - - ads1115_conversion = read_reg(ADS1115_POINTER_CONVERSION); - ads1115_volt = get_volt(ads1115_conversion); - int ads1115_voltdec = (int)((ads1115_volt - (int)ads1115_volt) * 1000); - ads1115_voltdec = ads1115_voltdec>0?ads1115_voltdec:0-ads1115_voltdec; - - lua_pushnumber(L, ads1115_volt); - lua_pushinteger(L, ads1115_voltdec); - lua_pushinteger(L, ads1115_conversion); - - return 3; + ads_ctrl_ud_t *ads_ctrl = luaL_checkudata(L, 1, metatable_name); + + uint16_t ads1115_conversion = read_reg(ads_ctrl->i2c_addr, ADS1115_POINTER_CONVERSION); + double ads1115_volt = get_volt(ads_ctrl->gain, ads1115_conversion); + int ads1115_voltdec = (int)((ads1115_volt - (int)ads1115_volt) * 1000); + ads1115_voltdec = ads1115_voltdec > 0 ? ads1115_voltdec : 0 - ads1115_voltdec; + + lua_pushnumber(L, ads1115_volt); + lua_pushinteger(L, ads1115_voltdec); + lua_pushinteger(L, ads1115_conversion); + + return 3; +} + +static int ads1115_lua_delete(lua_State *L) { + ads_ctrl_ud_t *ads_ctrl = luaL_checkudata(L, 1, metatable_name); + if (ads_ctrl->timer_ref != LUA_NOREF) { + os_timer_disarm(&ads_ctrl->timer); + luaL_unref(L, LUA_REGISTRYINDEX, ads_ctrl->timer_ref); + } + return 0; } static const LUA_REG_TYPE ads1115_map[] = { - { LSTRKEY( "setup" ), LFUNCVAL(ads1115_lua_setup) }, - { LSTRKEY( "setting" ), LFUNCVAL(ads1115_lua_setting) }, - { LSTRKEY( "startread" ), LFUNCVAL(ads1115_lua_startread) }, - { LSTRKEY( "read" ), LFUNCVAL(ads1115_lua_read) }, - { LSTRKEY( "ADDR_GND" ), LNUMVAL(ADS1115_I2C_ADDR_GND) }, - { LSTRKEY( "ADDR_VDD" ), LNUMVAL(ADS1115_I2C_ADDR_VDD) }, - { LSTRKEY( "ADDR_SDA" ), LNUMVAL(ADS1115_I2C_ADDR_SDA) }, - { LSTRKEY( "ADDR_SCL" ), LNUMVAL(ADS1115_I2C_ADDR_SCL) }, - { LSTRKEY( "SINGLE_SHOT" ), LNUMVAL(ADS1115_MODE_SINGLE) }, - { LSTRKEY( "CONTINUOUS" ), LNUMVAL(ADS1115_MODE_CONTIN) }, - { LSTRKEY( "DIFF_0_1" ), LNUMVAL(ADS1115_MUX_DIFF_0_1) }, - { LSTRKEY( "DIFF_0_3" ), LNUMVAL(ADS1115_MUX_DIFF_0_3) }, - { LSTRKEY( "DIFF_1_3" ), LNUMVAL(ADS1115_MUX_DIFF_1_3) }, - { LSTRKEY( "DIFF_2_3" ), LNUMVAL(ADS1115_MUX_DIFF_2_3) }, - { LSTRKEY( "SINGLE_0" ), LNUMVAL(ADS1115_MUX_SINGLE_0) }, - { LSTRKEY( "SINGLE_1" ), LNUMVAL(ADS1115_MUX_SINGLE_1) }, - { LSTRKEY( "SINGLE_2" ), LNUMVAL(ADS1115_MUX_SINGLE_2) }, - { LSTRKEY( "SINGLE_3" ), LNUMVAL(ADS1115_MUX_SINGLE_3) }, - { LSTRKEY( "GAIN_6_144V" ), LNUMVAL(ADS1115_PGA_6_144V) }, - { LSTRKEY( "GAIN_4_096V" ), LNUMVAL(ADS1115_PGA_4_096V) }, - { LSTRKEY( "GAIN_2_048V" ), LNUMVAL(ADS1115_PGA_2_048V) }, - { LSTRKEY( "GAIN_1_024V" ), LNUMVAL(ADS1115_PGA_1_024V) }, - { LSTRKEY( "GAIN_0_512V" ), LNUMVAL(ADS1115_PGA_0_512V) }, - { LSTRKEY( "GAIN_0_256V" ), LNUMVAL(ADS1115_PGA_0_256V) }, - { LSTRKEY( "DR_8SPS" ), LNUMVAL(ADS1115_DR_8SPS) }, - { LSTRKEY( "DR_16SPS" ), LNUMVAL(ADS1115_DR_16SPS) }, - { LSTRKEY( "DR_32SPS" ), LNUMVAL(ADS1115_DR_32SPS) }, - { LSTRKEY( "DR_64SPS" ), LNUMVAL(ADS1115_DR_64SPS) }, - { LSTRKEY( "DR_128SPS" ), LNUMVAL(ADS1115_DR_128SPS) }, - { LSTRKEY( "DR_250SPS" ), LNUMVAL(ADS1115_DR_250SPS) }, - { LSTRKEY( "DR_475SPS" ), LNUMVAL(ADS1115_DR_475SPS) }, - { LSTRKEY( "DR_860SPS" ), LNUMVAL(ADS1115_DR_860SPS) }, - { LSTRKEY( "CONV_RDY_1" ), LNUMVAL(ADS1115_CQUE_1CONV) }, - { LSTRKEY( "CONV_RDY_2" ), LNUMVAL(ADS1115_CQUE_2CONV) }, - { LSTRKEY( "CONV_RDY_4" ), LNUMVAL(ADS1115_CQUE_4CONV) }, - { LSTRKEY( "COMP_1CONV" ), LNUMVAL(ADS1115_CQUE_1CONV) }, - { LSTRKEY( "COMP_2CONV" ), LNUMVAL(ADS1115_CQUE_2CONV) }, - { LSTRKEY( "COMP_4CONV" ), LNUMVAL(ADS1115_CQUE_4CONV) }, - { LNILKEY, LNILVAL } + + { LSTRKEY( "ads1115" ), LFUNCVAL(ads1115_lua_register_1115) }, + { LSTRKEY( "ads1015" ), LFUNCVAL(ads1115_lua_register_1015) }, + { LSTRKEY( "reset" ), LFUNCVAL(ads1115_lua_reset) }, + { LSTRKEY( "ADDR_GND" ), LNUMVAL(ADS1115_I2C_ADDR_GND) }, + { LSTRKEY( "ADDR_VDD" ), LNUMVAL(ADS1115_I2C_ADDR_VDD) }, + { LSTRKEY( "ADDR_SDA" ), LNUMVAL(ADS1115_I2C_ADDR_SDA) }, + { LSTRKEY( "ADDR_SCL" ), LNUMVAL(ADS1115_I2C_ADDR_SCL) }, + { LSTRKEY( "SINGLE_SHOT" ), LNUMVAL(ADS1115_MODE_SINGLE) }, + { LSTRKEY( "CONTINUOUS" ), LNUMVAL(ADS1115_MODE_CONTIN) }, + { LSTRKEY( "DIFF_0_1" ), LNUMVAL(ADS1115_MUX_DIFF_0_1) }, + { LSTRKEY( "DIFF_0_3" ), LNUMVAL(ADS1115_MUX_DIFF_0_3) }, + { LSTRKEY( "DIFF_1_3" ), LNUMVAL(ADS1115_MUX_DIFF_1_3) }, + { LSTRKEY( "DIFF_2_3" ), LNUMVAL(ADS1115_MUX_DIFF_2_3) }, + { LSTRKEY( "SINGLE_0" ), LNUMVAL(ADS1115_MUX_SINGLE_0) }, + { LSTRKEY( "SINGLE_1" ), LNUMVAL(ADS1115_MUX_SINGLE_1) }, + { LSTRKEY( "SINGLE_2" ), LNUMVAL(ADS1115_MUX_SINGLE_2) }, + { LSTRKEY( "SINGLE_3" ), LNUMVAL(ADS1115_MUX_SINGLE_3) }, + { LSTRKEY( "GAIN_6_144V" ), LNUMVAL(ADS1115_PGA_6_144V) }, + { LSTRKEY( "GAIN_4_096V" ), LNUMVAL(ADS1115_PGA_4_096V) }, + { LSTRKEY( "GAIN_2_048V" ), LNUMVAL(ADS1115_PGA_2_048V) }, + { LSTRKEY( "GAIN_1_024V" ), LNUMVAL(ADS1115_PGA_1_024V) }, + { LSTRKEY( "GAIN_0_512V" ), LNUMVAL(ADS1115_PGA_0_512V) }, + { LSTRKEY( "GAIN_0_256V" ), LNUMVAL(ADS1115_PGA_0_256V) }, + { LSTRKEY( "DR_8SPS" ), LNUMVAL(ADS1115_DR_8SPS) }, + { LSTRKEY( "DR_16SPS" ), LNUMVAL(ADS1115_DR_16SPS) }, + { LSTRKEY( "DR_32SPS" ), LNUMVAL(ADS1115_DR_32SPS) }, + { LSTRKEY( "DR_64SPS" ), LNUMVAL(ADS1115_DR_64SPS) }, + { LSTRKEY( "DR_128SPS" ), LNUMVAL(ADS1115_DR_128SPS) }, + { LSTRKEY( "DR_250SPS" ), LNUMVAL(ADS1115_DR_250SPS) }, + { LSTRKEY( "DR_475SPS" ), LNUMVAL(ADS1115_DR_475SPS) }, + { LSTRKEY( "DR_490SPS" ), LNUMVAL(ADS1115_DR_490SPS) }, + { LSTRKEY( "DR_860SPS" ), LNUMVAL(ADS1115_DR_860SPS) }, + { LSTRKEY( "DR_920SPS" ), LNUMVAL(ADS1115_DR_920SPS) }, + { LSTRKEY( "DR_1600SPS" ), LNUMVAL(ADS1115_DR_1600SPS) }, + { LSTRKEY( "DR_2400SPS" ), LNUMVAL(ADS1115_DR_2400SPS) }, + { LSTRKEY( "DR_3300SPS" ), LNUMVAL(ADS1115_DR_3300SPS) }, + { LSTRKEY( "CONV_RDY_1" ), LNUMVAL(ADS1115_CQUE_1CONV) }, + { LSTRKEY( "CONV_RDY_2" ), LNUMVAL(ADS1115_CQUE_2CONV) }, + { LSTRKEY( "CONV_RDY_4" ), LNUMVAL(ADS1115_CQUE_4CONV) }, + { LSTRKEY( "COMP_1CONV" ), LNUMVAL(ADS1115_CQUE_1CONV) }, + { LSTRKEY( "COMP_2CONV" ), LNUMVAL(ADS1115_CQUE_2CONV) }, + { LSTRKEY( "COMP_4CONV" ), LNUMVAL(ADS1115_CQUE_4CONV) }, + { LSTRKEY( "CMODE_TRAD"), LNUMVAL(ADS1115_CMODE_TRAD) }, + { LSTRKEY( "CMODE_WINDOW"), LNUMVAL(ADS1115_CMODE_WINDOW) }, + { LNILKEY, LNILVAL } +}; + +static const LUA_REG_TYPE ads1115_instance_map[] = { + { LSTRKEY( "setting" ), LFUNCVAL(ads1115_lua_setting) }, + { LSTRKEY( "startread" ), LFUNCVAL(ads1115_lua_startread) }, + { LSTRKEY( "read" ), LFUNCVAL(ads1115_lua_read) }, + { LSTRKEY( "__index" ), LROVAL(ads1115_instance_map) }, + { LSTRKEY( "__gc" ), LFUNCVAL(ads1115_lua_delete) }, + { LNILKEY, LNILVAL } }; -NODEMCU_MODULE(ADS1115, "ads1115", ads1115_map, NULL); \ No newline at end of file + +int luaopen_ads1115(lua_State *L) { + luaL_rometatable(L, metatable_name, (void *)ads1115_instance_map); + return 0; +} + +NODEMCU_MODULE(ADS1115, "ads1115", ads1115_map, luaopen_ads1115); diff --git a/docs/en/modules/ads1115.md b/docs/en/modules/ads1115.md index f73310b49b..265cb8ea49 100644 --- a/docs/en/modules/ads1115.md +++ b/docs/en/modules/ads1115.md @@ -3,17 +3,96 @@ | :----- | :-------------------- | :---------- | :------ | | 2017-04-24 | [fetchbot](https://github.com/fetchbot) | [fetchbot](https://github.com/fetchbot) | [ads1115.c](../../../app/modules/ads1115.c)| -This module provides access to the ADS1115 16-Bit analog-to-digital converter. +This module provides access to the ADS1115 (16-Bit) and ADS1015 (12-Bit) analog-to-digital converters. +Other chips from the same family (ADS1113, ADS1114, ADS1013 and ADS1014) are likely to work. Missing hardware features will be silently ignored. + +This module supports multiple devices connected to I²C bus. The devices of different types can be mixed. +The addressing of ADS family allows for maximum of 4 devices connected to the same I²C bus. !!! caution The **ABSOLUTE MAXIMUM RATINGS** for all analog inputs are `–0.3V to VDD+0.3V` referred to GND. -## ads1115.read() + + +## ads1115.ads1115() +Registers ADS1115 (ADS1113, ADS1114) device. + +#### Syntax +`ads1115.ADS1115(I2C_ID, I2C_ADDR)` + +#### Parameters +- `I2C_ID` - always 0 +- `ADDRESS` - I²C address of a device + * `ads1115.ADDR_GND` + * `ads1115.ADDR_VDD` + * `ads1115.ADDR_SDA` + * `ads1115.ADDR_SCL` + +#### Returns +Registered `device` object + +#### Example +```lua +local id, sda, scl = 0, 6, 5 +i2c.setup(id, sda, scl, i2c.SLOW) +ads1115.reset() +adc1 = ads1115.ads1115(id, ads1115.ADDR_GND) +``` + + +## ads1115.ads1015() +Registers ADS1015 (ADS1013, ADS1014) device. + +#### Syntax +`ads1115.ads1015(I2C_ID, I2C_ADDR)` + +#### Parameters +- `I2C_ID` - always 0 +- `ADDRESS` - I²C address of a device + * `ads1115.ADDR_GND` + * `ads1115.ADDR_VDD` + * `ads1115.ADDR_SDA` + * `ads1115.ADDR_SCL` + +#### Returns +Registered `device` object + +#### Example +```lua +local id, sda, scl = 0, 6, 5 +i2c.setup(id, sda, scl, i2c.SLOW) +ads1115.reset() +adc1 = ads1115.ads1015(id, ads1115.ADDR_VDD) +adc2 = ads1115.ads1115(id, ads1115.ADDR_SDA) +``` +## ads1115.reset() +Reset all devices connected to I²C interface. + +### Syntax +ads1115.reset() + +#### Parameters +none + +#### Returns +`nil` + +#### Example +```lua +local id, alert_pin, sda, scl = 0, 7, 6, 5 +i2c.setup(id, sda, scl, i2c.SLOW) +ads1115.reset() +``` + + +# ADS Device + +## ads1115.device:read() Gets the result stored in the register of a previously issued conversion, e.g. in continuous mode or with a conversion ready interrupt. #### Syntax -`volt, volt_dec, adc = ads1115.read()` +`volt, volt_dec, adc = device:read()` #### Parameters none @@ -25,39 +104,43 @@ none !!! note - If using float firmware then `volt` is a floating point number. On an integer firmware, the final value has to be concatenated from `volt` and `volt_dec`. + If using float firmware then `volt` is a floating point number. On an integer firmware, the final value has to be concatenated from `volt` and `volt_dec`. Both values `volt` and `volt_dec` contains sign. #### Example ```lua local id, alert_pin, sda, scl = 0, 7, 6, 5 i2c.setup(id, sda, scl, i2c.SLOW) -ads1115.setup(ads1115.ADDR_GND) +ads1115.reset() +adc1 = ads1115.ads1115(id, ads1115.ADDR_GND) -- continuous mode -ads1115.setting(ads1115.GAIN_6_144V, ads1115.DR_128SPS, ads1115.SINGLE_0, ads1115.CONTINUOUS) +adc1:setting(ads1115.GAIN_6_144V, ads1115.DR_128SPS, ads1115.SINGLE_0, ads1115.CONTINUOUS) -- read adc result with read() -volt, volt_dec, adc = ads1115.read() +volt, volt_dec, adc = ads1:read() print(volt, volt_dec, adc) -- comparator -ads1115.setting(ads1115.GAIN_6_144V, ads1115.DR_128SPS, ads1115.SINGLE_0, ads1115.CONTINUOUS, ads1115.COMP_1CONV, 1000, 2000) +adc1:setting(ads1115.GAIN_6_144V, ads1115.DR_128SPS, ads1115.SINGLE_0, ads1115.CONTINUOUS, ads1115.COMP_1CONV, 1000, 2000) local function comparator(level, when) -- read adc result with read() when threshold reached - volt, volt_dec, adc = ads1115.read() + gpio.trig(alert_pin) + volt, volt_dec, adc = ads1:read() print(volt, volt_dec, adc) end gpio.mode(alert_pin, gpio.INT) gpio.trig(alert_pin, "both", comparator) + -- read adc result with read() -volt, volt_dec, adc = ads1115.read() +volt, volt_dec, adc = ads1115:read() print(volt, volt_dec, adc) ``` -## ads1115.setting() + +## ads1115.device:setting() Configuration settings for the ADC. #### Syntax -`ads1115.setting(GAIN, SAMPLES, CHANNEL, MODE[, CONVERSION_RDY][, COMPARATOR, THRESHOLD_LOW, THRESHOLD_HI])` +`device:setting(GAIN, SAMPLES, CHANNEL, MODE[, CONVERSION_RDY][, COMPARATOR, THRESHOLD_LOW, THRESHOLD_HI[,COMP_MODE]])` #### Parameters - `GAIN` Programmable gain amplifier @@ -68,14 +151,19 @@ Configuration settings for the ADC. * `ads1115.GAIN_0_512V` 8x Gain * `ads1115.GAIN_0_256V` 16x Gain - `SAMPLES` Data rate in samples per second - * `ads1115.DR_8SPS` - * `ads1115.DR_16SPS` - * `ads1115.DR_32SPS` - * `ads1115.DR_64SPS` + * `ads1115.DR_8SPS` ADS1115 only + * `ads1115.DR_16SPS` ADS1115 only + * `ads1115.DR_32SPS` ADS1115 only + * `ads1115.DR_64SPS` ADS1115 only * `ads1115.DR_128SPS` * `ads1115.DR_250SPS` - * `ads1115.DR_475SPS` - * `ads1115.DR_860SPS` + * `ads1115.DR_475SPS` ADS1115 only + * `ads1115.DR_490SPS` ADS1015 only + * `ads1115.DR_860SPS` ADS1115 only + * `ads1115.DR_920SPS` ADS1015 only + * `ads1115.DR_1600SPS` ADS1015 only + * `ads1115.DR_2400SPS` ADS1015 only + * `ads1115.DR_3300SPS` ADS1015 only - `CHANNEL` Input multiplexer for single-ended or differential measurement * `ads1115.SINGLE_0` channel 0 to GND * `ads1115.SINGLE_1` channel 1 to GND @@ -102,31 +190,11 @@ Configuration settings for the ADC. - `THRESHOLD_HI` * `0` - `+ GAIN_MAX` in mV for single-ended inputs * `- GAIN_MAX` - `+ GAIN_MAX` in mV for differential inputs +- `COMP_MODE` Comparator mode + * `ads1115.CMODE_TRAD` traditional comparator mode (with hysteresis) + * `ads1115.CMODE_WINDOW` window comparator mode -#### Returns -`nil` - -#### Example -```lua -local id, sda, scl = 0, 6, 5 -i2c.setup(id, sda, scl, i2c.SLOW) -ads1115.setup(ads1115.ADDR_GND) - -ads1115.setting(ads1115.GAIN_6_144V, ads1115.DR_128SPS, ads1115.SINGLE_0, ads1115.SINGLE_SHOT) -``` - -## ads1115.setup() -Initializes the device on the defined I²C device address. - -#### Syntax -`ads1115.setup(ADDRESS)` - -#### Parameters -- `ADDRESS` - * `ads1115.ADDR_GND` - * `ads1115.ADDR_VDD` - * `ads1115.ADDR_SDA` - * `ads1115.ADDR_SCL` +note: Comparator and conversion ready are always configured to non-latching, active low. #### Returns `nil` @@ -135,15 +203,18 @@ Initializes the device on the defined I²C device address. ```lua local id, sda, scl = 0, 6, 5 i2c.setup(id, sda, scl, i2c.SLOW) +ads1115.reset() +adc1 = ads1115.ads1015(id, ads1115.ADDR_GND) -ads1115.setup(ads1115.ADDR_GND) +adc1:setting(ads1115.GAIN_6_144V, ads1115.DR_3300SPS, ads1115.SINGLE_0, ads1115.SINGLE_SHOT) ``` -## ads1115.startread() + +## ads1115.device:startread() Starts the ADC reading for single-shot mode and after the conversion is done it will invoke an optional callback function in which the ADC conversion result can be obtained. #### Syntax -`ads1115.startread([CALLBACK])` +`device:startread([CALLBACK])` #### Parameters - `CALLBACK` callback function which will be invoked after the adc conversion is done @@ -156,21 +227,23 @@ Starts the ADC reading for single-shot mode and after the conversion is done it ```lua local id, alert_pin, sda, scl = 0, 7, 6, 5 i2c.setup(id, sda, scl, i2c.SLOW) -ads1115.setup(ads1115.ADDR_GND) +ads1115.reset() +adc1 = ads1115.ads1115(id, ads1115.ADDR_VDD) -- single shot -ads1115.setting(ads1115.GAIN_6_144V, ads1115.DR_128SPS, ads1115.SINGLE_0, ads1115.SINGLE_SHOT) +adc1:setting(ads1115.GAIN_6_144V, ads1115.DR_128SPS, ads1115.SINGLE_0, ads1115.SINGLE_SHOT) -- start adc conversion and get result in callback after conversion is ready -ads1115.startread(function(volt, volt_dec, adc) print(volt, volt_dec, adc) end) +adc1:startread(function(volt, volt_dec, adc) print(volt, volt_dec, adc) end) -- conversion ready -ads1115.setting(ads1115.GAIN_6_144V, ads1115.DR_128SPS, ads1115.SINGLE_0, ads1115.SINGLE_SHOT, ads1115.CONV_RDY_1) +adc1:setting(ads1115.GAIN_6_144V, ads1115.DR_128SPS, ads1115.SINGLE_0, ads1115.SINGLE_SHOT, ads1115.CONV_RDY_1) local function conversion_ready(level, when) - volt, volt_dec, adc = ads1115.read() + gpio.trig(alert_pin) + volt, volt_dec, adc = adc1:read() print(volt, volt_dec, adc) end gpio.mode(alert_pin, gpio.INT) gpio.trig(alert_pin, "down", conversion_ready) -- start conversion and get result with read() after conversion ready pin asserts -ads1115.startread() +adc1:startread() ```