From 97320b9aad7c2e34b93b2dee3b04fc0e1d720323 Mon Sep 17 00:00:00 2001 From: Pawel Switalski Date: Sat, 3 Feb 2018 21:59:01 -0800 Subject: [PATCH 1/2] Add support for HTU21D/SHT21 temperature and humidity sensors --- components/modules/Kconfig | 6 +++ components/modules/htu21.c | 29 ++++++++++ components/platform/htu21.c | 74 ++++++++++++++++++++++++++ components/platform/include/platform.h | 9 ++++ docs/en/modules/htu21.md | 25 +++++++++ mkdocs.yml | 1 + 6 files changed, 144 insertions(+) create mode 100644 components/modules/htu21.c create mode 100644 components/platform/htu21.c create mode 100755 docs/en/modules/htu21.md diff --git a/components/modules/Kconfig b/components/modules/Kconfig index 1d8ed4c3f4..c95199891a 100644 --- a/components/modules/Kconfig +++ b/components/modules/Kconfig @@ -98,6 +98,12 @@ config LUA_MODULE_GPIO help Includes the GPIO module (recommended). +config LUA_MODULE_HTU21 + bool "HTU21D/STH21 module" + default "n" + help + Includes the htu21 module. + config LUA_MODULE_I2C bool "I2C module" default "y" diff --git a/components/modules/htu21.c b/components/modules/htu21.c new file mode 100644 index 0000000000..e704436c2b --- /dev/null +++ b/components/modules/htu21.c @@ -0,0 +1,29 @@ +#include "module.h" +#include "lauxlib.h" +#include + +#include "platform.h" + + +static int htu21_read(lua_State *L) +{ + uint16_t rawT = platform_htu21_read(PLATFORM_HTU21_T_MEASUREMENT_HM); + uint16_t rawRH = platform_htu21_read(PLATFORM_HTU21_RH_MEASUREMENT_HM); + + if (rawT == PLATFORM_HTU21_CRC_ERROR || rawRH == PLATFORM_HTU21_CRC_ERROR) { + luaL_error(L, "htu21 invalid CRC"); + } + + lua_pushinteger(L, platform_htu21_temp_ticks_to_millicelsius(rawT)); + lua_pushinteger(L, platform_htu21_rh_ticks_to_per_cent_mille(rawRH)); + + return 2; +} + + +static const LUA_REG_TYPE htu21_map[] = { + {LSTRKEY("read"), LFUNCVAL(htu21_read)}, + {LNILKEY, LNILVAL} +}; + +NODEMCU_MODULE(HTU21, "htu21", htu21_map, NULL); \ No newline at end of file diff --git a/components/platform/htu21.c b/components/platform/htu21.c new file mode 100644 index 0000000000..96cdc47fa1 --- /dev/null +++ b/components/platform/htu21.c @@ -0,0 +1,74 @@ +/* + * Driver for HTU21D/SHT21 humidity/temperature sensor. + * + */ +#include "platform.h" +#include "lua.h" + +#define HTU21_ADDRESS 0x40 + +//Give this function the 2 byte message (measurement) and the check_value byte from the HTU21D +//If it returns 0, then the transmission was good +//If it returns something other than 0, then the communication was corrupted +//From: http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html +//POLYNOMIAL = 0x0131 = x^8 + x^5 + x^4 + 1 : http://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks +#define SHIFTED_DIVISOR 0x988000 //This is the 0x0131 polynomial shifted to farthest left of three bytes + +inline int32_t platform_htu21_temp_ticks_to_millicelsius(uint32_t ticks) +{ + ticks &= ~0x0003; /* clear status bits */ + /* + * Formula T = -46.85 + 175.72 * ST / 2^16 from datasheet p14, + * optimized for integer fixed point (3 digits) arithmetic + */ + return ((21965 * ticks) >> 13) - 46850; +} + +inline int32_t platform_htu21_rh_ticks_to_per_cent_mille(uint32_t ticks) +{ + ticks &= ~0x0003; /* clear status bits */ + /* + * Formula RH = -6 + 125 * SRH / 2^16 from datasheet p14, + * optimized for integer fixed point (3 digits) arithmetic + */ + return ((15625 * ticks) >> 13) - 6000; +} + +static uint8_t checkCRC(uint16_t ravValue, uint8_t checksum) +{ + uint32_t remainder = (uint32_t) ravValue << 8; //Pad with 8 bits because we have to add in the check value + remainder |= checksum; //Add on the check value + + uint32_t divsor = (uint32_t) SHIFTED_DIVISOR; + + //Operate on only 16 positions of max 24. The remaining 8 are our remainder and should be zero when we're done. + for (int i = 0; i < 16; i++) + { + if (remainder & (uint32_t) 1 << (23 - i)) //Check if there is a one in the left position + remainder ^= divsor; + + divsor >>= 1; //Rotate the divsor max 16 times so that we have 8 bits left of a remainder + } + + return (uint8_t) remainder; +} + +uint16_t platform_htu21_read(uint8_t reg) +{ + uint16_t rawValue; + uint8_t checksum; + + platform_i2c_send_start(0); + platform_i2c_send_address(0, HTU21_ADDRESS, PLATFORM_I2C_DIRECTION_TRANSMITTER, 0); + platform_i2c_send_byte(0, reg, 0); + platform_i2c_send_start(0); + platform_i2c_send_address(0, HTU21_ADDRESS, PLATFORM_I2C_DIRECTION_RECEIVER, 0); + + rawValue = (uint16_t) platform_i2c_recv_byte(0, 1) << 8; + rawValue |= platform_i2c_recv_byte(0, 1); + checksum = (uint8_t) platform_i2c_recv_byte(0, 0); + + platform_i2c_send_stop(0); + + return checkCRC(rawValue, checksum) != 0 ? PLATFORM_HTU21_CRC_ERROR : rawValue; +} \ No newline at end of file diff --git a/components/platform/include/platform.h b/components/platform/include/platform.h index c15701ac61..4ab59b51c9 100644 --- a/components/platform/include/platform.h +++ b/components/platform/include/platform.h @@ -224,6 +224,15 @@ uint16_t platform_onewire_crc16( const uint8_t* input, uint16_t len, uint16_t cr int platform_dht_read( uint8_t gpio_num, uint8_t wakeup_ms, uint8_t *data ); +// ***************************************************************************** +// HTU21 platform interface +#define PLATFORM_HTU21_CRC_ERROR (uint16_t) 1 +#define PLATFORM_HTU21_T_MEASUREMENT_HM 0xE3 +#define PLATFORM_HTU21_RH_MEASUREMENT_HM 0xE5 + +uint16_t platform_htu21_read( uint8_t reg ); +int32_t platform_htu21_temp_ticks_to_millicelsius( uint32_t ticks ); +int32_t platform_htu21_rh_ticks_to_per_cent_mille( uint32_t ticks ); // ***************************************************************************** // WS2812 platform interface diff --git a/docs/en/modules/htu21.md b/docs/en/modules/htu21.md new file mode 100755 index 0000000000..492bcda008 --- /dev/null +++ b/docs/en/modules/htu21.md @@ -0,0 +1,25 @@ +# HDC1080 Module +| Since | Origin / Contributor | Maintainer | Source | +| :----- | :-------------------- | :---------- | :------ | +| 2017-02-03 | [Pawel Switalski](https://github.com/s-pw) | [Pawel Switalski](https://github.com/s-pw) | [htu21.c](../../../components/modules/htu21.c)| + + +This module provides access to the [HTU21D](https://www.sparkfun.com/products/13763) temperature and humidity sensor. The module also works with SHT21. + +## htu21.read() +Samples the sensor then returns temperature and humidity value. + +#### Syntax +`htu21.read()` + +#### Returns +Temperature data in millidegree Celsius and humidity data in per cent mille + +#### Example +```lua +local sda, scl = 1, 2 +i2c.setup(i2c.SW, sda, scl, i2c.SLOW) -- call i2c.setup() only once +local temperature, humidity = htu21.read() +print(temperature / 1000 .. '°C') +print(humidity / 1000 .. '%') +``` \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 14f83f267a..6ad3d7129c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -39,6 +39,7 @@ pages: - 'dht': 'en/modules/dht.md' - 'file': 'en/modules/file.md' - 'gpio': 'en/modules/gpio.md' + - 'htu21': 'en/modules/htu21.md' - 'i2c': 'en/modules/i2c.md' - 'ledc': 'en/modules/ledc.md' - 'net': 'en/modules/net.md' From 1b3f0c134c654b40b10ad52ed07373a1767159d1 Mon Sep 17 00:00:00 2001 From: Pawel Switalski Date: Sun, 4 Mar 2018 13:00:19 -0800 Subject: [PATCH 2/2] Add i2c_id to htu21 module --- components/modules/htu21.c | 10 ++++++---- components/platform/htu21.c | 23 +++++++++++++---------- components/platform/include/platform.h | 4 ++-- docs/en/modules/htu21.md | 7 +++++-- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/components/modules/htu21.c b/components/modules/htu21.c index e704436c2b..edb89cffa7 100644 --- a/components/modules/htu21.c +++ b/components/modules/htu21.c @@ -7,11 +7,13 @@ static int htu21_read(lua_State *L) { - uint16_t rawT = platform_htu21_read(PLATFORM_HTU21_T_MEASUREMENT_HM); - uint16_t rawRH = platform_htu21_read(PLATFORM_HTU21_RH_MEASUREMENT_HM); + uint32_t i2c_id = (uint32_t) luaL_optinteger( L, 1, 0 ); - if (rawT == PLATFORM_HTU21_CRC_ERROR || rawRH == PLATFORM_HTU21_CRC_ERROR) { - luaL_error(L, "htu21 invalid CRC"); + uint16_t rawT = platform_htu21_read(i2c_id, PLATFORM_HTU21_T_MEASUREMENT_HM); + uint16_t rawRH = platform_htu21_read(i2c_id, PLATFORM_HTU21_RH_MEASUREMENT_HM); + + if (rawT == PLATFORM_HTU21_ERROR || rawRH == PLATFORM_HTU21_ERROR) { + luaL_error(L, "htu21 invalid CRC or i2c_id"); } lua_pushinteger(L, platform_htu21_temp_ticks_to_millicelsius(rawT)); diff --git a/components/platform/htu21.c b/components/platform/htu21.c index 96cdc47fa1..a84ac2b207 100644 --- a/components/platform/htu21.c +++ b/components/platform/htu21.c @@ -53,22 +53,25 @@ static uint8_t checkCRC(uint16_t ravValue, uint8_t checksum) return (uint8_t) remainder; } -uint16_t platform_htu21_read(uint8_t reg) +uint16_t platform_htu21_read(uint32_t i2c_id, uint8_t reg) { uint16_t rawValue; uint8_t checksum; - platform_i2c_send_start(0); - platform_i2c_send_address(0, HTU21_ADDRESS, PLATFORM_I2C_DIRECTION_TRANSMITTER, 0); - platform_i2c_send_byte(0, reg, 0); - platform_i2c_send_start(0); - platform_i2c_send_address(0, HTU21_ADDRESS, PLATFORM_I2C_DIRECTION_RECEIVER, 0); + if (platform_i2c_exists(i2c_id) == PLATFORM_ERR) + return PLATFORM_HTU21_ERROR; - rawValue = (uint16_t) platform_i2c_recv_byte(0, 1) << 8; - rawValue |= platform_i2c_recv_byte(0, 1); - checksum = (uint8_t) platform_i2c_recv_byte(0, 0); + platform_i2c_send_start(i2c_id); + platform_i2c_send_address(i2c_id, HTU21_ADDRESS, PLATFORM_I2C_DIRECTION_TRANSMITTER, 0); + platform_i2c_send_byte(i2c_id, reg, 0); + platform_i2c_send_start(i2c_id); + platform_i2c_send_address(i2c_id, HTU21_ADDRESS, PLATFORM_I2C_DIRECTION_RECEIVER, 0); + + rawValue = (uint16_t) platform_i2c_recv_byte(i2c_id, 1) << 8; + rawValue |= platform_i2c_recv_byte(i2c_id, 1); + checksum = (uint8_t) platform_i2c_recv_byte(i2c_id, 0); platform_i2c_send_stop(0); - return checkCRC(rawValue, checksum) != 0 ? PLATFORM_HTU21_CRC_ERROR : rawValue; + return checkCRC(rawValue, checksum) != 0 ? PLATFORM_HTU21_ERROR : rawValue; } \ No newline at end of file diff --git a/components/platform/include/platform.h b/components/platform/include/platform.h index 4ab59b51c9..07a2c1cf6d 100644 --- a/components/platform/include/platform.h +++ b/components/platform/include/platform.h @@ -226,11 +226,11 @@ int platform_dht_read( uint8_t gpio_num, uint8_t wakeup_ms, uint8_t *data ); // ***************************************************************************** // HTU21 platform interface -#define PLATFORM_HTU21_CRC_ERROR (uint16_t) 1 +#define PLATFORM_HTU21_ERROR (uint16_t) 1 #define PLATFORM_HTU21_T_MEASUREMENT_HM 0xE3 #define PLATFORM_HTU21_RH_MEASUREMENT_HM 0xE5 -uint16_t platform_htu21_read( uint8_t reg ); +uint16_t platform_htu21_read( uint32_t i2c_id, uint8_t reg ); int32_t platform_htu21_temp_ticks_to_millicelsius( uint32_t ticks ); int32_t platform_htu21_rh_ticks_to_per_cent_mille( uint32_t ticks ); diff --git a/docs/en/modules/htu21.md b/docs/en/modules/htu21.md index 492bcda008..3c1f3d013b 100755 --- a/docs/en/modules/htu21.md +++ b/docs/en/modules/htu21.md @@ -10,7 +10,10 @@ This module provides access to the [HTU21D](https://www.sparkfun.com/products/13 Samples the sensor then returns temperature and humidity value. #### Syntax -`htu21.read()` +`htu21.read([i2c_id])` + +#### Parameters +- `i2c_id` i2c interface id, defaults to i2c.SW if omitted #### Returns Temperature data in millidegree Celsius and humidity data in per cent mille @@ -19,7 +22,7 @@ Temperature data in millidegree Celsius and humidity data in per cent mille ```lua local sda, scl = 1, 2 i2c.setup(i2c.SW, sda, scl, i2c.SLOW) -- call i2c.setup() only once -local temperature, humidity = htu21.read() +local temperature, humidity = htu21.read(i2c.SW) print(temperature / 1000 .. '°C') print(humidity / 1000 .. '%') ``` \ No newline at end of file