Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drivers: sensor: a01nyub: added driver #58377

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/sensor/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: Apache-2.0

add_subdirectory_ifdef(CONFIG_A01NYUB a01nyub)
add_subdirectory_ifdef(CONFIG_ADC_CMP_NPCX nuvoton_adc_cmp_npcx)
add_subdirectory_ifdef(CONFIG_ADT7310 adt7310)
add_subdirectory_ifdef(CONFIG_ADT7420 adt7420)
Expand Down
1 change: 1 addition & 0 deletions drivers/sensor/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ config SENSOR_INFO

comment "Device Drivers"

source "drivers/sensor/a01nyub/Kconfig"
source "drivers/sensor/adt7310/Kconfig"
source "drivers/sensor/adt7420/Kconfig"
source "drivers/sensor/adxl345/Kconfig"
Expand Down
6 changes: 6 additions & 0 deletions drivers/sensor/a01nyub/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright (c) 2023 SteadConnect
# SPDX-License-Identifier: Apache-2.0

zephyr_library()

zephyr_library_sources(a01nyub.c)
10 changes: 10 additions & 0 deletions drivers/sensor/a01nyub/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright (c) 2023 SteadConnect
# SPDX-License-Identifier: Apache-2.0

config A01NYUB
bool "DFRobot A01NYUB distance sensor"
default y
depends on DT_HAS_DFROBOT_A01NYUB_ENABLED
depends on UART_INTERRUPT_DRIVEN
help
Enable driver for the DFRobot A01NYUB distance sensor.
211 changes: 211 additions & 0 deletions drivers/sensor/a01nyub/a01nyub.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
/*
* Copyright (c) 2023 SteadConnect
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://wiki.dfrobot.com/A01NYUB%20Waterproof%20Ultrasonic%20Sensor%20SKU:%20SEN0313
*
*/

#define DT_DRV_COMPAT dfrobot_a01nyub

#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/drivers/sensor.h>

LOG_MODULE_REGISTER(a01nyub_sensor, CONFIG_SENSOR_LOG_LEVEL);

#define A01NYUB_BUF_LEN 4
#define A01NYUB_CHECKSUM_IDX 3
#define A01NYUB_HEADER 0xff

const struct uart_config uart_cfg_a01nyub = {
.baudrate = 9600,
.parity = UART_CFG_PARITY_NONE,
.stop_bits = UART_CFG_STOP_BITS_1,
.data_bits = UART_CFG_DATA_BITS_8,
.flow_ctrl = UART_CFG_FLOW_CTRL_NONE
};

struct a01nyub_data {
/* Max data length is 16 bits */
uint16_t data;
uint8_t xfer_bytes;
uint8_t rd_data[A01NYUB_BUF_LEN];
};

struct a01nyub_cfg {
const struct device *uart_dev;
uart_irq_callback_user_data_t cb;
};

static void a01nyub_uart_flush(const struct device *uart_dev)
{
uint8_t c;

while (uart_fifo_read(uart_dev, &c, 1) > 0) {
continue;
}
}

static uint8_t a01nyub_checksum(const uint8_t *data)
{
uint16_t cs = 0;

for (uint8_t i = 0; i < A01NYUB_BUF_LEN - 1; i++) {
cs += data[i];
}

return (uint8_t) (cs & 0x00FF);
}

static inline int a01nyub_poll_data(const struct device *dev)
{
struct a01nyub_data *data = dev->data;
uint8_t checksum;

checksum = a01nyub_checksum(data->rd_data);
if (checksum != data->rd_data[A01NYUB_CHECKSUM_IDX]) {
LOG_DBG("Checksum mismatch: calculated 0x%x != data checksum 0x%x",
checksum,
data->rd_data[A01NYUB_CHECKSUM_IDX]);
LOG_DBG("Data bytes: (%x,%x,%x,%x)",
data->rd_data[0],
data->rd_data[1],
data->rd_data[2],
data->rd_data[3]);

return -EBADMSG;
}

data->data = (data->rd_data[1]<<8) + data->rd_data[2];

return 0;
}

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

if (chan != SENSOR_CHAN_DISTANCE) {
return -ENOTSUP;
}
/* val1 is meters, val2 is microns. Both are int32_t
* data->data is in mm and units of uint16_t
*/
val->val1 = (uint32_t) (data->data / (uint16_t) 1000);
val->val2 = (uint32_t) ((data->data % 1000) * 1000);
return 0;
}

static int a01nyub_sample_fetch(const struct device *dev, enum sensor_channel chan)
{
__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);

if (chan == SENSOR_CHAN_DISTANCE || chan == SENSOR_CHAN_ALL) {
return a01nyub_poll_data(dev);
}

return -ENOTSUP;
}

static const struct sensor_driver_api a01nyub_api_funcs = {
.sample_fetch = a01nyub_sample_fetch,
.channel_get = a01nyub_channel_get,
};

static void a01nyub_uart_isr(const struct device *uart_dev, void *user_data)
{
const struct device *dev = user_data;
struct a01nyub_data *data = dev->data;

if (uart_dev == NULL) {
LOG_DBG("UART device is NULL");
return;
}

if (!uart_irq_update(uart_dev)) {
LOG_DBG("Unable to start processing interrupts");
return;
}

if (uart_irq_rx_ready(uart_dev)) {
data->xfer_bytes += uart_fifo_read(uart_dev, &data->rd_data[data->xfer_bytes],
A01NYUB_BUF_LEN - data->xfer_bytes);

/* The first byte should be A01NYUB_HEADER for a valid read.
* If we do not read A01NYUB_HEADER on what we think is the
* first byte, then reset the number of bytes read until we do
*/
if ((data->rd_data[0] != A01NYUB_HEADER) & (data->xfer_bytes == 1)) {
LOG_DBG("First byte not header! Resetting # of bytes read.");
data->xfer_bytes = 0;
}

if (data->xfer_bytes == A01NYUB_BUF_LEN) {
LOG_DBG("Read (0x%x,0x%x,0x%x,0x%x)",
data->rd_data[0],
data->rd_data[1],
data->rd_data[2],
data->rd_data[3]);
a01nyub_uart_flush(uart_dev);
data->xfer_bytes = 0;
}
}
}

static int a01nyub_init(const struct device *dev)
{
const struct a01nyub_cfg *cfg = dev->config;
int ret = 0;

uart_irq_rx_disable(cfg->uart_dev);
uart_irq_tx_disable(cfg->uart_dev);

a01nyub_uart_flush(cfg->uart_dev);

LOG_DBG("Initializing A01NYUB driver");

ret = uart_configure(cfg->uart_dev, &uart_cfg_a01nyub);
if (ret == -ENOSYS) {
LOG_ERR("Unable to configure UART port");
return -ENOSYS;
}

ret = uart_irq_callback_user_data_set(cfg->uart_dev, cfg->cb, (void *)dev);

if (ret < 0) {
if (ret == -ENOTSUP) {
LOG_ERR("Interrupt-driven UART API support not enabled");
} else if (ret == -ENOSYS) {
LOG_ERR("UART device does not support interrupt-driven API");
} else {
LOG_ERR("Error setting UART callback: %d", ret);
}
return ret;
}

uart_irq_rx_enable(cfg->uart_dev);

return ret;
}

#define A01NYUB_INIT(inst) \
\
static struct a01nyub_data a01nyub_data_##inst; \
\
static const struct a01nyub_cfg a01nyub_cfg_##inst = { \
.uart_dev = DEVICE_DT_GET(DT_INST_BUS(inst)), \
.cb = a01nyub_uart_isr, \
}; \
\
SENSOR_DEVICE_DT_INST_DEFINE(inst, a01nyub_init, NULL, \
&a01nyub_data_##inst, &a01nyub_cfg_##inst, \
POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &a01nyub_api_funcs);

DT_INST_FOREACH_STATUS_OKAY(A01NYUB_INIT)
8 changes: 8 additions & 0 deletions dts/bindings/sensor/dfrobot,a01nyub.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) 2023 Steadconnect
# SPDX-License-Identifier: Apache-2.0

description: DFRobot A01NYUB Distance Sensor

compatible: "dfrobot,a01nyub"

include: [sensor-device.yaml, uart-device.yaml]
1 change: 1 addition & 0 deletions dts/bindings/vendor-prefixes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ delta Delta Electronics, Inc.
denx Denx Software Engineering
devantech Devantech, Ltd.
dfi DFI Inc.
dfrobot DFRobot
dh DH electronics GmbH
difrnce Shenzhen Yagu Electronic Technology Co., Ltd.
digi Digi International Inc.
Expand Down
4 changes: 4 additions & 0 deletions tests/drivers/build_all/sensor/uart.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ test_uart_grow_r502a {
int-gpios = <&test_gpio 0 0>;
};
};

test_uart_a01nyub {
compatible = "dfrobot,a01nyub";
};