drivers: sensor: akm09918: make submit function more unblocking
The driver now does not wait for the completion of a measurement in the submit function. Instead it schedule the fetch and the completion of the submission queue entry as delayed work to the system work queue. Signed-off-by: Florian Weber <Florian.Weber@live.de>
This commit is contained in:
parent
3b6555a992
commit
1a89d4b13e
3 changed files with 109 additions and 35 deletions
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Google LLC
|
||||
* Copyright (c) 2024 Florian Weber <Florian.Weber@live.de>
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
|
@ -21,21 +22,16 @@
|
|||
LOG_MODULE_REGISTER(AKM09918C, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
/**
|
||||
* @brief Perform the bus transaction to fetch samples
|
||||
* @brief Perform the bus transaction to start measurement.
|
||||
*
|
||||
* @param dev Sensor device to operate on
|
||||
* @param chan Channel ID to fetch
|
||||
* @param x Location to write X channel sample.
|
||||
* @param y Location to write Y channel sample.
|
||||
* @param z Location to write Z channel sample.
|
||||
* @param chan Channel ID for starting the measurement
|
||||
* @return int 0 if successful or error code
|
||||
*/
|
||||
int akm09918c_sample_fetch_helper(const struct device *dev, enum sensor_channel chan, int16_t *x,
|
||||
int16_t *y, int16_t *z)
|
||||
int akm09918c_start_measurement(const struct device *dev, enum sensor_channel chan)
|
||||
{
|
||||
struct akm09918c_data *data = dev->data;
|
||||
const struct akm09918c_config *cfg = dev->config;
|
||||
uint8_t buf[9] = {0};
|
||||
|
||||
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_MAGN_X && chan != SENSOR_CHAN_MAGN_Y &&
|
||||
chan != SENSOR_CHAN_MAGN_Z && chan != SENSOR_CHAN_MAGN_XYZ) {
|
||||
|
|
@ -49,11 +45,24 @@ int akm09918c_sample_fetch_helper(const struct device *dev, enum sensor_channel
|
|||
LOG_ERR("Failed to start measurement.");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Wait for sample */
|
||||
LOG_DBG("Waiting for sample...");
|
||||
k_usleep(AKM09918C_MEASURE_TIME_US);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Perform the bus transaction to fetch samples.
|
||||
*
|
||||
* @param dev Sensor device to operate on
|
||||
* @param chan Channel ID to fetch
|
||||
* @param x Location to write X channel sample.
|
||||
* @param y Location to write Y channel sample.
|
||||
* @param z Location to write Z channel sample.
|
||||
* @return int 0 if successful or error code
|
||||
*/
|
||||
int akm09918c_fetch_measurement(const struct device *dev, int16_t *x, int16_t *y, int16_t *z)
|
||||
{
|
||||
const struct akm09918c_config *cfg = dev->config;
|
||||
uint8_t buf[9] = {0};
|
||||
|
||||
/* We have to read through the TMPS register or the data_ready bit won't clear */
|
||||
if (i2c_burst_read_dt(&cfg->i2c, AKM09918C_REG_ST1, buf, ARRAY_SIZE(buf)) != 0) {
|
||||
|
|
@ -77,8 +86,16 @@ static int akm09918c_sample_fetch(const struct device *dev, enum sensor_channel
|
|||
{
|
||||
struct akm09918c_data *data = dev->data;
|
||||
|
||||
return akm09918c_sample_fetch_helper(dev, chan, &data->x_sample, &data->y_sample,
|
||||
&data->z_sample);
|
||||
int ret = akm09918c_start_measurement(dev, chan);
|
||||
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
/* Wait for sample */
|
||||
LOG_DBG("Waiting for sample...");
|
||||
k_usleep(AKM09918C_MEASURE_TIME_US);
|
||||
|
||||
return akm09918c_fetch_measurement(dev, &data->x_sample, &data->y_sample, &data->z_sample);
|
||||
}
|
||||
|
||||
static void akm09918c_convert(struct sensor_value *val, int16_t sample)
|
||||
|
|
@ -213,7 +230,10 @@ static int akm09918c_init(const struct device *dev)
|
|||
return rc;
|
||||
}
|
||||
data->mode = AKM09918C_CNTL2_PWR_DOWN;
|
||||
|
||||
#ifdef CONFIG_SENSOR_ASYNC_API
|
||||
/* init work for fetching after measurement has completed */
|
||||
k_work_init_delayable(&data->work_ctx.async_fetch_work, akm09918_async_fetch);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Google LLC
|
||||
* Copyright (c) 2024 Florian Weber <Florian.Weber@live.de>
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
|
@ -34,6 +35,13 @@ struct akm09918c_data {
|
|||
int16_t y_sample;
|
||||
int16_t z_sample;
|
||||
uint8_t mode;
|
||||
#ifdef CONFIG_SENSOR_ASYNC_API
|
||||
struct akm09918c_async_fetch_ctx {
|
||||
struct rtio_iodev_sqe *iodev_sqe;
|
||||
uint64_t timestamp;
|
||||
struct k_work_delayable async_fetch_work;
|
||||
} work_ctx;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct akm09918c_config {
|
||||
|
|
@ -74,22 +82,23 @@ static inline void akm09918c_reg_to_hz(uint8_t reg, struct sensor_value *val)
|
|||
break;
|
||||
}
|
||||
}
|
||||
int akm09918c_start_measurement(const struct device *dev, enum sensor_channel chan);
|
||||
|
||||
int akm09918c_fetch_measurement(const struct device *dev, int16_t *x, int16_t *y, int16_t *z);
|
||||
/*
|
||||
* RTIO types
|
||||
*/
|
||||
|
||||
struct akm09918c_decoder_header {
|
||||
uint64_t timestamp;
|
||||
} __attribute__((__packed__));
|
||||
} __packed;
|
||||
|
||||
struct akm09918c_encoded_data {
|
||||
struct akm09918c_decoder_header header;
|
||||
int16_t readings[3];
|
||||
};
|
||||
|
||||
int akm09918c_sample_fetch_helper(const struct device *dev, enum sensor_channel chan, int16_t *x,
|
||||
int16_t *y, int16_t *z);
|
||||
void akm09918_async_fetch(struct k_work *work);
|
||||
|
||||
int akm09918c_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Google LLC
|
||||
* Copyright (c) 2024 Croxel Inc.
|
||||
* Copyright (c) 2024 Florian Weber <Florian.Weber@live.de>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
|
@ -16,32 +17,46 @@ void akm09918c_submit_sync(struct rtio_iodev_sqe *iodev_sqe)
|
|||
{
|
||||
const struct sensor_read_config *cfg = iodev_sqe->sqe.iodev->data;
|
||||
const struct device *dev = cfg->sensor;
|
||||
uint32_t min_buf_len = sizeof(struct akm09918c_encoded_data);
|
||||
struct akm09918c_data *data = dev->data;
|
||||
const struct sensor_chan_spec *const channels = cfg->channels;
|
||||
const size_t num_channels = cfg->count;
|
||||
int rc;
|
||||
uint8_t *buf;
|
||||
uint32_t buf_len;
|
||||
struct akm09918c_encoded_data *edata;
|
||||
|
||||
/* Get the buffer for the frame, it may be allocated dynamically by the rtio context */
|
||||
rc = rtio_sqe_rx_buf(iodev_sqe, min_buf_len, min_buf_len, &buf, &buf_len);
|
||||
/* Check if the requested channels are supported */
|
||||
for (size_t i = 0; i < num_channels; i++) {
|
||||
switch (channels[i].chan_type) {
|
||||
case SENSOR_CHAN_MAGN_X:
|
||||
case SENSOR_CHAN_MAGN_Y:
|
||||
case SENSOR_CHAN_MAGN_Z:
|
||||
case SENSOR_CHAN_MAGN_XYZ:
|
||||
case SENSOR_CHAN_ALL:
|
||||
break;
|
||||
default:
|
||||
LOG_ERR("Unsupported channel type %d", channels[i].chan_type);
|
||||
rtio_iodev_sqe_err(iodev_sqe, -ENOTSUP);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* start the measurement in the sensor */
|
||||
rc = akm09918c_start_measurement(dev, SENSOR_CHAN_MAGN_XYZ);
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Failed to get a read buffer of size %u bytes", min_buf_len);
|
||||
LOG_ERR("Failed to fetch samples.");
|
||||
rtio_iodev_sqe_err(iodev_sqe, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
edata = (struct akm09918c_encoded_data *)buf;
|
||||
edata->header.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks());
|
||||
/* save information for the work item */
|
||||
data->work_ctx.timestamp = k_ticks_to_ns_floor64(k_uptime_ticks());
|
||||
data->work_ctx.iodev_sqe = iodev_sqe;
|
||||
|
||||
rc = akm09918c_sample_fetch_helper(dev, SENSOR_CHAN_MAGN_XYZ, &edata->readings[0],
|
||||
&edata->readings[1], &edata->readings[2]);
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Failed to fetch samples");
|
||||
rtio_iodev_sqe_err(iodev_sqe, rc);
|
||||
return;
|
||||
rc = k_work_schedule(&data->work_ctx.async_fetch_work, K_USEC(AKM09918C_MEASURE_TIME_US));
|
||||
if (rc == 0) {
|
||||
LOG_ERR("The last fetch has not finished yet. "
|
||||
"Try again later when the last sensor read operation has finished.");
|
||||
rtio_iodev_sqe_err(iodev_sqe, -EBUSY);
|
||||
}
|
||||
|
||||
rtio_iodev_sqe_ok(iodev_sqe, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
void akm09918c_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
|
||||
|
|
@ -57,3 +72,33 @@ void akm09918c_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe
|
|||
|
||||
rtio_work_req_submit(req, iodev_sqe, akm09918c_submit_sync);
|
||||
}
|
||||
|
||||
void akm09918_async_fetch(struct k_work *work)
|
||||
{
|
||||
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
|
||||
struct akm09918c_async_fetch_ctx *ctx =
|
||||
CONTAINER_OF(dwork, struct akm09918c_async_fetch_ctx, async_fetch_work);
|
||||
const struct sensor_read_config *cfg = ctx->iodev_sqe->sqe.iodev->data;
|
||||
const struct device *dev = cfg->sensor;
|
||||
uint32_t req_buf_len = sizeof(struct akm09918c_encoded_data);
|
||||
uint32_t buf_len;
|
||||
uint8_t *buf;
|
||||
struct akm09918c_encoded_data *edata;
|
||||
int rc;
|
||||
|
||||
/* Get the buffer for the frame, it may be allocated dynamically by the rtio context */
|
||||
rc = rtio_sqe_rx_buf(ctx->iodev_sqe, req_buf_len, req_buf_len, &buf, &buf_len);
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Failed to get a read buffer of size %u bytes", req_buf_len);
|
||||
rtio_iodev_sqe_err(ctx->iodev_sqe, rc);
|
||||
return;
|
||||
}
|
||||
edata = (struct akm09918c_encoded_data *)buf;
|
||||
rc = akm09918c_fetch_measurement(dev, &edata->readings[0], &edata->readings[1],
|
||||
&edata->readings[2]);
|
||||
if (rc != 0) {
|
||||
rtio_iodev_sqe_err(ctx->iodev_sqe, rc);
|
||||
return;
|
||||
}
|
||||
rtio_iodev_sqe_ok(ctx->iodev_sqe, 0);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue