mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-10-17 02:45:05 +00:00
Kernel IMU API (#650)
This commit is contained in:
parent
8556103eb1
commit
70af88ca5b
@ -2,6 +2,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <tactility/drivers/imu.h>
|
||||
#include <tactility/error.h>
|
||||
|
||||
struct Device;
|
||||
@ -15,18 +16,29 @@ struct Bmi270Config {
|
||||
uint8_t address;
|
||||
};
|
||||
|
||||
struct Bmi270Data {
|
||||
float ax, ay, az; // acceleration in g (±8g range)
|
||||
float gx, gy, gz; // angular rate in °/s (±2000°/s range)
|
||||
};
|
||||
|
||||
/**
|
||||
* Read accelerometer and gyroscope data.
|
||||
* Read accelerometer data only.
|
||||
* @param[in] device bmi270 device
|
||||
* @param[out] data Pointer to Bmi270Data structure to store the data
|
||||
* @param[out] data Pointer to ImuAccelData structure to store the data (±8g range)
|
||||
* @return ERROR_NONE on success
|
||||
*/
|
||||
error_t bmi270_read(struct Device* device, struct Bmi270Data* data);
|
||||
error_t bmi270_read_accel(struct Device* device, struct ImuAccelData* data);
|
||||
|
||||
/**
|
||||
* Read gyroscope data only.
|
||||
* @param[in] device bmi270 device
|
||||
* @param[out] data Pointer to ImuGyroData structure to store the data (±2000°/s range)
|
||||
* @return ERROR_NONE on success
|
||||
*/
|
||||
error_t bmi270_read_gyro(struct Device* device, struct ImuGyroData* data);
|
||||
|
||||
/**
|
||||
* Read the chip's on-die temperature.
|
||||
* @param[in] device bmi270 device
|
||||
* @param[out] temperature_c Pointer to store the temperature, in °C
|
||||
* @return ERROR_NONE on success
|
||||
*/
|
||||
error_t bmi270_read_temperature(struct Device* device, float* temperature_c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
static constexpr uint8_t REG_CHIP_ID = 0x00; // read: expect 0x24
|
||||
static constexpr uint8_t REG_DATA_ACC = 0x0C; // 6 bytes: acc X/Y/Z LSB/MSB
|
||||
static constexpr uint8_t REG_DATA_GYR = 0x12; // 6 bytes: gyr X/Y/Z LSB/MSB
|
||||
static constexpr uint8_t REG_TEMPERATURE = 0x22; // 2 bytes: on-die temperature, 0x8000 = invalid
|
||||
static constexpr uint8_t REG_INTERNAL_ST = 0x21; // bit0: init done
|
||||
static constexpr uint8_t REG_ACC_CONF = 0x40; // ODR + BWP + filter_perf
|
||||
static constexpr uint8_t REG_ACC_RANGE = 0x41; // range selector
|
||||
@ -152,14 +153,11 @@ static error_t stop(Device* device) {
|
||||
|
||||
extern "C" {
|
||||
|
||||
error_t bmi270_read(Device* device, Bmi270Data* data) {
|
||||
error_t bmi270_read_accel(Device* device, ImuAccelData* data) {
|
||||
auto* i2c_controller = device_get_parent(device);
|
||||
|
||||
auto address = GET_CONFIG(device)->address;
|
||||
|
||||
// Burst-read 12 bytes: acc X/Y/Z (6 bytes) + gyro X/Y/Z (6 bytes)
|
||||
// Registers: 0x0C–0x17 are contiguous for acc+gyro in I2C mode (no dummy byte)
|
||||
uint8_t buffer[12] = {};
|
||||
uint8_t buffer[6] = {};
|
||||
error_t error = i2c_controller_read_register(i2c_controller, address, REG_DATA_ACC, buffer, sizeof(buffer), I2C_TIMEOUT_TICKS);
|
||||
if (error != ERROR_NONE) return error;
|
||||
|
||||
@ -167,23 +165,61 @@ error_t bmi270_read(Device* device, Bmi270Data* data) {
|
||||
return static_cast<int16_t>(static_cast<uint16_t>(hi) << 8 | lo);
|
||||
};
|
||||
|
||||
data->ax = toI16(buffer[0], buffer[1]) * ACCEL_SCALE;
|
||||
data->ay = toI16(buffer[2], buffer[3]) * ACCEL_SCALE;
|
||||
data->az = toI16(buffer[4], buffer[5]) * ACCEL_SCALE;
|
||||
data->gx = toI16(buffer[6], buffer[7]) * GYRO_SCALE;
|
||||
data->gy = toI16(buffer[8], buffer[9]) * GYRO_SCALE;
|
||||
data->gz = toI16(buffer[10], buffer[11]) * GYRO_SCALE;
|
||||
data->ax = toI16(buffer[0], buffer[1]) * ACCEL_SCALE;
|
||||
data->ay = toI16(buffer[2], buffer[3]) * ACCEL_SCALE;
|
||||
data->az = toI16(buffer[4], buffer[5]) * ACCEL_SCALE;
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t bmi270_read_gyro(Device* device, ImuGyroData* data) {
|
||||
auto* i2c_controller = device_get_parent(device);
|
||||
auto address = GET_CONFIG(device)->address;
|
||||
|
||||
uint8_t buffer[6] = {};
|
||||
error_t error = i2c_controller_read_register(i2c_controller, address, REG_DATA_GYR, buffer, sizeof(buffer), I2C_TIMEOUT_TICKS);
|
||||
if (error != ERROR_NONE) return error;
|
||||
|
||||
auto toI16 = [](uint8_t lo, uint8_t hi) -> int16_t {
|
||||
return static_cast<int16_t>(static_cast<uint16_t>(hi) << 8 | lo);
|
||||
};
|
||||
|
||||
data->gx = toI16(buffer[0], buffer[1]) * GYRO_SCALE;
|
||||
data->gy = toI16(buffer[2], buffer[3]) * GYRO_SCALE;
|
||||
data->gz = toI16(buffer[4], buffer[5]) * GYRO_SCALE;
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t bmi270_read_temperature(Device* device, float* temperature_c) {
|
||||
auto* i2c_controller = device_get_parent(device);
|
||||
auto address = GET_CONFIG(device)->address;
|
||||
|
||||
uint8_t buffer[2] = {};
|
||||
error_t error = i2c_controller_read_register(i2c_controller, address, REG_TEMPERATURE, buffer, sizeof(buffer), I2C_TIMEOUT_TICKS);
|
||||
if (error != ERROR_NONE) return error;
|
||||
|
||||
uint16_t raw = static_cast<uint16_t>(buffer[1]) << 8 | buffer[0];
|
||||
if (raw == 0x8000) return ERROR_NOT_FOUND; // sensor reports "invalid" (not enabled/not ready)
|
||||
|
||||
// Datasheet: temperature = raw / 512 + 23 (°C), raw is a signed 16-bit value
|
||||
*temperature_c = static_cast<int16_t>(raw) / 512.0f + 23.0f;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
ImuApi bmi270_imu_api = {
|
||||
.read_accel = bmi270_read_accel,
|
||||
.read_gyro = bmi270_read_gyro,
|
||||
.read_temperature = bmi270_read_temperature
|
||||
};
|
||||
|
||||
Driver bmi270_driver = {
|
||||
.name = "bmi270",
|
||||
.compatible = (const char*[]) { "bosch,bmi270", nullptr},
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.api = nullptr,
|
||||
.device_type = nullptr,
|
||||
.api = &bmi270_imu_api,
|
||||
.device_type = &IMU_TYPE,
|
||||
.owner = &bmi270_module,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
@ -11,12 +11,9 @@ static Driver* const bmi270_drivers[] = {
|
||||
nullptr
|
||||
};
|
||||
|
||||
extern const ModuleSymbol bmi270_module_symbols[];
|
||||
|
||||
Module bmi270_module = {
|
||||
.name = "bmi270",
|
||||
.drivers = bmi270_drivers,
|
||||
.symbols = bmi270_module_symbols
|
||||
.drivers = bmi270_drivers
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <drivers/bmi270.h>
|
||||
#include <tactility/module.h>
|
||||
|
||||
const struct ModuleSymbol bmi270_module_symbols[] = {
|
||||
DEFINE_MODULE_SYMBOL(bmi270_read),
|
||||
MODULE_SYMBOL_TERMINATOR
|
||||
};
|
||||
@ -2,6 +2,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <tactility/drivers/imu.h>
|
||||
#include <tactility/error.h>
|
||||
|
||||
struct Device;
|
||||
@ -15,18 +16,29 @@ struct Mpu6886Config {
|
||||
uint8_t address;
|
||||
};
|
||||
|
||||
struct Mpu6886Data {
|
||||
float ax, ay, az; // acceleration in g (±8g range)
|
||||
float gx, gy, gz; // angular rate in °/s (±2000°/s range)
|
||||
};
|
||||
|
||||
/**
|
||||
* Read accelerometer and gyroscope data.
|
||||
* Read accelerometer data only.
|
||||
* @param[in] device mpu6886 device
|
||||
* @param[out] data Pointer to Mpu6886Data to populate
|
||||
* @param[out] data Pointer to ImuAccelData to populate (±8g range)
|
||||
* @return ERROR_NONE on success
|
||||
*/
|
||||
error_t mpu6886_read(struct Device* device, struct Mpu6886Data* data);
|
||||
error_t mpu6886_read_accel(struct Device* device, struct ImuAccelData* data);
|
||||
|
||||
/**
|
||||
* Read gyroscope data only.
|
||||
* @param[in] device mpu6886 device
|
||||
* @param[out] data Pointer to ImuGyroData to populate (±2000°/s range)
|
||||
* @return ERROR_NONE on success
|
||||
*/
|
||||
error_t mpu6886_read_gyro(struct Device* device, struct ImuGyroData* data);
|
||||
|
||||
/**
|
||||
* Read the chip's on-die temperature.
|
||||
* @param[in] device mpu6886 device
|
||||
* @param[out] temperature_c Pointer to store the temperature, in °C
|
||||
* @return ERROR_NONE on success
|
||||
*/
|
||||
error_t mpu6886_read_temperature(struct Device* device, float* temperature_c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -11,12 +11,9 @@ static Driver* const mpu6886_drivers[] = {
|
||||
nullptr
|
||||
};
|
||||
|
||||
extern const ModuleSymbol mpu6886_module_symbols[];
|
||||
|
||||
Module mpu6886_module = {
|
||||
.name = "mpu6886",
|
||||
.drivers = mpu6886_drivers,
|
||||
.symbols = mpu6886_module_symbols,
|
||||
.drivers = mpu6886_drivers
|
||||
};
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@ -16,6 +16,7 @@ static constexpr uint8_t REG_ACCEL_CONFIG2 = 0x1D; // accel low-pass filter
|
||||
static constexpr uint8_t REG_INT_PIN_CFG = 0x37; // interrupt pin config
|
||||
static constexpr uint8_t REG_INT_ENABLE = 0x38; // interrupt enable
|
||||
static constexpr uint8_t REG_ACCEL_XOUT_H = 0x3B; // first accel output register
|
||||
static constexpr uint8_t REG_TEMP_OUT_H = 0x41; // temperature output register
|
||||
static constexpr uint8_t REG_GYRO_XOUT_H = 0x43; // first gyro output register
|
||||
static constexpr uint8_t REG_USER_CTRL = 0x6A; // user control (DMP, FIFO, I2C)
|
||||
static constexpr uint8_t REG_PWR_MGMT_1 = 0x6B; // power management 1
|
||||
@ -126,38 +127,72 @@ static error_t stop(Device* device) {
|
||||
|
||||
extern "C" {
|
||||
|
||||
error_t mpu6886_read(Device* device, Mpu6886Data* data) {
|
||||
error_t mpu6886_read_accel(Device* device, ImuAccelData* data) {
|
||||
auto* i2c_controller = device_get_parent(device);
|
||||
auto address = GET_CONFIG(device)->address;
|
||||
|
||||
// MPU6886 is big-endian (MSB first), unlike BMI270
|
||||
auto toI16 = [](uint8_t hi, uint8_t lo) -> int16_t {
|
||||
return static_cast<int16_t>(static_cast<uint16_t>(hi) << 8 | lo);
|
||||
};
|
||||
|
||||
// Burst read: accel (6) + temp (2) + gyro (6) = 14 bytes at 0x3B
|
||||
uint8_t buf[14] = {};
|
||||
uint8_t buf[6] = {};
|
||||
error_t error = i2c_controller_read_register(i2c_controller, address, REG_ACCEL_XOUT_H, buf, sizeof(buf), I2C_TIMEOUT_TICKS);
|
||||
if (error != ERROR_NONE) return error;
|
||||
|
||||
data->ax = toI16(buf[0], buf[1]) * ACCEL_SCALE;
|
||||
data->ay = toI16(buf[2], buf[3]) * ACCEL_SCALE;
|
||||
data->az = toI16(buf[4], buf[5]) * ACCEL_SCALE;
|
||||
// buf[6..7] = temperature (skipped)
|
||||
data->gx = toI16(buf[8], buf[9]) * GYRO_SCALE;
|
||||
data->gy = toI16(buf[10], buf[11]) * GYRO_SCALE;
|
||||
data->gz = toI16(buf[12], buf[13]) * GYRO_SCALE;
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t mpu6886_read_gyro(Device* device, ImuGyroData* data) {
|
||||
auto* i2c_controller = device_get_parent(device);
|
||||
auto address = GET_CONFIG(device)->address;
|
||||
|
||||
auto toI16 = [](uint8_t hi, uint8_t lo) -> int16_t {
|
||||
return static_cast<int16_t>(static_cast<uint16_t>(hi) << 8 | lo);
|
||||
};
|
||||
|
||||
uint8_t buf[6] = {};
|
||||
error_t error = i2c_controller_read_register(i2c_controller, address, REG_GYRO_XOUT_H, buf, sizeof(buf), I2C_TIMEOUT_TICKS);
|
||||
if (error != ERROR_NONE) return error;
|
||||
|
||||
data->gx = toI16(buf[0], buf[1]) * GYRO_SCALE;
|
||||
data->gy = toI16(buf[2], buf[3]) * GYRO_SCALE;
|
||||
data->gz = toI16(buf[4], buf[5]) * GYRO_SCALE;
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t mpu6886_read_temperature(Device* device, float* temperature_c) {
|
||||
auto* i2c_controller = device_get_parent(device);
|
||||
auto address = GET_CONFIG(device)->address;
|
||||
|
||||
uint8_t buf[2] = {};
|
||||
error_t error = i2c_controller_read_register(i2c_controller, address, REG_TEMP_OUT_H, buf, sizeof(buf), I2C_TIMEOUT_TICKS);
|
||||
if (error != ERROR_NONE) return error;
|
||||
|
||||
auto raw = static_cast<int16_t>(static_cast<uint16_t>(buf[0]) << 8 | buf[1]);
|
||||
|
||||
// Datasheet: temperature = raw / 326.8 + 25 (°C)
|
||||
*temperature_c = static_cast<float>(raw) / 326.8f + 25.0f;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
ImuApi mpu6886_imu_api = {
|
||||
.read_accel = mpu6886_read_accel,
|
||||
.read_gyro = mpu6886_read_gyro,
|
||||
.read_temperature = mpu6886_read_temperature
|
||||
};
|
||||
|
||||
Driver mpu6886_driver = {
|
||||
.name = "mpu6886",
|
||||
.compatible = (const char*[]) { "invensense,mpu6886", nullptr },
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.api = nullptr,
|
||||
.device_type = nullptr,
|
||||
.api = &mpu6886_imu_api,
|
||||
.device_type = &IMU_TYPE,
|
||||
.owner = &mpu6886_module,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <drivers/mpu6886.h>
|
||||
#include <tactility/module.h>
|
||||
|
||||
const struct ModuleSymbol mpu6886_module_symbols[] = {
|
||||
DEFINE_MODULE_SYMBOL(mpu6886_read),
|
||||
MODULE_SYMBOL_TERMINATOR
|
||||
};
|
||||
@ -2,6 +2,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <tactility/drivers/imu.h>
|
||||
#include <tactility/error.h>
|
||||
|
||||
struct Device;
|
||||
@ -15,18 +16,29 @@ struct Qmi8658Config {
|
||||
uint8_t address;
|
||||
};
|
||||
|
||||
struct Qmi8658Data {
|
||||
float ax, ay, az; // acceleration in g (±8g range)
|
||||
float gx, gy, gz; // angular rate in °/s (±2048°/s range)
|
||||
};
|
||||
|
||||
/**
|
||||
* Read accelerometer and gyroscope data.
|
||||
* Read accelerometer data only.
|
||||
* @param[in] device qmi8658 device
|
||||
* @param[out] data Pointer to Qmi8658Data to populate
|
||||
* @param[out] data Pointer to ImuAccelData to populate (±8g range)
|
||||
* @return ERROR_NONE on success
|
||||
*/
|
||||
error_t qmi8658_read(struct Device* device, struct Qmi8658Data* data);
|
||||
error_t qmi8658_read_accel(struct Device* device, struct ImuAccelData* data);
|
||||
|
||||
/**
|
||||
* Read gyroscope data only.
|
||||
* @param[in] device qmi8658 device
|
||||
* @param[out] data Pointer to ImuGyroData to populate (±2048°/s range)
|
||||
* @return ERROR_NONE on success
|
||||
*/
|
||||
error_t qmi8658_read_gyro(struct Device* device, struct ImuGyroData* data);
|
||||
|
||||
/**
|
||||
* Read the chip's on-die temperature.
|
||||
* @param[in] device qmi8658 device
|
||||
* @param[out] temperature_c Pointer to store the temperature, in °C
|
||||
* @return ERROR_NONE on success
|
||||
*/
|
||||
error_t qmi8658_read_temperature(struct Device* device, float* temperature_c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -11,12 +11,9 @@ static Driver* const qmi8658_drivers[] = {
|
||||
nullptr
|
||||
};
|
||||
|
||||
extern const ModuleSymbol qmi8658_module_symbols[];
|
||||
|
||||
Module qmi8658_module = {
|
||||
.name = "qmi8658",
|
||||
.drivers = qmi8658_drivers,
|
||||
.symbols = qmi8658_module_symbols,
|
||||
.drivers = qmi8658_drivers
|
||||
};
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@ -13,7 +13,9 @@ static constexpr uint8_t REG_CTRL1 = 0x02; // serial interface config
|
||||
static constexpr uint8_t REG_CTRL2 = 0x03; // accel: range[6:4] + ODR[3:0]
|
||||
static constexpr uint8_t REG_CTRL3 = 0x04; // gyro: range[6:4] + ODR[3:0]
|
||||
static constexpr uint8_t REG_CTRL7 = 0x08; // sensor enable: bit0=accel, bit1=gyro
|
||||
static constexpr uint8_t REG_TEMP_L = 0x33; // 2 bytes: on-die temperature
|
||||
static constexpr uint8_t REG_AX_L = 0x35; // first data register (accel X LSB)
|
||||
static constexpr uint8_t REG_GX_L = 0x3B; // first gyro data register (gyro X LSB)
|
||||
|
||||
static constexpr uint8_t WHO_AM_I_VALUE = 0x05;
|
||||
|
||||
@ -93,13 +95,11 @@ static error_t stop(Device* device) {
|
||||
|
||||
extern "C" {
|
||||
|
||||
error_t qmi8658_read(Device* device, Qmi8658Data* data) {
|
||||
error_t qmi8658_read_accel(Device* device, ImuAccelData* data) {
|
||||
auto* i2c_controller = device_get_parent(device);
|
||||
auto address = GET_CONFIG(device)->address;
|
||||
|
||||
// Burst-read 12 bytes starting at AX_L (0x35): accel X/Y/Z then gyro X/Y/Z
|
||||
// QMI8658 is little-endian (LSB first), same as BMI270
|
||||
uint8_t buf[12] = {};
|
||||
uint8_t buf[6] = {};
|
||||
error_t error = i2c_controller_read_register(i2c_controller, address, REG_AX_L, buf, sizeof(buf), I2C_TIMEOUT_TICKS);
|
||||
if (error != ERROR_NONE) return error;
|
||||
|
||||
@ -107,23 +107,60 @@ error_t qmi8658_read(Device* device, Qmi8658Data* data) {
|
||||
return static_cast<int16_t>(static_cast<uint16_t>(hi) << 8 | lo);
|
||||
};
|
||||
|
||||
data->ax = toI16(buf[0], buf[1]) * ACCEL_SCALE;
|
||||
data->ay = toI16(buf[2], buf[3]) * ACCEL_SCALE;
|
||||
data->az = toI16(buf[4], buf[5]) * ACCEL_SCALE;
|
||||
data->gx = toI16(buf[6], buf[7]) * GYRO_SCALE;
|
||||
data->gy = toI16(buf[8], buf[9]) * GYRO_SCALE;
|
||||
data->gz = toI16(buf[10], buf[11]) * GYRO_SCALE;
|
||||
data->ax = toI16(buf[0], buf[1]) * ACCEL_SCALE;
|
||||
data->ay = toI16(buf[2], buf[3]) * ACCEL_SCALE;
|
||||
data->az = toI16(buf[4], buf[5]) * ACCEL_SCALE;
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t qmi8658_read_gyro(Device* device, ImuGyroData* data) {
|
||||
auto* i2c_controller = device_get_parent(device);
|
||||
auto address = GET_CONFIG(device)->address;
|
||||
|
||||
uint8_t buf[6] = {};
|
||||
error_t error = i2c_controller_read_register(i2c_controller, address, REG_GX_L, buf, sizeof(buf), I2C_TIMEOUT_TICKS);
|
||||
if (error != ERROR_NONE) return error;
|
||||
|
||||
auto toI16 = [](uint8_t lo, uint8_t hi) -> int16_t {
|
||||
return static_cast<int16_t>(static_cast<uint16_t>(hi) << 8 | lo);
|
||||
};
|
||||
|
||||
data->gx = toI16(buf[0], buf[1]) * GYRO_SCALE;
|
||||
data->gy = toI16(buf[2], buf[3]) * GYRO_SCALE;
|
||||
data->gz = toI16(buf[4], buf[5]) * GYRO_SCALE;
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t qmi8658_read_temperature(Device* device, float* temperature_c) {
|
||||
auto* i2c_controller = device_get_parent(device);
|
||||
auto address = GET_CONFIG(device)->address;
|
||||
|
||||
uint8_t buf[2] = {};
|
||||
error_t error = i2c_controller_read_register(i2c_controller, address, REG_TEMP_L, buf, sizeof(buf), I2C_TIMEOUT_TICKS);
|
||||
if (error != ERROR_NONE) return error;
|
||||
|
||||
auto raw = static_cast<int16_t>(static_cast<uint16_t>(buf[1]) << 8 | buf[0]);
|
||||
|
||||
// Datasheet: temperature = raw / 256 (°C)
|
||||
*temperature_c = static_cast<float>(raw) / 256.0f;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
ImuApi qmi8658_imu_api = {
|
||||
.read_accel = qmi8658_read_accel,
|
||||
.read_gyro = qmi8658_read_gyro,
|
||||
.read_temperature = qmi8658_read_temperature
|
||||
};
|
||||
|
||||
Driver qmi8658_driver = {
|
||||
.name = "qmi8658",
|
||||
.compatible = (const char*[]) { "qst,qmi8658", nullptr },
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.api = nullptr,
|
||||
.device_type = nullptr,
|
||||
.api = &qmi8658_imu_api,
|
||||
.device_type = &IMU_TYPE,
|
||||
.owner = &qmi8658_module,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <drivers/qmi8658.h>
|
||||
#include <tactility/module.h>
|
||||
|
||||
const struct ModuleSymbol qmi8658_module_symbols[] = {
|
||||
DEFINE_MODULE_SYMBOL(qmi8658_read),
|
||||
MODULE_SYMBOL_TERMINATOR
|
||||
};
|
||||
77
TactilityKernel/include/tactility/drivers/imu.h
Normal file
77
TactilityKernel/include/tactility/drivers/imu.h
Normal file
@ -0,0 +1,77 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/error.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ImuAccelData {
|
||||
float ax, ay, az; // acceleration, in g
|
||||
};
|
||||
|
||||
struct ImuGyroData {
|
||||
float gx, gy, gz; // angular rate, in °/s
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief API for IMU (accelerometer + gyroscope) drivers.
|
||||
*
|
||||
* @note read_accel(), read_gyro() and read_temperature() are each a single-register-window I2C
|
||||
* transaction. All three are optional per driver: a driver that can't service one leaves it
|
||||
* NULL, and the matching imu_read_*() wrapper returns ERROR_NOT_SUPPORTED.
|
||||
*/
|
||||
struct ImuApi {
|
||||
/**
|
||||
* @brief Reads only the current accelerometer data.
|
||||
* @param[in] device the IMU device
|
||||
* @param[out] data pointer to store the current reading
|
||||
* @retval ERROR_NOT_SUPPORTED if the driver has no accel-only read path
|
||||
* @retval ERROR_NONE on success
|
||||
*/
|
||||
error_t (*read_accel)(struct Device* device, struct ImuAccelData* data);
|
||||
|
||||
/**
|
||||
* @brief Reads only the current gyroscope data.
|
||||
* @param[in] device the IMU device
|
||||
* @param[out] data pointer to store the current reading
|
||||
* @retval ERROR_NOT_SUPPORTED if the driver has no gyro-only read path
|
||||
* @retval ERROR_NONE on success
|
||||
*/
|
||||
error_t (*read_gyro)(struct Device* device, struct ImuGyroData* data);
|
||||
|
||||
/**
|
||||
* @brief Reads the chip's on-die temperature.
|
||||
* @param[in] device the IMU device
|
||||
* @param[out] temperature_c pointer to store the current reading, in °C
|
||||
* @retval ERROR_NOT_SUPPORTED if the driver has no temperature sensor/register
|
||||
* @retval ERROR_NONE on success
|
||||
*/
|
||||
error_t (*read_temperature)(struct Device* device, float* temperature_c);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Reads only the current accelerometer data using the specified IMU device.
|
||||
* @retval ERROR_NOT_SUPPORTED if the driver has no accel-only read path
|
||||
*/
|
||||
error_t imu_read_accel(struct Device* device, struct ImuAccelData* data);
|
||||
|
||||
/**
|
||||
* @brief Reads only the current gyroscope data using the specified IMU device.
|
||||
* @retval ERROR_NOT_SUPPORTED if the driver has no gyro-only read path
|
||||
*/
|
||||
error_t imu_read_gyro(struct Device* device, struct ImuGyroData* data);
|
||||
|
||||
/**
|
||||
* @brief Reads the chip's on-die temperature using the specified IMU device, in °C.
|
||||
* @retval ERROR_NOT_SUPPORTED if the driver has no temperature sensor/register
|
||||
*/
|
||||
error_t imu_read_temperature(struct Device* device, float* temperature_c);
|
||||
|
||||
extern const struct DeviceType IMU_TYPE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
34
TactilityKernel/source/drivers/imu.cpp
Normal file
34
TactilityKernel/source/drivers/imu.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <tactility/drivers/imu.h>
|
||||
#include <tactility/device.h>
|
||||
|
||||
#define IMU_DRIVER_API(driver) ((struct ImuApi*)driver->api)
|
||||
|
||||
extern "C" {
|
||||
|
||||
error_t imu_read_accel(Device* device, ImuAccelData* data) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
auto* api = IMU_DRIVER_API(driver);
|
||||
if (!api->read_accel) return ERROR_NOT_SUPPORTED;
|
||||
return api->read_accel(device, data);
|
||||
}
|
||||
|
||||
error_t imu_read_gyro(Device* device, ImuGyroData* data) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
auto* api = IMU_DRIVER_API(driver);
|
||||
if (!api->read_gyro) return ERROR_NOT_SUPPORTED;
|
||||
return api->read_gyro(device, data);
|
||||
}
|
||||
|
||||
error_t imu_read_temperature(Device* device, float* temperature_c) {
|
||||
const auto* driver = device_get_driver(device);
|
||||
auto* api = IMU_DRIVER_API(driver);
|
||||
if (!api->read_temperature) return ERROR_NOT_SUPPORTED;
|
||||
return api->read_temperature(device, temperature_c);
|
||||
}
|
||||
|
||||
const DeviceType IMU_TYPE {
|
||||
.name = "imu"
|
||||
};
|
||||
|
||||
}
|
||||
@ -23,6 +23,7 @@
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/drivers/i2s_controller.h>
|
||||
#include <tactility/drivers/i8080_controller.h>
|
||||
#include <tactility/drivers/imu.h>
|
||||
#include <tactility/drivers/keyboard.h>
|
||||
#include <tactility/drivers/lora.h>
|
||||
#include <tactility/drivers/pointer.h>
|
||||
@ -240,6 +241,11 @@ const struct ModuleSymbol KERNEL_SYMBOLS[] = {
|
||||
DEFINE_MODULE_SYMBOL(I2S_CONTROLLER_TYPE),
|
||||
// drivers/i8080_controller
|
||||
DEFINE_MODULE_SYMBOL(I8080_CONTROLLER_TYPE),
|
||||
// drivers/imu
|
||||
DEFINE_MODULE_SYMBOL(imu_read_accel),
|
||||
DEFINE_MODULE_SYMBOL(imu_read_gyro),
|
||||
DEFINE_MODULE_SYMBOL(imu_read_temperature),
|
||||
DEFINE_MODULE_SYMBOL(IMU_TYPE),
|
||||
// drivers/keyboard
|
||||
DEFINE_MODULE_SYMBOL(keyboard_read_key),
|
||||
DEFINE_MODULE_SYMBOL(KEYBOARD_TYPE),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user