Skip to content

Commit c953e81

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

File tree

5 files changed

+188
-0
lines changed

5 files changed

+188
-0
lines changed

drivers/sensor/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ add_subdirectory_ifdef(CONFIG_ADC_CMP_NPCX nuvoton_adc_cmp_npcx)
111111
add_subdirectory_ifdef(CONFIG_TACH_IT8XXX2 ite_tach_it8xxx2)
112112
add_subdirectory_ifdef(CONFIG_VCMP_IT8XXX2 ite_vcmp_it8xxx2)
113113
add_subdirectory_ifdef(CONFIG_PCNT_ESP32 pcnt_esp32)
114+
add_subdirectory_ifdef(CONFIG_AHT20 aht20)
114115

115116
if(CONFIG_USERSPACE OR CONFIG_SENSOR_SHELL OR CONFIG_SENSOR_SHELL_BATTERY)
116117
# The above if() is needed or else CMake would complain about

drivers/sensor/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,4 +261,6 @@ source "drivers/sensor/ite_vcmp_it8xxx2/Kconfig"
261261

262262
source "drivers/sensor/pcnt_esp32/Kconfig"
263263

264+
source "drivers/sensor/aht20/Kconfig"
265+
264266
endif # SENSOR

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: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright (c) 2016 Intel Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config AHT20
5+
bool "AHT20 Temperature and Humidity Sensor"
6+
depends on I2C
7+
help
8+
Enable driver for the AHT20 temperature and humidity sensor.

drivers/sensor/aht20/aht20.c

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
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_READ_LENGTH 6
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] */
36+
uint8_t cal_enable : 1; /* bit [3] */
37+
uint8_t: 1; /* bit [4] */
38+
uint8_t: 2; /* bit [5:6], AHT20 datasheet v1.1 removed 2 mode bits */
39+
uint8_t busy : 1; /* bit [7] */
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+
break;
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+
80+
k_sleep(K_MSEC(40)); /* wait for 40ms */
81+
82+
int ret = 0;
83+
aht20_status sensor_status = {0};
84+
85+
static uint8_t const inquire_status_seq[] = {AHT20_CMD_GET_STATUS};
86+
87+
ret = i2c_write_read_dt(&drv_data->bus, inquire_status_seq, sizeof(inquire_status_seq),
88+
&sensor_status.all, AHT20_STATUS_LENGTH);
89+
if (ret != 0) {
90+
LOG_ERR("Failed to inquire status");
91+
}
92+
93+
if (!sensor_status.cal_enable) {
94+
static uint8_t const initialize_seq[] = {AHT20_CMD_INITIALIZE};
95+
96+
ret = i2c_write_dt(&drv_data->bus, initialize_seq, sizeof(initialize_seq));
97+
if (ret != 0) {
98+
LOG_ERR("Failed to inquire status");
99+
}
100+
k_sleep(K_MSEC(10));
101+
}
102+
103+
return ret;
104+
}
105+
106+
static int aht20_sample_fetch(const struct device *dev, enum sensor_channel chan)
107+
{
108+
struct aht20_data *drv_data = dev->data;
109+
110+
__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_AMBIENT_TEMP ||
111+
chan == SENSOR_CHAN_HUMIDITY);
112+
113+
uint8_t tx_buf[] = {AHT20_CMD_TRIGGER_MEASURE, AHT20_TRIGGER_MEASURE_BYTE_0,
114+
AHT20_TRIGGER_MEASURE_BYTE_1};
115+
uint8_t rx_buf[7] = {0};
116+
117+
int rc = i2c_write_dt(&drv_data->bus, tx_buf, sizeof(tx_buf));
118+
119+
if (rc < 0) {
120+
return -EIO;
121+
}
122+
123+
aht20_status sensor_status = {0};
124+
125+
/* tested with AHT20, 40ms is enough for measuring, datasheet said wait 80ms */
126+
k_sleep(K_MSEC(40));
127+
128+
while (1) {
129+
rc = i2c_read_dt(&drv_data->bus, rx_buf, AHT20_STATUS_LENGTH + AHT20_READ_LENGTH);
130+
if (rc < 0) {
131+
return -EIO;
132+
}
133+
sensor_status.all = rx_buf[0];
134+
if (sensor_status.busy) {
135+
k_sleep(K_MSEC(5));
136+
} else {
137+
break;
138+
}
139+
}
140+
141+
/* the read 7 bytes contains the following data: */
142+
/* status: 8 bits */
143+
/* humidity: 20 bits */
144+
/* temperature: 20 bits */
145+
/* crc8: 8 bits */
146+
drv_data->humidity = sys_get_be24(rx_buf + 1);
147+
drv_data->humidity >>= 24 - AHT20_FULL_RANGE_BITS;
148+
drv_data->temperature = sys_get_be24(rx_buf + 3);
149+
drv_data->temperature &= (1L << AHT20_FULL_RANGE_BITS) - 1;
150+
151+
uint8_t crc = crc8(rx_buf, AHT20_STATUS_LENGTH + AHT20_READ_LENGTH - 1, AHT20_CRC_POLY,
152+
AHT20_CRC_INIT, false);
153+
154+
if (crc != rx_buf[AHT20_STATUS_LENGTH + AHT20_READ_LENGTH - 1]) {
155+
return -EIO;
156+
}
157+
return 0;
158+
}
159+
160+
static const struct sensor_driver_api aht20_driver_api = {
161+
.sample_fetch = aht20_sample_fetch,
162+
.channel_get = aht20_channel_get,
163+
};
164+
165+
#define AHT20_INIT(n) \
166+
static struct aht20_data aht20_data_##n = { \
167+
.bus = I2C_DT_SPEC_INST_GET(n), \
168+
}; \
169+
DEVICE_DT_INST_DEFINE(n, &aht20_init, NULL, &aht20_data_##n, NULL, POST_KERNEL, \
170+
CONFIG_SENSOR_INIT_PRIORITY, &aht20_driver_api);
171+
172+
DT_INST_FOREACH_STATUS_OKAY(AHT20_INIT)

0 commit comments

Comments
 (0)