drivers: sensor: ens210: Implement AMS ens210 Sensor
Implementation of AMS (Austria Micro Systems) ENS210 temperature and relative humidity sensor. Signed-off-by: Alexander Wachter <alexander.wachter@student.tugraz.at>
This commit is contained in:
parent
f989f2d0f9
commit
f29ec12f21
7 changed files with 413 additions and 0 deletions
|
@ -15,6 +15,7 @@ add_subdirectory_ifdef(CONFIG_BMI160 bmi160)
|
||||||
add_subdirectory_ifdef(CONFIG_BMM150 bmm150)
|
add_subdirectory_ifdef(CONFIG_BMM150 bmm150)
|
||||||
add_subdirectory_ifdef(CONFIG_CCS811 ccs811)
|
add_subdirectory_ifdef(CONFIG_CCS811 ccs811)
|
||||||
add_subdirectory_ifdef(CONFIG_DHT dht)
|
add_subdirectory_ifdef(CONFIG_DHT dht)
|
||||||
|
add_subdirectory_ifdef(CONFIG_ENS210 ens210)
|
||||||
add_subdirectory_ifdef(CONFIG_FXAS21002 fxas21002)
|
add_subdirectory_ifdef(CONFIG_FXAS21002 fxas21002)
|
||||||
add_subdirectory_ifdef(CONFIG_FXOS8700 fxos8700)
|
add_subdirectory_ifdef(CONFIG_FXOS8700 fxos8700)
|
||||||
add_subdirectory(grove)
|
add_subdirectory(grove)
|
||||||
|
|
|
@ -55,6 +55,8 @@ source "drivers/sensor/ccs811/Kconfig"
|
||||||
|
|
||||||
source "drivers/sensor/dht/Kconfig"
|
source "drivers/sensor/dht/Kconfig"
|
||||||
|
|
||||||
|
source "drivers/sensor/ens210/Kconfig"
|
||||||
|
|
||||||
source "drivers/sensor/fxas21002/Kconfig"
|
source "drivers/sensor/fxas21002/Kconfig"
|
||||||
|
|
||||||
source "drivers/sensor/fxos8700/Kconfig"
|
source "drivers/sensor/fxos8700/Kconfig"
|
||||||
|
|
5
drivers/sensor/ens210/CMakeLists.txt
Normal file
5
drivers/sensor/ens210/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
zephyr_library()
|
||||||
|
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_ENS210 ens210.c)
|
35
drivers/sensor/ens210/Kconfig
Normal file
35
drivers/sensor/ens210/Kconfig
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# Kconfig - ENS210 Digital Temperature and Humidity sensor configuration options
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2018 Alexander Wachter.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
menuconfig ENS210
|
||||||
|
bool "ENS210 Digital Temperature and Humidity sensor"
|
||||||
|
depends on I2C && HAS_DTS_I2C
|
||||||
|
help
|
||||||
|
Enable driver for ENS210 Digital Temperature and Humidity sensor.
|
||||||
|
if ENS210
|
||||||
|
|
||||||
|
config ENS210_CRC_CHECK
|
||||||
|
bool "Enable CRC Check"
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Check the crc value after data reading.
|
||||||
|
|
||||||
|
config ENS210_MAX_STAT_RETRIES
|
||||||
|
int "Number of status read retries"
|
||||||
|
default 4
|
||||||
|
help
|
||||||
|
Number of retries when status reading failed or device not ready.
|
||||||
|
|
||||||
|
config ENS210_MAX_READ_RETRIES
|
||||||
|
int "Number of value reading retries"
|
||||||
|
default 4
|
||||||
|
help
|
||||||
|
Number of retries when value reading failed, value not valid
|
||||||
|
or crc not ok.
|
||||||
|
|
||||||
|
endif # ENS210
|
262
drivers/sensor/ens210/ens210.c
Normal file
262
drivers/sensor/ens210/ens210.c
Normal file
|
@ -0,0 +1,262 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Alexander Wachter.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <device.h>
|
||||||
|
#include <i2c.h>
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <misc/byteorder.h>
|
||||||
|
#include <misc/util.h>
|
||||||
|
#include <sensor.h>
|
||||||
|
#include <misc/__assert.h>
|
||||||
|
#include <logging/log.h>
|
||||||
|
#include "ens210.h"
|
||||||
|
|
||||||
|
#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL
|
||||||
|
LOG_MODULE_REGISTER(ENS210);
|
||||||
|
|
||||||
|
#ifdef ENS210_CRC_CHECK
|
||||||
|
u32_t ens210_crc7(u32_t bitstream)
|
||||||
|
{
|
||||||
|
u32_t polynomial = (ENS210_CRC7_POLY << (ENS210_CRC7_DATA_WIDTH - 1));
|
||||||
|
u32_t bit = ENS210_CRC7_DATA_MSB << ENS210_CRC7_WIDTH;
|
||||||
|
u32_t val = (bitstream << ENS210_CRC7_WIDTH) | ENS210_CRC7_IVEC;
|
||||||
|
|
||||||
|
while (bit & (ENS210_CRC7_DATA_MASK << ENS210_CRC7_WIDTH)) {
|
||||||
|
if (bit & val) {
|
||||||
|
val ^= polynomial;
|
||||||
|
}
|
||||||
|
|
||||||
|
bit >>= 1;
|
||||||
|
polynomial >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
#endif /*ENS210_CRC_CHECK*/
|
||||||
|
|
||||||
|
static int ens210_sample_fetch(struct device *dev, enum sensor_channel chan)
|
||||||
|
{
|
||||||
|
struct ens210_data *drv_data = dev->driver_data;
|
||||||
|
struct ens210_value_data data[2];
|
||||||
|
int ret, cnt;
|
||||||
|
|
||||||
|
#ifdef ENS210_CRC_CHECK
|
||||||
|
u32_t temp_valid, humidity_valid;
|
||||||
|
#endif /*ENS210_CRC_CHECK*/
|
||||||
|
|
||||||
|
__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);
|
||||||
|
|
||||||
|
for (cnt = 0; cnt <= CONFIG_ENS210_MAX_READ_RETRIES; cnt++) {
|
||||||
|
ret = i2c_burst_read(drv_data->i2c, DT_AMS_ENS210_0_BASE_ADDRESS,
|
||||||
|
ENS210_REG_T_VAL, (u8_t *)&data, sizeof(data));
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to read data");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data[0].valid) {
|
||||||
|
LOG_WRN("Temperature not valid");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data[1].valid) {
|
||||||
|
LOG_WRN("Humidity not valid");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENS210_CRC_CHECK
|
||||||
|
temp_valid = data[0].val |
|
||||||
|
(data[0].valid << (sizeof(data[0].val) * 8));
|
||||||
|
humidity_valid = data[1].val |
|
||||||
|
(data[1].valid << (sizeof(data[1].val) * 8));
|
||||||
|
|
||||||
|
if (ens210_crc7(temp_valid) != data[0].crc7) {
|
||||||
|
LOG_WRN("Temperature CRC error");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ens210_crc7(humidity_valid) != data[1].crc7) {
|
||||||
|
LOG_WRN("Humidity CRC error");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif /*ENS210_CRC_CHECK*/
|
||||||
|
|
||||||
|
drv_data->temp = data[0];
|
||||||
|
drv_data->humidity = data[1];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ens210_channel_get(struct device *dev,
|
||||||
|
enum sensor_channel chan,
|
||||||
|
struct sensor_value *val)
|
||||||
|
{
|
||||||
|
struct ens210_data *drv_data = dev->driver_data;
|
||||||
|
s32_t temp_frac;
|
||||||
|
s32_t humidity_frac;
|
||||||
|
|
||||||
|
switch (chan) {
|
||||||
|
case SENSOR_CHAN_AMBIENT_TEMP:
|
||||||
|
/* Temperature is in 1/64 Kelvin. Subtract 273.15 for Celsius */
|
||||||
|
temp_frac = sys_le16_to_cpu(drv_data->temp.val) * (1000000 / 64);
|
||||||
|
temp_frac -= 273150000;
|
||||||
|
|
||||||
|
val->val1 = temp_frac / 1000000;
|
||||||
|
val->val2 = temp_frac - val->val1;
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_HUMIDITY:
|
||||||
|
humidity_frac = sys_le16_to_cpu(drv_data->humidity.val) *
|
||||||
|
(1000000 / 512);
|
||||||
|
val->val1 = humidity_frac / 1000000;
|
||||||
|
val->val2 = humidity_frac - val->val1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ens210_sys_reset(struct device *i2c_dev)
|
||||||
|
{
|
||||||
|
const struct ens210_sys_ctrl sys_ctrl = {.low_power = 0, .reset = 1};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = i2c_reg_write_byte(i2c_dev, DT_AMS_ENS210_0_BASE_ADDRESS,
|
||||||
|
ENS210_REG_SYS_CTRL, *(u8_t *)&sys_ctrl);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to set SYS_CTRL to 0x%x", *(u8_t *)&sys_ctrl);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ens210_sys_enable(struct device *i2c_dev)
|
||||||
|
{
|
||||||
|
const struct ens210_sys_ctrl sys_ctrl = {.low_power = 0, .reset = 0};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = i2c_reg_write_byte(i2c_dev, DT_AMS_ENS210_0_BASE_ADDRESS,
|
||||||
|
ENS210_REG_SYS_CTRL, *(u8_t *)&sys_ctrl);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to set SYS_CTRL to 0x%x", *(u8_t *)&sys_ctrl);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ens210_wait_boot(struct device *i2c_dev)
|
||||||
|
{
|
||||||
|
int cnt;
|
||||||
|
int ret;
|
||||||
|
struct ens210_sys_stat sys_stat;
|
||||||
|
|
||||||
|
for (cnt = 0; cnt <= CONFIG_ENS210_MAX_STAT_RETRIES; cnt++) {
|
||||||
|
ret = i2c_reg_read_byte(i2c_dev, DT_AMS_ENS210_0_BASE_ADDRESS,
|
||||||
|
ENS210_REG_SYS_STAT,
|
||||||
|
(u8_t *)&sys_stat);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
k_sleep(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sys_stat.sys_active) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cnt == 0) {
|
||||||
|
ens210_sys_reset(i2c_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
ens210_sys_enable(i2c_dev);
|
||||||
|
|
||||||
|
k_sleep(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to read SYS_STATE");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOG_ERR("Sensor is not in active state");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sensor_driver_api en210_driver_api = {
|
||||||
|
.sample_fetch = ens210_sample_fetch,
|
||||||
|
.channel_get = ens210_channel_get,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int ens210_init(struct device *dev)
|
||||||
|
{
|
||||||
|
struct ens210_data *drv_data = dev->driver_data;
|
||||||
|
const struct ens210_sens_run sense_run = {
|
||||||
|
.t_run = 1,
|
||||||
|
.h_run = 1
|
||||||
|
};
|
||||||
|
const struct ens210_sens_start sense_start = {
|
||||||
|
.t_start = 1,
|
||||||
|
.h_start = 1
|
||||||
|
};
|
||||||
|
int ret;
|
||||||
|
u16_t part_id;
|
||||||
|
|
||||||
|
drv_data->i2c = device_get_binding(DT_AMS_ENS210_0_BUS_NAME);
|
||||||
|
if (drv_data->i2c == NULL) {
|
||||||
|
LOG_ERR("Failed to get pointer to %s device!",
|
||||||
|
DT_AMS_ENS210_0_BUS_NAME);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait until the device is ready. */
|
||||||
|
ret = ens210_wait_boot(drv_data->i2c);
|
||||||
|
if (ret < 0) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check Hardware ID. This is only possible after device is ready */
|
||||||
|
ret = i2c_burst_read(drv_data->i2c, DT_AMS_ENS210_0_BASE_ADDRESS,
|
||||||
|
ENS210_REG_PART_ID, (u8_t *)&part_id,
|
||||||
|
sizeof(part_id));
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to read Part ID register");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (part_id != ENS210_PART_ID) {
|
||||||
|
LOG_ERR("Part ID does not match. Want 0x%x, got 0x%x",
|
||||||
|
ENS210_PART_ID, part_id);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set continuous measurement */
|
||||||
|
ret = i2c_reg_write_byte(drv_data->i2c, DT_AMS_ENS210_0_BASE_ADDRESS,
|
||||||
|
ENS210_REG_SENS_RUN, *(u8_t *)&sense_run);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to set SENS_RUN to 0x%x",
|
||||||
|
*(u8_t *)&sense_run);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start measuring */
|
||||||
|
ret = i2c_reg_write_byte(drv_data->i2c, DT_AMS_ENS210_0_BASE_ADDRESS,
|
||||||
|
ENS210_REG_SENS_START, *(u8_t *)&sense_start);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to set SENS_START to 0x%x",
|
||||||
|
*(u8_t *)&sense_start);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ens210_data ens210_driver;
|
||||||
|
|
||||||
|
DEVICE_AND_API_INIT(ens210, DT_AMS_ENS210_0_LABEL, ens210_init, &ens210_driver,
|
||||||
|
NULL, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,
|
||||||
|
&en210_driver_api);
|
87
drivers/sensor/ens210/ens210.h
Normal file
87
drivers/sensor/ens210/ens210.h
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Alexander Wachter.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZEPHYR_DRIVERS_SENSOR_ENS210_ENS210_H_
|
||||||
|
#define ZEPHYR_DRIVERS_SENSOR_CCS8ZEPHYR_DRIVERS_SENSOR_ENS210_ENS210_H_11_CCS811_H_
|
||||||
|
|
||||||
|
#include <device.h>
|
||||||
|
#include <gpio.h>
|
||||||
|
#include <misc/util.h>
|
||||||
|
|
||||||
|
/* Registers */
|
||||||
|
#define ENS210_REG_PART_ID 0x00
|
||||||
|
#define ENS210_REG_UID 0x04
|
||||||
|
#define ENS210_REG_SYS_CTRL 0x10
|
||||||
|
#define ENS210_REG_SYS_STAT 0x11
|
||||||
|
#define ENS210_REG_SENS_RUN 0x21
|
||||||
|
#define ENS210_REG_SENS_START 0x22
|
||||||
|
#define ENS210_REG_SENS_STOP 0x23
|
||||||
|
#define ENS210_REG_SENS_STAT 0x24
|
||||||
|
#define ENS210_REG_T_VAL 0x30
|
||||||
|
#define ENS210_REG_H_VAL 0x33
|
||||||
|
|
||||||
|
#define ENS210_PART_ID 0x0210
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Polynomial
|
||||||
|
* 0b 1000 1001 ~ x^7+x^3+x^0
|
||||||
|
* 0x 8 9
|
||||||
|
*/
|
||||||
|
#define ENS210_CRC7_WIDTH 7
|
||||||
|
#define ENS210_CRC7_POLY 0x89
|
||||||
|
#define ENS210_CRC7_IVEC ((1UL << ENS210_CRC7_WIDTH) - 1)
|
||||||
|
#define ENS210_CRC7_DATA_WIDTH 17
|
||||||
|
#define ENS210_CRC7_DATA_MASK ((1UL << ENS210_CRC7_DATA_WIDTH) - 1)
|
||||||
|
#define ENS210_CRC7_DATA_MSB (1UL << (ENS210_CRC7_DATA_WIDTH - 1))
|
||||||
|
|
||||||
|
struct ens210_value_data {
|
||||||
|
u16_t val;
|
||||||
|
u8_t valid : 1;
|
||||||
|
u8_t crc7 : 7;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ens210_sys_ctrl {
|
||||||
|
u8_t low_power : 1;
|
||||||
|
u8_t reserved : 6;
|
||||||
|
u8_t reset : 1;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ens210_sys_stat {
|
||||||
|
u8_t sys_active : 1;
|
||||||
|
u8_t reserved : 7;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ens210_sens_run {
|
||||||
|
u8_t t_run : 1;
|
||||||
|
u8_t h_run : 1;
|
||||||
|
u8_t reserved : 6;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ens210_sens_start {
|
||||||
|
u8_t t_start : 1;
|
||||||
|
u8_t h_start : 1;
|
||||||
|
u8_t reserved : 6;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ens210_sens_stop {
|
||||||
|
u8_t t_stop : 1;
|
||||||
|
u8_t h_stop : 1;
|
||||||
|
u8_t reserved : 6;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ens210_sens_stat {
|
||||||
|
u8_t t_stat : 1;
|
||||||
|
u8_t h_stat : 1;
|
||||||
|
u8_t reserved : 6;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct ens210_data {
|
||||||
|
struct device *i2c;
|
||||||
|
struct ens210_value_data temp;
|
||||||
|
struct ens210_value_data humidity;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* ZEPHYR_DRIVERS_SENSOR_ENS210_ENS210_H_ */
|
21
dts/bindings/sensor/ams,ens210.yaml
Normal file
21
dts/bindings/sensor/ams,ens210.yaml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2018, Alexander Wachter
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
---
|
||||||
|
title: AMS (Austria Mikro Systeme) Relative Humidity and Temperature Sensor
|
||||||
|
version: 0.1
|
||||||
|
|
||||||
|
description: >
|
||||||
|
This binding gives a base representation of ens210 Relative Humidity and
|
||||||
|
Temperature Sensor
|
||||||
|
|
||||||
|
inherits:
|
||||||
|
!include i2c-device.yaml
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
constraint: "ams,ens210"
|
||||||
|
|
||||||
|
...
|
Loading…
Add table
Add a link
Reference in a new issue