Hi,
I am trying to enable a sensor shell stream from an IMU connected over I2C. I am using a k_timer to get the sensor values and not DRDY since DRDY was not connected on an older version of the board I have. Here are some observations from USB shell:
1. When my sensor API is something like this, it gives sensor data correctly using `sensor get..`, however, it does not stream using 'sensor trig...` followed by `sensor stream...`.
static int lsm6dsr_get_decoder(const struct device *dev, const struct sensor_decoder_api **api) { *api = &__sensor_default_decoder; return 0; } static const struct sensor_driver_api lsm6dsr_api = { .attr_set = lsm6dsr_attr_set, .sample_fetch = lsm6dsr_sample_fetch, .channel_get = lsm6dsr_channel_get, .trigger_set = lsm6dsr_trigger_set, .get_decoder = lsm6dsr_get_decoder };
uart:~$ sensor get LSM6DSR accel_xyz channel type=3(accel_xyz) index=0 shift=1 num_samples=1 value=137052246093ns, (0.015440, -0.027160, 1.030455) uart:~$ sensor get LSM6DSR accel_xyz channel type=3(accel_xyz) index=0 shift=0 num_samples=1 value=143734680175ns, (0.998045, 0.048521, 0.084898) uart:~$ sensor get LSM6DSR accel_xyz channel type=3(accel_xyz) index=0 shift=1 num_samples=1 value=144496673583ns, (1.000182, 0.056273, 0.098814) uart:~$ sensor get LSM6DSR accel_xyz channel type=3(accel_xyz) index=0 shift=0 num_samples=1 value=145070739746ns, (0.994994, 0.051878, 0.097716) uart:~$ sensor get LSM6DSR accel_xyz channel type=3(accel_xyz) index=0 shift=0 num_samples=1 value=145834075927ns, (0.978636, 0.031798, 0.081847)
2. When I implement a custom decoder and submit function, I see an endless stream of data. However, it only has the first sample populated in the stream endlessly for the `sensor get..` command. `sensor stream ...` or `sensor trig ...` does not work, just freezes and gives a blank shell output.
static void lsm6dsr_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) { struct lsm6dsr_data *data = dev->data; uint8_t *buf; uint32_t buf_len; int ret; /* Check if we have enough buffer space */ ret = rtio_sqe_rx_buf(iodev_sqe, sizeof(struct minimal_buffer), sizeof(struct minimal_buffer), &buf, &buf_len); if (ret != 0) { LOG_ERR("Failed to get buffer: %d", ret); rtio_iodev_sqe_err(iodev_sqe, -ENOMEM); // Stop the timer to prevent further submit calls k_timer_stop(&data->timer); // Clear the handler to ensure no more callbacks data->timer_handler = NULL; LOG_ERR("Critical error at buffer grab, stopping sensor stream"); return; } /* Fetch the latest sample */ ret = lsm6dsr_sample_fetch(dev, SENSOR_CHAN_ALL); if (ret != 0) { LOG_ERR("Failed to fetch sample: %d", ret); rtio_iodev_sqe_err(iodev_sqe, ret); // Stop the timer to prevent further submit calls k_timer_stop(&data->timer); // Clear the handler to ensure no more callbacks data->timer_handler = NULL; LOG_ERR("Critical error at fetch, stopping sensor stream"); return; } /* Use a local buffer first to avoid alignment issues */ struct minimal_buffer local_buffer; /* Set timestamp safely using memcpy */ uint64_t timestamp = k_uptime_get() * 1000000; /* Convert to nanoseconds */ memcpy(&local_buffer.timestamp, ×tamp, sizeof(uint64_t)); /* Get channel type from the request */ const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data; if (cfg && cfg->count > 0) { enum sensor_channel chan_type = cfg->channels[0].chan_type; /* Lock mutex before accessing sensor data */ k_mutex_lock(&data->mutex, K_FOREVER); if (chan_type == SENSOR_CHAN_ACCEL_XYZ) { /* Convert floating point accelerometer data to fixed point */ q31_t x = (q31_t)(data->scaled_sample.acc_x * (float)(1 << 31)); q31_t y = (q31_t)(data->scaled_sample.acc_y * (float)(1 << 31)); q31_t z = (q31_t)(data->scaled_sample.acc_z * (float)(1 << 31)); /* Copy values safely using memcpy */ memcpy(&local_buffer.values[0], &x, sizeof(q31_t)); memcpy(&local_buffer.values[1], &y, sizeof(q31_t)); memcpy(&local_buffer.values[2], &z, sizeof(q31_t)); LOG_INF("LSM6DSR accel data: %f, %f, %f", data->scaled_sample.acc_x, data->scaled_sample.acc_y, data->scaled_sample.acc_z); } else if (chan_type == SENSOR_CHAN_GYRO_XYZ) { /* Convert floating point gyroscope data to fixed point */ q31_t x = (q31_t)(data->scaled_sample.gyr_x * (float)(1 << 31)); q31_t y = (q31_t)(data->scaled_sample.gyr_y * (float)(1 << 31)); q31_t z = (q31_t)(data->scaled_sample.gyr_z * (float)(1 << 31)); /* Copy values safely using memcpy */ memcpy(&local_buffer.values[0], &x, sizeof(q31_t)); memcpy(&local_buffer.values[1], &y, sizeof(q31_t)); memcpy(&local_buffer.values[2], &z, sizeof(q31_t)); LOG_INF("LSM6DSR gyro data: %f, %f, %f", data->scaled_sample.gyr_x, data->scaled_sample.gyr_y, data->scaled_sample.gyr_z); } else { /* Default values for unsupported channels */ q31_t val1 = 1000000; q31_t val2 = 1000000; q31_t val3 = 1000000; memcpy(&local_buffer.values[0], &val1, sizeof(q31_t)); memcpy(&local_buffer.values[1], &val2, sizeof(q31_t)); memcpy(&local_buffer.values[2], &val3, sizeof(q31_t)); LOG_WRN("Unsupported channel type: %d", chan_type); } k_mutex_unlock(&data->mutex); } else { /* Default values if no channel info */ q31_t val1 = 1000000; q31_t val2 = 2000000; q31_t val3 = 3000000; memcpy(&local_buffer.values[0], &val1, sizeof(q31_t)); memcpy(&local_buffer.values[1], &val2, sizeof(q31_t)); memcpy(&local_buffer.values[2], &val3, sizeof(q31_t)); } /* Copy the entire local buffer to the output buffer */ memcpy(buf, &local_buffer, sizeof(struct minimal_buffer)); /* Complete the RTIO operation */ rtio_iodev_sqe_ok(iodev_sqe, sizeof(struct minimal_buffer)); } // This is to pass values to the sensor shell callback for printing values static bool lsm6dsr_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger) { /* Return true when trigger is set */ return (trigger == SENSOR_TRIG_TIMER || trigger == SENSOR_TRIG_DATA_READY); } static int lsm6dsr_get_decoder(const struct device *dev, const struct sensor_decoder_api **api) { extern const struct sensor_decoder_api minimal_three_axis_decoder; *api = &minimal_three_axis_decoder; return 0; } static const struct sensor_driver_api lsm6dsr_api = { .attr_set = lsm6dsr_attr_set, .sample_fetch = lsm6dsr_sample_fetch, .channel_get = lsm6dsr_channel_get, #if CONFIG_SENSOR_SHELL_STREAM .trigger_set = lsm6dsr_trigger_set, .get_decoder = lsm6dsr_get_decoder, .submit = lsm6dsr_submit, #endif };
channel type=3(accel_xyz) index=807 shift=0 num_samples=1 value=14824000000ns, (-0.011474, 0.007812, -1.000000) channel type=3(accel_xyz) index=808 shift=0 num_samples=1 value=14824000000ns, (-0.011474, 0.007812, -1.000000) channel type=3(accel_xyz) index=809 shift=0 num_samples=1 value=14824000000ns, (-0.011474, 0.007812, -1.000000) channel type=3(accel_xyz) index=810 shift=0 num_samples=1 value=14824000000ns, (-0.011474, 0.007812, -1.000000) channel type=3(accel_xyz) index=811 shift=0 num_samples=1 value=14824000000ns, (-0.011474, 0.007812, -1.000000) channel type=3(accel_xyz) index=812 shift=0 num_samples=1 value=14824000000ns, (-0.011474, 0.007812, -1.000000) channel type=3(accel_xyz) index=813 shift=0 num_samples=1 value=14824000000ns, (-0.011474, 0.007812, -1.000000) channel type=3(accel_xyz) index=814 shift=0 num_samples=1 value=14824000000ns, (-0.011474, 0.007812, -1.000000) channel type=3(accel_xyz) index=815 shift=0 num_samples=1 value=14824000000ns, (-0.011474, 0.007812, -1.000000) channel type=3(accel_xyz) index=816 shift=0 num_samples=1 value=14824000000ns, (-0.011474, 0.007812, -1.000000) channel type=3(accel_xyz) index=817 shift=0 num_samples=1 value=14824000000ns, (-0.011474, 0.007812, -1.000000) channel type=3(accel_xyz) index=818 shift=0 num_samples=1 value=14824000000ns, (-0.011474, 0.007812, -1.000000)
My repository is attached. Please help me implement the sensor stream function for the sensor in the correct manner.
Build settings:
SDK and toolchain: 2.8.0
board: nrf52840dk_nrf52840
overlay: euryale.overlay, usb.overlay
config: prj.conf, overlay-usb.conf
build: optimize for debugging
Thanks,
Devang