|
| 1 | +/* |
| 2 | + * Copyright (c) 2022 Intel Corporation |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Apache-2.0 |
| 5 | + */ |
| 6 | + |
| 7 | +#include <zephyr/kernel.h> |
| 8 | +#include <zephyr/drivers/sensor.h> |
| 9 | +#include <zephyr/rtio/rtio.h> |
| 10 | +#include <zephyr/rtio/rtio_executor_simple.h> |
| 11 | + |
| 12 | +#include <stdint.h> |
| 13 | +#include <stdio.h> |
| 14 | + |
| 15 | +#include <zephyr/logging/log.h> |
| 16 | +LOG_MODULE_REGISTER(TDK_ROBOKIT1, CONFIG_SENSOR_LOG_LEVEL); |
| 17 | + |
| 18 | +/* Power of 2 number of stream buffers */ |
| 19 | +#define N_BUFS 4 |
| 20 | + |
| 21 | +RTIO_EXECUTOR_SIMPLE_DEFINE(r_exec); |
| 22 | + |
| 23 | +/* Show no over/under flows with a 4 buffer queue */ |
| 24 | +RTIO_DEFINE(r4, (struct rtio_executor *)&r_exec, N_BUFS, N_BUFS); |
| 25 | + |
| 26 | +/* Show over/underflows with a single buffer queue */ |
| 27 | +RTIO_DEFINE(r1, (struct rtio_executor *)&r_exec, 1, 1); |
| 28 | + |
| 29 | +#define FIFO_ITERS 4096 |
| 30 | + |
| 31 | +struct fifo_header { |
| 32 | + uint8_t int_status; |
| 33 | + uint16_t gyro_odr: 4; |
| 34 | + uint16_t accel_odr: 4; |
| 35 | + uint16_t gyro_fs: 3; |
| 36 | + uint16_t accel_fs: 3; |
| 37 | + uint16_t packet_format: 2; |
| 38 | +} __packed; |
| 39 | + |
| 40 | +/* The fifo size (2048) bytes plus 3 for the header */ |
| 41 | +#define ICM42688_FIFO_BUF_LEN 2051 |
| 42 | +static uint8_t icm42688_fifo_bufs[N_BUFS][ICM42688_FIFO_BUF_LEN]; |
| 43 | + |
| 44 | + |
| 45 | +void fifo_stream(const struct device *icm42688, struct rtio *r, uint32_t n_bufs) |
| 46 | +{ |
| 47 | + struct rtio_iodev *iodev; |
| 48 | + struct rtio_sqe *sqe; |
| 49 | + |
| 50 | + LOG_INF("FIFO with RTIO context %p, context size %u", r, sizeof(*r)); |
| 51 | + |
| 52 | + /* obtain reference the stream */ |
| 53 | + (void)sensor_fifo_iodev(icm42688, &iodev); |
| 54 | + |
| 55 | + LOG_INF("Setting up RX requests"); |
| 56 | + |
| 57 | + __ASSERT_NO_MSG(iodev != NULL); |
| 58 | + |
| 59 | + /* Feed initial read requests */ |
| 60 | + for (int i = 0; i < n_bufs; i++) { |
| 61 | + sqe = rtio_spsc_acquire(r->sq); |
| 62 | + rtio_sqe_prep_read(sqe, iodev, 0, &icm42688_fifo_bufs[i][0], ICM42688_FIFO_BUF_LEN, |
| 63 | + (void *)(uintptr_t)i); |
| 64 | + rtio_spsc_produce(r->sq); |
| 65 | + } |
| 66 | + |
| 67 | + /* Submits requests */ |
| 68 | + rtio_submit(r, 0); |
| 69 | + |
| 70 | + /* Setup requests, starting stream */ |
| 71 | + LOG_INF("Polling RX Requests"); |
| 72 | + |
| 73 | + /* Enable the fifo automatic triggering (via gpio) */ |
| 74 | + sensor_fifo_start(icm42688); |
| 75 | + |
| 76 | + uint32_t overflows = 0; |
| 77 | + |
| 78 | + /* Now poll for ready fifo buffers for a little bit, at 32KHz sampling |
| 79 | + * and a 1024 buffer read with 16 bytes a sample, the fifo holds |
| 80 | + * 64 samples. At 32KHz it triggers every 2ms! this means |
| 81 | + * Every buffer has ~2ms to process or we lose the next sample. |
| 82 | + * |
| 83 | + * Every 8th buffer we busy wait just over 2ms to show how no data |
| 84 | + * is lost even with some variable latency involved. This could |
| 85 | + * come from data processing or attempting to transport the data |
| 86 | + * to another device. |
| 87 | + * |
| 88 | + * From the sensor a lack of buffer to read into is an underflow |
| 89 | + * and from the application perspective being unable to keep up |
| 90 | + * is an overflow. |
| 91 | + */ |
| 92 | + for (int i = 0; i < FIFO_ITERS; i++) { |
| 93 | + struct rtio_cqe *cqe = rtio_cqe_consume_block(r); |
| 94 | + int32_t result = cqe->result; |
| 95 | + uintptr_t buf_idx = (uintptr_t)cqe->userdata; |
| 96 | + uint8_t *buf = &icm42688_fifo_bufs[buf_idx][0]; |
| 97 | + |
| 98 | + rtio_spsc_release(r->cq); |
| 99 | + |
| 100 | + /* The first byte is the interrupt status and can be |
| 101 | + * checked for a FIFO FULL signifying an overflow |
| 102 | + */ |
| 103 | + struct fifo_header *hdr = (void *)&buf[0]; |
| 104 | + |
| 105 | + if (hdr->int_status & BIT(1)) { |
| 106 | + overflows++; |
| 107 | + } |
| 108 | + |
| 109 | + |
| 110 | + if (i % 128 == 0) { |
| 111 | + printk("Slow mode on iteration %d, underflows (sensor overflows) %u, buf " |
| 112 | + "%lu, data int status %x, result %d\n", |
| 113 | + i, overflows, buf_idx, buf[0], result); |
| 114 | + k_busy_wait(4000); |
| 115 | + } |
| 116 | + |
| 117 | + /* Now to recycle the buffer by putting it back in the queue */ |
| 118 | + struct rtio_sqe *sqe = rtio_spsc_acquire(r->sq); |
| 119 | + |
| 120 | + __ASSERT_NO_MSG(sqe != NULL); |
| 121 | + rtio_sqe_prep_read(sqe, iodev, 0, &icm42688_fifo_bufs[buf_idx][0], |
| 122 | + ICM42688_FIFO_BUF_LEN, (void *)(uintptr_t)buf_idx); |
| 123 | + rtio_spsc_produce(r->sq); |
| 124 | + |
| 125 | + rtio_submit(r, 0); |
| 126 | + |
| 127 | + } |
| 128 | + |
| 129 | + LOG_INF("Checking In, Sensor Overflows %u", overflows); |
| 130 | + |
| 131 | + /* All done streaming */ |
| 132 | + sensor_fifo_stop(icm42688); |
| 133 | + |
| 134 | + LOG_INF("DONE! FIFO should be DISABLED"); |
| 135 | +} |
| 136 | + |
| 137 | +void main(void) |
| 138 | +{ |
| 139 | + const struct device *icm42688 = DEVICE_DT_GET_ONE(invensense_icm42688); |
| 140 | + struct sensor_value accel[3]; |
| 141 | + struct sensor_value gyro[3]; |
| 142 | + struct sensor_value temp; |
| 143 | + |
| 144 | + |
| 145 | + LOG_INF("TDK RoboKit1 Sample"); |
| 146 | + |
| 147 | + |
| 148 | + if (!device_is_ready(icm42688)) { |
| 149 | + LOG_INF("%s: device not ready.", icm42688->name); |
| 150 | + return; |
| 151 | + } |
| 152 | + |
| 153 | + LOG_INF("Fetch + Read"); |
| 154 | + |
| 155 | + /* A few polling readings */ |
| 156 | + for (int i = 0; i < 10; i++) { |
| 157 | + |
| 158 | + /* Fetch everything */ |
| 159 | + sensor_sample_fetch_chan(icm42688, SENSOR_CHAN_ALL); |
| 160 | + |
| 161 | + sensor_channel_get(icm42688, SENSOR_CHAN_ACCEL_XYZ, accel); |
| 162 | + sensor_channel_get(icm42688, SENSOR_CHAN_GYRO_XYZ, gyro); |
| 163 | + sensor_channel_get(icm42688, SENSOR_CHAN_DIE_TEMP, &temp); |
| 164 | + |
| 165 | + LOG_INF("ICM42688: Accel (m/s^2): x: %d.%06d, y: %d.%06d, z: %d.%06d", |
| 166 | + accel[0].val1, accel[0].val2, |
| 167 | + accel[1].val1, accel[1].val2, |
| 168 | + accel[2].val1, accel[2].val2); |
| 169 | + LOG_INF("ICM42688: Gyro (rad/s): x: %d.%06d, y: %d.%06d, z: %d.%06di", |
| 170 | + gyro[0].val1, gyro[0].val2, |
| 171 | + gyro[1].val1, gyro[1].val2, |
| 172 | + gyro[2].val1, gyro[2].val2); |
| 173 | + LOG_INF("ICM42688: Temp (C): %d.%06d\n", |
| 174 | + temp.val1, temp.val2); |
| 175 | + |
| 176 | + k_sleep(K_MSEC(100)); |
| 177 | + } |
| 178 | + |
| 179 | + LOG_INF("Showing under/over flows with 1 buffer queue"); |
| 180 | + fifo_stream(icm42688, &r1, 1); |
| 181 | + |
| 182 | + LOG_INF("Showing no under/over flows with 4 buffer queue"); |
| 183 | + fifo_stream(icm42688, &r4, 4); |
| 184 | + |
| 185 | + LOG_INF("Done!"); |
| 186 | + |
| 187 | + while (true) { |
| 188 | + k_msleep(1000); |
| 189 | + } |
| 190 | +} |
0 commit comments