forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
drivers: sensor: a01nyub: added driver
Added a driver for the DFRobot A01NYUB distance sensor. This sensor sends its readings via UART at 9600 baud. This driver uses interrupts to read the data from the sensor. Signed-off-by: Oliver King <[email protected]>
- Loading branch information
1 parent
7bfe096
commit fbc6a91
Showing
8 changed files
with
242 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters