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

add Low Power Sensor Fusion (SFLP) support in lsm6dsv16x sensor driver #83094

Merged
merged 4 commits into from
Jan 2, 2025
Merged
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
2 changes: 1 addition & 1 deletion drivers/sensor/st/lps2xdf/ilps22qs.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ int st_ilps22qs_init(const struct device *dev)

/* Select bus interface */
ilps22qs_bus_mode_get(ctx, &bus_mode);
bus_mode.filter = ILPS22QS_AUTO;
bus_mode.filter = ILPS22QS_FILTER_AUTO;
bus_mode.interface = ILPS22QS_SEL_BY_HW;
ilps22qs_bus_mode_set(ctx, &bus_mode);
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/sensor/st/lps2xdf/lps22df.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ int st_lps22df_init(const struct device *dev)

/* Select bus interface */
lps22df_bus_mode_get(ctx, &bus_mode);
bus_mode.filter = LPS22DF_AUTO;
bus_mode.filter = LPS22DF_FILTER_AUTO;
bus_mode.interface = LPS22DF_SEL_BY_HW;
lps22df_bus_mode_set(ctx, &bus_mode);
}
Expand Down
2 changes: 2 additions & 0 deletions drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.c
Original file line number Diff line number Diff line change
Expand Up @@ -1138,6 +1138,8 @@ static int lsm6dsv16x_init(const struct device *dev)
(.fifo_wtm = DT_INST_PROP(inst, fifo_watermark), \
.accel_batch = DT_INST_PROP(inst, accel_fifo_batch_rate), \
.gyro_batch = DT_INST_PROP(inst, gyro_fifo_batch_rate), \
.sflp_odr = DT_INST_PROP(inst, sflp_odr), \
.sflp_fifo_en = DT_INST_PROP(inst, sflp_fifo_enable), \
.temp_batch = DT_INST_PROP(inst, temp_fifo_batch_rate),)) \
IF_ENABLED(UTIL_OR(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \
DT_INST_NODE_HAS_PROP(inst, int2_gpios)), \
Expand Down
5 changes: 4 additions & 1 deletion drivers/sensor/st/lsm6dsv16x/lsm6dsv16x.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ struct lsm6dsv16x_config {
uint8_t accel_batch : 4;
uint8_t gyro_batch : 4;
uint8_t temp_batch : 2;
uint8_t sflp_odr : 3;
uint8_t sflp_fifo_en : 3;
#endif
#ifdef CONFIG_LSM6DSV16X_TRIGGER
const struct gpio_dt_spec int1_gpio;
Expand Down Expand Up @@ -158,7 +160,8 @@ struct lsm6dsv16x_data {
uint8_t gyro_batch_odr : 4;
uint8_t temp_batch_odr : 2;
uint8_t bus_type : 2; /* I2C is 0, SPI is 1, I3C is 2 */
uint8_t reserved : 4;
uint8_t sflp_batch_odr : 3;
uint8_t reserved : 1;
#endif

#ifdef CONFIG_LSM6DSV16X_TRIGGER
Expand Down
162 changes: 162 additions & 0 deletions drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,23 @@ static const uint32_t temp_period_ns[] = {
[LSM6DSV16X_TEMP_BATCHED_AT_60Hz] = UINT32_C(1000000000) / 60,
};
#endif

static const uint32_t sflp_period_ns[] = {
[LSM6DSV16X_DT_SFLP_ODR_AT_15Hz] = UINT32_C(1000000000) / 15,
[LSM6DSV16X_DT_SFLP_ODR_AT_30Hz] = UINT32_C(1000000000) / 30,
[LSM6DSV16X_DT_SFLP_ODR_AT_60Hz] = UINT32_C(1000000000) / 60,
[LSM6DSV16X_DT_SFLP_ODR_AT_120Hz] = UINT32_C(1000000000) / 120,
[LSM6DSV16X_DT_SFLP_ODR_AT_240Hz] = UINT32_C(1000000000) / 240,
[LSM6DSV16X_DT_SFLP_ODR_AT_480Hz] = UINT32_C(1000000000) / 480,
};
#endif /* CONFIG_LSM6DSV16X_STREAM */

/*
* Expand val to q31_t according to its range; this is achieved multiplying by 2^31/2^range.
*/
#define Q31_SHIFT_VAL(val, range) \
(q31_t) (round((val) * ((int64_t)1 << (31 - (range)))))

/*
* Expand micro_val (a generic micro unit) to q31_t according to its range; this is achieved
* multiplying by 2^31/2^range. Then transform it to val.
Expand Down Expand Up @@ -157,6 +172,7 @@ static int lsm6dsv16x_decoder_get_frame_count(const uint8_t *buffer,
const uint8_t *buffer_end;
uint8_t fifo_tag;
uint8_t tot_accel_fifo_words = 0, tot_gyro_fifo_words = 0;
uint8_t tot_sflp_gbias = 0, tot_sflp_gravity = 0, tot_sflp_game_rotation = 0;

#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
uint8_t tot_temp_fifo_words = 0;
Expand All @@ -181,6 +197,15 @@ static int lsm6dsv16x_decoder_get_frame_count(const uint8_t *buffer,
tot_temp_fifo_words++;
break;
#endif
case LSM6DSV16X_SFLP_GYROSCOPE_BIAS_TAG:
tot_sflp_gbias++;
break;
case LSM6DSV16X_SFLP_GRAVITY_VECTOR_TAG:
tot_sflp_gravity++;
break;
case LSM6DSV16X_SFLP_GAME_ROTATION_VECTOR_TAG:
tot_sflp_game_rotation++;
break;
default:
break;
}
Expand Down Expand Up @@ -208,11 +233,21 @@ static int lsm6dsv16x_decoder_get_frame_count(const uint8_t *buffer,
*frame_count = tot_temp_fifo_words;
break;
#endif
case SENSOR_CHAN_GAME_ROTATION_VECTOR:
*frame_count = tot_sflp_game_rotation;
break;
case SENSOR_CHAN_GRAVITY_VECTOR:
*frame_count = tot_sflp_gravity;
break;
case SENSOR_CHAN_GBIAS_XYZ:
*frame_count = tot_sflp_gbias;
break;
default:
*frame_count = 0;
break;
}
#endif

return 0;
}

Expand All @@ -231,6 +266,7 @@ static int lsm6dsv16x_decode_fifo(const uint8_t *buffer, struct sensor_chan_spec
#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
uint16_t temp_count = 0;
#endif
uint16_t game_rot_count = 0, gravity_count = 0, gbias_count = 0;
int ret;

/* count total FIFO word for each tag */
Expand Down Expand Up @@ -261,6 +297,12 @@ static int lsm6dsv16x_decode_fifo(const uint8_t *buffer, struct sensor_chan_spec
edata->header.timestamp -
(tot_chan_fifo_words - 1) * temp_period_ns[edata->temp_batch_odr];
#endif
} else if (chan_spec.chan_type == SENSOR_CHAN_GRAVITY_VECTOR ||
chan_spec.chan_type == SENSOR_CHAN_GAME_ROTATION_VECTOR ||
chan_spec.chan_type == SENSOR_CHAN_GBIAS_XYZ) {
((struct sensor_data_header *)data_out)->base_timestamp_ns =
edata->header.timestamp -
(tot_chan_fifo_words - 1) * sflp_period_ns[edata->sflp_batch_odr];
}

while (count < max_count && buffer < buffer_end) {
Expand Down Expand Up @@ -365,6 +407,126 @@ static int lsm6dsv16x_decode_fifo(const uint8_t *buffer, struct sensor_chan_spec
break;
}
#endif
case LSM6DSV16X_SFLP_GAME_ROTATION_VECTOR_TAG: {
struct sensor_game_rotation_vector_data *out = data_out;
union { float32_t f; uint32_t i; } x, y, z;
float32_t w, sumsq;

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

if (chan_spec.chan_type != SENSOR_CHAN_GAME_ROTATION_VECTOR) {
buffer = frame_end;
continue;
}

out->readings[count].timestamp_delta =
(game_rot_count - 1) * sflp_period_ns[edata->sflp_batch_odr];

x.i = lsm6dsv16x_from_f16_to_f32(buffer[1] | (buffer[2] << 8));
y.i = lsm6dsv16x_from_f16_to_f32(buffer[3] | (buffer[4] << 8));
z.i = lsm6dsv16x_from_f16_to_f32(buffer[5] | (buffer[6] << 8));

sumsq = powf(x.f, 2) + powf(y.f, 2) + powf(z.f, 2);

/*
* Theoretically sumsq should never be greater than 1, but due to
* lack of precision it might happen. So, add a software correction
* which consists in normalizing the (x, y, z) vector.
*/
if (sumsq > 1.0f) {
float n = sqrtf(sumsq);

x.f /= n;
y.f /= n;
z.f /= n;
sumsq = 1.0f;
}

/* unity vector quaternions */
w = sqrtf(1.0f - sumsq);

/*
* Quaternions are numbers between -1 and 1. So let's select the signed
* Q0.31 format (m = 0, n (fractional bits) == 31)
*/
out->shift = 0;

out->readings[count].x = Q31_SHIFT_VAL(x.f, out->shift);
out->readings[count].y = Q31_SHIFT_VAL(y.f, out->shift);
out->readings[count].z = Q31_SHIFT_VAL(z.f, out->shift);
out->readings[count].w = Q31_SHIFT_VAL(w, out->shift);

break;
}

case LSM6DSV16X_SFLP_GYROSCOPE_BIAS_TAG: {
struct sensor_three_axis_data *out = data_out;
int16_t x, y, z;
const int32_t scale = gyro_scaler[LSM6DSV16X_DT_FS_125DPS];

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

if (chan_spec.chan_type != SENSOR_CHAN_GBIAS_XYZ) {
buffer = frame_end;
continue;
}

out->readings[count].timestamp_delta =
(gbias_count - 1) * sflp_period_ns[edata->sflp_batch_odr];

x = buffer[1] | (buffer[2] << 8);
y = buffer[3] | (buffer[4] << 8);
z = buffer[5] | (buffer[6] << 8);

out->shift = gyro_range[LSM6DSV16X_DT_FS_125DPS];

out->readings[count].x = Q31_SHIFT_MICROVAL(scale * x, out->shift);
out->readings[count].y = Q31_SHIFT_MICROVAL(scale * y, out->shift);
out->readings[count].z = Q31_SHIFT_MICROVAL(scale * z, out->shift);
break;
}

case LSM6DSV16X_SFLP_GRAVITY_VECTOR_TAG: {
struct sensor_three_axis_data *out = data_out;
float32_t x, y, z;

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

if (chan_spec.chan_type != SENSOR_CHAN_GRAVITY_VECTOR) {
buffer = frame_end;
continue;
}

out->readings[count].timestamp_delta =
(gravity_count - 1) * sflp_period_ns[edata->sflp_batch_odr];

x = lsm6dsv16x_from_sflp_to_mg(buffer[1] | (buffer[2] << 8));
y = lsm6dsv16x_from_sflp_to_mg(buffer[3] | (buffer[4] << 8));
z = lsm6dsv16x_from_sflp_to_mg(buffer[5] | (buffer[6] << 8));

out->shift = 12;

out->readings[count].x = Q31_SHIFT_VAL(x, out->shift);
out->readings[count].y = Q31_SHIFT_VAL(y, out->shift);
out->readings[count].z = Q31_SHIFT_VAL(z, out->shift);
break;
}

default:
/* skip unhandled FIFO tag */
buffer = frame_end;
Expand Down
3 changes: 2 additions & 1 deletion drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ struct lsm6dsv16x_fifo_data {
uint16_t gyro_batch_odr: 4;
uint16_t accel_batch_odr: 4;
uint16_t temp_batch_odr: 4;
uint16_t reserved_2: 4;
uint16_t sflp_batch_odr: 3;
uint16_t reserved_2: 1;
} __attribute__((__packed__));

struct lsm6dsv16x_rtio_data {
Expand Down
22 changes: 22 additions & 0 deletions drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_rtio_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ static void lsm6dsv16x_config_fifo(const struct device *dev, uint8_t fifo_irq)
lsm6dsv16x_fifo_gy_batch_t gy_batch = LSM6DSV16X_DT_GY_NOT_BATCHED;
lsm6dsv16x_fifo_temp_batch_t temp_batch = LSM6DSV16X_DT_TEMP_NOT_BATCHED;
lsm6dsv16x_fifo_mode_t fifo_mode = LSM6DSV16X_BYPASS_MODE;
lsm6dsv16x_sflp_data_rate_t sflp_odr = LSM6DSV16X_SFLP_120Hz;
lsm6dsv16x_fifo_sflp_raw_t sflp_fifo = { 0 };

/* disable FIFO as first thing */
lsm6dsv16x_fifo_mode_set(ctx, LSM6DSV16X_BYPASS_MODE);
Expand All @@ -48,6 +50,20 @@ static void lsm6dsv16x_config_fifo(const struct device *dev, uint8_t fifo_irq)

fifo_mode = LSM6DSV16X_STREAM_MODE;
fifo_wtm = config->fifo_wtm;

if (config->sflp_fifo_en & LSM6DSV16X_DT_SFLP_FIFO_GAME_ROTATION) {
sflp_fifo.game_rotation = 1;
}

if (config->sflp_fifo_en & LSM6DSV16X_DT_SFLP_FIFO_GRAVITY) {
sflp_fifo.gravity = 1;
}

if (config->sflp_fifo_en & LSM6DSV16X_DT_SFLP_FIFO_GBIAS) {
sflp_fifo.gbias = 1;
}

sflp_odr = config->sflp_odr;
}

/*
Expand All @@ -69,6 +85,11 @@ static void lsm6dsv16x_config_fifo(const struct device *dev, uint8_t fifo_irq)
lsm6dsv16x->temp_batch_odr = temp_batch;
#endif

lsm6dsv16x_sflp_data_rate_set(ctx, sflp_odr);
lsm6dsv16x->sflp_batch_odr = sflp_odr;
lsm6dsv16x_fifo_sflp_batch_set(ctx, sflp_fifo);
lsm6dsv16x_sflp_game_rotation_set(ctx, PROPERTY_ENABLE);

/* Set pin interrupt (fifo_th could be on or off) */
if ((config->drdy_pin == 1) || (ON_I3C_BUS(config) && (!I3C_INT_PIN(config)))) {
lsm6dsv16x_pin_int1_route_set(ctx, &pin_int);
Expand Down Expand Up @@ -306,6 +327,7 @@ static void lsm6dsv16x_read_fifo_cb(struct rtio *r, const struct rtio_sqe *sqe,
#if defined(CONFIG_LSM6DSV16X_ENABLE_TEMP)
.temp_batch_odr = lsm6dsv16x->temp_batch_odr,
#endif
.sflp_batch_odr = lsm6dsv16x->sflp_batch_odr,
};

memcpy(buf, &hdr, sizeof(hdr));
Expand Down
9 changes: 7 additions & 2 deletions drivers/sensor/st/lsm6dsv16x/lsm6dsv16x_trigger.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,11 @@ static void lsm6dsv16x_handle_interrupt(const struct device *dev)
int ret;

while (1) {
if (IS_ENABLED(CONFIG_LSM6DSV16X_STREAM)) {
/* When using I3C IBI interrupt the status register is already automatically
* read (clearing the interrupt condition), so we can skip the extra bus
* transaction for FIFO stream case.
*/
if (ON_I3C_BUS(cfg) && !I3C_INT_PIN(cfg) && IS_ENABLED(CONFIG_LSM6DSV16X_STREAM)) {
break;
}

Expand All @@ -186,7 +190,8 @@ static void lsm6dsv16x_handle_interrupt(const struct device *dev)
return;
}

if ((status.drdy_xl == 0) && (status.drdy_gy == 0)) {
if (((status.drdy_xl == 0) && (status.drdy_gy == 0)) ||
IS_ENABLED(CONFIG_LSM6DSV16X_STREAM)) {
break;
}

Expand Down
38 changes: 38 additions & 0 deletions dts/bindings/sensor/st,lsm6dsv16x-common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -258,3 +258,41 @@ properties:
- 0x3 # LSM6DSV16X_DT_TEMP_BATCHED_AT_60Hz

enum: [0x00, 0x01, 0x02, 0x03]

sflp-odr:
type: int
default: 0x3
description: |
Specify the Sensor Fusion Low Power output data rate expressed in samples per second (Hz).
The values are taken in accordance to lsm6dsv16x_sflp_data_rate_t enumerative in hal/st
module.
Default is power-up configuration.

- 0x0 # LSM6DSV16X_DT_SFLP_ODR_AT_15Hz
- 0x1 # LSM6DSV16X_DT_SFLP_ODR_AT_30Hz
- 0x2 # LSM6DSV16X_DT_SFLP_ODR_AT_60Hz
- 0x3 # LSM6DSV16X_DT_SFLP_ODR_AT_120Hz
- 0x4 # LSM6DSV16X_DT_SFLP_ODR_AT_240Hz
- 0x5 # LSM6DSV16X_DT_SFLP_ODR_AT_480Hz

enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05]

sflp-fifo-enable:
type: int
default: 0x0
description: |
Specify what Sensor Fusion Low Power component has to be batched in FIFO.
The values are taken in accordance to lsm6dsv16x_fifo_sflp_raw_t enumerative in hal/st
module.
Default is power-up configuration.

- 0x0 # LSM6DSV16X_DT_SFLP_FIFO_OFF
- 0x1 # LSM6DSV16X_DT_SFLP_FIFO_GAME_ROTATION
- 0x2 # LSM6DSV16X_DT_SFLP_FIFO_GRAVITY
- 0x3 # LSM6DSV16X_DT_SFLP_FIFO_GAME_ROTATION_GRAVITY
- 0x4 # LSM6DSV16X_DT_SFLP_FIFO_GBIAS
- 0x5 # LSM6DSV16X_DT_SFLP_FIFO_GAME_ROTATION_GBIAS
- 0x6 # LSM6DSV16X_DT_SFLP_FIFO_GRAVITY_GBIAS
- 0x7 # LSM6DSV16X_DT_SFLP_FIFO_GAME_ROTATION_GRAVITY_GBIAS

enum: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]
Loading
Loading