Skip to content

Commit

Permalink
drivers: sensor: Add initial support for hm330x dust sensor
Browse files Browse the repository at this point in the history
Adds initial support for hm330x dust sensor series. Allows to read PM1,
PM2.5 and PM10 concentrations in atmospheric environment. A further
update to the driver may add support for also reading "standard" CF1
concentrations by exposing of a custom sensor attribute or a Kconfig
option. Tested with Grove - Laser PM2.5 Sensor (HM3301) attached to a
Wio Terminal.

Signed-off-by: Benjamin Cabé <[email protected]>
  • Loading branch information
kartben authored and carlescufi committed Sep 25, 2023
1 parent 0ff2ba8 commit 4d10c96
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/sensor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ add_subdirectory_ifdef(CONFIG_FXOS8700 fxos8700)
add_subdirectory_ifdef(CONFIG_GROVE_SENSORS grove)
add_subdirectory_ifdef(CONFIG_GROW_R502A grow_r502a)
add_subdirectory_ifdef(CONFIG_HAS_STMEMSC stmemsc)
add_subdirectory_ifdef(CONFIG_HM330X hm330x)
add_subdirectory_ifdef(CONFIG_HMC5883L hmc5883l)
add_subdirectory_ifdef(CONFIG_HP206C hp206c)
add_subdirectory_ifdef(CONFIG_HTS221 hts221)
Expand Down
1 change: 1 addition & 0 deletions drivers/sensor/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ source "drivers/sensor/fxas21002/Kconfig"
source "drivers/sensor/fxos8700/Kconfig"
source "drivers/sensor/grove/Kconfig"
source "drivers/sensor/grow_r502a/Kconfig"
source "drivers/sensor/hm330x/Kconfig"
source "drivers/sensor/hmc5883l/Kconfig"
source "drivers/sensor/hp206c/Kconfig"
source "drivers/sensor/hts221/Kconfig"
Expand Down
5 changes: 5 additions & 0 deletions drivers/sensor/hm330x/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# SPDX-License-Identifier: Apache-2.0

zephyr_library()

zephyr_library_sources(hm330x.c)
12 changes: 12 additions & 0 deletions drivers/sensor/hm330x/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Seeed Studio HM330x dust particle sensor configuration options

# Copyright (c) 2023 Benjamin Cabé <[email protected]>
# SPDX-License-Identifier: Apache-2.0

config HM330X
bool "HM330X dust particle sensor"
default y
depends on DT_HAS_SEEED_HM330X_ENABLED
select I2C
help
Enable driver for the HM330X dust particle sensor.
121 changes: 121 additions & 0 deletions drivers/sensor/hm330x/hm330x.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright (c) 2023 Benjamin Cabé <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT seeed_hm330x

#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/init.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/__assert.h>

LOG_MODULE_REGISTER(HM3301, CONFIG_SENSOR_LOG_LEVEL);

#define HM330X_SELECT_COMM_CMD 0X88

#define HM330X_PM_1_0_ATM 10
#define HM330X_PM_2_5_ATM 12
#define HM330X_PM_10_ATM 14

#define HM330X_FRAME_LEN 29

struct hm330x_data {
uint16_t pm_1_0_sample;
uint16_t pm_2_5_sample;
uint16_t pm_10_sample;
};

struct hm330x_config {
struct i2c_dt_spec i2c;
};

static int hm330x_sample_fetch(const struct device *dev,
enum sensor_channel chan)
{
struct hm330x_data *drv_data = dev->data;
const struct hm330x_config *config = dev->config;
uint8_t buf[HM330X_FRAME_LEN];
uint8_t checksum = 0;

__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);

if (i2c_burst_read_dt(&config->i2c,
0, buf, HM330X_FRAME_LEN) < 0) {
return -EIO;
}

drv_data->pm_1_0_sample = (buf[HM330X_PM_1_0_ATM] << 8) | buf[HM330X_PM_1_0_ATM + 1];
drv_data->pm_2_5_sample = (buf[HM330X_PM_2_5_ATM] << 8) | buf[HM330X_PM_2_5_ATM + 1];
drv_data->pm_10_sample = (buf[HM330X_PM_10_ATM] << 8) | buf[HM330X_PM_10_ATM + 1];

for (int i = 0; i < HM330X_FRAME_LEN - 1; i++) {
checksum += buf[i];
}
if (checksum != buf[HM330X_FRAME_LEN - 1]) {
LOG_ERR("Checksum error");
return -EBADMSG;
}

return 0;
}

static int hm330x_channel_get(const struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
struct hm330x_data *drv_data = dev->data;

if (chan == SENSOR_CHAN_PM_1_0) {
val->val1 = drv_data->pm_1_0_sample;
val->val2 = 0;
} else if (chan == SENSOR_CHAN_PM_2_5) {
val->val1 = drv_data->pm_2_5_sample;
val->val2 = 0;
} else if (chan == SENSOR_CHAN_PM_10) {
val->val1 = drv_data->pm_10_sample;
val->val2 = 0;
} else {
return -ENOTSUP;
}

return 0;
}

static const struct sensor_driver_api hm330x_driver_api = {
.sample_fetch = hm330x_sample_fetch,
.channel_get = hm330x_channel_get
};

int hm330x_init(const struct device *dev)
{
const struct hm330x_config *config = dev->config;

if (!i2c_is_ready_dt(&config->i2c)) {
LOG_ERR("I2C bus device not ready");
return -ENODEV;
}

/** Enable I2C communications (module defaults to UART) */
if (i2c_reg_write_byte_dt(&config->i2c, 0, HM330X_SELECT_COMM_CMD) < 0) {
LOG_ERR("Failed to switch to I2C");
return -EIO;
}

return 0;
}

#define HM330X_DEFINE(inst) \
static struct hm330x_data hm330x_data_##inst; \
\
static const struct hm330x_config hm330x_config##inst = { \
.i2c = I2C_DT_SPEC_INST_GET(inst) \
}; \
\
SENSOR_DEVICE_DT_INST_DEFINE(inst, hm330x_init, NULL, &hm330x_data_##inst, \
&hm330x_config##inst, POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, &hm330x_driver_api); \

DT_INST_FOREACH_STATUS_OKAY(HM330X_DEFINE)
9 changes: 9 additions & 0 deletions dts/bindings/sensor/seeed,hm330x.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2023 [email protected]
# SPDX-License-Identifier: Apache-2.0

description: |
Seeed Studio HM330x dust particle sensor
compatible: "seeed,hm330x"

include: [sensor-device.yaml, i2c-device.yaml]
6 changes: 6 additions & 0 deletions tests/drivers/build_all/sensor/i2c.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -765,3 +765,9 @@ test_i2c_adltc2990@72 {
pin-v3-voltage-divider-resistors = <100 100>;
pin-v4-voltage-divider-resistors = <0 1>;
};

test_i2c_hm330x@73 {
compatible = "seeed,hm330x";
reg = <0x73>;
status = "okay";
};

0 comments on commit 4d10c96

Please sign in to comment.