Adds a new sample application that demonstrates using the RTIO subsystem to read periodic sensor data directly into buffers allocated by the application, asynchronously process batches of data with an algorithm, and recycle buffers back for reading additional sensor data. The sensor iodev in this application is an timer-driven device that executes one read request per timer period. It doesn't actually send any transactions to a real I2C/SPI bus or read any real data into the application-provided buffers. This timer-driven behavior mimics how a real sensor periodically triggers a GPIO interrupt when new data is ready. The sensor iodev currently uses an internal message queue to store pending requests from the time they are submitted until the next timer expiration. At least one pending request needs to be stored by the iodev to ensure that it has a buffer available to read data into. However, any more than that should probably be handled by the application, since it's the application that determines how often it can submit new requests and therefore how deep the queue needs to be. The sensor iodev is implemented to support multiple instances with devicetree, but additional work remains to enable and use more than one in the application. Tested on native_posix and frdm_k64f. Signed-off-by: Maureen Helm <maureen.helm@intel.com>
99 lines
2.5 KiB
C
99 lines
2.5 KiB
C
/*
|
|
* Copyright (c) 2022 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr.h>
|
|
#include <zephyr/rtio/rtio.h>
|
|
#include <zephyr/rtio/rtio_executor_simple.h>
|
|
#include <zephyr/logging/log.h>
|
|
|
|
LOG_MODULE_REGISTER(main);
|
|
|
|
#define N (8)
|
|
#define M (N/2)
|
|
#define SQ_SZ (N)
|
|
#define CQ_SZ (N)
|
|
|
|
#define NODE_ID DT_INST(0, vnd_sensor)
|
|
#define SAMPLE_PERIOD DT_PROP(NODE_ID, sample_period)
|
|
#define SAMPLE_SIZE DT_PROP(NODE_ID, sample_size)
|
|
#define PROCESS_TIME ((M - 1) * SAMPLE_PERIOD)
|
|
|
|
RTIO_EXECUTOR_SIMPLE_DEFINE(simple_exec);
|
|
RTIO_DEFINE(ez_io, (struct rtio_executor *)&simple_exec, SQ_SZ, CQ_SZ);
|
|
|
|
static uint8_t bufs[N][SAMPLE_SIZE];
|
|
|
|
void main(void)
|
|
{
|
|
const struct device *vnd_sensor = DEVICE_DT_GET(NODE_ID);
|
|
struct rtio_iodev *iodev = vnd_sensor->data;
|
|
|
|
/* Fill the entire submission queue. */
|
|
for (int n = 0; n < N; n++) {
|
|
struct rtio_sqe *sqe = rtio_spsc_acquire(ez_io.sq);
|
|
|
|
rtio_sqe_prep_read(sqe, iodev, RTIO_PRIO_HIGH, bufs[n],
|
|
SAMPLE_SIZE, bufs[n]);
|
|
rtio_spsc_produce(ez_io.sq);
|
|
}
|
|
|
|
while (true) {
|
|
int m = 0;
|
|
uint8_t *userdata[M];
|
|
|
|
LOG_INF("Submitting %d read requests", M);
|
|
rtio_submit(&ez_io, M);
|
|
|
|
/* Consume completion events until there is enough sensor data
|
|
* available to execute a batch processing algorithm, such as
|
|
* an FFT.
|
|
*/
|
|
while (m < M) {
|
|
struct rtio_cqe *cqe = rtio_spsc_consume(ez_io.cq);
|
|
|
|
if (cqe == NULL) {
|
|
LOG_DBG("No completion events available");
|
|
k_msleep(SAMPLE_PERIOD);
|
|
continue;
|
|
}
|
|
LOG_DBG("Consumed completion event %d", m);
|
|
|
|
if (cqe->result < 0) {
|
|
LOG_ERR("Operation failed");
|
|
}
|
|
|
|
userdata[m] = cqe->userdata;
|
|
rtio_spsc_release(ez_io.cq);
|
|
m++;
|
|
}
|
|
|
|
/* Here is where we would execute a batch processing algorithm.
|
|
* Model as a long sleep that takes multiple sensor sample
|
|
* periods. The sensor driver can continue reading new data
|
|
* during this time because we submitted more buffers into the
|
|
* queue than we needed for the batch processing algorithm.
|
|
*/
|
|
LOG_INF("Start processing %d samples", M);
|
|
for (m = 0; m < M; m++) {
|
|
LOG_HEXDUMP_DBG(userdata[m], SAMPLE_SIZE, "Sample data:");
|
|
}
|
|
k_msleep(PROCESS_TIME);
|
|
LOG_INF("Finished processing %d samples", M);
|
|
|
|
/* Recycle the sensor data buffers and refill the submission
|
|
* queue.
|
|
*/
|
|
for (m = 0; m < M; m++) {
|
|
struct rtio_sqe *sqe = rtio_spsc_acquire(ez_io.sq);
|
|
|
|
rtio_sqe_prep_read(sqe, iodev, RTIO_PRIO_HIGH,
|
|
userdata[m], SAMPLE_SIZE,
|
|
userdata[m]);
|
|
rtio_spsc_produce(ez_io.sq);
|
|
}
|
|
}
|
|
}
|