From f4da9b97058e0fcde0929e43f5ac6a2f8c04bf62 Mon Sep 17 00:00:00 2001 From: Mark Chen Date: Tue, 22 Oct 2024 10:39:56 +0800 Subject: [PATCH] drivers: sensor: Add sensor clock API support This commit introduces a new Sensor Clock API, enabling the retrieval of cycle counts and conversion to nanoseconds based on the system or external clock. The API includes: - `sensor_clock_get_cycles()` to get the current cycle count from the sensor clock. - `sensor_clock_cycles_to_ns()` to convert cycles to nanoseconds using the clock's frequency. The implementation supports both system clocks and external clocks defined in the device tree, making the sensor clock integration more flexible for various sensor use cases. Signed-off-by: Mark Chen --- doc/releases/release-notes-4.1.rst | 27 ++++++++ drivers/sensor/CMakeLists.txt | 12 ++++ drivers/sensor/Kconfig | 2 + drivers/sensor/Kconfig.sensor_clock | 30 +++++++++ drivers/sensor/adi/adxl345/adxl345_stream.c | 14 ++++- drivers/sensor/adi/adxl362/adxl362_stream.c | 14 ++++- drivers/sensor/adi/adxl367/adxl367_stream.c | 14 ++++- drivers/sensor/adi/adxl372/adxl372_stream.c | 13 +++- .../asahi_kasei/akm09918c/akm09918c_async.c | 11 +++- drivers/sensor/bosch/bma4xx/bma4xx.c | 11 +++- drivers/sensor/bosch/bme280/bme280_async.c | 11 +++- drivers/sensor/default_rtio_sensor.c | 15 ++++- drivers/sensor/memsic/mmc56x3/mmc56x3_async.c | 11 +++- drivers/sensor/sensor_clock_external.c | 63 +++++++++++++++++++ drivers/sensor/sensor_clock_sys.c | 29 +++++++++ .../sensor/st/lsm6dsv16x/lsm6dsv16x_rtio.c | 11 +++- .../st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c | 12 +++- .../sensor/tdk/icm42688/icm42688_decoder.c | 11 +++- drivers/sensor/tdk/icm42688/icm42688_rtio.c | 7 ++- .../tdk/icm42688/icm42688_rtio_stream.c | 13 +++- include/zephyr/drivers/sensor_clock.h | 45 +++++++++++++ samples/sensor/clock/CMakeLists.txt | 12 ++++ samples/sensor/clock/README.rst | 53 ++++++++++++++++ .../clock/boards/nrf52833dk_nrf52833.overlay | 13 ++++ .../clock/boards/nrf52840dk_nrf52840.overlay | 13 ++++ .../clock/boards/nrf528xx_counter.overlay | 11 ++++ .../sensor/clock/boards/nrf528xx_rtc.overlay | 11 ++++ samples/sensor/clock/prj.conf | 14 +++++ samples/sensor/clock/sample.yaml | 38 +++++++++++ samples/sensor/clock/src/main.c | 36 +++++++++++ tests/drivers/sensor/icm42688/prj.conf | 3 + 31 files changed, 558 insertions(+), 22 deletions(-) create mode 100644 drivers/sensor/Kconfig.sensor_clock create mode 100644 drivers/sensor/sensor_clock_external.c create mode 100644 drivers/sensor/sensor_clock_sys.c create mode 100644 include/zephyr/drivers/sensor_clock.h create mode 100644 samples/sensor/clock/CMakeLists.txt create mode 100644 samples/sensor/clock/README.rst create mode 100644 samples/sensor/clock/boards/nrf52833dk_nrf52833.overlay create mode 100644 samples/sensor/clock/boards/nrf52840dk_nrf52840.overlay create mode 100644 samples/sensor/clock/boards/nrf528xx_counter.overlay create mode 100644 samples/sensor/clock/boards/nrf528xx_rtc.overlay create mode 100644 samples/sensor/clock/prj.conf create mode 100644 samples/sensor/clock/sample.yaml create mode 100644 samples/sensor/clock/src/main.c 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