Browse Source

add ads1115 module (#1942)

* add ads1115 module

* replace os_delay with os_timer

* typo
fetchbot 7 years ago
parent
commit
faefc09595
4 changed files with 626 additions and 2 deletions
  1. 1 1
      app/include/user_modules.h
  2. 448 0
      app/modules/ads1115.c
  3. 176 0
      docs/en/modules/ads1115.md
  4. 1 1
      mkdocs.yml

+ 1 - 1
app/include/user_modules.h

@@ -18,6 +18,7 @@
 // See https://github.com/nodemcu/nodemcu-firmware/pull/1127 for discussions.
 // New modules should be disabled by default and added in alphabetical order.
 #define LUA_USE_MODULES_ADC
+//#define LUA_USE_MODULES_ADS1115
 //#define LUA_USE_MODULES_ADXL345
 //#define LUA_USE_MODULES_AM2320
 //#define LUA_USE_MODULES_APA102
@@ -78,4 +79,3 @@
 
 #endif  /* LUA_CROSS_COMPILER */
 #endif	/* __USER_MODULES_H__ */
-

+ 448 - 0
app/modules/ads1115.c

@@ -0,0 +1,448 @@
+//***************************************************************************
+// Si7021 module for ESP8266 with nodeMCU
+// fetchbot @github
+// MIT license, http://opensource.org/licenses/MIT
+//***************************************************************************
+
+#include "module.h"
+#include "lauxlib.h"
+#include "platform.h"
+#include "osapi.h"
+
+//***************************************************************************
+// 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)
+
+//***************************************************************************
+// 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)
+
+//***************************************************************************
+// 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)
+
+//***************************************************************************
+
+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 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;
+}
+
+// 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;
+}
+
+// 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;
+}
+
+// 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;
+}
+
+// Change ADC settings
+// Lua: 	ads1115.setting(GAIN,SAMPLES,CHANNEL,MODE[,CONVERSION_RDY][,COMPARATOR,THRESHOLD_LOW,THRESHOLD_HI])
+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;
+}
+
+// Read the conversion register from the ADC
+// Lua: 	ads1115.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;
+	}
+}
+
+// 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);
+}
+
+// Read the conversion register from the ADC
+// Lua: 	volt,voltdec,adc = ads1115.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;
+}
+
+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											}
+};
+
+NODEMCU_MODULE(ADS1115, "ads1115", ads1115_map, NULL);

+ 176 - 0
docs/en/modules/ads1115.md

@@ -0,0 +1,176 @@
+# ADS1115 Module
+| Since  | Origin / Contributor  | Maintainer  | Source  |
+| :----- | :-------------------- | :---------- | :------ |
+| 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.
+
+!!! caution
+
+	The **ABSOLUTE MAXIMUM RATINGS** for all analog inputs are `–0.3V to VDD+0.3V` referred to GND.
+
+## ads1115.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()`
+
+#### Parameters
+none
+
+#### Returns
+- `volt` voltage in mV (see note below)
+- `volt_dec` voltage decimal (see note below)
+- `adc` raw adc value
+
+!!! 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`.
+
+#### Example
+```lua
+local id, alert_pin, sda, scl = 0, 7, 6, 5
+i2c.setup(id, sda, scl, i2c.SLOW)
+ads1115.setup(ads1115.ADDR_GND)
+
+-- continuous mode
+ads1115.setting(ads1115.GAIN_6_144V, ads1115.DR_128SPS, ads1115.SINGLE_0, ads1115.CONTINUOUS)
+-- read adc result with read()
+volt, volt_dec, adc = ads1115.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)
+local function comparator(level, when)
+	-- read adc result with read() when threshold reached
+	volt, volt_dec, adc = ads1115.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()
+print(volt, volt_dec, adc)
+```
+
+## ads1115.setting()
+Configuration settings for the ADC.
+
+#### Syntax
+`ads1115.setting(GAIN, SAMPLES, CHANNEL, MODE[, CONVERSION_RDY][, COMPARATOR, THRESHOLD_LOW, THRESHOLD_HI])`
+
+#### Parameters
+- `GAIN` Programmable gain amplifier
+	* `ads1115.GAIN_6_144V` 2/3x Gain
+	* `ads1115.GAIN_4_096V` 1x Gain
+	* `ads1115.GAIN_2_048V` 2x Gain
+	* `ads1115.GAIN_1_024V` 4x Gain
+	* `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_128SPS`
+	* `ads1115.DR_250SPS`
+	* `ads1115.DR_475SPS`
+	* `ads1115.DR_860SPS`
+- `CHANNEL` Input multiplexer for single-ended or differential measurement
+	* `ads1115.SINGLE_0` channel 0 to GND
+	* `ads1115.SINGLE_1` channel 1 to GND
+	* `ads1115.SINGLE_2` channel 2 to GND
+	* `ads1115.SINGLE_3` channel 3 to GND
+	* `ads1115.DIFF_0_1` channel 0 to 1
+	* `ads1115.DIFF_0_3` channel 0 to 3
+	* `ads1115.DIFF_1_3` channel 1 to 3
+	* `ads1115.DIFF_2_3` channel 2 to 3
+- `MODE` Device operating mode
+	* `ads1115.SINGLE_SHOT` single-shot mode
+	* `ads1115.CONTINUOUS` continuous mode
+- `CONVERSION_RDY` Number of conversions after conversion ready asserts (optional)
+	* `ads1115.CONV_RDY_1`
+	* `ads1115.CONV_RDY_2`
+	* `ads1115.CONV_RDY_4`
+- `COMPARATOR` Number of conversions after comparator asserts (optional)
+	* `ads1115.COMP_1CONV`
+	* `ads1115.COMP_2CONV`
+	* `ads1115.COMP_4CONV`
+- `THRESHOLD_LOW`
+	* `0` - `+ GAIN_MAX` in mV for single-ended inputs
+	* `- GAIN_MAX` - `+ GAIN_MAX` in mV for differential inputs
+- `THRESHOLD_HI`
+	* `0` - `+ GAIN_MAX` in mV for single-ended inputs
+	* `- GAIN_MAX` - `+ GAIN_MAX` in mV for differential inputs
+
+#### 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`
+
+#### Returns
+`nil`
+
+#### Example
+```lua
+local id, sda, scl = 0, 6, 5
+i2c.setup(id, sda, scl, i2c.SLOW)
+
+ads1115.setup(ads1115.ADDR_GND)
+```
+
+## ads1115.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])`
+
+#### Parameters
+- `CALLBACK` callback function which will be invoked after the adc conversion is done
+	* `function(volt, volt_dec, adc) end`
+
+#### Returns
+- `nil`
+
+#### Example
+```lua
+local id, alert_pin, sda, scl = 0, 7, 6, 5
+i2c.setup(id, sda, scl, i2c.SLOW)
+ads1115.setup(ads1115.ADDR_GND)
+
+-- single shot
+ads1115.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)
+
+-- conversion ready
+ads1115.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()
+	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()
+```

+ 1 - 1
mkdocs.yml

@@ -36,6 +36,7 @@ pages:
     - Support: 'en/support.md'
     - Modules:
         - 'adc': 'en/modules/adc.md'
+        - 'ads1115' : 'en/modules/ads1115.md'
         - 'adxl345': 'en/modules/adxl345.md'
         - 'am2320': 'en/modules/am2320.md'
         - 'apa102': 'en/modules/apa102.md'
@@ -96,4 +97,3 @@ pages:
         - 'xpt2046': 'en/modules/xpt2046.md'
 #- Deutsch:
 #    - Home: 'de/index.md'
-