diff --git a/doc/releases/release-notes-4.1.rst b/doc/releases/release-notes-4.1.rst index b89e86be51f..48be86f9937 100644 --- a/doc/releases/release-notes-4.1.rst +++ b/doc/releases/release-notes-4.1.rst @@ -242,6 +242,33 @@ Drivers and Sensors * Sensors + * Sensor Clock + + * The asynchronous sensor API now supports external clock sources. To use an external clock source + with the asynchronous sensor API, the following configurations are required: + + * Enable one of the Kconfig options: + :kconfig:option:`CONFIG_SENSOR_CLOCK_COUNTER`, + :kconfig:option:`CONFIG_SENSOR_CLOCK_RTC`, or + :kconfig:option:`CONFIG_SENSOR_CLOCK_SYSTEM`. + + * If not using the system clock, define the ``zephyr,sensor-clock`` property in the device tree to specify + the external clock source. + + A typical configuration in the device tree structure is as follows: + + .. code-block:: devicetree + + / { + chosen { + zephyr,sensor-clock = &timer0; + }; + }; + + &timer0 { + status = "okay"; + }; + * Serial * SPI diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index ca65a412800..8803ba37bb5 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -74,3 +74,15 @@ zephyr_library_sources_ifdef(CONFIG_SENSOR_SHELL sensor_shell.c) zephyr_library_sources_ifdef(CONFIG_SENSOR_SHELL_STREAM sensor_shell_stream.c) zephyr_library_sources_ifdef(CONFIG_SENSOR_SHELL_BATTERY shell_battery.c) zephyr_library_sources_ifdef(CONFIG_SENSOR_ASYNC_API sensor_decoders_init.c default_rtio_sensor.c) + +dt_has_chosen(has_zephyr_sensor_clock PROPERTY "zephyr,sensor-clock") + +if(CONFIG_SENSOR_CLOCK_RTC OR CONFIG_SENSOR_CLOCK_COUNTER) + if(has_zephyr_sensor_clock) + zephyr_library_sources(sensor_clock_external.c) + else() + message(FATAL_ERROR "Sensor clock type (RTC or Counter) is selected, but no zephyr,sensor-clock is defined in the device tree.") + endif() +elseif(CONFIG_SENSOR_CLOCK_SYSTEM) + zephyr_library_sources(sensor_clock_sys.c) +endif() diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index 452d8182eb7..3c9f0bdf996 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -82,6 +82,8 @@ config SENSOR_SHELL_MAX_TRIGGER_DEVICES config SENSOR_INFO bool "Sensor Info iterable section" +source "drivers/sensor/Kconfig.sensor_clock" + comment "Device Drivers" # zephyr-keep-sorted-start diff --git a/drivers/sensor/Kconfig.sensor_clock b/drivers/sensor/Kconfig.sensor_clock new file mode 100644 index 00000000000..be985746197 --- /dev/null +++ b/drivers/sensor/Kconfig.sensor_clock @@ -0,0 +1,30 @@ +# Sensor clock configuration options +# Copyright(c) 2024 Cienet +# SPDX-License-Identifier: Apache-2.0 + +config SENSOR_CLOCK + bool + default y if SENSOR_ASYNC_API + help + Configure the sensor clock source for the system. + +if SENSOR_CLOCK + +choice + prompt "Sensor clock type" + default SENSOR_CLOCK_SYSTEM + help + Select the clock source to be used for sensor timing. + +config SENSOR_CLOCK_SYSTEM + bool "Use the system counter for sensor time" + +config SENSOR_CLOCK_COUNTER + bool "Use a counter device/API for sensor time" + +config SENSOR_CLOCK_RTC + bool "Use an RTC device/API for sensor time" + +endchoice + +endif # SENSOR_CLOCK diff --git a/drivers/sensor/adi/adxl345/adxl345_stream.c b/drivers/sensor/adi/adxl345/adxl345_stream.c index 054ca555f08..def97865f14 100644 --- a/drivers/sensor/adi/adxl345/adxl345_stream.c +++ b/drivers/sensor/adi/adxl345/adxl345_stream.c @@ -6,7 +6,7 @@ #include #include - +#include #include "adxl345.h" LOG_MODULE_DECLARE(ADXL345, CONFIG_SENSOR_LOG_LEVEL); @@ -358,11 +358,21 @@ void adxl345_stream_irq_handler(const struct device *dev) { struct adxl345_dev_data *data = (struct adxl345_dev_data *) dev->data; const struct adxl345_dev_config *cfg = (const struct adxl345_dev_config *) dev->config; + uint64_t cycles; + int rc; if (data->sqe == NULL) { return; } - data->timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + + rc = sensor_clock_get_cycles(&cycles); + if (rc != 0) { + LOG_ERR("Failed to get sensor clock cycles"); + rtio_iodev_sqe_err(data->sqe, rc); + return; + } + + data->timestamp = sensor_clock_cycles_to_ns(cycles); struct rtio_sqe *write_status_addr = rtio_sqe_acquire(data->rtio_ctx); struct rtio_sqe *read_status_reg = rtio_sqe_acquire(data->rtio_ctx); struct rtio_sqe *check_status_reg = rtio_sqe_acquire(data->rtio_ctx); diff --git a/drivers/sensor/adi/adxl362/adxl362_stream.c b/drivers/sensor/adi/adxl362/adxl362_stream.c index 55175a4f9b0..453ed334348 100644 --- a/drivers/sensor/adi/adxl362/adxl362_stream.c +++ b/drivers/sensor/adi/adxl362/adxl362_stream.c @@ -6,7 +6,7 @@ #include #include - +#include #include "adxl362.h" LOG_MODULE_DECLARE(ADXL362, CONFIG_SENSOR_LOG_LEVEL); @@ -384,12 +384,20 @@ static void adxl362_process_status_cb(struct rtio *r, const struct rtio_sqe *sqr void adxl362_stream_irq_handler(const struct device *dev) { struct adxl362_data *data = (struct adxl362_data *) dev->data; - + uint64_t cycles; + int rc; if (data->sqe == NULL) { return; } - data->timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + rc = sensor_clock_get_cycles(&cycles); + if (rc != 0) { + LOG_ERR("Failed to get sensor clock cycles"); + rtio_iodev_sqe_err(data->sqe, rc); + return; + } + + data->timestamp = sensor_clock_cycles_to_ns(cycles); struct rtio_sqe *write_status_addr = rtio_sqe_acquire(data->rtio_ctx); struct rtio_sqe *read_status_reg = rtio_sqe_acquire(data->rtio_ctx); diff --git a/drivers/sensor/adi/adxl367/adxl367_stream.c b/drivers/sensor/adi/adxl367/adxl367_stream.c index 5826ed8d6cc..eb57349a299 100644 --- a/drivers/sensor/adi/adxl367/adxl367_stream.c +++ b/drivers/sensor/adi/adxl367/adxl367_stream.c @@ -6,7 +6,7 @@ #include #include - +#include #include "adxl367.h" LOG_MODULE_DECLARE(ADXL362, CONFIG_SENSOR_LOG_LEVEL); @@ -537,12 +537,20 @@ static void adxl367_process_status_cb(struct rtio *r, const struct rtio_sqe *sqr void adxl367_stream_irq_handler(const struct device *dev) { struct adxl367_data *data = (struct adxl367_data *) dev->data; - + uint64_t cycles; + int rc; if (data->sqe == NULL) { return; } - data->timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + rc = sensor_clock_get_cycles(&cycles); + if (rc != 0) { + LOG_ERR("Failed to get sensor clock cycles"); + rtio_iodev_sqe_err(data->sqe, rc); + return; + } + + data->timestamp = sensor_clock_cycles_to_ns(cycles); struct rtio_sqe *write_status_addr = rtio_sqe_acquire(data->rtio_ctx); struct rtio_sqe *read_status_reg = rtio_sqe_acquire(data->rtio_ctx); diff --git a/drivers/sensor/adi/adxl372/adxl372_stream.c b/drivers/sensor/adi/adxl372/adxl372_stream.c index a4dda2f2ce8..c5ea6b2b3bf 100644 --- a/drivers/sensor/adi/adxl372/adxl372_stream.c +++ b/drivers/sensor/adi/adxl372/adxl372_stream.c @@ -6,6 +6,7 @@ #include #include +#include #include "adxl372.h" @@ -424,12 +425,20 @@ static void adxl372_process_status1_cb(struct rtio *r, const struct rtio_sqe *sq void adxl372_stream_irq_handler(const struct device *dev) { struct adxl372_data *data = (struct adxl372_data *)dev->data; - + uint64_t cycles; + int rc; if (data->sqe == NULL) { return; } - data->timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + rc = sensor_clock_get_cycles(&cycles); + if (rc != 0) { + LOG_ERR("Failed to get sensor clock cycles"); + rtio_iodev_sqe_err(data->sqe, rc); + return; + } + + data->timestamp = sensor_clock_cycles_to_ns(cycles); struct rtio_sqe *write_status_addr = rtio_sqe_acquire(data->rtio_ctx); struct rtio_sqe *read_status_reg = rtio_sqe_acquire(data->rtio_ctx); diff --git a/drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c b/drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c index 832d046bdd7..dedc2411489 100644 --- a/drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c +++ b/drivers/sensor/asahi_kasei/akm09918c/akm09918c_async.c @@ -8,6 +8,7 @@ #include #include +#include #include "akm09918c.h" @@ -20,6 +21,7 @@ void akm09918c_submit_sync(struct rtio_iodev_sqe *iodev_sqe) struct akm09918c_data *data = dev->data; const struct sensor_chan_spec *const channels = cfg->channels; const size_t num_channels = cfg->count; + uint64_t cycles; int rc; /* Check if the requested channels are supported */ @@ -46,8 +48,15 @@ void akm09918c_submit_sync(struct rtio_iodev_sqe *iodev_sqe) return; } + rc = sensor_clock_get_cycles(&cycles); + if (rc != 0) { + LOG_ERR("Failed to get sensor clock cycles"); + rtio_iodev_sqe_err(iodev_sqe, rc); + return; + } + /* save information for the work item */ - data->work_ctx.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + data->work_ctx.timestamp = sensor_clock_cycles_to_ns(cycles); data->work_ctx.iodev_sqe = iodev_sqe; rc = k_work_schedule(&data->work_ctx.async_fetch_work, K_USEC(AKM09918C_MEASURE_TIME_US)); diff --git a/drivers/sensor/bosch/bma4xx/bma4xx.c b/drivers/sensor/bosch/bma4xx/bma4xx.c index 219d65dc5ed..0340f20ed47 100644 --- a/drivers/sensor/bosch/bma4xx/bma4xx.c +++ b/drivers/sensor/bosch/bma4xx/bma4xx.c @@ -14,6 +14,7 @@ #include #include #include +#include LOG_MODULE_REGISTER(bma4xx, CONFIG_SENSOR_LOG_LEVEL); #include "bma4xx.h" @@ -352,6 +353,7 @@ static void bma4xx_submit_one_shot(const struct device *dev, struct rtio_iodev_s struct bma4xx_encoded_data *edata; uint8_t *buf; uint32_t buf_len; + uint64_t cycles; int rc; /* Get the buffer for the frame, it may be allocated dynamically by the rtio context */ @@ -362,11 +364,18 @@ static void bma4xx_submit_one_shot(const struct device *dev, struct rtio_iodev_s return; } + rc = sensor_clock_get_cycles(&cycles); + if (rc != 0) { + LOG_ERR("Failed to get sensor clock cycles"); + rtio_iodev_sqe_err(iodev_sqe, rc); + return; + } + /* Prepare response */ edata = (struct bma4xx_encoded_data *)buf; edata->header.is_fifo = false; edata->header.accel_fs = bma4xx->accel_fs_range; - edata->header.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + edata->header.timestamp = sensor_clock_cycles_to_ns(cycles); edata->has_accel = 0; edata->has_temp = 0; diff --git a/drivers/sensor/bosch/bme280/bme280_async.c b/drivers/sensor/bosch/bme280/bme280_async.c index 0cf0359b094..1ad6e3d22d2 100644 --- a/drivers/sensor/bosch/bme280/bme280_async.c +++ b/drivers/sensor/bosch/bme280/bme280_async.c @@ -7,6 +7,7 @@ #include #include +#include #include "bme280.h" @@ -16,6 +17,7 @@ void bme280_submit_sync(struct rtio_iodev_sqe *iodev_sqe) { uint32_t min_buf_len = sizeof(struct bme280_encoded_data); int rc; + uint64_t cycles; uint8_t *buf; uint32_t buf_len; @@ -31,10 +33,17 @@ void bme280_submit_sync(struct rtio_iodev_sqe *iodev_sqe) return; } + rc = sensor_clock_get_cycles(&cycles); + if (rc != 0) { + LOG_ERR("Failed to get sensor clock cycles"); + rtio_iodev_sqe_err(iodev_sqe, rc); + return; + } + struct bme280_encoded_data *edata; edata = (struct bme280_encoded_data *)buf; - edata->header.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + edata->header.timestamp = sensor_clock_cycles_to_ns(cycles); edata->has_temp = 0; edata->has_humidity = 0; edata->has_press = 0; diff --git a/drivers/sensor/default_rtio_sensor.c b/drivers/sensor/default_rtio_sensor.c index 7a0117df66c..511ad0b6f00 100644 --- a/drivers/sensor/default_rtio_sensor.c +++ b/drivers/sensor/default_rtio_sensor.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -119,11 +120,21 @@ static void sensor_submit_fallback_sync(struct rtio_iodev_sqe *iodev_sqe) const struct sensor_chan_spec *const channels = cfg->channels; const int num_output_samples = compute_num_samples(channels, cfg->count); uint32_t min_buf_len = compute_min_buf_len(num_output_samples); - uint64_t timestamp_ns = k_ticks_to_ns_floor64(k_uptime_ticks()); - int rc = sensor_sample_fetch(dev); + uint64_t cycles; + int rc; + + rc = sensor_clock_get_cycles(&cycles); + if (rc != 0) { + LOG_ERR("Failed to get sensor clock cycles"); + rtio_iodev_sqe_err(iodev_sqe, rc); + return; + } + + uint64_t timestamp_ns = sensor_clock_cycles_to_ns(cycles); uint8_t *buf; uint32_t buf_len; + rc = sensor_sample_fetch(dev); /* Check that the fetch succeeded */ if (rc != 0) { LOG_WRN("Failed to fetch samples"); diff --git a/drivers/sensor/memsic/mmc56x3/mmc56x3_async.c b/drivers/sensor/memsic/mmc56x3/mmc56x3_async.c index 353293d3609..63b8e931899 100644 --- a/drivers/sensor/memsic/mmc56x3/mmc56x3_async.c +++ b/drivers/sensor/memsic/mmc56x3/mmc56x3_async.c @@ -5,6 +5,7 @@ #include #include +#include #include "mmc56x3.h" @@ -16,6 +17,7 @@ void mmc56x3_submit_sync(struct rtio_iodev_sqe *iodev_sqe) int rc; uint8_t *buf; uint32_t buf_len; + uint64_t cycles; const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; const struct device *dev = cfg->sensor; @@ -29,10 +31,17 @@ void mmc56x3_submit_sync(struct rtio_iodev_sqe *iodev_sqe) return; } + rc = sensor_clock_get_cycles(&cycles); + if (rc != 0) { + LOG_ERR("Failed to get sensor clock cycles"); + rtio_iodev_sqe_err(iodev_sqe, rc); + return; + } + struct mmc56x3_encoded_data *edata; edata = (struct mmc56x3_encoded_data *)buf; - edata->header.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + edata->header.timestamp = sensor_clock_cycles_to_ns(cycles); edata->has_temp = 0; edata->has_magn_x = 0; edata->has_magn_y = 0; diff --git a/drivers/sensor/sensor_clock_external.c b/drivers/sensor/sensor_clock_external.c new file mode 100644 index 00000000000..5baf1ac1563 --- /dev/null +++ b/drivers/sensor/sensor_clock_external.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024 Cienet + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(sensor_clock, CONFIG_SENSOR_LOG_LEVEL); + +static const struct device *external_sensor_clock = DEVICE_DT_GET(DT_CHOSEN(zephyr_sensor_clock)); +static uint32_t freq; + +static int external_sensor_clock_init(void) +{ + int rc; + + rc = counter_start(external_sensor_clock); + if (rc != 0) { + LOG_ERR("Failed to start sensor clock counter: %d\n", rc); + return rc; + } + + freq = counter_get_frequency(external_sensor_clock); + if (freq == 0) { + LOG_ERR("Sensor clock %s has no fixed frequency\n", external_sensor_clock->name); + return -EINVAL; + } + + return 0; +} + +int sensor_clock_get_cycles(uint64_t *cycles) +{ + __ASSERT_NO_MSG(counter_is_counting_up(external_sensor_clock)); + + int rc; + const struct counter_driver_api *api = + (const struct counter_driver_api *)external_sensor_clock->api; + + if (api->get_value_64) { + rc = counter_get_value_64(external_sensor_clock, cycles); + } else { + uint32_t result_32; + + rc = counter_get_value(external_sensor_clock, &result_32); + *cycles = (uint64_t)result_32; + } + + return rc; +} + +uint64_t sensor_clock_cycles_to_ns(uint64_t cycles) +{ + return (cycles * NSEC_PER_SEC) / freq; +} + +SYS_INIT(external_sensor_clock_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/drivers/sensor/sensor_clock_sys.c b/drivers/sensor/sensor_clock_sys.c new file mode 100644 index 00000000000..e9829268466 --- /dev/null +++ b/drivers/sensor/sensor_clock_sys.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024 Cienet + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +int sensor_clock_get_cycles(uint64_t *cycles) +{ + if (cycles == NULL) { + return -EINVAL; + } + +#ifdef CONFIG_TIMER_HAS_64BIT_CYCLE_COUNTER + *cycles = k_cycle_get_64(); +#else + *cycles = (uint64_t)k_cycle_get_32(); +#endif + + return 0; +} + +uint64_t sensor_clock_cycles_to_ns(uint64_t cycles) +{ + return (cycles * NSEC_PER_SEC) / sys_clock_hw_cycles_per_sec(); +} diff --git a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio.c b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio.c index c43f0c9b898..e4ee7af4727 100644 --- a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio.c +++ b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio.c @@ -11,6 +11,7 @@ #include "lsm6dsv16x_rtio.h" #include "lsm6dsv16x_decoder.h" #include +#include #include LOG_MODULE_REGISTER(LSM6DSV16X_RTIO, CONFIG_SENSOR_LOG_LEVEL); @@ -21,6 +22,7 @@ static void lsm6dsv16x_submit_sample(const struct device *dev, struct rtio_iodev const struct sensor_chan_spec *const channels = cfg->channels; const size_t num_channels = cfg->count; uint32_t min_buf_len = sizeof(struct lsm6dsv16x_rtio_data); + uint64_t cycles; int rc = 0; uint8_t *buf; uint32_t buf_len; @@ -112,10 +114,17 @@ static void lsm6dsv16x_submit_sample(const struct device *dev, struct rtio_iodev } } + rc = sensor_clock_get_cycles(&cycles); + if (rc != 0) { + LOG_ERR("Failed to get sensor clock cycles"); + rtio_iodev_sqe_err(iodev_sqe, rc); + goto err; + } + edata->header.is_fifo = false; edata->header.accel_fs = data->accel_fs; edata->header.gyro_fs = data->gyro_fs; - edata->header.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + edata->header.timestamp = sensor_clock_cycles_to_ns(cycles); rtio_iodev_sqe_ok(iodev_sqe, 0); diff --git a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c index 27635c3e910..b2b16149779 100644 --- a/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c +++ b/drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c @@ -13,6 +13,7 @@ #include "lsm6dsv16x.h" #include "lsm6dsv16x_decoder.h" #include +#include #include LOG_MODULE_DECLARE(LSM6DSV16X_RTIO); @@ -377,13 +378,22 @@ void lsm6dsv16x_stream_irq_handler(const struct device *dev) #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) const struct lsm6dsv16x_config *config = dev->config; #endif + uint64_t cycles; + int rc; if (lsm6dsv16x->streaming_sqe == NULL) { return; } + rc = sensor_clock_get_cycles(&cycles); + if (rc != 0) { + LOG_ERR("Failed to get sensor clock cycles"); + rtio_iodev_sqe_err(lsm6dsv16x->streaming_sqe, rc); + return; + } + /* get timestamp as soon as the irq is served */ - lsm6dsv16x->fifo_timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + lsm6dsv16x->fifo_timestamp = sensor_clock_cycles_to_ns(cycles); #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) if (ON_I3C_BUS(config) && (!I3C_INT_PIN(config))) { diff --git a/drivers/sensor/tdk/icm42688/icm42688_decoder.c b/drivers/sensor/tdk/icm42688/icm42688_decoder.c index c01cc3f9c27..1e6fa75a306 100644 --- a/drivers/sensor/tdk/icm42688/icm42688_decoder.c +++ b/drivers/sensor/tdk/icm42688/icm42688_decoder.c @@ -10,6 +10,8 @@ #include #include +#include + LOG_MODULE_REGISTER(ICM42688_DECODER, CONFIG_SENSOR_LOG_LEVEL); #define DT_DRV_COMPAT invensense_icm42688 @@ -183,6 +185,8 @@ int icm42688_encode(const struct device *dev, const struct sensor_chan_spec *con { struct icm42688_dev_data *data = dev->data; struct icm42688_encoded_data *edata = (struct icm42688_encoded_data *)buf; + uint64_t cycles; + int rc; edata->channels = 0; @@ -190,10 +194,15 @@ int icm42688_encode(const struct device *dev, const struct sensor_chan_spec *con edata->channels |= icm42688_encode_channel(channels[i].chan_type); } + rc = sensor_clock_get_cycles(&cycles); + if (rc != 0) { + return rc; + } + edata->header.is_fifo = false; edata->header.accel_fs = data->cfg.accel_fs; edata->header.gyro_fs = data->cfg.gyro_fs; - edata->header.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + edata->header.timestamp = sensor_clock_cycles_to_ns(cycles); return 0; } diff --git a/drivers/sensor/tdk/icm42688/icm42688_rtio.c b/drivers/sensor/tdk/icm42688/icm42688_rtio.c index aaa640699f9..1d865110758 100644 --- a/drivers/sensor/tdk/icm42688/icm42688_rtio.c +++ b/drivers/sensor/tdk/icm42688/icm42688_rtio.c @@ -66,7 +66,12 @@ static void icm42688_submit_one_shot(const struct device *dev, struct rtio_iodev edata = (struct icm42688_encoded_data *)buf; - icm42688_encode(dev, channels, num_channels, buf); + rc = icm42688_encode(dev, channels, num_channels, buf); + if (rc != 0) { + LOG_ERR("Failed to encode sensor data"); + rtio_iodev_sqe_err(iodev_sqe, rc); + return; + } rc = icm42688_rtio_sample_fetch(dev, edata->readings); /* Check that the fetch succeeded */ diff --git a/drivers/sensor/tdk/icm42688/icm42688_rtio_stream.c b/drivers/sensor/tdk/icm42688/icm42688_rtio_stream.c index fd901742309..2fd4c766f8a 100644 --- a/drivers/sensor/tdk/icm42688/icm42688_rtio_stream.c +++ b/drivers/sensor/tdk/icm42688/icm42688_rtio_stream.c @@ -5,7 +5,7 @@ */ #include - +#include #include "icm42688.h" #include "icm42688_decoder.h" #include "icm42688_reg.h" @@ -292,12 +292,21 @@ void icm42688_fifo_event(const struct device *dev) struct icm42688_dev_data *drv_data = dev->data; struct rtio_iodev *spi_iodev = drv_data->spi_iodev; struct rtio *r = drv_data->r; + uint64_t cycles; + int rc; if (drv_data->streaming_sqe == NULL) { return; } - drv_data->timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()); + rc = sensor_clock_get_cycles(&cycles); + if (rc != 0) { + LOG_ERR("Failed to get sensor clock cycles"); + rtio_iodev_sqe_err(drv_data->streaming_sqe, err); + return; + } + + drv_data->timestamp = sensor_clock_cycles_to_ns(cycles); /* * Setup rtio chain of ops with inline calls to make decisions diff --git a/include/zephyr/drivers/sensor_clock.h b/include/zephyr/drivers/sensor_clock.h new file mode 100644 index 00000000000..8a67ce0a3c9 --- /dev/null +++ b/include/zephyr/drivers/sensor_clock.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 Cienet + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_CLOCK_H_ +#define ZEPHYR_DRIVERS_SENSOR_CLOCK_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Retrieve the current sensor clock cycles. + * + * This function obtains the current cycle count from the selected + * sensor clock source. The clock source may be the system clock or + * an external clock, depending on the configuration. + * + * @param[out] cycles Pointer to a 64-bit unsigned integer where the + * current clock cycle count will be stored. + * + * @return 0 on success, or an error code on failure. + */ +int sensor_clock_get_cycles(uint64_t *cycles); + +/** + * @brief Convert clock cycles to nanoseconds. + * + * This function converts clock cycles into nanoseconds based on the + * clock frequency. + * + * @param cycles Clock cycles to convert. + * @return Time in nanoseconds. + */ +uint64_t sensor_clock_cycles_to_ns(uint64_t cycles); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_CLOCK_H_ */ diff --git a/samples/sensor/clock/CMakeLists.txt b/samples/sensor/clock/CMakeLists.txt new file mode 100644 index 00000000000..412f9ec7bfd --- /dev/null +++ b/samples/sensor/clock/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright (c) 2024 Cienet +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(clock) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/sensor/clock/README.rst b/samples/sensor/clock/README.rst new file mode 100644 index 00000000000..b213e787beb --- /dev/null +++ b/samples/sensor/clock/README.rst @@ -0,0 +1,53 @@ +.. zephyr:code-sample:: sensor_clock + :name: Sensor Clock + :relevant-api: sensor_interface + + Test and debug Sensor Clock functionality. + +Overview +******** + +This sample application demonstrates how to select the sensor clock source +and utilize the Sensor Clock API. + +Building and Running +******************** + +The sample below uses the :ref:`nrf52840dk_nrf52840` and :ref:`nrf52833dk_nrf52833` boards. + +To run this sample, ensure the following configurations: + + * Enable one of the Kconfig options: + :kconfig:option:`CONFIG_SENSOR_CLOCK_COUNTER`, + :kconfig:option:`CONFIG_SENSOR_CLOCK_RTC`, or + :kconfig:option:`CONFIG_SENSOR_CLOCK_SYSTEM`. + +Build and run the sample with the following command: + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/clock + :board: + :goals: build flash + +Sample Output +============= + +The application will print the current sensor clock cycles and +their corresponding time in nanoseconds. + +.. code-block:: console + + Cycles: 143783087 + Nanoseconds: 8986442937 + Cycles: 159776386 + Nanoseconds: 9986024125 + Cycles: 175772543 + Nanoseconds: 10985783937 + Cycles: 191771203 + Nanoseconds: 11985700187 + Cycles: 207758870 + Nanoseconds: 12984929375 + Cycles: 223752074 + Nanoseconds: 13984504625 + + ... diff --git a/samples/sensor/clock/boards/nrf52833dk_nrf52833.overlay b/samples/sensor/clock/boards/nrf52833dk_nrf52833.overlay new file mode 100644 index 00000000000..057465d1075 --- /dev/null +++ b/samples/sensor/clock/boards/nrf52833dk_nrf52833.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Cienet + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&rtc0 { + status = "okay"; +}; + +&timer0 { + status = "okay"; +}; diff --git a/samples/sensor/clock/boards/nrf52840dk_nrf52840.overlay b/samples/sensor/clock/boards/nrf52840dk_nrf52840.overlay new file mode 100644 index 00000000000..057465d1075 --- /dev/null +++ b/samples/sensor/clock/boards/nrf52840dk_nrf52840.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024 Cienet + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&rtc0 { + status = "okay"; +}; + +&timer0 { + status = "okay"; +}; diff --git a/samples/sensor/clock/boards/nrf528xx_counter.overlay b/samples/sensor/clock/boards/nrf528xx_counter.overlay new file mode 100644 index 00000000000..51def7ff522 --- /dev/null +++ b/samples/sensor/clock/boards/nrf528xx_counter.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 Cienet + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,sensor-clock = &timer0; + }; +}; diff --git a/samples/sensor/clock/boards/nrf528xx_rtc.overlay b/samples/sensor/clock/boards/nrf528xx_rtc.overlay new file mode 100644 index 00000000000..ddacc146841 --- /dev/null +++ b/samples/sensor/clock/boards/nrf528xx_rtc.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 Cienet + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + zephyr,sensor-clock = &rtc0; + }; +}; diff --git a/samples/sensor/clock/prj.conf b/samples/sensor/clock/prj.conf new file mode 100644 index 00000000000..8fdcaf2c196 --- /dev/null +++ b/samples/sensor/clock/prj.conf @@ -0,0 +1,14 @@ +# +# Copyright (c) 2024 Cienet +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_LOG=y +CONFIG_LOG_DEFAULT_LEVEL=3 + +CONFIG_SENSOR=y +CONFIG_COUNTER=y +CONFIG_RTC=y +CONFIG_SENSOR_ASYNC_API=y + +CONFIG_SENSOR_CLOCK_COUNTER=y diff --git a/samples/sensor/clock/sample.yaml b/samples/sensor/clock/sample.yaml new file mode 100644 index 00000000000..08ee185c212 --- /dev/null +++ b/samples/sensor/clock/sample.yaml @@ -0,0 +1,38 @@ +# +# Copyright (c) 2024 Cienet +# +# SPDX-License-Identifier: Apache-2.0 + +tests: + sample.sensor.clock.counter: + filter: CONFIG_SENSOR_CLOCK_COUNTER + tags: + - drivers + - sensor + - counter + platform_allow: + - nrf52840dk/nrf52840 + - nrf52833dk/nrf52833 + extra_dtc_overlay_files: + - "boards/${BOARD}${NORMALIZED_BOARD_QUALIFIERS}.overlay" + - "boards/nrf528xx_counter.overlay" + + sample.sensor.clock.rtc: + filter: CONFIG_SENSOR_CLOCK_RTC + tags: + - drivers + - sensor + - rtc + platform_allow: + - nrf52840dk/nrf52840 + - nrf52833dk/nrf52833 + extra_dtc_overlay_files: + - "boards/${BOARD}${NORMALIZED_BOARD_QUALIFIERS}.overlay" + - "boards/nrf528xx_rtc.overlay" + + sample.sensor.clock.system: + filter: CONFIG_SENSOR_CLOCK_SYSTEM + tags: + - drivers + - sensor + - system_clock diff --git a/samples/sensor/clock/src/main.c b/samples/sensor/clock/src/main.c new file mode 100644 index 00000000000..fcaf6520af4 --- /dev/null +++ b/samples/sensor/clock/src/main.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Cienet + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +int main(void) +{ + uint64_t cycles = 0; + uint64_t delta_ns = 0; + int err; + + while (true) { + k_sleep(K_MSEC(1000)); + + err = sensor_clock_get_cycles(&cycles); + if (err) { + printf("Failed to get sensor clock cycles, error: %d\n", err); + continue; + } + + printf("Cycles: %llu\n", cycles); + + delta_ns = sensor_clock_cycles_to_ns(cycles); + + printf("Nanoseconds: %llu\n", delta_ns); + } + + return 0; +} diff --git a/tests/drivers/sensor/icm42688/prj.conf b/tests/drivers/sensor/icm42688/prj.conf index 61addc37590..e62f65fa930 100644 --- a/tests/drivers/sensor/icm42688/prj.conf +++ b/tests/drivers/sensor/icm42688/prj.conf @@ -11,3 +11,6 @@ CONFIG_SENSOR=y # Enable emulation CONFIG_EMUL=y + +CONFIG_SENSOR_ASYNC_API=y +CONFIG_SENSOR_CLOCK_SYSTEM=y