drivers: sensor: hc-sr04: add driver
Add a simple driver for the HC-SR04 ultrasonic distance sensor. Signed-off-by: Adrien Leravat <adrien.leravat@gmail.com>
This commit is contained in:
parent
6d187ba882
commit
9df661ea1a
6 changed files with 229 additions and 0 deletions
|
@ -42,6 +42,7 @@ add_subdirectory_ifdef(CONFIG_EXPLORIR_M explorir_m)
|
||||||
add_subdirectory_ifdef(CONFIG_F75303 f75303)
|
add_subdirectory_ifdef(CONFIG_F75303 f75303)
|
||||||
add_subdirectory_ifdef(CONFIG_FCX_MLDX5 fcx_mldx5)
|
add_subdirectory_ifdef(CONFIG_FCX_MLDX5 fcx_mldx5)
|
||||||
add_subdirectory_ifdef(CONFIG_GROW_R502A grow_r502a)
|
add_subdirectory_ifdef(CONFIG_GROW_R502A grow_r502a)
|
||||||
|
add_subdirectory_ifdef(CONFIG_HC_SR04 hc_sr04)
|
||||||
add_subdirectory_ifdef(CONFIG_HP206C hp206c)
|
add_subdirectory_ifdef(CONFIG_HP206C hp206c)
|
||||||
add_subdirectory_ifdef(CONFIG_IST8310 ist8310)
|
add_subdirectory_ifdef(CONFIG_IST8310 ist8310)
|
||||||
add_subdirectory_ifdef(CONFIG_LM35 lm35)
|
add_subdirectory_ifdef(CONFIG_LM35 lm35)
|
||||||
|
|
|
@ -126,6 +126,7 @@ source "drivers/sensor/explorir_m/Kconfig"
|
||||||
source "drivers/sensor/f75303/Kconfig"
|
source "drivers/sensor/f75303/Kconfig"
|
||||||
source "drivers/sensor/fcx_mldx5/Kconfig"
|
source "drivers/sensor/fcx_mldx5/Kconfig"
|
||||||
source "drivers/sensor/grow_r502a/Kconfig"
|
source "drivers/sensor/grow_r502a/Kconfig"
|
||||||
|
source "drivers/sensor/hc_sr04/Kconfig"
|
||||||
source "drivers/sensor/hp206c/Kconfig"
|
source "drivers/sensor/hp206c/Kconfig"
|
||||||
source "drivers/sensor/ist8310/Kconfig"
|
source "drivers/sensor/ist8310/Kconfig"
|
||||||
source "drivers/sensor/lm35/Kconfig"
|
source "drivers/sensor/lm35/Kconfig"
|
||||||
|
|
4
drivers/sensor/hc_sr04/CMakeLists.txt
Normal file
4
drivers/sensor/hc_sr04/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
zephyr_library()
|
||||||
|
zephyr_library_sources(hc_sr04.c)
|
12
drivers/sensor/hc_sr04/Kconfig
Normal file
12
drivers/sensor/hc_sr04/Kconfig
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# HC-SR04 Ultrasound sensor configuration options
|
||||||
|
|
||||||
|
# Copyright (c) 2024 Adrien Leravat
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
config HC_SR04
|
||||||
|
bool "HC-SR04 Ultrasound distance sensor"
|
||||||
|
default y
|
||||||
|
depends on DT_HAS_HC_SR04_ENABLED
|
||||||
|
depends on GPIO
|
||||||
|
help
|
||||||
|
Enable driver for HC-SR04 distance sensor.
|
189
drivers/sensor/hc_sr04/hc_sr04.c
Normal file
189
drivers/sensor/hc_sr04/hc_sr04.c
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Adrien Leravat
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT hc_sr04
|
||||||
|
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/drivers/gpio.h>
|
||||||
|
#include <zephyr/drivers/sensor.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(HC_SR04, CONFIG_SENSOR_LOG_LEVEL);
|
||||||
|
|
||||||
|
#define HC_SR04_MM_PER_MS 171
|
||||||
|
|
||||||
|
static const uint32_t hw_cycles_per_ms = sys_clock_hw_cycles_per_sec() / 1000;
|
||||||
|
|
||||||
|
struct hcsr04_data {
|
||||||
|
const struct device *dev;
|
||||||
|
struct gpio_callback gpio_cb;
|
||||||
|
struct k_sem sem;
|
||||||
|
uint32_t start_cycles;
|
||||||
|
atomic_t echo_high_cycles;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hcsr04_config {
|
||||||
|
struct gpio_dt_spec trigger_gpios;
|
||||||
|
struct gpio_dt_spec echo_gpios;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void hcsr04_gpio_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins);
|
||||||
|
|
||||||
|
static int hcsr04_configure_gpios(const struct hcsr04_config *cfg)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!gpio_is_ready_dt(&cfg->trigger_gpios)) {
|
||||||
|
LOG_ERR("GPIO '%s' not ready", cfg->trigger_gpios.port->name);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
ret = gpio_pin_configure_dt(&cfg->trigger_gpios, GPIO_OUTPUT_LOW);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to configure '%s' as output: %d", cfg->trigger_gpios.port->name,
|
||||||
|
ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gpio_is_ready_dt(&cfg->echo_gpios)) {
|
||||||
|
LOG_ERR("GPIO '%s' not ready", cfg->echo_gpios.port->name);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
ret = gpio_pin_configure_dt(&cfg->echo_gpios, GPIO_INPUT);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to configure '%s' as output: %d", cfg->echo_gpios.port->name, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hcsr04_configure_interrupt(const struct hcsr04_config *cfg, struct hcsr04_data *data)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Disable initially to avoid spurious interrupts. */
|
||||||
|
ret = gpio_pin_interrupt_configure(cfg->echo_gpios.port, cfg->echo_gpios.pin,
|
||||||
|
GPIO_INT_DISABLE);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to configure '%s' as interrupt: %d", cfg->echo_gpios.port->name,
|
||||||
|
ret);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
gpio_init_callback(&data->gpio_cb, &hcsr04_gpio_callback, BIT(cfg->echo_gpios.pin));
|
||||||
|
ret = gpio_add_callback(cfg->echo_gpios.port, &data->gpio_cb);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to add callback on '%s': %d", cfg->echo_gpios.port->name, ret);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hcsr04_init(const struct device *dev)
|
||||||
|
{
|
||||||
|
const struct hcsr04_config *cfg = dev->config;
|
||||||
|
struct hcsr04_data *data = dev->data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
k_sem_init(&data->sem, 0, 1);
|
||||||
|
|
||||||
|
ret = hcsr04_configure_gpios(cfg);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hcsr04_configure_interrupt(cfg, data);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hcsr04_gpio_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
|
||||||
|
{
|
||||||
|
struct hcsr04_data *data = CONTAINER_OF(cb, struct hcsr04_data, gpio_cb);
|
||||||
|
const struct hcsr04_config *cfg = data->dev->config;
|
||||||
|
|
||||||
|
if (gpio_pin_get(dev, cfg->echo_gpios.pin) == 1) {
|
||||||
|
data->start_cycles = k_cycle_get_32();
|
||||||
|
} else {
|
||||||
|
atomic_set(&data->echo_high_cycles, k_cycle_get_32() - data->start_cycles);
|
||||||
|
gpio_pin_interrupt_configure_dt(&cfg->echo_gpios, GPIO_INT_DISABLE);
|
||||||
|
k_sem_give(&data->sem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hcsr04_sample_fetch(const struct device *dev, enum sensor_channel chan)
|
||||||
|
{
|
||||||
|
const struct hcsr04_config *cfg = dev->config;
|
||||||
|
struct hcsr04_data *data = dev->data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = gpio_pin_interrupt_configure_dt(&cfg->echo_gpios, GPIO_INT_EDGE_BOTH);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to set configure echo pin as interrupt: %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate 10us trigger */
|
||||||
|
ret = gpio_pin_set_dt(&cfg->trigger_gpios, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to set trigger pin: %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_busy_wait(10);
|
||||||
|
|
||||||
|
ret = gpio_pin_set_dt(&cfg->trigger_gpios, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERR("Failed to set trigger pin: %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k_sem_take(&data->sem, K_MSEC(10)) != 0) {
|
||||||
|
LOG_ERR("Echo signal was not received");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hcsr04_channel_get(const struct device *dev, enum sensor_channel chan,
|
||||||
|
struct sensor_value *val)
|
||||||
|
{
|
||||||
|
const struct hcsr04_data *data = dev->data;
|
||||||
|
uint32_t distance_mm;
|
||||||
|
|
||||||
|
if (chan != SENSOR_CHAN_DISTANCE) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
distance_mm = HC_SR04_MM_PER_MS * atomic_get(&data->echo_high_cycles) /
|
||||||
|
hw_cycles_per_ms;
|
||||||
|
return sensor_value_from_milli(val, distance_mm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sensor_driver_api hcsr04_driver_api = {
|
||||||
|
.sample_fetch = hcsr04_sample_fetch,
|
||||||
|
.channel_get = hcsr04_channel_get
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define HC_SR04_INIT(index) \
|
||||||
|
static struct hcsr04_data hcsr04_data_##index = { \
|
||||||
|
.dev = DEVICE_DT_INST_GET(index), \
|
||||||
|
.start_cycles = 0, \
|
||||||
|
.echo_high_cycles = ATOMIC_INIT(0), \
|
||||||
|
}; \
|
||||||
|
static struct hcsr04_config hcsr04_config_##index = { \
|
||||||
|
.trigger_gpios = GPIO_DT_SPEC_INST_GET(index, trigger_gpios), \
|
||||||
|
.echo_gpios = GPIO_DT_SPEC_INST_GET(index, echo_gpios), \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
SENSOR_DEVICE_DT_INST_DEFINE(index, &hcsr04_init, NULL, &hcsr04_data_##index, \
|
||||||
|
&hcsr04_config_##index, POST_KERNEL, \
|
||||||
|
CONFIG_SENSOR_INIT_PRIORITY, &hcsr04_driver_api); \
|
||||||
|
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(HC_SR04_INIT)
|
22
dts/bindings/sensor/hc-sr04.yaml
Normal file
22
dts/bindings/sensor/hc-sr04.yaml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# Copyright (c) 2024, Adrien Leravat
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
description: HC-SR04 ultrasound sensor.
|
||||||
|
|
||||||
|
compatible: "hc-sr04"
|
||||||
|
|
||||||
|
include: sensor-device.yaml
|
||||||
|
|
||||||
|
properties:
|
||||||
|
trigger-gpios:
|
||||||
|
type: phandle-array
|
||||||
|
required: true
|
||||||
|
description: |
|
||||||
|
Output pin used to trigger the distance measurement.
|
||||||
|
echo-gpios:
|
||||||
|
type: phandle-array
|
||||||
|
required: true
|
||||||
|
description: |
|
||||||
|
Input pin. The pulse received on this pin corresponds to
|
||||||
|
the duration between the ultrasonic pulse emission and
|
||||||
|
the reception of its "echo".
|
Loading…
Add table
Add a link
Reference in a new issue