drivers: sensor: adxl367: Added RTIO stream

Updated ADXL367 driver with RTIO stream functionality.
RTIO stream is using both FIFO threshold and FIFO full triggers.
Together with RTIO stream, RTIO async read is also implemented.
Supported FIFO_CHANNEL configurations:
- XYZ
- X
- Y
- Z
- XYZT
- XT
- YT
- ZT
Configurations with external ADC are currently not supported.

Signed-off-by: Vladislav Pejic <vladislav.pejic@orioninc.com>
This commit is contained in:
Vladislav Pejic 2024-10-30 09:32:20 +01:00 committed by Benjamin Cabé
commit aad4c69068
8 changed files with 1601 additions and 23 deletions

View file

@ -9,3 +9,5 @@ zephyr_library_sources(adxl367.c)
zephyr_library_sources(adxl367_spi.c)
zephyr_library_sources(adxl367_i2c.c)
zephyr_library_sources_ifdef(CONFIG_ADXL367_TRIGGER adxl367_trigger.c)
zephyr_library_sources_ifdef(CONFIG_SENSOR_ASYNC_API adxl367_rtio.c adxl367_decoder.c)
zephyr_library_sources_ifdef(CONFIG_ADXL367_STREAM adxl367_stream.c adxl367_decoder.c)

View file

@ -115,6 +115,15 @@ config ADXL367_TRIGGER_OWN_THREAD
endchoice
config ADXL367_STREAM
bool "Use FIFO to stream data"
select ADXL367_TRIGGER
default y
depends on SPI_RTIO
depends on SENSOR_ASYNC_API
help
Use this configuration option to enable streaming sensor data via RTIO.
config ADXL367_TRIGGER
bool

View file

@ -108,8 +108,13 @@ static int adxl367_setup_inactivity_detection(const struct device *dev,
*
* @return 0 in case of success, negative error code otherwise.
*/
#ifdef CONFIG_ADXL367_STREAM
int adxl367_set_op_mode(const struct device *dev,
enum adxl367_op_mode op_mode)
#else
static int adxl367_set_op_mode(const struct device *dev,
enum adxl367_op_mode op_mode)
#endif /* CONFIG_ADXL367_STREAM */
{
struct adxl367_data *data = dev->data;
int ret;
@ -126,6 +131,11 @@ static int adxl367_set_op_mode(const struct device *dev,
k_sleep(K_MSEC(100));
}
#ifdef CONFIG_ADXL367_STREAM
data->pwr_reg &= ~ADXL367_POWER_CTL_MEASURE_MSK;
data->pwr_reg |= FIELD_PREP(ADXL367_POWER_CTL_MEASURE_MSK, op_mode);
#endif /* CONFIG_ADXL372_STREAM */
return 0;
}
@ -141,11 +151,21 @@ static int adxl367_set_op_mode(const struct device *dev,
*/
static int adxl367_set_autosleep(const struct device *dev, bool enable)
{
int ret;
struct adxl367_data *data = dev->data;
return data->hw_tf->write_reg_mask(dev, ADXL367_POWER_CTL,
ret = data->hw_tf->write_reg_mask(dev, ADXL367_POWER_CTL,
ADXL367_POWER_CTL_AUTOSLEEP_MSK,
FIELD_PREP(ADXL367_POWER_CTL_AUTOSLEEP_MSK, enable));
#ifdef CONFIG_ADXL367_STREAM
if (ret == 0) {
data->pwr_reg &= ~ADXL367_POWER_CTL_AUTOSLEEP_MSK;
data->pwr_reg |= FIELD_PREP(ADXL367_POWER_CTL_AUTOSLEEP_MSK, enable);
}
#endif /* CONFIG_ADXL372_STREAM */
return ret;
}
/**
@ -159,11 +179,21 @@ static int adxl367_set_autosleep(const struct device *dev, bool enable)
*/
static int adxl367_set_low_noise(const struct device *dev, bool enable)
{
int ret;
struct adxl367_data *data = dev->data;
return data->hw_tf->write_reg_mask(dev, ADXL367_POWER_CTL,
ret = data->hw_tf->write_reg_mask(dev, ADXL367_POWER_CTL,
ADXL367_POWER_CTL_NOISE_MSK,
FIELD_PREP(ADXL367_POWER_CTL_NOISE_MSK, enable));
#ifdef CONFIG_ADXL367_STREAM
if (ret == 0) {
data->pwr_reg &= ~ADXL367_POWER_CTL_NOISE_MSK;
data->pwr_reg |= FIELD_PREP(ADXL367_POWER_CTL_NOISE_MSK, enable);
}
#endif /* CONFIG_ADXL372_STREAM */
return ret;
}
/**
@ -203,11 +233,20 @@ static int adxl367_set_act_proc_mode(const struct device *dev,
int adxl367_set_output_rate(const struct device *dev, enum adxl367_odr odr)
{
struct adxl367_data *data = dev->data;
int ret;
return data->hw_tf->write_reg_mask(dev,
ret = data->hw_tf->write_reg_mask(dev,
ADXL367_FILTER_CTL,
ADXL367_FILTER_CTL_ODR_MSK,
FIELD_PREP(ADXL367_FILTER_CTL_ODR_MSK, odr));
#ifdef CONFIG_ADXL367_STREAM
if (ret == 0) {
data->odr = odr;
}
#endif /* CONFIG_ADXL367_STREAM */
return ret;
}
/**
@ -224,11 +263,20 @@ int adxl367_set_output_rate(const struct device *dev, enum adxl367_odr odr)
int adxl367_set_range(const struct device *dev, enum adxl367_range range)
{
struct adxl367_data *data = dev->data;
int ret;
return data->hw_tf->write_reg_mask(dev,
ret = data->hw_tf->write_reg_mask(dev,
ADXL367_FILTER_CTL,
ADXL367_FILTER_CTL_RANGE_MSK,
FIELD_PREP(ADXL367_FILTER_CTL_RANGE_MSK, range));
#ifdef CONFIG_ADXL367_STREAM
if (ret == 0) {
data->range = range;
}
#endif /* CONFIG_ADXL367_STREAM */
return ret;
}
/**
@ -594,7 +642,21 @@ int adxl367_fifo_setup(const struct device *dev,
return ret;
}
return adxl367_set_fifo_read_mode(dev, read_mode);
ret = adxl367_set_fifo_read_mode(dev, read_mode);
if (ret != 0) {
return ret;
}
#ifdef CONFIG_ADXL367_STREAM
struct adxl367_data *data = (struct adxl367_data *)dev->data;
data->fifo_config.fifo_mode = mode;
data->fifo_config.fifo_format = format;
data->fifo_config.fifo_samples = sets_nb;
data->fifo_config.fifo_read_mode = read_mode;
#endif /* CONFIG_ADXL367_STREAM */
return ret;
}
/**
@ -820,20 +882,26 @@ static int adxl367_sample_fetch(const struct device *dev,
return adxl367_get_temp_data(dev, &data->temp_val);
}
static void adxl367_accel_convert(const struct device *dev,
struct sensor_value *val, int16_t value)
#ifdef CONFIG_SENSOR_ASYNC_API
void adxl367_accel_convert(struct sensor_value *val, int16_t value,
enum adxl367_range range)
#else
static void adxl367_accel_convert(struct sensor_value *val, int16_t value,
enum adxl367_range range)
#endif /*CONFIG_SENSOR_ASYNC_API*/
{
struct adxl367_data *data = dev->data;
int64_t micro_ms2 = value * (SENSOR_G * 250 / 10000 *
adxl367_scale_mul[data->range] / 1000);
adxl367_scale_mul[range] / 1000);
val->val1 = micro_ms2 / 1000000;
val->val2 = micro_ms2 % 1000000;
}
#ifdef CONFIG_SENSOR_ASYNC_API
void adxl367_temp_convert(struct sensor_value *val, int16_t value)
#else
static void adxl367_temp_convert(struct sensor_value *val, int16_t value)
#endif /*CONFIG_SENSOR_ASYNC_API*/
{
int64_t temp_data = (value + ADXL367_TEMP_OFFSET) * ADXL367_TEMP_SCALE;
@ -849,18 +917,18 @@ static int adxl367_channel_get(const struct device *dev,
switch (chan) {
case SENSOR_CHAN_ACCEL_X:
adxl367_accel_convert(dev, val, data->sample.x);
adxl367_accel_convert(val, data->sample.x, data->range);
break;
case SENSOR_CHAN_ACCEL_Y:
adxl367_accel_convert(dev, val, data->sample.y);
adxl367_accel_convert(val, data->sample.y, data->range);
break;
case SENSOR_CHAN_ACCEL_Z:
adxl367_accel_convert(dev, val, data->sample.z);
adxl367_accel_convert(val, data->sample.z, data->range);
break;
case SENSOR_CHAN_ACCEL_XYZ:
adxl367_accel_convert(dev, val++, data->sample.x);
adxl367_accel_convert(dev, val++, data->sample.y);
adxl367_accel_convert(dev, val, data->sample.z);
adxl367_accel_convert(val++, data->sample.x, data->range);
adxl367_accel_convert(val++, data->sample.y, data->range);
adxl367_accel_convert(val, data->sample.z, data->range);
break;
case SENSOR_CHAN_DIE_TEMP:
adxl367_temp_convert(val, data->temp_val);
@ -878,6 +946,10 @@ static const struct sensor_driver_api adxl367_api_funcs = {
#ifdef CONFIG_ADXL367_TRIGGER
.trigger_set = adxl367_trigger_set,
#endif
#ifdef CONFIG_SENSOR_ASYNC_API
.submit = adxl367_submit,
.get_decoder = adxl367_get_decoder,
#endif /* CONFIG_SENSOR_ASYNC_API */
};
static int adxl367_probe(const struct device *dev)
@ -1055,19 +1127,28 @@ static int adxl367_init(const struct device *dev)
/*
* Instantiation macros used when a device is on a SPI bus.
*/
#define ADXL367_SPI_CFG SPI_WORD_SET(8) | SPI_TRANSFER_MSB
#define ADXL367_RTIO_DEFINE(inst) \
SPI_DT_IODEV_DEFINE(adxl367_iodev_##inst, DT_DRV_INST(inst), \
ADXL367_SPI_CFG, 0U); \
RTIO_DEFINE(adxl367_rtio_ctx_##inst, 8, 8);
#define ADXL367_CONFIG_SPI(inst) \
{ \
.bus_init = adxl367_spi_init, \
.spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8) | \
SPI_TRANSFER_MSB, 0), \
.spi = SPI_DT_SPEC_INST_GET(inst, ADXL367_SPI_CFG, 0), \
ADXL367_CONFIG(inst) \
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, int1_gpios), \
(ADXL367_CFG_IRQ(inst)), ()) \
}
#define ADXL367_DEFINE_SPI(inst) \
static struct adxl367_data adxl367_data_##inst; \
IF_ENABLED(CONFIG_ADXL367_STREAM, (ADXL367_RTIO_DEFINE(inst))); \
static struct adxl367_data adxl367_data_##inst = { \
IF_ENABLED(CONFIG_ADXL367_STREAM, (.rtio_ctx = &adxl367_rtio_ctx_##inst, \
.iodev = &adxl367_iodev_##inst,)) \
}; \
static const struct adxl367_dev_config adxl367_config_##inst = \
ADXL367_CONFIG_SPI(inst); \
ADXL367_DEVICE_INIT(inst)

View file

@ -14,6 +14,8 @@
#include <zephyr/kernel.h>
#include <zephyr/sys/util.h>
#define DT_DRV_COMPAT adi_adxl367
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
#include <zephyr/drivers/spi.h>
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */
@ -102,6 +104,7 @@
#define ADXL367_TO_REG(x) ((x) >> 1)
#define ADXL367_SPI_WRITE_REG 0x0Au
#define ADXL367_SPI_READ_REG 0x0Bu
#define ADXL367_SPI_READ_FIFO 0x0Du
#define ADXL367_ABSOLUTE 0x00
#define ADXL367_REFERENCED 0x01
@ -201,10 +204,19 @@
/* Max change = 270mg. Sensitivity = 4LSB / mg */
#define ADXL367_SELF_TEST_MAX (270 * 100 / 25)
/* ADXL367 get fifo sample header */
#define ADXL367_FIFO_HDR_GET_ACCEL_AXIS(x) (((x) & 0xC000) >> 14)
#define ADXL367_FIFO_HDR_CHECK_TEMP(x) ((((x) & 0xC000) >> 14) == 0x3)
/* ADXL362 scale factors from specifications */
#define ADXL367_ACCEL_2G_LSB_PER_G 4000
#define ADXL367_ACCEL_4G_LSB_PER_G 2000
#define ADXL367_ACCEL_8G_LSB_PER_G 1000
enum adxl367_axis {
ADXL367_X_AXIS,
ADXL367_Y_AXIS,
ADXL367_Z_AXIS
ADXL367_X_AXIS = 0x0,
ADXL367_Y_AXIS = 0x1,
ADXL367_Z_AXIS = 0x2
};
enum adxl367_op_mode {
@ -279,6 +291,16 @@ struct adxl367_xyz_accel_data {
int16_t x;
int16_t y;
int16_t z;
enum adxl367_range range;
};
struct adxl367_sample_data {
#ifdef CONFIG_ADXL367_STREAM
uint8_t is_fifo: 1;
uint8_t res: 7;
#endif /*CONFIG_ADXL367_STREAM*/
struct adxl367_xyz_accel_data xyz;
int16_t raw_temp;
};
struct adxl367_transfer_function {
@ -316,6 +338,20 @@ struct adxl367_data {
struct k_work work;
#endif
#endif /* CONFIG_ADXL367_TRIGGER */
#ifdef CONFIG_ADXL367_STREAM
uint8_t status;
uint8_t fifo_ent[2];
struct rtio_iodev_sqe *sqe;
struct rtio *rtio_ctx;
struct rtio_iodev *iodev;
uint64_t timestamp;
struct rtio *r_cb;
uint8_t fifo_full_irq: 1;
uint8_t fifo_wmark_irq: 1;
uint8_t res: 6;
enum adxl367_odr odr;
uint8_t pwr_reg;
#endif /* CONFIG_ADXL367_STREAM */
};
struct adxl367_dev_config {
@ -349,6 +385,27 @@ struct adxl367_dev_config {
uint8_t activity_time;
};
struct adxl367_fifo_data {
uint8_t is_fifo: 1;
uint8_t res: 7;
uint8_t packet_size;
uint8_t fifo_read_mode;
uint8_t has_tmp: 1;
uint8_t has_adc: 1;
uint8_t has_x: 1;
uint8_t has_y: 1;
uint8_t has_z: 1;
uint8_t res1: 3;
uint8_t int_status;
uint8_t accel_odr: 4;
uint8_t range: 4;
uint16_t fifo_byte_count;
uint64_t timestamp;
} __attribute__((__packed__));
BUILD_ASSERT(sizeof(struct adxl367_fifo_data) % 4 == 0,
"adxl367_fifo_data struct should be word aligned");
int adxl367_spi_init(const struct device *dev);
int adxl367_i2c_init(const struct device *dev);
int adxl367_trigger_set(const struct device *dev,
@ -356,5 +413,29 @@ int adxl367_trigger_set(const struct device *dev,
sensor_trigger_handler_t handler);
int adxl367_init_interrupt(const struct device *dev);
void adxl367_submit_stream(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe);
void adxl367_stream_irq_handler(const struct device *dev);
#ifdef CONFIG_SENSOR_ASYNC_API
void adxl367_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe);
int adxl367_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder);
int adxl367_get_accel_data(const struct device *dev,
struct adxl367_xyz_accel_data *accel_data);
int adxl367_get_temp_data(const struct device *dev, int16_t *raw_temp);
void adxl367_accel_convert(struct sensor_value *val, int16_t value,
enum adxl367_range range);
void adxl367_temp_convert(struct sensor_value *val, int16_t value);
#endif /* CONFIG_SENSOR_ASYNC_API */
#ifdef CONFIG_ADXL367_STREAM
int adxl367_fifo_setup(const struct device *dev,
enum adxl367_fifo_mode mode,
enum adxl367_fifo_format format,
enum adxl367_fifo_read_mode read_mode,
uint8_t sets_nb);
int adxl367_set_op_mode(const struct device *dev,
enum adxl367_op_mode op_mode);
size_t adxl367_get_packet_size(const struct adxl367_dev_config *cfg);
#endif /* CONFIG_ADXL367_STREAM */
#endif /* ZEPHYR_DRIVERS_SENSOR_ADXL367_ADXL367_H_ */

View file

@ -0,0 +1,767 @@
/*
* Copyright (c) 2024 Analog Devices Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "adxl367.h"
#include <zephyr/sys/byteorder.h>
#ifdef CONFIG_ADXL367_STREAM
#define ADXL367_COMPLEMENT 0xC000
/* Scale factor is the same for all ranges. */
/* (1.0 / sensor sensitivity) * (2^31 / 2^sensor shift ) * SENSOR_G / 1000000 */
#define SENSOR_QSCALE_FACTOR UINT32_C(164584)
/* (2^31 / 2^8(shift) */
#define ADXL367_TEMP_QSCALE 8388608
#define ADXL367_TEMP_SENSITIVITY 54 /* LSB/C */
#define ADXL367_TEMP_BIAS_TEST_CONDITION 25 /*C*/
static const uint32_t accel_period_ns[] = {
[ADXL367_ODR_12P5HZ] = UINT32_C(10000000000) / 125,
[ADXL367_ODR_25HZ] = UINT32_C(1000000000) / 25,
[ADXL367_ODR_50HZ] = UINT32_C(1000000000) / 50,
[ADXL367_ODR_100HZ] = UINT32_C(1000000000) / 100,
[ADXL367_ODR_200HZ] = UINT32_C(1000000000) / 200,
[ADXL367_ODR_400HZ] = UINT32_C(1000000000) / 400,
};
static const uint32_t range_to_shift[] = {
[ADXL367_2G_RANGE] = 5,
[ADXL367_4G_RANGE] = 6,
[ADXL367_8G_RANGE] = 7,
};
enum adxl367_12b_packet_start {
ADXL367_12B_PACKET_ALIGNED = 0,
ADXL367_12B_PACKET_NOT_ALIGNED = 1,
};
static inline void adxl367_temp_convert_q31(q31_t *out, const uint8_t *buff,
const enum adxl367_fifo_read_mode read_mode, uint8_t sample_aligned)
{
int16_t data_in;
unsigned int convert_value = 0;
switch (read_mode) {
case ADXL367_8B:
/* Because full resolution is 14b and this is 8 MSB bits. */
data_in = ((*((int8_t *)buff)) << 6) & 0x3FC0;
convert_value = 1;
break;
case ADXL367_12B:
/* Sample starts from the bit 4 of a first byte in buff. */
if (sample_aligned == 0) {
data_in = ((int16_t)(*buff & 0x0F) << 8) | *(buff + 1);
} else {
data_in = ((int16_t)(*buff) << 4) | (*(buff + 1) >> 4);
}
/* Because full resolution is 14b and this is 12 MSB bits. */
data_in = (data_in << 2) & 0x3FFC;
convert_value = 1;
break;
case ADXL367_12B_CHID:
data_in = sys_le16_to_cpu(*((int16_t *)(buff)));
if (ADXL367_FIFO_HDR_CHECK_TEMP(data_in)) {
/* Remove channel ID. */
data_in &= 0x3FFF;
/* Because full resolution is 14b and this is 12 MSB bits. */
data_in = (data_in << 2) & 0x3FFC;
convert_value = 1;
}
break;
case ADXL367_14B_CHID:
uint16_t *tmp_buf = (uint16_t *)buff;
data_in = (int16_t)(((*tmp_buf >> 8) & 0xFF) | ((*tmp_buf << 8) & 0xFF00));
if (ADXL367_FIFO_HDR_CHECK_TEMP(data_in)) {
/* Remove channel ID. */
data_in &= 0x3FFF;
convert_value = 1;
}
break;
default:
break;
}
if (convert_value) {
if (data_in & BIT(13)) {
data_in |= ADXL367_COMPLEMENT;
}
*out = ((data_in - ADXL367_TEMP_25C) / ADXL367_TEMP_SENSITIVITY
+ ADXL367_TEMP_BIAS_TEST_CONDITION) * ADXL367_TEMP_QSCALE;
}
}
static inline void adxl367_accel_convert_q31(q31_t *out, const uint8_t *buff,
const enum adxl367_fifo_read_mode read_mode, uint8_t axis, uint8_t sample_aligned)
{
int16_t data_in;
unsigned int convert_value = 0;
switch (read_mode) {
case ADXL367_8B:
/* Because full resolution is 14b and this is 8 MSB bits. */
data_in = ((*((int8_t *)buff)) << 6) & 0x3FC0;
convert_value = 1;
break;
case ADXL367_12B:
/* Sample starts from the bit 4 of a first byte in buff. */
if (sample_aligned == 0) {
data_in = ((int16_t)(*buff & 0x0F) << 8) | *(buff + 1);
} else {
data_in = ((int16_t)(*buff) << 4) | (*(buff + 1) >> 4);
}
/* Because full resolution is 14b and this is 12 MSB bits. */
data_in = (data_in << 2) & 0x3FFC;
convert_value = 1;
break;
case ADXL367_12B_CHID:
data_in = sys_le16_to_cpu(*((int16_t *)(buff)));
if (ADXL367_FIFO_HDR_GET_ACCEL_AXIS(data_in) == axis) {
/* Remove channel ID. */
data_in &= 0x3FFF;
/* Because full resolution is 14b and this is 12 MSB bits. */
data_in = (data_in << 2) & 0x3FFC;
convert_value = 1;
}
break;
case ADXL367_14B_CHID:
uint16_t *tmp_buf = (uint16_t *)buff;
data_in = (int16_t)(((*tmp_buf >> 8) & 0xFF) | ((*tmp_buf << 8) & 0xFF00));
if (ADXL367_FIFO_HDR_GET_ACCEL_AXIS(data_in) == axis) {
/* Remove channel ID. */
data_in &= 0x3FFF;
convert_value = 1;
}
break;
default:
break;
}
if (convert_value) {
if (data_in & BIT(13)) {
data_in |= ADXL367_COMPLEMENT;
}
*out = data_in * SENSOR_QSCALE_FACTOR;
}
}
static int adxl367_get_accel(const struct adxl367_fifo_data *enc_data,
struct sensor_three_axis_data *data, const uint8_t *buffer, int count,
uint8_t sample_size, struct sensor_chan_spec chan_spec,
uint64_t period_ns, uint8_t sample_num)
{
int ret = 0;
switch (chan_spec.chan_type) {
case SENSOR_CHAN_ACCEL_X:
if (enc_data->has_x) {
data->readings[count].timestamp_delta =
sample_num * period_ns;
adxl367_accel_convert_q31(&data->readings[count].x,
buffer, enc_data->fifo_read_mode,
ADXL367_X_AXIS, 1);
}
break;
case SENSOR_CHAN_ACCEL_Y:
if (enc_data->has_y) {
uint8_t buff_offset = 0;
/* If packet has X channel, then Y channel has offset. */
if (enc_data->has_x) {
buff_offset = sample_size;
}
data->readings[count].timestamp_delta = sample_num * period_ns;
adxl367_accel_convert_q31(&data->readings[count].y,
(buffer + buff_offset), enc_data->fifo_read_mode,
ADXL367_Y_AXIS, 1);
}
break;
case SENSOR_CHAN_ACCEL_Z:
if (enc_data->has_z) {
uint8_t buff_offset = 0;
/* If packet has X channel and/or Y channel,
* then Z channel has offset.
*/
if (enc_data->has_x) {
buff_offset = sample_size;
}
if (enc_data->has_y) {
buff_offset += sample_size;
}
data->readings[count].timestamp_delta =
sample_num * period_ns;
adxl367_accel_convert_q31(&data->readings[count].z,
(buffer + buff_offset), enc_data->fifo_read_mode,
ADXL367_Z_AXIS, 1);
}
break;
case SENSOR_CHAN_ACCEL_XYZ:
data->readings[count].timestamp_delta =
sample_num * period_ns;
uint8_t buff_offset = 0;
if (enc_data->has_x) {
adxl367_accel_convert_q31(&data->readings[count].x,
buffer, enc_data->fifo_read_mode,
ADXL367_X_AXIS, 1);
buff_offset = sample_size;
}
if (enc_data->has_y) {
adxl367_accel_convert_q31(&data->readings[count].y,
(buffer + buff_offset), enc_data->fifo_read_mode,
ADXL367_Y_AXIS, 1);
buff_offset += sample_size;
}
if (enc_data->has_z) {
adxl367_accel_convert_q31(&data->readings[count].z,
(buffer + buff_offset), enc_data->fifo_read_mode,
ADXL367_Z_AXIS, 1);
}
break;
default:
ret = -ENOTSUP;
break;
}
return ret;
}
static int adxl367_get_12b_accel(const struct adxl367_fifo_data *enc_data,
struct sensor_three_axis_data *data, const uint8_t *buffer, int count,
uint8_t packet_size, struct sensor_chan_spec chan_spec, uint8_t packet_alignment,
uint64_t period_ns, uint8_t sample_num)
{
int ret = 0;
uint8_t sample_aligned = 1;
uint8_t buff_offset = 0;
uint8_t samples_before = 0;
switch (chan_spec.chan_type) {
case SENSOR_CHAN_ACCEL_X:
if (enc_data->has_x) {
if (packet_alignment == ADXL367_12B_PACKET_NOT_ALIGNED) {
sample_aligned = 0;
}
data->readings[count].timestamp_delta = sample_num * period_ns;
adxl367_accel_convert_q31(&data->readings[count].x,
buffer, enc_data->fifo_read_mode,
ADXL367_X_AXIS, sample_aligned);
}
break;
case SENSOR_CHAN_ACCEL_Y:
if (enc_data->has_y) {
buff_offset = 0;
/* If packet has X channel,
* then Y channel has offset.
*/
if (enc_data->has_x) {
buff_offset = 2;
if (packet_alignment == ADXL367_12B_PACKET_ALIGNED) {
sample_aligned = 0;
buff_offset = 1;
}
}
data->readings[count].timestamp_delta = sample_num * period_ns;
adxl367_accel_convert_q31(&data->readings[count].y,
(buffer + buff_offset), enc_data->fifo_read_mode,
ADXL367_Y_AXIS, sample_aligned);
}
break;
case SENSOR_CHAN_ACCEL_Z:
if (enc_data->has_z) {
buff_offset = 0;
samples_before = 0;
/* If packet has X channel and/or Y channel,
* then Z channel has offset.
*/
if (enc_data->has_x) {
samples_before++;
}
if (enc_data->has_y) {
samples_before++;
}
if (samples_before == 0) {
if (packet_alignment == ADXL367_12B_PACKET_NOT_ALIGNED) {
sample_aligned = 0;
}
} else {
buff_offset = (samples_before * 12) / 8;
if (samples_before == 1) {
if (packet_alignment == ADXL367_12B_PACKET_ALIGNED) {
sample_aligned = 0;
} else {
buff_offset++;
}
} else {
if (packet_alignment == ADXL367_12B_PACKET_NOT_ALIGNED) {
sample_aligned = 0;
}
}
}
data->readings[count].timestamp_delta = sample_num * period_ns;
adxl367_accel_convert_q31(&data->readings[count].z,
(buffer + buff_offset), enc_data->fifo_read_mode,
ADXL367_Z_AXIS, sample_aligned);
}
break;
case SENSOR_CHAN_ACCEL_XYZ:
data->readings[count].timestamp_delta = sample_num * period_ns;
buff_offset = 0;
samples_before = 0;
if (enc_data->has_x) {
if (packet_alignment == ADXL367_12B_PACKET_NOT_ALIGNED) {
sample_aligned = 0;
}
samples_before++;
adxl367_accel_convert_q31(&data->readings[count].x,
buffer, enc_data->fifo_read_mode, ADXL367_X_AXIS,
sample_aligned);
}
if (enc_data->has_y) {
if (samples_before) {
if (packet_alignment == ADXL367_12B_PACKET_ALIGNED) {
buff_offset = 1;
sample_aligned = 0;
} else {
buff_offset = 2;
sample_aligned = 1;
}
} else {
if (packet_alignment == ADXL367_12B_PACKET_NOT_ALIGNED) {
sample_aligned = 0;
buff_offset = 0;
}
}
samples_before++;
adxl367_accel_convert_q31(&data->readings[count].y,
(buffer + buff_offset), enc_data->fifo_read_mode,
ADXL367_Y_AXIS, sample_aligned);
}
if (enc_data->has_z) {
/* Z can have 2 samples in the packet before it or 0. */
if (samples_before) {
if (packet_alignment == ADXL367_12B_PACKET_ALIGNED) {
sample_aligned = 1;
} else {
sample_aligned = 0;
}
buff_offset = 3;
} else {
if (packet_alignment == ADXL367_12B_PACKET_NOT_ALIGNED) {
sample_aligned = 0;
buff_offset = 0;
}
}
adxl367_accel_convert_q31(&data->readings[count].z,
(buffer + buff_offset), enc_data->fifo_read_mode,
ADXL367_Z_AXIS, sample_aligned);
}
break;
default:
ret = -ENOTSUP;
break;
}
return ret;
}
static void adxl367_get_12b_temp(const struct adxl367_fifo_data *enc_data,
struct sensor_q31_data *data, const uint8_t *buffer, int count, uint8_t packet_size)
{
if (enc_data->has_tmp) {
uint8_t offset = ((packet_size - 1) * 12) / 8;
uint8_t start_offset = ((packet_size - 1) * 12) % 8;
uint8_t sample_aligned = 1;
if (start_offset) {
sample_aligned = 0;
}
adxl367_temp_convert_q31(&data->readings[count].temperature,
(buffer + offset), enc_data->fifo_read_mode,
sample_aligned);
}
}
static int adxl367_decode_12b_stream(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
uint32_t *fit, uint16_t max_count, void *data_out,
const struct adxl367_fifo_data *enc_data)
{
const uint8_t *buffer_end =
buffer + sizeof(struct adxl367_fifo_data) + enc_data->fifo_byte_count;
uint8_t packet_size = enc_data->packet_size;
uint64_t period_ns = accel_period_ns[enc_data->accel_odr];
uint8_t sample_num = 0;
int count = 0;
uint8_t packet_alignment = ADXL367_12B_PACKET_ALIGNED;
while (count < max_count && buffer < buffer_end) {
const uint8_t *sample_end = buffer;
/* For ADXL367_12B mode packet_size is number of samples in one
* packet. If packet size is not aligned, sample_end will be on
* the byte that contains part of a last sample.
*/
if (packet_alignment == ADXL367_12B_PACKET_ALIGNED) {
sample_end += (packet_size * 12) / 8;
} else {
sample_end += (packet_size * 12) / 8 + 1;
}
/* If fit is larger than buffer this frame was already decoded,
* move on to the next frame.
*/
if ((uintptr_t)buffer < *fit) {
/* If number of samples in one packet is odd number,
* alignment changes for each packet.
*/
if (enc_data->packet_size % 2) {
if (packet_alignment == ADXL367_12B_PACKET_ALIGNED) {
packet_alignment = ADXL367_12B_PACKET_NOT_ALIGNED;
} else {
packet_alignment = ADXL367_12B_PACKET_ALIGNED;
}
}
buffer = sample_end;
sample_num++;
continue;
}
if (chan_spec.chan_type == SENSOR_CHAN_DIE_TEMP) {
struct sensor_q31_data *data = (struct sensor_q31_data *)data_out;
memset(data, 0, sizeof(struct sensor_three_axis_data));
data->header.base_timestamp_ns = enc_data->timestamp;
data->header.reading_count = 1;
data->shift = 8;
data->readings[count].timestamp_delta =
period_ns * sample_num;
adxl367_get_12b_temp(enc_data, data, buffer, count, packet_size);
} else {
struct sensor_three_axis_data *data =
(struct sensor_three_axis_data *)data_out;
memset(data, 0, sizeof(struct sensor_three_axis_data));
data->header.base_timestamp_ns = enc_data->timestamp;
data->header.reading_count = 1;
data->shift = range_to_shift[enc_data->range];
int ret = adxl367_get_12b_accel(enc_data, data, buffer, count, packet_size,
chan_spec, packet_alignment, period_ns, sample_num);
if (ret != 0) {
return ret;
}
}
buffer = sample_end;
*fit = (uintptr_t)sample_end;
count++;
}
return count;
}
static int adxl367_decode_stream(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
uint32_t *fit, uint16_t max_count, void *data_out)
{
const struct adxl367_fifo_data *enc_data = (const struct adxl367_fifo_data *)buffer;
const uint8_t *buffer_end =
buffer + sizeof(struct adxl367_fifo_data) + enc_data->fifo_byte_count;
int count = 0;
uint8_t sample_num = 0;
if ((uintptr_t)buffer_end <= *fit || chan_spec.chan_idx != 0) {
return 0;
}
buffer += sizeof(struct adxl367_fifo_data);
uint8_t packet_size = enc_data->packet_size;
uint64_t period_ns = accel_period_ns[enc_data->accel_odr];
uint8_t sample_size = 2;
if (enc_data->fifo_read_mode == ADXL367_8B) {
sample_size = 1;
}
if (enc_data->fifo_read_mode == ADXL367_12B) {
count = adxl367_decode_12b_stream(buffer, chan_spec, fit, max_count,
data_out, enc_data);
} else {
/* Calculate which sample is decoded. */
if ((uint8_t *)*fit >= buffer) {
sample_num = ((uint8_t *)*fit - buffer) / packet_size;
}
while (count < max_count && buffer < buffer_end) {
const uint8_t *sample_end = buffer;
sample_end += packet_size;
if ((uintptr_t)buffer < *fit) {
/* This frame was already decoded, move on to the next frame */
buffer = sample_end;
continue;
}
if (chan_spec.chan_type == SENSOR_CHAN_DIE_TEMP) {
struct sensor_q31_data *data = (struct sensor_q31_data *)data_out;
memset(data, 0, sizeof(struct sensor_three_axis_data));
data->header.base_timestamp_ns = enc_data->timestamp;
data->header.reading_count = 1;
data->shift = 8;
data->readings[count].timestamp_delta =
period_ns * sample_num;
if (enc_data->has_tmp) {
uint8_t offset = (packet_size - 1) * sample_size;
adxl367_temp_convert_q31(&data->readings[count].temperature,
(buffer + offset), enc_data->fifo_read_mode, 1);
}
} else {
struct sensor_three_axis_data *data =
(struct sensor_three_axis_data *)data_out;
memset(data, 0, sizeof(struct sensor_three_axis_data));
data->header.base_timestamp_ns = enc_data->timestamp;
data->header.reading_count = 1;
data->shift = range_to_shift[enc_data->range];
int ret = adxl367_get_accel(enc_data, data, buffer, count,
sample_size, chan_spec,
period_ns, sample_num);
if (ret != 0) {
return ret;
}
}
buffer = sample_end;
*fit = (uintptr_t)sample_end;
count++;
}
}
return count;
}
uint16_t adxl367_get_frame_count(const struct adxl367_fifo_data *data)
{
uint16_t frame_count = 0;
if (data->fifo_read_mode == ADXL367_12B) {
frame_count = data->fifo_byte_count * 8 / (data->packet_size * 12);
} else {
frame_count = data->fifo_byte_count / data->packet_size;
}
return frame_count;
}
#endif /* CONFIG_ADXL367_STREAM */
static int adxl367_decoder_get_frame_count(const uint8_t *buffer,
struct sensor_chan_spec chan_spec,
uint16_t *frame_count)
{
int32_t ret = -ENOTSUP;
if (chan_spec.chan_idx != 0) {
return ret;
}
#ifdef CONFIG_ADXL367_STREAM
const struct adxl367_fifo_data *data = (const struct adxl367_fifo_data *)buffer;
if (!data->is_fifo) {
#endif /* CONFIG_ADXL367_STREAM */
switch (chan_spec.chan_type) {
case SENSOR_CHAN_ACCEL_X:
case SENSOR_CHAN_ACCEL_Y:
case SENSOR_CHAN_ACCEL_Z:
case SENSOR_CHAN_ACCEL_XYZ:
*frame_count = 1;
ret = 0;
break;
default:
break;
}
#ifdef CONFIG_ADXL367_STREAM
} else {
if (data->fifo_byte_count == 0) {
*frame_count = 0;
ret = 0;
} else {
switch (chan_spec.chan_type) {
case SENSOR_CHAN_ACCEL_X:
if (data->has_x) {
*frame_count = adxl367_get_frame_count(data);
ret = 0;
}
break;
case SENSOR_CHAN_ACCEL_Y:
if (data->has_y) {
*frame_count = adxl367_get_frame_count(data);
ret = 0;
}
break;
case SENSOR_CHAN_ACCEL_Z:
if (data->has_z) {
*frame_count = adxl367_get_frame_count(data);
ret = 0;
}
break;
case SENSOR_CHAN_ACCEL_XYZ:
if (data->has_x || data->has_y || data->has_z) {
*frame_count = adxl367_get_frame_count(data);
ret = 0;
}
break;
case SENSOR_CHAN_DIE_TEMP:
if (data->has_tmp) {
*frame_count = adxl367_get_frame_count(data);
ret = 0;
break;
}
break;
default:
break;
}
}
}
#endif /* CONFIG_ADXL367_STREAM */
return ret;
}
static int adxl367_decode_sample(const struct adxl367_sample_data *data,
struct sensor_chan_spec chan_spec, uint32_t *fit, uint16_t max_count, void *data_out)
{
struct sensor_value *out = (struct sensor_value *) data_out;
if (*fit > 0) {
return -ENOTSUP;
}
switch (chan_spec.chan_type) {
case SENSOR_CHAN_ACCEL_X: /* Acceleration on the X axis, in m/s^2. */
adxl367_accel_convert(out, data->xyz.x, data->xyz.range);
break;
case SENSOR_CHAN_ACCEL_Y: /* Acceleration on the Y axis, in m/s^2. */
adxl367_accel_convert(out, data->xyz.y, data->xyz.range);
break;
case SENSOR_CHAN_ACCEL_Z: /* Acceleration on the Z axis, in m/s^2. */
adxl367_accel_convert(out, data->xyz.z, data->xyz.range);
break;
case SENSOR_CHAN_ACCEL_XYZ: /* Acceleration on the XYZ axis, in m/s^2. */
adxl367_accel_convert(out++, data->xyz.x, data->xyz.range);
adxl367_accel_convert(out++, data->xyz.y, data->xyz.range);
adxl367_accel_convert(out, data->xyz.z, data->xyz.range);
break;
case SENSOR_CHAN_DIE_TEMP: /* Temperature in degrees Celsius. */
adxl367_temp_convert(out, data->raw_temp);
break;
default:
return -ENOTSUP;
}
*fit = 1;
return 0;
}
static int adxl367_decoder_decode(const uint8_t *buffer, struct sensor_chan_spec chan_spec,
uint32_t *fit, uint16_t max_count, void *data_out)
{
const struct adxl367_sample_data *data = (const struct adxl367_sample_data *)buffer;
#ifdef CONFIG_ADXL367_STREAM
if (data->is_fifo) {
return adxl367_decode_stream(buffer, chan_spec, fit, max_count, data_out);
}
#endif /* CONFIG_ADXL367_STREAM */
return adxl367_decode_sample(data, chan_spec, fit, max_count, data_out);
}
static bool adxl367_decoder_has_trigger(const uint8_t *buffer, enum sensor_trigger_type trigger)
{
const struct adxl367_fifo_data *data = (const struct adxl367_fifo_data *)buffer;
if (!data->is_fifo) {
return false;
}
switch (trigger) {
case SENSOR_TRIG_DATA_READY:
return (ADXL367_STATUS_DATA_RDY & data->int_status);
case SENSOR_TRIG_FIFO_WATERMARK:
return (ADXL367_STATUS_FIFO_WATERMARK & data->int_status);
case SENSOR_TRIG_FIFO_FULL:
return (ADXL367_STATUS_FIFO_WATERMARK & data->int_status);
default:
return false;
}
}
SENSOR_DECODER_API_DT_DEFINE() = {
.get_frame_count = adxl367_decoder_get_frame_count,
.decode = adxl367_decoder_decode,
.has_trigger = adxl367_decoder_has_trigger,
};
int adxl367_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder)
{
ARG_UNUSED(dev);
*decoder = &SENSOR_DECODER_NAME();
return 0;
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2024 Analog Devices Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/rtio/work.h>
#include <zephyr/logging/log.h>
#include <zephyr/drivers/sensor.h>
#include "adxl367.h"
LOG_MODULE_DECLARE(ADXL367, CONFIG_SENSOR_LOG_LEVEL);
static void adxl367_submit_fetch(struct rtio_iodev_sqe *iodev_sqe)
{
const struct sensor_read_config *cfg =
(const struct sensor_read_config *) iodev_sqe->sqe.iodev->data;
const struct device *dev = cfg->sensor;
struct adxl367_data *data = dev->data;
int rc;
uint32_t min_buffer_len = sizeof(struct adxl367_sample_data);
uint8_t *buffer;
uint32_t buffer_len;
rc = rtio_sqe_rx_buf(iodev_sqe, min_buffer_len, min_buffer_len, &buffer, &buffer_len);
if (rc != 0) {
LOG_ERR("Failed to get a read buffer of size %u bytes", min_buffer_len);
rtio_iodev_sqe_err(iodev_sqe, rc);
return;
}
struct adxl367_sample_data *enc_data = (struct adxl367_sample_data *)buffer;
#ifdef CONFIG_ADXL367_STREAM
enc_data->is_fifo = 0;
#endif /*CONFIG_ADXL367_STREAM*/
rc = adxl367_get_accel_data(dev, &enc_data->xyz);
if (rc != 0) {
LOG_ERR("Failed to fetch xyz samples");
rtio_iodev_sqe_err(iodev_sqe, rc);
return;
}
enc_data->xyz.range = data->range;
rc = adxl367_get_temp_data(dev, &enc_data->raw_temp);
if (rc != 0) {
LOG_ERR("Failed to fetch temp samples");
rtio_iodev_sqe_err(iodev_sqe, rc);
return;
}
rtio_iodev_sqe_ok(iodev_sqe, 0);
}
void adxl367_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
{
const struct sensor_read_config *cfg =
(const struct sensor_read_config *) iodev_sqe->sqe.iodev->data;
if (!cfg->is_streaming) {
struct rtio_work_req *req = rtio_work_req_alloc();
__ASSERT_NO_MSG(req);
rtio_work_req_submit(req, iodev_sqe, adxl367_submit_fetch);
} else if (IS_ENABLED(CONFIG_ADXL367_STREAM)) {
adxl367_submit_stream(dev, iodev_sqe);
} else {
rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP);
}
}

View file

@ -0,0 +1,558 @@
/*
* Copyright (c) 2024 Analog Devices Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
#include <zephyr/drivers/sensor.h>
#include "adxl367.h"
LOG_MODULE_DECLARE(ADXL362, CONFIG_SENSOR_LOG_LEVEL);
static void adxl367_sqe_done(const struct adxl367_dev_config *cfg,
struct rtio_iodev_sqe *iodev_sqe, int res)
{
if (res < 0) {
rtio_iodev_sqe_err(iodev_sqe, res);
} else {
rtio_iodev_sqe_ok(iodev_sqe, res);
}
gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_EDGE_TO_ACTIVE);
}
static void adxl367_irq_en_cb(struct rtio *r, const struct rtio_sqe *sqr, void *arg)
{
const struct device *dev = (const struct device *)arg;
const struct adxl367_dev_config *cfg = dev->config;
gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_EDGE_TO_ACTIVE);
}
static void adxl367_fifo_flush_rtio(const struct device *dev)
{
struct adxl367_data *data = dev->data;
uint8_t pow_reg = data->pwr_reg;
pow_reg &= ~ADXL367_POWER_CTL_MEASURE_MSK;
pow_reg |= FIELD_PREP(ADXL367_POWER_CTL_MEASURE_MSK, ADXL367_STANDBY);
struct rtio_sqe *sqe = rtio_sqe_acquire(data->rtio_ctx);
const uint8_t reg_addr_w[3] = {ADXL367_SPI_WRITE_REG, ADXL367_POWER_CTL, pow_reg};
rtio_sqe_prep_tiny_write(sqe, data->iodev, RTIO_PRIO_NORM, reg_addr_w, 3, NULL);
sqe = rtio_sqe_acquire(data->rtio_ctx);
const uint8_t reg_addr_w2[3] = {ADXL367_SPI_WRITE_REG, ADXL367_FIFO_CONTROL,
FIELD_PREP(ADXL367_FIFO_CONTROL_FIFO_MODE_MSK, ADXL367_FIFO_DISABLED)};
rtio_sqe_prep_tiny_write(sqe, data->iodev, RTIO_PRIO_NORM, reg_addr_w2, 3, NULL);
sqe = rtio_sqe_acquire(data->rtio_ctx);
const uint8_t reg_addr_w3[3] = {ADXL367_SPI_WRITE_REG, ADXL367_FIFO_CONTROL,
FIELD_PREP(ADXL367_FIFO_CONTROL_FIFO_MODE_MSK, data->fifo_config.fifo_mode)};
rtio_sqe_prep_tiny_write(sqe, data->iodev, RTIO_PRIO_NORM, reg_addr_w3, 3, NULL);
pow_reg = data->pwr_reg;
pow_reg &= ~ADXL367_POWER_CTL_MEASURE_MSK;
pow_reg |= FIELD_PREP(ADXL367_POWER_CTL_MEASURE_MSK, ADXL367_MEASURE);
sqe = rtio_sqe_acquire(data->rtio_ctx);
struct rtio_sqe *complete_op = rtio_sqe_acquire(data->rtio_ctx);
const uint8_t reg_addr_w4[3] = {ADXL367_SPI_WRITE_REG, ADXL367_POWER_CTL, pow_reg};
rtio_sqe_prep_tiny_write(sqe, data->iodev, RTIO_PRIO_NORM, reg_addr_w4, 3, NULL);
sqe->flags |= RTIO_SQE_CHAINED;
rtio_sqe_prep_callback(complete_op, adxl367_irq_en_cb, (void *)dev, NULL);
rtio_submit(data->rtio_ctx, 0);
}
void adxl367_submit_stream(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
{
const struct sensor_read_config *cfg =
(const struct sensor_read_config *)iodev_sqe->sqe.iodev->data;
struct adxl367_data *data = (struct adxl367_data *)dev->data;
const struct adxl367_dev_config *cfg_367 = dev->config;
uint8_t int_mask = 0;
uint8_t int_value = 0;
uint8_t fifo_wmark_irq = 0;
uint8_t fifo_full_irq = 0;
int rc = gpio_pin_interrupt_configure_dt(&cfg_367->interrupt,
GPIO_INT_DISABLE);
if (rc < 0) {
return;
}
for (size_t i = 0; i < cfg->count; i++) {
if (cfg->triggers[i].trigger == SENSOR_TRIG_FIFO_WATERMARK) {
int_mask |= ADXL367_FIFO_WATERMARK;
int_value |= ADXL367_FIFO_WATERMARK;
fifo_wmark_irq = 1;
}
if (cfg->triggers[i].trigger == SENSOR_TRIG_FIFO_FULL) {
int_mask |= ADXL367_FIFO_OVERRUN;
int_value |= ADXL367_FIFO_OVERRUN;
fifo_full_irq = 1;
}
}
if (data->fifo_wmark_irq && (fifo_wmark_irq == 0)) {
int_mask |= ADXL367_FIFO_WATERMARK;
}
if (data->fifo_full_irq && (fifo_full_irq == 0)) {
int_mask |= ADXL367_FIFO_OVERRUN;
}
/* Do not flush the FIFO if interrupts are already enabled. */
if ((fifo_wmark_irq != data->fifo_wmark_irq) || (fifo_full_irq != data->fifo_full_irq)) {
data->fifo_wmark_irq = fifo_wmark_irq;
data->fifo_full_irq = fifo_full_irq;
rc = data->hw_tf->write_reg_mask(dev, ADXL367_INTMAP1_LOWER, int_mask, int_value);
if (rc < 0) {
return;
}
/* Flush the FIFO by disabling it. Save current mode for after the reset. */
enum adxl367_fifo_mode current_fifo_mode = data->fifo_config.fifo_mode;
if (current_fifo_mode == ADXL367_FIFO_DISABLED) {
LOG_ERR("ERROR: FIFO DISABLED");
return;
}
adxl367_set_op_mode(dev, ADXL367_STANDBY);
adxl367_fifo_setup(dev, ADXL367_FIFO_DISABLED, data->fifo_config.fifo_format,
data->fifo_config.fifo_read_mode, data->fifo_config.fifo_samples);
adxl367_fifo_setup(dev, current_fifo_mode, data->fifo_config.fifo_format,
data->fifo_config.fifo_read_mode, data->fifo_config.fifo_samples);
adxl367_set_op_mode(dev, cfg_367->op_mode);
}
rc = gpio_pin_interrupt_configure_dt(&cfg_367->interrupt,
GPIO_INT_EDGE_TO_ACTIVE);
if (rc < 0) {
return;
}
data->sqe = iodev_sqe;
}
static void adxl367_fifo_read_cb(struct rtio *rtio_ctx, const struct rtio_sqe *sqe, void *arg)
{
const struct device *dev = (const struct device *)arg;
const struct adxl367_dev_config *cfg = (const struct adxl367_dev_config *)dev->config;
struct rtio_iodev_sqe *iodev_sqe = sqe->userdata;
adxl367_sqe_done(cfg, iodev_sqe, 0);
}
size_t adxl367_get_numb_of_samp_in_pkt(const struct adxl367_data *data)
{
size_t sample_numb;
switch (data->fifo_config.fifo_format) {
case ADXL367_FIFO_FORMAT_X:
case ADXL367_FIFO_FORMAT_Y:
case ADXL367_FIFO_FORMAT_Z:
sample_numb = 1;
break;
case ADXL367_FIFO_FORMAT_XT:
case ADXL367_FIFO_FORMAT_YT:
case ADXL367_FIFO_FORMAT_ZT:
case ADXL367_FIFO_FORMAT_XA:
case ADXL367_FIFO_FORMAT_YA:
case ADXL367_FIFO_FORMAT_ZA:
sample_numb = 2;
break;
case ADXL367_FIFO_FORMAT_XYZT:
case ADXL367_FIFO_FORMAT_XYZA:
sample_numb = 4;
break;
default:
sample_numb = 3;
break;
}
return sample_numb;
}
static void adxl367_process_fifo_samples_cb(struct rtio *r, const struct rtio_sqe *sqr, void *arg)
{
const struct device *dev = (const struct device *)arg;
struct adxl367_data *data = (struct adxl367_data *)dev->data;
const struct adxl367_dev_config *cfg = (const struct adxl367_dev_config *)dev->config;
struct rtio_iodev_sqe *current_sqe = data->sqe;
uint16_t fifo_samples = ((data->fifo_ent[0]) | ((data->fifo_ent[1] & 0x3) << 8));
size_t sample_numb = adxl367_get_numb_of_samp_in_pkt(data);
size_t packet_size = sample_numb;
uint16_t fifo_packet_cnt = fifo_samples / sample_numb;
uint16_t fifo_bytes = 0;
switch (data->fifo_config.fifo_read_mode) {
case ADXL367_8B:
fifo_bytes = fifo_packet_cnt;
break;
case ADXL367_12B:
unsigned int fifo_bits = fifo_packet_cnt * sample_numb * 12;
if (fifo_bits % 8 == 0) {
fifo_bytes = fifo_bits / 8;
} else {
while (fifo_bits % 8) {
if (fifo_bits >= sample_numb * 12) {
fifo_bits -= sample_numb * 12;
} else {
fifo_bits = 0;
break;
}
}
if (fifo_bits) {
fifo_bytes = fifo_bits / 8;
} else {
LOG_ERR("fifo_bytes error: %d", fifo_bytes);
adxl367_sqe_done(cfg, current_sqe, -1);
return;
}
}
packet_size = packet_size * 12 / 8;
if ((sample_numb * 12) % 8) {
packet_size++;
}
break;
default:
fifo_bytes = fifo_packet_cnt * 2;
packet_size *= 2;
break;
}
data->sqe = NULL;
/* Not inherently an underrun/overrun as we may have a buffer to fill next time */
if (current_sqe == NULL) {
LOG_ERR("No pending SQE");
gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_EDGE_TO_ACTIVE);
return;
}
const size_t min_read_size = sizeof(struct adxl367_fifo_data) + packet_size;
const size_t ideal_read_size = sizeof(struct adxl367_fifo_data) + fifo_bytes;
uint8_t *buf;
uint32_t buf_len;
if (rtio_sqe_rx_buf(current_sqe, min_read_size, ideal_read_size, &buf, &buf_len) != 0) {
LOG_ERR("Failed to get buffer");
adxl367_sqe_done(cfg, current_sqe, -ENOMEM);
return;
}
LOG_DBG("Requesting buffer [%u, %u] got %u", (unsigned int)min_read_size,
(unsigned int)ideal_read_size, buf_len);
/* Read FIFO and call back to rtio with rtio_sqe completion */
struct adxl367_fifo_data *hdr = (struct adxl367_fifo_data *)buf;
hdr->is_fifo = 1;
hdr->timestamp = data->timestamp;
hdr->int_status = data->status;
hdr->accel_odr = data->odr;
hdr->range = data->range;
hdr->fifo_read_mode = data->fifo_config.fifo_read_mode;
if (data->fifo_config.fifo_read_mode == ADXL367_12B) {
hdr->packet_size = sample_numb;
} else {
hdr->packet_size = packet_size;
}
if ((data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_X) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_XT) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_XA) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_XYZ) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_XYZA) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_XYZT)) {
hdr->has_x = 1;
}
if ((data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_Y) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_YT) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_YA) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_XYZ) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_XYZA) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_XYZT)) {
hdr->has_y = 1;
}
if ((data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_Z) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_ZT) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_ZA) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_XYZ) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_XYZA) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_XYZT)) {
hdr->has_z = 1;
}
if ((data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_XT) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_YT) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_ZT) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_XYZT)) {
hdr->has_tmp = 1;
}
if ((data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_XA) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_YA) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_ZA) ||
(data->fifo_config.fifo_format == ADXL367_FIFO_FORMAT_XYZA)) {
hdr->has_adc = 1;
}
uint32_t buf_avail = buf_len;
buf_avail -= sizeof(*hdr);
uint32_t read_len = MIN(fifo_bytes, buf_avail);
if (data->fifo_config.fifo_read_mode == ADXL367_12B) {
unsigned int read_bits = read_len * 8;
unsigned int packet_size_bits = sample_numb * 12;
unsigned int read_packet_num = read_bits / packet_size_bits;
unsigned int read_len_bits = read_packet_num * sample_numb * 12;
if (read_len_bits % 8 == 0) {
read_len = read_len_bits / 8;
} else {
while (read_len_bits % 8) {
if (read_len_bits >= sample_numb * 12) {
read_len_bits -= sample_numb * 12;
} else {
read_len_bits = 0;
break;
}
}
if (read_len_bits) {
read_len = read_len_bits / 8;
} else {
LOG_ERR("read_len error");
adxl367_sqe_done(cfg, current_sqe, -ENOMEM);
return;
}
}
} else {
uint32_t pkts = read_len / packet_size;
read_len = pkts * packet_size;
}
((struct adxl367_fifo_data *)buf)->fifo_byte_count = read_len;
__ASSERT_NO_MSG(read_len % pkt_size == 0);
uint8_t *read_buf = buf + sizeof(*hdr);
/* Flush completions */
struct rtio_cqe *cqe;
int res = 0;
do {
cqe = rtio_cqe_consume(data->rtio_ctx);
if (cqe != NULL) {
if ((cqe->result < 0 && res == 0)) {
LOG_ERR("Bus error: %d", cqe->result);
res = cqe->result;
}
rtio_cqe_release(data->rtio_ctx, cqe);
}
} while (cqe != NULL);
/* Bail/cancel attempt to read sensor on any error */
if (res != 0) {
adxl367_sqe_done(cfg, current_sqe, res);
return;
}
/* Setup new rtio chain to read the fifo data and report then check the
* result
*/
struct rtio_sqe *write_fifo_addr = rtio_sqe_acquire(data->rtio_ctx);
struct rtio_sqe *read_fifo_data = rtio_sqe_acquire(data->rtio_ctx);
struct rtio_sqe *complete_op = rtio_sqe_acquire(data->rtio_ctx);
const uint8_t reg_addr = ADXL367_SPI_READ_FIFO;
rtio_sqe_prep_tiny_write(write_fifo_addr, data->iodev, RTIO_PRIO_NORM, &reg_addr, 1, NULL);
write_fifo_addr->flags = RTIO_SQE_TRANSACTION;
rtio_sqe_prep_read(read_fifo_data, data->iodev, RTIO_PRIO_NORM, read_buf, read_len,
current_sqe);
read_fifo_data->flags = RTIO_SQE_CHAINED;
rtio_sqe_prep_callback(complete_op, adxl367_fifo_read_cb, (void *)dev, current_sqe);
rtio_submit(data->rtio_ctx, 0);
}
static void adxl367_process_status_cb(struct rtio *r, const struct rtio_sqe *sqr, void *arg)
{
const struct device *dev = (const struct device *)arg;
struct adxl367_data *data = (struct adxl367_data *) dev->data;
const struct adxl367_dev_config *cfg = (const struct adxl367_dev_config *) dev->config;
struct rtio_iodev_sqe *current_sqe = data->sqe;
struct sensor_read_config *read_config;
uint8_t status = data->status;
__ASSERT(data->sqe != NULL, "%s data->sqe = NULL", __func__);
read_config = (struct sensor_read_config *)data->sqe->sqe.iodev->data;
__ASSERT(read_config != NULL, "%s read_config = NULL", __func__);
__ASSERT(read_config->is_streaming != false,
"%s read_config->is_streaming = false", __func__);
gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_DISABLE);
struct sensor_stream_trigger *fifo_wmark_cfg = NULL;
struct sensor_stream_trigger *fifo_full_cfg = NULL;
for (int i = 0; i < read_config->count; ++i) {
if (read_config->triggers[i].trigger == SENSOR_TRIG_FIFO_WATERMARK) {
fifo_wmark_cfg = &read_config->triggers[i];
continue;
}
if (read_config->triggers[i].trigger == SENSOR_TRIG_FIFO_FULL) {
fifo_full_cfg = &read_config->triggers[i];
continue;
}
}
bool fifo_full_irq = false;
bool fifo_wmark_irq = false;
if ((fifo_wmark_cfg != NULL) && FIELD_GET(ADXL367_STATUS_FIFO_WATERMARK, status)) {
fifo_wmark_irq = true;
}
if ((fifo_full_cfg != NULL) && FIELD_GET(ADXL367_STATUS_FIFO_OVERRUN, status)) {
fifo_full_irq = true;
}
if (!fifo_full_irq && !fifo_wmark_irq) {
gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_EDGE_TO_ACTIVE);
return;
}
/* Flush completions */
struct rtio_cqe *cqe;
int res = 0;
do {
cqe = rtio_cqe_consume(data->rtio_ctx);
if (cqe != NULL) {
if ((cqe->result < 0 && res == 0)) {
LOG_ERR("Bus error: %d", cqe->result);
res = cqe->result;
}
rtio_cqe_release(data->rtio_ctx, cqe);
}
} while (cqe != NULL);
/* Bail/cancel attempt to read sensor on any error */
if (res != 0) {
adxl367_sqe_done(cfg, current_sqe, res);
return;
}
enum sensor_stream_data_opt data_opt;
if ((fifo_wmark_cfg != NULL) && (fifo_full_cfg == NULL)) {
data_opt = fifo_wmark_cfg->opt;
} else if ((fifo_wmark_cfg == NULL) && (fifo_full_cfg != NULL)) {
data_opt = fifo_full_cfg->opt;
} else {
data_opt = MIN(fifo_wmark_cfg->opt, fifo_full_cfg->opt);
}
if (data_opt == SENSOR_STREAM_DATA_NOP || data_opt == SENSOR_STREAM_DATA_DROP) {
uint8_t *buf;
uint32_t buf_len;
/* Clear streaming_sqe since we're done with the call */
data->sqe = NULL;
if (rtio_sqe_rx_buf(current_sqe, sizeof(struct adxl367_fifo_data),
sizeof(struct adxl367_fifo_data), &buf, &buf_len) != 0) {
adxl367_sqe_done(cfg, current_sqe, -ENOMEM);
return;
}
struct adxl367_fifo_data *rx_data = (struct adxl367_fifo_data *)buf;
memset(buf, 0, buf_len);
rx_data->is_fifo = 1;
rx_data->timestamp = data->timestamp;
rx_data->int_status = status;
rx_data->fifo_byte_count = 0;
if (data_opt == SENSOR_STREAM_DATA_DROP) {
/* Flush the FIFO by disabling it. Save current mode for after the reset. */
adxl367_fifo_flush_rtio(dev);
return;
}
adxl367_sqe_done(cfg, current_sqe, 0);
return;
}
struct rtio_sqe *write_fifo_addr = rtio_sqe_acquire(data->rtio_ctx);
struct rtio_sqe *read_fifo_data = rtio_sqe_acquire(data->rtio_ctx);
struct rtio_sqe *complete_op = rtio_sqe_acquire(data->rtio_ctx);
const uint8_t reg[2] = {ADXL367_SPI_READ_REG, ADXL367_FIFO_ENTRIES_L};
rtio_sqe_prep_tiny_write(write_fifo_addr, data->iodev, RTIO_PRIO_NORM, reg, 2, NULL);
write_fifo_addr->flags = RTIO_SQE_TRANSACTION;
rtio_sqe_prep_read(read_fifo_data, data->iodev, RTIO_PRIO_NORM, data->fifo_ent, 2,
current_sqe);
read_fifo_data->flags = RTIO_SQE_CHAINED;
rtio_sqe_prep_callback(complete_op, adxl367_process_fifo_samples_cb, (void *)dev,
current_sqe);
rtio_submit(data->rtio_ctx, 0);
}
void adxl367_stream_irq_handler(const struct device *dev)
{
struct adxl367_data *data = (struct adxl367_data *) dev->data;
if (data->sqe == NULL) {
return;
}
data->timestamp = k_ticks_to_ns_floor64(k_uptime_ticks());
struct rtio_sqe *write_status_addr = rtio_sqe_acquire(data->rtio_ctx);
struct rtio_sqe *read_status_reg = rtio_sqe_acquire(data->rtio_ctx);
struct rtio_sqe *check_status_reg = rtio_sqe_acquire(data->rtio_ctx);
const uint8_t reg[2] = {ADXL367_SPI_READ_REG, ADXL367_STATUS};
rtio_sqe_prep_tiny_write(write_status_addr, data->iodev, RTIO_PRIO_NORM, reg, 2, NULL);
write_status_addr->flags = RTIO_SQE_TRANSACTION;
rtio_sqe_prep_read(read_status_reg, data->iodev, RTIO_PRIO_NORM, &data->status, 1, NULL);
read_status_reg->flags = RTIO_SQE_CHAINED;
rtio_sqe_prep_callback(check_status_reg, adxl367_process_status_cb, (void *)dev, NULL);
rtio_submit(data->rtio_ctx, 0);
}

View file

@ -16,6 +16,7 @@
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(ADXL367, CONFIG_SENSOR_LOG_LEVEL);
#if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD) || defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD)
static void adxl367_thread_cb(const struct device *dev)
{
const struct adxl367_dev_config *cfg = dev->config;
@ -45,6 +46,7 @@ static void adxl367_thread_cb(const struct device *dev)
GPIO_INT_EDGE_TO_ACTIVE);
__ASSERT(ret == 0, "Interrupt configuration failed");
}
#endif /* CONFIG_ADXL367_TRIGGER_OWN_THREAD || CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD */
static void adxl367_gpio_callback(const struct device *dev,
struct gpio_callback *cb, uint32_t pins)
@ -55,6 +57,10 @@ static void adxl367_gpio_callback(const struct device *dev,
gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_DISABLE);
if (IS_ENABLED(CONFIG_ADXL367_STREAM)) {
adxl367_stream_irq_handler(drv_data->dev);
}
#if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD)
k_sem_give(&drv_data->gpio_sem);
#elif defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD)