Skip to content
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

lsm6dsv16x: add RTIO async and fifo stream #81447

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

avisconti
Copy link
Collaborator

@avisconti avisconti commented Nov 15, 2024

Add RTIO async and RTIO stream functionalities that enables, among all the other things, the sensor data streaming from FIFO. RTIO stream is using both SENSOR_TRIG_FIFO_WATERMARK and SENSOR_TRIG_FIFO_FULL triggers. The decoder currently only supports following FIFO tags:

  - LSM6DSV16X_XL_NC_TAG
  - LSM6DSV16X_GY_NC_TAG
  - LSM6DSV16X_TEMP_NC_TAG

In DT it is possible to configure following FIFO params:

  - fifo-watermark (defaults to 32)
  - accel-fifo-batch-rate (defaults to LSM6DSV16X_DT_XL_NOT_BATCHED)
  - gyro-fifo-batch-rate (defaults to LSM6DSV16X_DT_GY_NOT_BATCHED)
  - temp-fifo-batch-rate (defaults to LSM6DSV16X_DT_TEMP_NOT_BATCHED)

Since I do not have any boards with a chipset with I2C/SPI rtio supported zephyr driver, I tested this solution using I2C rtio default driver. Waiting for #71961 to be reviewed, as well as a proper solution for STM32 SPI.

Moreover, this PR does not contain any specific sample (in the future I may add one), but I'm using a modified version of samples/sensor/accel_polling to test the FIFO streaming.

Save gyroscope range set from DT or SENSOR_ATTR in data
structure.

Signed-off-by: Armando Visconti <[email protected]>
Copy link
Collaborator

@teburd teburd left a comment

Choose a reason for hiding this comment

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

looking pretty good to me, I do think the workq could be avoided here with a little effort to do the reads asynchronously, or configure the sensor asynchronously (though I get this is a little bit of a hassle).

The workq does add some code size in trade for convenience.

#define LSM6DSV16X_SPI_RTIO_DEFINE(inst) \
SPI_DT_IODEV_DEFINE(lsm6dsv16x_iodev_##inst, \
DT_DRV_INST(inst), LSM6DSV16X_SPI_OP, 0U); \
RTIO_DEFINE(lsm6dsv16x_rtio_ctx_##inst, 16, 16);
Copy link
Collaborator

Choose a reason for hiding this comment

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

16 is quite a large number of submissions and completions to keep in the pool Each one is going to be ~32bytes, 16*32 512B of potential space here.

Likely only needs 2 to 4 depending on what kind of transactions you are doing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ok

/*
* Instantiation macros used when a device is on an I2C bus.
*/

#define LSM6DSV16X_I2C_RTIO_DEFINE(inst) \
I2C_DT_IODEV_DEFINE(lsm6dsv16x_iodev_##inst, DT_DRV_INST(inst));\
RTIO_DEFINE(lsm6dsv16x_rtio_ctx_##inst, 16, 16);
Copy link
Collaborator

@teburd teburd Nov 15, 2024

Choose a reason for hiding this comment

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

Same comment as above, I'd recommend reducing the number of submissions (and completions) in the pool to something like 2 or 4 here. Likely 4 for doing the typical write a register, read a value, do a callback.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

But other sensor drivers are using 8/16. Maybe I could fix it to 4?

Copy link
Collaborator

Choose a reason for hiding this comment

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

If they are using 16, this is likely wasteful... I'd try fixing it to 4

read_fifo_status_reg->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART;
}
rtio_sqe_prep_callback(check_fifo_status_reg,
lsm6dsv16x_read_fifo_cb, (void *)dev, NULL);
Copy link
Collaborator

@teburd teburd Nov 15, 2024

Choose a reason for hiding this comment

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

Not required, but one possibility here is to look at the current request options and sensor config to assign an appropriate callback here avoiding some branching.

Potentially you could directly read the FIFO perhaps because the watermark is set, you can see if the data is requested with it.

Other possibilities to reduce branching are likely here but I get the current example drivers don't do 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.

Sorry, this is the only thing I'm not addressing. If it is really requested I'll explore it. :(

Copy link
Collaborator

@teburd teburd Nov 21, 2024

Choose a reason for hiding this comment

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

Understandable on the branching front

probably worth ignoring the response of the callback

check_fifo_status_reg->flags |= RTIO_SQE_NO_RESPONSE;

I'm still wondering about callbacks and responses, but today they do result in a completion response.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I had forgotten @JordanYates added a helper for this,

rtio_sqe_prep_callback_no_cqe()

https://github.com/zephyrproject-rtos/zephyr/blob/main/include/zephyr/rtio/rtio.h#L618

drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_decoder.c Outdated Show resolved Hide resolved
drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_decoder.c Outdated Show resolved Hide resolved
@avisconti
Copy link
Collaborator Author

re-pushed with some fix in order to (hopefully) pass CI. Still need to go thru some of the review comments...

Add attr_get() driver API

Signed-off-by: Armando Visconti <[email protected]>
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&config->ctx;

/* Flush the FIFO by disabling it. */
lsm6dsv16x_fifo_mode_set(ctx, LSM6DSV16X_BYPASS_MODE);
Copy link
Member

Choose a reason for hiding this comment

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

but then shouldn't you reenable it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think it is done in the next rtio submit which calls lsm6dsv16x_config_fifo(). Actually I'm quite new on the rtio philosophy, so I might be wrong. Maybe @teburd can comment more properly here.

Copy link
Collaborator

@teburd teburd Nov 22, 2024

Choose a reason for hiding this comment

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

This is a bit confusing I agree.

This should enable the triggers/fifo/data collection options as needed by the sensor stream configuration. I guess the question would then be when do we stop collecting and flush the FIFO. There's no explicit control API for this today that I recall offhand.

Collecting until we have no more buffers to fill (we overrun) is pretty simple and automatic. It's what I'd recommend. This works if you cancel the stream submission, or are cycling through multiple buffers (like double/triple/quadruple buffering sensor data). @yperess might have some other ideas here though.

Flushing (disabling/enabling) on each submission regardless doesn't seem like the right thing to do. Data would potentially be lost.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Well, what you are saying is in fact what I have understood earlier looking at following code in the comments:

 673  * int main(void) {
 674  *   struct rtio_sqe *handle;
 675  *   sensor_stream(&imu_stream, &rtio, NULL, &handle);
 676  *   k_msleep(1000);
 677  *   rtio_sqe_cancel(handle);
 678  * }

Here seems that sensor_stream is done only once initially, then FIFO streaming is self-sustained by FIFO_TH interrupts, and when you are done you just cancel the rtio_sqe handle. If this is correct, maybe the SENSOR_STREAM_DATA_DROP action really have to re-enable the FIFO, as no more sensor_stream will be re-issued.

Copy link
Member

@XenuIsWatching XenuIsWatching left a comment

Choose a reason for hiding this comment

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

I actually also did the same thing (almost in the same way here) except with I3C with FIFO streaming with I3C RTIO.... I'll get to creating a PR on top of this maybe this week or next... but I still need a review on #79346

@avisconti
Copy link
Collaborator Author

I actually also did the same thing (almost in the same way here) except with I3C with FIFO streaming with I3C RTIO.... I'll get to creating a PR on top of this maybe this week or next... but I still need a review on #79346

OK, I'm going to review #79346 right now. Thanks

@avisconti
Copy link
Collaborator Author

I actually also did the same thing (almost in the same way here) except with I3C with FIFO streaming with I3C RTIO.... I'll get to creating a PR on top of this maybe this week or next... but I still need a review on #79346

BTW, what hardware are you using? It seems that you already have a rtio-enabled I3C bus driver.

Copy link
Collaborator

@teburd teburd left a comment

Choose a reason for hiding this comment

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

Some small noteworthy things I took notice of. Hopefully the last round

drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c Outdated Show resolved Hide resolved
drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c Outdated Show resolved Hide resolved
drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c Outdated Show resolved Hide resolved
drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c Outdated Show resolved Hide resolved
rtio_sqe_prep_read(read_fifo_dout_reg, iodev, RTIO_PRIO_NORM,
read_buf, buf_avail, lsm6dsv16x->streaming_sqe);
read_fifo_dout_reg->flags = RTIO_SQE_CHAINED;
if (lsm6dsv16x->bus_type == 0) {
Copy link
Member

Choose a reason for hiding this comment

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

I think you mean to use the define here

if (lsm6dsv16x->bus_type == BUS_I2C) {

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yes, thx for getting this typo...

rtio_sqe_prep_read(read_fifo_status_reg, iodev, RTIO_PRIO_NORM,
lsm6dsv16x->fifo_status, 2, NULL);
read_fifo_status_reg->flags = RTIO_SQE_CHAINED;
if (lsm6dsv16x->bus_type == 0) {
Copy link
Member

Choose a reason for hiding this comment

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

I think you mean to use the define here

if (lsm6dsv16x->bus_type == BUS_I2C) {

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ack

edata->has_temp = 0;

for (int i = 0; i < num_channels; i++) {
switch (channels[i].chan_type) {
Copy link
Member

@XenuIsWatching XenuIsWatching Nov 20, 2024

Choose a reason for hiding this comment

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

do you want to support SENSOR_CHAN_ALL?

	case SENSOR_CHAN_ALL:
            edata->has_accel = 1;
            edata->has_gyro = 1;
#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
            edata->has_temp = 1;
#endif
	     break;

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ack

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I also reviewed the error checking and sqe error reporting

.is_fifo = true,
.accel_fs = lsm6dsv16x->accel_fs,
.gyro_fs = lsm6dsv16x->gyro_fs,
.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks()),
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't the timestamp be recorded when the interrupt occurs rather than when it gets done reading the fifo status

Copy link
Collaborator Author

@avisconti avisconti Nov 21, 2024

Choose a reason for hiding this comment

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

Yes, like it is done in the rtio simple case. Good catch

EDIT:
Well, actually it is before reading the FIFO. It is done just after reading the FIFO status and getting to know that it is actually a good interrupt. So, I think it is correct.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Another way of thinking about it is considering if you had an accelerometer running at 1hz and a FIFO threshold of 1 sample, and the sampling is aligned to N second boundaries.

T = 0.0 accelerometer start
T = 0.9 high priority task starts
T = 1.0 accelerometer samples, interrupt fires
T = 1.2 high priority task finishes
T = 1.3 read the FIFO status

The timestamp associated with the sample should not be 1.3, as reading the FIFO status is not strictly tied to the sampling.

Comment on lines 207 to 248
out->header.base_timestamp_ns = edata->header.timestamp;
out->readings[count].timestamp_delta =
(xl_count - 1) * accel_period_ns[edata->accel_batch_odr];
Copy link
Member

@XenuIsWatching XenuIsWatching Nov 20, 2024

Choose a reason for hiding this comment

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

I'm rather confused by this... but I see other drivers do this as well.

If the timestamp is recorded when the fifo is full or the watermark is hit, then that time is the time of the very last sample in the fifo.... but as it is a fifo, the first sample read out will be the oldest sample which the actual time of the sampling would of been quite a bit before the time of the last sampling. base_timestamp_ns would the time of the first sample recorded and timestamp_delta is the time difference in the future of when that sampling occured relative to the base_timestamp_ns

In my implementation... I did this where I first count up the total number of frames and then work backwards as to when the first sample timestamp actually occured.

static int lsm6dsv16x_fifo_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
				  uint32_t *fit, uint16_t max_count, void *data_out)
{
	const struct lsm6dsv16x_fifo_data *edata = (const struct lsm6dsv16x_fifo_data *)buffer;
	const struct lsm6dsv16x_decoder_header *header = &edata->header;
	struct lsm6dsv16x_settings cfg = {
		.accel_range = edata->header.accel_fs,
		.gyro_range = edata->header.gyro_fs,
	};
	const uint8_t *buffer_end =
		buffer + sizeof(struct lsm6dsv16x_fifo_data) + (edata->fifo_count * 7);
	const uint8_t *temp_buffer = buffer;
	lsm6dsv16x_fifo_data_out_tag_t tag;
	int count = 0;
	int accel_frame_count = 0;
	int gyro_frame_count = 0;
	int total_accel_frames = 0;
	int total_gyro_frames = 0;
	int rc;

	if ((uintptr_t)buffer_end <= *fit || chan_spec.chan_idx != 0) {
		return 0;
	}

	while (temp_buffer < buffer_end) {
		memcpy(&tag, &buffer[0], sizeof(tag));
		/* frame counters */
		switch (tag.tag_sensor) {
		case LSM6DSV16X_XL_NC_TAG:
			total_accel_frames++;
			break;
		case LSM6DSV16X_GY_NC_TAG:
			total_gyro_frames++;
			break;
		case LSM6DSV16X_CFG_CHANGE_TAG:
			/* TODO: record ODR changes */
			break;
		default:
			break;
		}

		/* A frame is 7 Bytes */
		temp_buffer += 7;
	}

	/*
	 * as the timestamp is when the fifo event occured, the base timestamp needs the time of the
	 * first frame which will be the first frame read out of the FIFO. Back date the timestamp by
	 * the total number of frames in the FIFO * the period of the ODR.
	 * TODO: This could have issues of the ODR was changed while streaming.
	 */
	if (IS_ACCEL(chan_spec.chan_type)) {
		((struct sensor_data_header *)data_out)->base_timestamp_ns =
			edata->header.timestamp -
			(total_accel_frames - 1) * period_ns[edata->accel_odr];
	} else if (IS_GYRO(chan_spec.chan_type)) {
		((struct sensor_data_header *)data_out)->base_timestamp_ns =
			edata->header.timestamp -
			(total_gyro_frames - 1) * period_ns[edata->gyro_odr];
	}

	/* Get the start of the FIFO data */
	buffer += sizeof(struct lsm6dsv16x_fifo_data);
	while (count < max_count && buffer < buffer_end) {
		memcpy(&tag, &buffer[0], sizeof(tag));
		/* frame counters */
		switch (tag.tag_sensor) {
		case LSM6DSV16X_XL_NC_TAG:
			accel_frame_count++;
			break;
		case LSM6DSV16X_GY_NC_TAG:
			gyro_frame_count++;
			break;
		default:
			break;
		}

		if ((uintptr_t)buffer < *fit) {
			/* This frame was already decoded, move on to the next frame */
			buffer += 7;
			continue;
		}

		switch (tag.tag_sensor) {
		case LSM6DSV16X_XL_NC_TAG:
			if (IS_ACCEL(chan_spec.chan_type)) {
				/* Decode accel */
				struct sensor_three_axis_data *data =
					(struct sensor_three_axis_data *)data_out;
				uint64_t accel_period_ns = period_ns[edata->accel_odr];

				rc = lsm6dsv16x_get_shift(SENSOR_CHAN_ACCEL_XYZ, header->accel_fs,
							  header->gyro_fs, &data->shift);
				if (rc != 0) {
					return -EINVAL;
				}

				/* extract raw data from fifo frame */
				int16_t accel_x_raw = sys_get_le16(&buffer[1]);
				int16_t accel_y_raw = sys_get_le16(&buffer[3]);
				int16_t accel_z_raw = sys_get_le16(&buffer[5]);

				data->readings[count].timestamp_delta =
					(accel_frame_count - 1) * accel_period_ns;
				lsm6dsv16x_convert_raw_to_q31(&cfg, SENSOR_CHAN_ACCEL_X,
							      accel_x_raw,
							      &data->readings[count].x);
				lsm6dsv16x_convert_raw_to_q31(&cfg, SENSOR_CHAN_ACCEL_Y,
							      accel_y_raw,
							      &data->readings[count].y);
				lsm6dsv16x_convert_raw_to_q31(&cfg, SENSOR_CHAN_ACCEL_Z,
							      accel_z_raw,
							      &data->readings[count].z);
				count++;
			}
			break;
		case LSM6DSV16X_GY_NC_TAG:
			if (IS_GYRO(chan_spec.chan_type)) {
				/* Decode gyro */
				struct sensor_three_axis_data *data =
					(struct sensor_three_axis_data *)data_out;
				uint64_t gyro_period_ns = period_ns[edata->gyro_odr];

				rc = lsm6dsv16x_get_shift(SENSOR_CHAN_GYRO_XYZ, header->accel_fs,
							  header->gyro_fs, &data->shift);
				if (rc != 0) {
					return -EINVAL;
				}

				/* extract raw data from fifo frame */
				int16_t gyro_x_raw = sys_get_le16(&buffer[1]);
				int16_t gyro_y_raw = sys_get_le16(&buffer[3]);
				int16_t gyro_z_raw = sys_get_le16(&buffer[5]);

				data->readings[count].timestamp_delta =
					(gyro_frame_count - 1) * gyro_period_ns;
				lsm6dsv16x_convert_raw_to_q31(&cfg, SENSOR_CHAN_GYRO_X, gyro_x_raw,
							      &data->readings[count].x);
				lsm6dsv16x_convert_raw_to_q31(&cfg, SENSOR_CHAN_GYRO_Y, gyro_y_raw,
							      &data->readings[count].y);
				lsm6dsv16x_convert_raw_to_q31(&cfg, SENSOR_CHAN_GYRO_Z, gyro_z_raw,
							      &data->readings[count].z);
				count++;
			}
			break;
#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
		case LSM6DSV16X_TEMPERATURE_TAG:
			if (chan_spec.chan_type == SENSOR_CHAN_DIE_TEMP) {
				/* Decode temperature */
				struct sensor_q31_data *data = (struct sensor_q31_data *)data_out;

				rc = lsm6dsv16x_get_shift(SENSOR_CHAN_DIE_TEMP, 0, &data->shift);
				if (rc != 0) {
					return -EINVAL;
				}

				/* extract raw data from fifo frame */
				int16_t temp_raw = sys_get_le16(&buffer[1]);

				lsm6dsv16x_convert_raw_to_q31(&cfg, SENSOR_CHAN_DIE_TEMP, temp_raw,
							      &data->readings[count].temperature);
				count++;
			}
			break;
#endif /* CONFIG_LSM6DSV16X_ENABLE_TEMP */
		case LSM6DSV16X_TIMESTAMP_TAG:
			/* Decode timestamp */
			// uint32_t timestamp = sys_get_le32(&buffer[1]);

			/* TODO: Word also contains other metadata that may be useful */

			break;
		case LSM6DSV16X_FIFO_EMPTY:
		default:
			break;
		}
		/* A frame is 7 Bytes */
		buffer += 7;
		*fit = (uintptr_t)buffer;
	}
	return count;
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Leave it open for the moment... I'll think more about it

Copy link
Collaborator Author

@avisconti avisconti Nov 21, 2024

Choose a reason for hiding this comment

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

think you are right. I'll count the frames and set base_timestamp_ns accordingly. Thanks for your example code, seems correct.

@XenuIsWatching
Copy link
Member

XenuIsWatching commented Nov 21, 2024

I actually also did the same thing (almost in the same way here) except with I3C with FIFO streaming with I3C RTIO.... I'll get to creating a PR on top of this maybe this week or next... but I still need a review on #79346

BTW, what hardware are you using? It seems that you already have a rtio-enabled I3C bus driver.

I'm using a custom silicon that I can't say anything about 🤐 .
If you want something off the shelf (and I think you work for ST?) there is a st i3c pr for review for the stm32h5 family, that may be the easiest for you to get a hold of #81190

I also have a i3c-rtio PR that is needing a review as well #80177

@avisconti
Copy link
Collaborator Author

avisconti commented Nov 21, 2024

I actually also did the same thing (almost in the same way here) except with I3C with FIFO streaming with I3C RTIO.... I'll get to creating a PR on top of this maybe this week or next... but I still need a review on #79346

BTW, what hardware are you using? It seems that you already have a rtio-enabled I3C bus driver.

I'm using a custom silicon that I can't say anything about 🤐 . If you want something off the shelf (and I think you work for ST?) there is a st i3c pr for review for the stm32h5 family, that may be the easiest for you to get a hold of #81190

Yes, I work in ST in Milano in Italy. I saw that you are based in Seattle, which recalls in my mind very good old memories...
I already knew about #81190, with my friend Erwan working on it.

I also have a i3c-rtio PR that is needing a review as well #80177

That's terrific. I'll take a look at it

Comment on lines 35 to 51
pin_int.fifo_th = PROPERTY_DISABLE;

if (enable != 0) {
pin_int.fifo_th = PROPERTY_ENABLE;

xl_batch = config->accel_batch;
gy_batch = config->gyro_batch;
temp_batch = config->temp_batch;

fifo_mode = LSM6DSV16X_STREAM_MODE;
fifo_wtm = config->fifo_wtm;
}
Copy link
Member

@XenuIsWatching XenuIsWatching Nov 21, 2024

Choose a reason for hiding this comment

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

This is always forcing the pin_int.fifo_th interrupt and not checking the enabled triggers for either SENSOR_TRIG_FIFO_WATERMARK or SENSOR_TRIG_FIFO_FULL for pin_int.fifo_full as well

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

correct, ack

Comment on lines +173 to +186
cqe = rtio_cqe_consume(lsm6dsv16x->rtio_ctx);
if (cqe != NULL) {
if ((cqe->result < 0) && (res == 0)) {
LOG_ERR("Bus error: %d", cqe->result);
res = cqe->result;
}
rtio_cqe_release(lsm6dsv16x->rtio_ctx, cqe);
}
Copy link
Member

@XenuIsWatching XenuIsWatching Nov 21, 2024

Choose a reason for hiding this comment

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

if I run with the fifo_th interrupt, all of sudden I this error after running for less than a minute. I don't know much about the internals of RTIO as to why...
If I run with the fifo_full interrupt which doesn't trigger as often, I don't see it

@teburd do you have any ideas?

[00:00:10.651,000] <err> LSM6DSV16X_RTIO: Bus error: -140

Copy link
Collaborator

Choose a reason for hiding this comment

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

-ECANCELLED implies an error or intentional cancellation of that submission or one before it in the same chain/transaction. Beyond that its not obvious, I'd add some logging.

Copy link
Member

Choose a reason for hiding this comment

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

I'm not doing any intentional cancellation so it must be error... I'll try to do some digging on my own here

Copy link
Member

@XenuIsWatching XenuIsWatching Nov 21, 2024

Choose a reason for hiding this comment

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

@teburd somehow increasing cq_sz in RTIO_DEFINE(name, sq_sz, cq_sz) from 4 to 8 makes the error not happen anymore, I'm not quite sure how that is used

Copy link
Collaborator

@teburd teburd Nov 21, 2024

Choose a reason for hiding this comment

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

cq_sz is the pool of available completions, likely the gpio interrupt for handling the sensor fifo events is being unmasked before clearing out the results of the last gpio interrupt in some manner. One possible source could be caused the callback submissions generating completions and not dealing with those if the flag isn't set to not do that. I get that its maybe surprising behavior on that front, @JordanYates I believe ran into something similar in #76351

Copy link
Collaborator

Choose a reason for hiding this comment

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

rtio_sqe_prep_callback_no_cqe() is helpful for the first case

https://github.com/zephyrproject-rtos/zephyr/blob/main/include/zephyr/rtio/rtio.h#L618

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@XenuIsWatching not able to replicate. Can you give me more details on your tests? (i.e. fifo watermark, batching odr, ...). Also, I'm using I2C, but you are using I3C, so maybe not replicable on my side.

Copy link
Member

Choose a reason for hiding this comment

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

yes, I am using I3C here

Copy link
Member

@XenuIsWatching XenuIsWatching Nov 24, 2024

Choose a reason for hiding this comment

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

I'm using zephyr 3.7 (just with this patched in), fifo watermark is 0x20, batching odr is 960Hz for accel and gyro along with running on I3C w/ IBI interrupts on my own commit (i'll try to get draft commit up soon, it's just that it has so many dependencies on unmerged PRs)

adding check_fifo_status_reg->flags |= RTIO_SQE_NO_RESPONSE; didn't fix it for me :(, but still having the cqe_sz set to 8 does....

DT_INST_NODE_HAS_PROP(inst, int2_gpios)), \
(LSM6DSV16X_CFG_IRQ(inst)))
#define LSM6DSV16X_SPI_RTIO_DEFINE(inst) \
SPI_DT_IODEV_DEFINE(lsm6dsv16x_iodev_##inst, \
Copy link
Member

Choose a reason for hiding this comment

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

unlikely situation: you want to give lsm6dsv16x_iodev_##inst different names as someone could have both SPI and I2C defined

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, I thought about this possibility as well. But ##inst would come out as different numbers in that case, no?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, I thought about this possibility as well. But ##inst would come out as different numbers in that case, no?

oh... yes, you are right

/*
* Instantiation macros used when a device is on an I2C bus.
*/

#define LSM6DSV16X_I2C_RTIO_DEFINE(inst) \
I2C_DT_IODEV_DEFINE(lsm6dsv16x_iodev_##inst, DT_DRV_INST(inst));\
Copy link
Member

Choose a reason for hiding this comment

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

unlikely situation: you want to give lsm6dsv16x_iodev_##inst different names as someone could have both SPI and I2C defined

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ditto

drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c Outdated Show resolved Hide resolved
read_fifo_status_reg->iodev_flags |= RTIO_IODEV_I2C_STOP | RTIO_IODEV_I2C_RESTART;
}
rtio_sqe_prep_callback(check_fifo_status_reg,
lsm6dsv16x_read_fifo_cb, (void *)dev, NULL);
Copy link
Collaborator

@teburd teburd Nov 21, 2024

Choose a reason for hiding this comment

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

Understandable on the branching front

probably worth ignoring the response of the callback

check_fifo_status_reg->flags |= RTIO_SQE_NO_RESPONSE;

I'm still wondering about callbacks and responses, but today they do result in a completion response.

drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c Outdated Show resolved Hide resolved
teburd
teburd previously approved these changes Nov 22, 2024
/* disable FIFO as first thing */
lsm6dsv16x_fifo_mode_set(ctx, LSM6DSV16X_BYPASS_MODE);

pin_int.fifo_th = PROPERTY_DISABLE;
Copy link
Member

Choose a reason for hiding this comment

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

should you also be setting pin_int.fifo_full = PROPERTY_DISABLE

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

... oooops, correct!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'll submit a new commit set on Monday. I'm leaving for the week

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done. We should be all set I guess

Add RTIO async and RTIO stream functionalities that enables,
among all the other things, the sensor data streaming from FIFO.

RTIO stream is using both SENSOR_TRIG_FIFO_WATERMARK and
SENSOR_TRIG_FIFO_FULL triggers. The decoder currently only supports
following FIFO tags:

  - LSM6DSV16X_XL_NC_TAG
  - LSM6DSV16X_GY_NC_TAG
  - LSM6DSV16X_TEMP_NC_TAG

Following FIFO parameters has to be defined in device tree to
correctly stream sensor data:

  - fifo-watermark (defaults to 32)
  - accel-fifo-batch-rate (defaults to LSM6DSV16X_DT_XL_NOT_BATCHED)
  - gyro-fifo-batch-rate (defaults to LSM6DSV16X_DT_GY_NOT_BATCHED)
  - temp-fifo-batch-rate (defaults to LSM6DSV16X_DT_TEMP_NOT_BATCHED)

Signed-off-by: Armando Visconti <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Devicetree Binding PR modifies or adds a Device Tree binding area: Drivers area: RTIO area: Sensors Sensors
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants