mirror of
https://github.com/esphome/esphome.git
synced 2026-10-16 03:02:51 +00:00
[lsm6ds] Add the LSM6DSO and match all chips to their datasheets (#20733)
This commit is contained in:
@@ -27,17 +27,23 @@ static const LogString *gyro_range_to_str(LSM6DSGyroRange range) {
|
||||
}
|
||||
}
|
||||
|
||||
static const LogString *chip_name_from_who_am_i(uint8_t who_am_i) {
|
||||
const LogString *chip_name_from_who_am_i(uint8_t who_am_i) {
|
||||
switch (who_am_i) {
|
||||
case 0x69:
|
||||
return LOG_STR("LSMDSO");
|
||||
case 0x6A:
|
||||
case LSM6DS_WHO_AM_I_LSM6DS3:
|
||||
return LOG_STR("LSM6DS3");
|
||||
case LSM6DS_WHO_AM_I_LSM6DS3TR_C:
|
||||
return LOG_STR("LSM6DS3TR-C");
|
||||
case LSM6DS_WHO_AM_I_LSM6DSO:
|
||||
return LOG_STR("LSM6DSO");
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t temperature_sensitivity_from_who_am_i(uint8_t who_am_i) {
|
||||
return who_am_i == LSM6DS_WHO_AM_I_LSM6DS3 ? 16 : 256;
|
||||
}
|
||||
|
||||
void LSM6DSComponent::setup() {
|
||||
MotionComponent::setup();
|
||||
uint8_t who_am_i = 0;
|
||||
@@ -54,6 +60,7 @@ void LSM6DSComponent::setup() {
|
||||
}
|
||||
ESP_LOGD(TAG, "Found %s (WHO_AM_I = 0x%02X)", LOG_STR_ARG(chip_name), who_am_i);
|
||||
this->chip_name_ = chip_name;
|
||||
this->temperature_sensitivity_ = temperature_sensitivity_from_who_am_i(who_am_i);
|
||||
|
||||
// 2. Software reset — clears all registers to defaults
|
||||
if (this->write_register(LSM6DS_REG_CTRL3_C, &CTRL3_C_SW_RESET, 1) != i2c::ERROR_OK) {
|
||||
@@ -185,12 +192,12 @@ bool LSM6DSComponent::update_data(motion::MotionData &data) {
|
||||
// Temperature (lazy — only read if a listener is registered)
|
||||
// Kept as a separate 2-byte read to avoid extending the burst to 14 bytes when
|
||||
// temperature is not needed.
|
||||
// Formula: T(°C) = (raw / 256.0) + 25.0 (datasheet Table 90, OUT_TEMP register)
|
||||
// Formula: T(°C) = raw / sensitivity + 25.0, sensitivity in LSB/°C per chip (0 LSB at 25 °C)
|
||||
if (!this->temperature_callback_.empty()) {
|
||||
uint8_t raw_t[2];
|
||||
if (this->read_bytes(LSM6DS_REG_OUT_TEMP_L, raw_t, 2)) {
|
||||
int16_t temp_raw = (int16_t) ((raw_t[1] << 8) | raw_t[0]);
|
||||
float temperature = (temp_raw / 256.0f) + 25.0f;
|
||||
float temperature = temp_raw / static_cast<float>(this->temperature_sensitivity_) + 25.0f;
|
||||
this->temperature_callback_.call(temperature);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,15 +9,19 @@ namespace esphome::lsm6ds {
|
||||
|
||||
// ── Register map (datasheet DocID030071 Rev 3, Table 19) ────────────────────
|
||||
static const uint8_t LSM6DS_REG_WHO_AM_I = 0x0F;
|
||||
static const uint8_t LSM6DS_REG_CTRL1_XL = 0x10; // Accel ODR + FS
|
||||
static const uint8_t LSM6DS_REG_CTRL2_G = 0x11; // Gyro ODR + FS
|
||||
static const uint8_t LSM6DS_REG_CTRL3_C = 0x12; // SW_RESET, BDU, IF_INC
|
||||
static const uint8_t LSM6DS_REG_CTRL6_C = 0x15; // Accel HP disable, Gyro LPF1
|
||||
static const uint8_t LSM6DS_REG_CTRL7_G = 0x16; // Gyro HP disable
|
||||
static const uint8_t LSM6DS_REG_STATUS = 0x1E; // XLDA, GDA, TDA
|
||||
static const uint8_t LSM6DS_REG_OUT_TEMP_L = 0x20; // Temperature LSB
|
||||
static const uint8_t LSM6DS_REG_OUTX_L_G = 0x22; // Gyro X LSB (burst start)
|
||||
static const uint8_t LSM6DS_REG_OUTX_L_XL = 0x28; // Accel X LSB
|
||||
// WHO_AM_I values; the LSM6DS3 (DocID026899) and LSM6DSO (DS12140) use the same registers as the TR-C here
|
||||
static constexpr uint8_t LSM6DS_WHO_AM_I_LSM6DS3 = 0x69;
|
||||
static constexpr uint8_t LSM6DS_WHO_AM_I_LSM6DS3TR_C = 0x6A;
|
||||
static constexpr uint8_t LSM6DS_WHO_AM_I_LSM6DSO = 0x6C; // also the LSM6DSO32, whose accel ranges differ (unsupported)
|
||||
static const uint8_t LSM6DS_REG_CTRL1_XL = 0x10; // Accel ODR + FS
|
||||
static const uint8_t LSM6DS_REG_CTRL2_G = 0x11; // Gyro ODR + FS
|
||||
static const uint8_t LSM6DS_REG_CTRL3_C = 0x12; // SW_RESET, BDU, IF_INC
|
||||
static const uint8_t LSM6DS_REG_CTRL6_C = 0x15; // Accel HP disable, Gyro LPF1
|
||||
static const uint8_t LSM6DS_REG_CTRL7_G = 0x16; // Gyro HP disable
|
||||
static const uint8_t LSM6DS_REG_STATUS = 0x1E; // XLDA, GDA, TDA
|
||||
static const uint8_t LSM6DS_REG_OUT_TEMP_L = 0x20; // Temperature LSB
|
||||
static const uint8_t LSM6DS_REG_OUTX_L_G = 0x22; // Gyro X LSB (burst start)
|
||||
static const uint8_t LSM6DS_REG_OUTX_L_XL = 0x28; // Accel X LSB
|
||||
|
||||
// Burst read from 0x22 to 0x2D inclusive: gyro XYZ (6 bytes) + accel XYZ (6 bytes)
|
||||
static const uint8_t LSM6DS_BURST_LEN = 12;
|
||||
@@ -83,6 +87,11 @@ enum LSM6DSGyroODR : uint8_t {
|
||||
};
|
||||
|
||||
// ── Main component class ─────────────────────────────────────────────────────
|
||||
/// Chip name for a WHO_AM_I value, or nullptr when the chip is not supported.
|
||||
const LogString *chip_name_from_who_am_i(uint8_t who_am_i);
|
||||
/// Temperature sensitivity in LSB/°C for a supported WHO_AM_I value, from the chip's datasheet.
|
||||
uint16_t temperature_sensitivity_from_who_am_i(uint8_t who_am_i);
|
||||
|
||||
class LSM6DSComponent final : public motion::MotionComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
void setup() override;
|
||||
@@ -105,6 +114,7 @@ class LSM6DSComponent final : public motion::MotionComponent, public i2c::I2CDev
|
||||
LSM6DSAccelODR accel_odr_{LSM6DS_ACCEL_ODR_104};
|
||||
LSM6DSGyroRange gyro_range_{LSM6DS_GYRO_RANGE_2000};
|
||||
LSM6DSGyroODR gyro_odr_{LSM6DS_GYRO_ODR_208};
|
||||
uint16_t temperature_sensitivity_{256}; // LSB/°C: 16 on the LSM6DS3, 256 on the others
|
||||
|
||||
LazyCallbackManager<void(float)> temperature_callback_{};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
from tests.testing_helpers import ComponentManifestOverride
|
||||
|
||||
|
||||
def override_manifest(manifest: ComponentManifestOverride) -> None:
|
||||
# lsm6ds declares i2c on its motion platform, which the harness does not walk
|
||||
manifest.dependencies = manifest.dependencies + ["i2c", "motion"]
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "esphome/components/lsm6ds/lsm6ds.h"
|
||||
|
||||
namespace esphome::lsm6ds::testing {
|
||||
|
||||
// WHO_AM_I values and temperature sensitivities from ST's datasheets:
|
||||
// LSM6DS3 DocID026899, LSM6DS3TR-C DocID030071, LSM6DSO DS12140
|
||||
|
||||
static const char *name_of(uint8_t who_am_i) {
|
||||
const LogString *name = chip_name_from_who_am_i(who_am_i);
|
||||
return name == nullptr ? nullptr : LOG_STR_ARG(name);
|
||||
}
|
||||
|
||||
TEST(LSM6DSChipIds, Lsm6ds3) {
|
||||
EXPECT_STREQ(name_of(0x69), "LSM6DS3");
|
||||
EXPECT_EQ(temperature_sensitivity_from_who_am_i(0x69), 16);
|
||||
}
|
||||
|
||||
TEST(LSM6DSChipIds, Lsm6ds3trC) {
|
||||
EXPECT_STREQ(name_of(0x6A), "LSM6DS3TR-C");
|
||||
EXPECT_EQ(temperature_sensitivity_from_who_am_i(0x6A), 256);
|
||||
}
|
||||
|
||||
TEST(LSM6DSChipIds, Lsm6dso) {
|
||||
EXPECT_STREQ(name_of(0x6C), "LSM6DSO");
|
||||
EXPECT_EQ(temperature_sensitivity_from_who_am_i(0x6C), 256);
|
||||
}
|
||||
|
||||
TEST(LSM6DSChipIds, UnknownIsRejected) {
|
||||
EXPECT_EQ(name_of(0x00), nullptr);
|
||||
EXPECT_EQ(name_of(0x6B), nullptr);
|
||||
EXPECT_EQ(name_of(0xFF), nullptr);
|
||||
}
|
||||
|
||||
} // namespace esphome::lsm6ds::testing
|
||||
Reference in New Issue
Block a user