diff --git a/Drivers/bmi270-module/include/drivers/bmi270.h b/Drivers/bmi270-module/include/drivers/bmi270.h index aa8227a60..ece8ef288 100644 --- a/Drivers/bmi270-module/include/drivers/bmi270.h +++ b/Drivers/bmi270-module/include/drivers/bmi270.h @@ -2,6 +2,7 @@ #pragma once #include +#include #include 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 data only. + * @param[in] device bmi270 device + * @param[out] data Pointer to ImuAccelData structure to store the data (±8g range) + * @return ERROR_NONE on success + */ +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 accelerometer and gyroscope data. + * Read the chip's on-die temperature. * @param[in] device bmi270 device - * @param[out] data Pointer to Bmi270Data structure to store the data + * @param[out] temperature_c Pointer to store the temperature, in °C * @return ERROR_NONE on success */ -error_t bmi270_read(struct Device* device, struct Bmi270Data* data); +error_t bmi270_read_temperature(struct Device* device, float* temperature_c); #ifdef __cplusplus } diff --git a/Drivers/bmi270-module/source/bmi270.cpp b/Drivers/bmi270-module/source/bmi270.cpp index d4ce55807..c42ba8da4 100644 --- a/Drivers/bmi270-module/source/bmi270.cpp +++ b/Drivers/bmi270-module/source/bmi270.cpp @@ -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(static_cast(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(static_cast(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(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(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 }; diff --git a/Drivers/bmi270-module/source/module.cpp b/Drivers/bmi270-module/source/module.cpp index 9dfac1285..2c8758dfe 100644 --- a/Drivers/bmi270-module/source/module.cpp +++ b/Drivers/bmi270-module/source/module.cpp @@ -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 }; } diff --git a/Drivers/bmi270-module/source/symbols.c b/Drivers/bmi270-module/source/symbols.c deleted file mode 100644 index 68dc957ce..000000000 --- a/Drivers/bmi270-module/source/symbols.c +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -#include -#include - -const struct ModuleSymbol bmi270_module_symbols[] = { - DEFINE_MODULE_SYMBOL(bmi270_read), - MODULE_SYMBOL_TERMINATOR -}; diff --git a/Drivers/mpu6886-module/include/drivers/mpu6886.h b/Drivers/mpu6886-module/include/drivers/mpu6886.h index 7de0a60ff..1a150d20b 100644 --- a/Drivers/mpu6886-module/include/drivers/mpu6886.h +++ b/Drivers/mpu6886-module/include/drivers/mpu6886.h @@ -2,6 +2,7 @@ #pragma once #include +#include #include 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 data only. + * @param[in] device mpu6886 device + * @param[out] data Pointer to ImuAccelData to populate (±8g range) + * @return ERROR_NONE on success + */ +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 accelerometer and gyroscope data. + * Read the chip's on-die temperature. * @param[in] device mpu6886 device - * @param[out] data Pointer to Mpu6886Data to populate + * @param[out] temperature_c Pointer to store the temperature, in °C * @return ERROR_NONE on success */ -error_t mpu6886_read(struct Device* device, struct Mpu6886Data* data); +error_t mpu6886_read_temperature(struct Device* device, float* temperature_c); #ifdef __cplusplus } diff --git a/Drivers/mpu6886-module/source/module.cpp b/Drivers/mpu6886-module/source/module.cpp index 99b530f09..0dfc26be9 100644 --- a/Drivers/mpu6886-module/source/module.cpp +++ b/Drivers/mpu6886-module/source/module.cpp @@ -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" diff --git a/Drivers/mpu6886-module/source/mpu6886.cpp b/Drivers/mpu6886-module/source/mpu6886.cpp index f3e673f90..9d975ab60 100644 --- a/Drivers/mpu6886-module/source/mpu6886.cpp +++ b/Drivers/mpu6886-module/source/mpu6886.cpp @@ -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(static_cast(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(static_cast(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(static_cast(buf[0]) << 8 | buf[1]); + + // Datasheet: temperature = raw / 326.8 + 25 (°C) + *temperature_c = static_cast(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 }; diff --git a/Drivers/mpu6886-module/source/symbols.c b/Drivers/mpu6886-module/source/symbols.c deleted file mode 100644 index c94694fb9..000000000 --- a/Drivers/mpu6886-module/source/symbols.c +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -#include -#include - -const struct ModuleSymbol mpu6886_module_symbols[] = { - DEFINE_MODULE_SYMBOL(mpu6886_read), - MODULE_SYMBOL_TERMINATOR -}; diff --git a/Drivers/qmi8658-module/include/drivers/qmi8658.h b/Drivers/qmi8658-module/include/drivers/qmi8658.h index ff1ba67a6..69a4badcc 100644 --- a/Drivers/qmi8658-module/include/drivers/qmi8658.h +++ b/Drivers/qmi8658-module/include/drivers/qmi8658.h @@ -2,6 +2,7 @@ #pragma once #include +#include #include 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 data only. + * @param[in] device qmi8658 device + * @param[out] data Pointer to ImuAccelData to populate (±8g range) + * @return ERROR_NONE on success + */ +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 accelerometer and gyroscope data. + * Read the chip's on-die temperature. * @param[in] device qmi8658 device - * @param[out] data Pointer to Qmi8658Data to populate + * @param[out] temperature_c Pointer to store the temperature, in °C * @return ERROR_NONE on success */ -error_t qmi8658_read(struct Device* device, struct Qmi8658Data* data); +error_t qmi8658_read_temperature(struct Device* device, float* temperature_c); #ifdef __cplusplus } diff --git a/Drivers/qmi8658-module/source/module.cpp b/Drivers/qmi8658-module/source/module.cpp index 6f365a63d..6f9808162 100644 --- a/Drivers/qmi8658-module/source/module.cpp +++ b/Drivers/qmi8658-module/source/module.cpp @@ -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" diff --git a/Drivers/qmi8658-module/source/qmi8658.cpp b/Drivers/qmi8658-module/source/qmi8658.cpp index 38d47e472..2d6b31991 100644 --- a/Drivers/qmi8658-module/source/qmi8658.cpp +++ b/Drivers/qmi8658-module/source/qmi8658.cpp @@ -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(static_cast(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(static_cast(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(static_cast(buf[1]) << 8 | buf[0]); + + // Datasheet: temperature = raw / 256 (°C) + *temperature_c = static_cast(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 }; diff --git a/Drivers/qmi8658-module/source/symbols.c b/Drivers/qmi8658-module/source/symbols.c deleted file mode 100644 index 47ba5e540..000000000 --- a/Drivers/qmi8658-module/source/symbols.c +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -#include -#include - -const struct ModuleSymbol qmi8658_module_symbols[] = { - DEFINE_MODULE_SYMBOL(qmi8658_read), - MODULE_SYMBOL_TERMINATOR -}; diff --git a/TactilityKernel/include/tactility/drivers/imu.h b/TactilityKernel/include/tactility/drivers/imu.h new file mode 100644 index 000000000..a03fa0b66 --- /dev/null +++ b/TactilityKernel/include/tactility/drivers/imu.h @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: Apache-2.0 +#pragma once + +#include +#include + +#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 diff --git a/TactilityKernel/source/drivers/imu.cpp b/TactilityKernel/source/drivers/imu.cpp new file mode 100644 index 000000000..a1e1777b4 --- /dev/null +++ b/TactilityKernel/source/drivers/imu.cpp @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: Apache-2.0 +#include +#include + +#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" +}; + +} diff --git a/TactilityKernel/source/symbols.c b/TactilityKernel/source/symbols.c index a4efa0ab4..9ec070509 100644 --- a/TactilityKernel/source/symbols.c +++ b/TactilityKernel/source/symbols.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -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),