zephyr/drivers/sensor/bosch/bmi08x/bmi08x_gyro_trigger.c
Wenxi Xu a490c90dc3 drivers: sensor: bmi08x: fix interfaceand trigger
1. Temperature Interface
According to BMI08x datasheet, temperature reading
requires both MSB and LSB bytes to be read and
processed correctly.

Temp data processing should follow the formula:
Temp in °C = (temp_msb * 8) + (temp_lsb / 32)

This patch implements the correct reading
sequence and calculation method as specified
in the datasheet.

2. Trigger Setting
Previously we set handler and then trigger struct.
However under some situation, as long as we set
the handler, we get into ISR immediately and never
set trigger struct.
I simply changed the sequence.

Testing:
- Verified temperature readings match datasheet
- Tested on stm32f407igh board with BMI08x sensor

Fixes: #82375

Signed-off-by: Wenxi Xu <xuwenxi0517@gmail.com>
2025-01-15 19:04:06 +01:00

135 lines
3.4 KiB
C

/* Bosch BMI08X inertial measurement unit driver, trigger implementation
*
* Copyright (c) 2022 Meta Platforms, Inc. and its affiliates
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/pm/device.h>
#include <zephyr/kernel.h>
#define DT_DRV_COMPAT bosch_bmi08x_gyro
#include "bmi08x.h"
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(BMI08X_GYRO, CONFIG_SENSOR_LOG_LEVEL);
static void bmi08x_handle_drdy_gyr(const struct device *dev)
{
struct bmi08x_gyro_data *data = dev->data;
#ifdef CONFIG_PM_DEVICE
enum pm_device_state state;
(void)pm_device_state_get(dev, &state);
if (state != PM_DEVICE_STATE_ACTIVE) {
return;
}
#endif
if (data->handler_drdy_gyr) {
data->handler_drdy_gyr(dev, data->drdy_trig_gyr);
}
}
static void bmi08x_handle_interrupts_gyr(void *arg)
{
const struct device *dev = (const struct device *)arg;
bmi08x_handle_drdy_gyr(dev);
}
#ifdef CONFIG_BMI08X_GYRO_TRIGGER_OWN_THREAD
static void bmi08x_gyr_thread_main(void *arg1, void *unused1, void *unused2)
{
k_thread_name_set(NULL, "bmi08x_gyr_trig");
ARG_UNUSED(unused1);
ARG_UNUSED(unused2);
const struct device *dev = (const struct device *)arg1;
struct bmi08x_gyro_data *data = dev->data;
while (1) {
k_sem_take(&data->sem, K_FOREVER);
bmi08x_handle_interrupts_gyr((void *)dev);
}
}
#endif
#ifdef CONFIG_BMI08X_GYRO_TRIGGER_GLOBAL_THREAD
static void bmi08x_gyr_work_handler(struct k_work *work)
{
struct bmi08x_gyro_data *data = CONTAINER_OF(work, struct bmi08x_gyro_data, work);
bmi08x_handle_interrupts_gyr((void *)data->dev);
}
#endif
static void bmi08x_gyr_gpio_callback(const struct device *port, struct gpio_callback *cb,
uint32_t pin)
{
struct bmi08x_gyro_data *data = CONTAINER_OF(cb, struct bmi08x_gyro_data, gpio_cb);
ARG_UNUSED(port);
ARG_UNUSED(pin);
#if defined(CONFIG_BMI08X_GYRO_TRIGGER_OWN_THREAD)
k_sem_give(&data->sem);
#elif defined(CONFIG_BMI08X_GYRO_TRIGGER_GLOBAL_THREAD)
k_work_submit(&data->work);
#endif
}
int bmi08x_trigger_set_gyr(const struct device *dev, const struct sensor_trigger *trig,
sensor_trigger_handler_t handler)
{
struct bmi08x_gyro_data *data = dev->data;
if ((trig->chan == SENSOR_CHAN_GYRO_XYZ) && (trig->type == SENSOR_TRIG_DATA_READY)) {
data->drdy_trig_gyr = trig;
data->handler_drdy_gyr = handler;
return 0;
}
return -ENOTSUP;
}
int bmi08x_gyr_trigger_mode_init(const struct device *dev)
{
struct bmi08x_gyro_data *data = dev->data;
const struct bmi08x_gyro_config *cfg = dev->config;
int ret;
if (!gpio_is_ready_dt(&cfg->int_gpio)) {
LOG_ERR("GPIO device not ready");
return -ENODEV;
}
#if defined(CONFIG_BMI08X_GYRO_TRIGGER_OWN_THREAD)
k_sem_init(&data->sem, 0, K_SEM_MAX_LIMIT);
k_thread_create(&data->thread, data->thread_stack,
CONFIG_BMI08X_GYRO_THREAD_STACK_SIZE, bmi08x_gyr_thread_main, (void *)dev,
NULL, NULL, K_PRIO_COOP(CONFIG_BMI08X_GYRO_THREAD_PRIORITY), 0, K_NO_WAIT);
#elif defined(CONFIG_BMI08X_GYRO_TRIGGER_GLOBAL_THREAD)
data->work.handler = bmi08x_gyr_work_handler;
data->dev = dev;
#endif
gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INPUT);
gpio_init_callback(&data->gpio_cb, bmi08x_gyr_gpio_callback, BIT(cfg->int_gpio.pin));
ret = gpio_add_callback(cfg->int_gpio.port, &data->gpio_cb);
if (ret < 0) {
LOG_ERR("Failed to set gpio callback.");
return ret;
}
gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_EDGE_TO_ACTIVE);
return ret;
}