Skip to content

Commit ee0066e

Browse files
committed
sensors: aht20: Add AHT20 temperature humidity sensor
Add support of AHT20 Temperature and Humidity Sensor Signed-off-by: Rafael Lee <[email protected]>
1 parent f0199dc commit ee0066e

File tree

5 files changed

+184
-0
lines changed

5 files changed

+184
-0
lines changed

drivers/sensor/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ add_subdirectory_ifdef(CONFIG_ADT7420 adt7420)
44
add_subdirectory_ifdef(CONFIG_ADXL345 adxl345)
55
add_subdirectory_ifdef(CONFIG_ADXL362 adxl362)
66
add_subdirectory_ifdef(CONFIG_ADXL372 adxl372)
7+
add_subdirectory_ifdef(CONFIG_AHT20 aht20)
78
add_subdirectory_ifdef(CONFIG_AK8975 ak8975)
89
add_subdirectory_ifdef(CONFIG_AMG88XX amg88xx)
910
add_subdirectory_ifdef(CONFIG_AMS_IAQ_CORE ams_iAQcore)

drivers/sensor/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ source "drivers/sensor/adxl362/Kconfig"
4949

5050
source "drivers/sensor/adxl372/Kconfig"
5151

52+
source "drivers/sensor/aht20/Kconfig"
53+
5254
source "drivers/sensor/ak8975/Kconfig"
5355

5456
source "drivers/sensor/amg88xx/Kconfig"

drivers/sensor/aht20/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
zephyr_library()
4+
5+
zephyr_library_sources(aht20.c)

drivers/sensor/aht20/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright (c) 2022 Rafael Lee
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config AHT20
5+
bool "AHT20 Temperature and Humidity Sensor"
6+
default y
7+
depends on DT_HAS_ASAIR_AHT20_ENABLED
8+
select I2C
9+
help
10+
Enable driver for the AHT20 temperature and humidity sensor.

drivers/sensor/aht20/aht20.c

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
* Copyright (c) 2022 Rafael Lee <[email protected]>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT asair_aht20
8+
9+
#include <zephyr/device.h>
10+
#include <zephyr/drivers/i2c.h>
11+
#include <zephyr/drivers/sensor.h>
12+
#include <zephyr/kernel.h>
13+
#include <zephyr/logging/log.h>
14+
#include <zephyr/sys/byteorder.h>
15+
#include <zephyr/sys/crc.h>
16+
17+
#define AHT20_STATUS_LENGTH 1
18+
#define AHT20_TOTAL_READ_LENGTH 7
19+
#define AHT20_CRC_POLY 0x31 /* polynomial 1 + x^4 + x^5 + x^8 */
20+
#define AHT20_CRC_INIT 0xff
21+
22+
#define AHT20_CMD_RESET 0xBA
23+
#define AHT20_CMD_TRIGGER_MEASURE 0xAC
24+
#define AHT20_TRIGGER_MEASURE_BYTE_0 0x33
25+
#define AHT20_TRIGGER_MEASURE_BYTE_1 0x00
26+
#define AHT20_CMD_GET_STATUS 0x71
27+
#define AHT20_CMD_INITIALIZE 0xBE
28+
29+
#define AHT20_FULL_RANGE_BITS 20
30+
#define AHT20_TEMPERATURE_RANGE 200
31+
#define AHT20_TEMPERATURE_OFFSET 50.0
32+
33+
typedef union {
34+
struct {
35+
uint8_t: 3; /* bit [0:2] reserved */
36+
uint8_t calibrated: 1; /* bit [3] calibrated */
37+
uint8_t: 1; /* bit [4] reserved */
38+
uint8_t: 2; /* bit [5:6], AHT20 datasheet v1.1 removed 2 mode bits */
39+
uint8_t busy: 1; /* bit [7] reserved */
40+
};
41+
uint8_t all;
42+
} __attribute__((__packed__)) aht20_status;
43+
44+
struct aht20_data {
45+
struct i2c_dt_spec bus;
46+
uint32_t humidity;
47+
uint32_t temperature;
48+
};
49+
50+
LOG_MODULE_REGISTER(AHT20, CONFIG_SENSOR_LOG_LEVEL);
51+
52+
static int aht20_channel_get(const struct device *dev, enum sensor_channel chan,
53+
struct sensor_value *val)
54+
{
55+
struct aht20_data *drv_data = dev->data;
56+
float temperature;
57+
58+
switch (chan) {
59+
case SENSOR_CHAN_HUMIDITY:
60+
val->val1 = 0;
61+
val->val2 = (drv_data->humidity) * 1000000LL / (1 << AHT20_FULL_RANGE_BITS);
62+
break;
63+
case SENSOR_CHAN_AMBIENT_TEMP:
64+
temperature = (float)drv_data->temperature / (1 << AHT20_FULL_RANGE_BITS) *
65+
AHT20_TEMPERATURE_RANGE -
66+
AHT20_TEMPERATURE_OFFSET;
67+
val->val1 = (int32_t)temperature;
68+
val->val2 = (temperature - val->val1) * 1000000LL;
69+
break;
70+
default:
71+
return -ENOTSUP;
72+
}
73+
return 0;
74+
}
75+
76+
static int aht20_init(const struct device *dev)
77+
{
78+
struct aht20_data *drv_data = dev->data;
79+
aht20_status sensor_status = {0};
80+
uint8_t const inquire_status_seq[] = {AHT20_CMD_GET_STATUS};
81+
uint8_t const initialize_seq[] = {AHT20_CMD_INITIALIZE};
82+
int ret = 0;
83+
84+
k_sleep(K_MSEC(40)); /* wait for 40ms */
85+
ret = i2c_write_read_dt(&drv_data->bus, inquire_status_seq, sizeof(inquire_status_seq),
86+
&sensor_status.all, AHT20_STATUS_LENGTH);
87+
if (ret) {
88+
LOG_ERR("Inquire status failed");
89+
} else {
90+
LOG_INF("Inquire status successfully");
91+
}
92+
if (!sensor_status.calibrated) {
93+
LOG_INF("Calibrated bit is 0, need initialization");
94+
ret = i2c_write_dt(&drv_data->bus, initialize_seq, sizeof(initialize_seq));
95+
if (ret) {
96+
LOG_ERR("Initialization filaed");
97+
} else {
98+
LOG_INF("Initialization successful");
99+
}
100+
k_sleep(K_MSEC(10));
101+
}
102+
return ret;
103+
}
104+
105+
static int aht20_sample_fetch(const struct device *dev, enum sensor_channel chan)
106+
{
107+
uint8_t tx_buf[] = {AHT20_CMD_TRIGGER_MEASURE, AHT20_TRIGGER_MEASURE_BYTE_0,
108+
AHT20_TRIGGER_MEASURE_BYTE_1};
109+
uint8_t rx_buf[AHT20_TOTAL_READ_LENGTH] = {0};
110+
aht20_status sensor_status = {0};
111+
struct aht20_data *drv_data = dev->data;
112+
int rc = 0;
113+
114+
__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_AMBIENT_TEMP ||
115+
chan == SENSOR_CHAN_HUMIDITY);
116+
rc = i2c_write_dt(&drv_data->bus, tx_buf, sizeof(tx_buf));
117+
if (rc < 0) {
118+
LOG_ERR("I2C write failed");
119+
return -EIO;
120+
}
121+
/* tested with AHT20, 40ms is enough for measuring, datasheet said wait 80ms */
122+
k_sleep(K_MSEC(40));
123+
while (1) {
124+
rc = i2c_read_dt(&drv_data->bus, rx_buf, AHT20_TOTAL_READ_LENGTH);
125+
if (rc < 0) {
126+
LOG_ERR("I2C read failed");
127+
return -EIO;
128+
}
129+
sensor_status.all = rx_buf[0];
130+
if (sensor_status.busy) {
131+
k_sleep(K_MSEC(5));
132+
} else {
133+
break;
134+
}
135+
}
136+
/* the read 7 bytes contains the following data: */
137+
/* status: 8 bits */
138+
/* humidity: 20 bits */
139+
/* temperature: 20 bits */
140+
/* crc8: 8 bits */
141+
drv_data->humidity = sys_get_be24(rx_buf + 1);
142+
drv_data->humidity >>= 24 - AHT20_FULL_RANGE_BITS;
143+
drv_data->temperature = sys_get_be24(rx_buf + 3);
144+
drv_data->temperature &= (1L << AHT20_FULL_RANGE_BITS) - 1;
145+
uint8_t crc =
146+
crc8(rx_buf, AHT20_TOTAL_READ_LENGTH - 1, AHT20_CRC_POLY, AHT20_CRC_INIT, false);
147+
if (crc != rx_buf[AHT20_TOTAL_READ_LENGTH - 1]) {
148+
LOG_ERR("CRC error");
149+
return -EIO;
150+
}
151+
return 0;
152+
}
153+
154+
static const struct sensor_driver_api aht20_driver_api = {
155+
.sample_fetch = aht20_sample_fetch,
156+
.channel_get = aht20_channel_get,
157+
};
158+
159+
#define AHT20_INIT(n) \
160+
static struct aht20_data aht20_data_##n = { \
161+
.bus = I2C_DT_SPEC_INST_GET(n), \
162+
}; \
163+
SENSOR_DEVICE_DT_INST_DEFINE(n, &aht20_init, NULL, &aht20_data_##n, NULL, POST_KERNEL, \
164+
CONFIG_SENSOR_INIT_PRIORITY, &aht20_driver_api);
165+
166+
DT_INST_FOREACH_STATUS_OKAY(AHT20_INIT)

0 commit comments

Comments
 (0)