Skip to content

rtio: Real-Time Stream and Sensor API #17434

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

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .known-issues/doc/rtio.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#
# RTIO
#
#
# include/rtio.h warnings
#
^(?P<filename>([\-:\\/\w\.])+[/\\]doc[/\\]reference[/\\]peripherals[/\\]rtio.rst):(?P<lineno>[0-9]+): WARNING: Invalid definition: Expected identifier in nested name. \[error at [0-9]+]
^[ \t]*
^[ \t]*\^
^(?P=filename):(?P=lineno): WARNING: Invalid definition: Expected identifier in nested name. \[error at [0-9]+]
^[ \t]*
^[ \t]*\^
^(?P=filename):(?P=lineno): WARNING: Invalid definition: Expected end of definition. \[error at [0-9]+]
^.*rtio_trigger_config.options
^[- \t]*\^
#
5 changes: 5 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@
/drivers/net/ @jukkar @tbursztyka
/drivers/ptp_clock/ @jukkar
/drivers/pwm/pwm_shell.c @henrikbrixandersen
/drivers/rtio/ @bfrog
/drivers/spi/ @tbursztyka
/drivers/spi/spi_ll_stm32.* @superna9999
/drivers/spi/spi_rv32m1_lpspi* @karstenkoenig
Expand Down Expand Up @@ -234,6 +235,8 @@
/include/drivers/hwinfo.h @alexanderwachter
/include/drivers/led.h @Mani-Sadhasivam
/include/drivers/led_strip.h @mbolivar
/include/drivers/rtio.h @bfrog
/include/drivers/rtio_sensor.h @bfrog
/include/drivers/sensor.h @MaureenHelm
/include/drivers/spi.h @tbursztyka
/include/app_memory/ @andrewboie
Expand Down Expand Up @@ -391,6 +394,7 @@
/tests/drivers/can/ @alexanderwachter
/tests/drivers/flash_simulator/ @nvlsianpu
/tests/drivers/hwinfo/ @alexanderwachter
/tests/drivers/rtio/ @bfrog
/tests/drivers/spi/ @tbursztyka
/tests/drivers/uart/uart_async_api/ @Mierunski
/tests/kernel/ @andrewboie @andyross @nashif
Expand All @@ -405,6 +409,7 @@
/tests/subsys/fs/ @nashif @wentongwu
/tests/subsys/settings/ @nvlsianpu
/tests/subsys/shell/ @jakub-uC @nordic-krch

# Get all docs reviewed
*.rst @dbkinder
*posix*.rst @dbkinder @aescolar
1 change: 1 addition & 0 deletions doc/reference/peripherals/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Peripherals
pinmux.rst
pwm.rst
ps2.rst
rtio.rst
sensor.rst
spi.rst
uart.rst
Expand Down
59 changes: 59 additions & 0 deletions doc/reference/peripherals/rtio.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
.. _rtio_interface:

Real-Time IO
############

The real-time I/O or RTIO subsystem exposes an API for efficiently
moving information in a latency and processing friendly way, between
a Zephyr application and external I2C or SPI devices (such as sensors).

Overview
********

RTIO provides an API for allocating and describing continguous blocks of
memory as well as an API for sourcing these blocks from a physical device.

Blocks, defined by :c:type:`struct rtio_block`, provide the unit of data
being transferred. These blocks contain a layout identifier provided by
the source of the block, timestamps for when the block
began and finished being created, as well as the length and size in bytes.

Blocks are used to allow for simple DMA transfers as well as controlling the
latency between a source and sink.

The block layout identifier is a way for the source of the block to describe
whats in the block. This can be used to identify which channels of information
are in the block, the sample size, and more. It is source defined and
not unique between different sources.

The begin and end timestamps may be used to interpolate when events have
occurred without needing a timestamp for every reading. For example when
reading a hardware FIFO from a device sampling at a constant rate the
begin and and timestamps may be used to infer when each sample in the block
happened in your application by doing simple linear interpolation.

They may also be used to understand the sample rate of the device better
as often times devices have nominal sampling rates that vary device to device.

Sources of blocks can be sensors such as a high sample rate accelerometer, gyro,
and magnetometer. In these cases the driver will typically provide blocks
encoded in the sensor's native format which is often times the most compact
representation.

Intermediary processing steps representing both sinks and sources of data are
also possible. One possible task is taking 6 or 9 axis IMU sensor and
producing a orientation quaternion vectors relative to earth.

The driving event of actually starting the read from a device is the
`rtio_trigger_read` function. It is meant to be an ISR safe function, meaning
it can be called in any interrupt handler such as a GPIO interrupt callback.

The RTIO subsystem lets you both efficiently move data around and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this documentation. It would be nice to add a few sentences about triggers to this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely, I have some function comments on rtio_trigger but nothing in the general docs explaining what its there for.

efficiently process chunks of data at a time in a flexible way.


API Reference
*************

.. doxygengroup:: rtio_interface
:project: Zephyr
1 change: 1 addition & 0 deletions drivers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ add_subdirectory_if_kconfig(ps2)
add_subdirectory_if_kconfig(kscan)
add_subdirectory_if_kconfig(video)
add_subdirectory_if_kconfig(eeprom)
add_subdirectory_if_kconfig(rtio)

add_subdirectory_ifdef(CONFIG_FLASH_HAS_DRIVER_ENABLED flash)
add_subdirectory_ifdef(CONFIG_SERIAL_HAS_DRIVER serial)
Expand Down
3 changes: 3 additions & 0 deletions drivers/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,7 @@ source "drivers/video/Kconfig"

source "drivers/eeprom/Kconfig"

source "drivers/rtio/Kconfig"


endmenu
6 changes: 6 additions & 0 deletions drivers/rtio/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# SPDX-License-Identifier: Apache-2.0

zephyr_library()

zephyr_library_sources_ifdef(CONFIG_RTIO_CONTEXT rtio_context.c)
zephyr_library_sources_ifdef(CONFIG_RTIO_RAMP rtio_ramp.c)
38 changes: 38 additions & 0 deletions drivers/rtio/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Kconfig - rtio configuration options

#
# Copyright (c) 2019 Tom Burdick <[email protected]>
#
# SPDX-License-Identifier: Apache-2.0
#

menuconfig RTIO
bool "RTIO Drivers"
select NET_BUF
help
Include rtio drivers in system config

if RTIO

module = RTIO
module-str = rtio
source "subsys/logging/Kconfig.template.log_config"

config RTIO_INIT_PRIORITY
int "RTIO init priority"
default 90
help
RTIO initialization priority.

config RTIO_CONTEXT
# Private option; will be selected by the drivers if
# this feature is required.
bool

config RTIO_RAMP
bool "RTIO ramp driver"
select RTIO_CONTEXT
help
RTIO ramp driver

endif # RTIO
134 changes: 134 additions & 0 deletions drivers/rtio/rtio_context.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* Copyright (c) 2019 Tom Burdick <[email protected]>
* Copyright (c) 2019 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <kernel.h>
#include <drivers/rtio.h>
#include "rtio_context.h"

#define LOG_DOMAIN "rtio_context"
#define LOG_LEVEL CONFIG_RTIO_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(rtio_context);

static void rtio_context_output_timeout(struct k_timer *timer)
{
struct rtio_context *ctx =
CONTAINER_OF(timer, struct rtio_context, output_timer);

int res = k_sem_take(&ctx->sem, K_NO_WAIT);

if (res == 0) {
if (ctx->block != NULL &&
ctx->config.output_config.fifo != NULL) {
k_fifo_put(ctx->config.output_config.fifo, ctx->block);
ctx->block = NULL;
}
k_sem_give(&ctx->sem);
}
}

void rtio_context_init(struct rtio_context *ctx)
{
k_sem_init(&ctx->sem, 0, 1);
rtio_output_config_init(&ctx->config.output_config);
ctx->block = NULL;
k_timer_init(&ctx->output_timer, rtio_context_output_timeout, NULL);
k_sem_give(&ctx->sem);
}

int rtio_context_configure_begin(struct rtio_context *ctx)
{
k_sem_take(&ctx->sem, K_FOREVER);
if (ctx->block != NULL && ctx->config.output_config.fifo != NULL) {
k_fifo_put(ctx->config.output_config.fifo, ctx->block);
ctx->block = NULL;
return 1;
}
return 0;
}

void rtio_context_configure_end(struct rtio_context *ctx,
struct rtio_config *config)
{
s32_t timeout;

memcpy(&ctx->config, config, sizeof(struct rtio_config));

/* Setup timer if needed */
k_timer_stop(&ctx->output_timer);
timeout = ctx->config.output_config.timeout;
if (timeout != K_FOREVER && timeout != K_NO_WAIT) {
k_timer_start(&ctx->output_timer, timeout, timeout);
}

k_sem_give(&ctx->sem);
}

int rtio_context_trigger_read_begin(struct rtio_context *ctx,
struct rtio_block **block,
s32_t timeout)
{
int res = 0;

res = k_sem_take(&ctx->sem, timeout);
if (res != 0) {
return -EBUSY;
}

if (ctx->block == NULL) {
res = rtio_block_alloc(ctx->config.output_config.allocator,
&ctx->block,
ctx->config.output_config.byte_size,
timeout);
if (res != 0) {
goto error;
}
}

*block = ctx->block;
return res;

error:
k_sem_give(&ctx->sem);
return res;
}

/**
* @brief Check if a block has met an output policy expectations
*
* @return 1 if the policy has been met, 0 otherwise
*/
static inline int rtio_context_output_check(struct rtio_output_config *cfg,
struct rtio_block *block)
{
/*
if (k_cycle_get_32() - block->begin_tstamp > cfg->timeout) {
return true;
}
*/
if (rtio_block_used(block) >= cfg->byte_size) {
return 1;
}
return 0;
}

int rtio_context_trigger_read_end(struct rtio_context *ctx)
{
struct rtio_output_config *out_cfg = &ctx->config.output_config;
int res;

if (rtio_context_output_check(out_cfg, ctx->block) == 1) {
k_fifo_put(out_cfg->fifo, ctx->block);
ctx->block = NULL;
res = 1;
} else {
res = 0;
}

k_sem_give(&ctx->sem);
return res;
}
Loading