ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
lis3dh.cpp
Go to the documentation of this file.
1#include "lis3dh.h"
2#include "esphome/core/hal.h"
3#include "esphome/core/log.h"
4
5namespace esphome::lis3dh {
6
7ESPHOME_LOG_TAG(TAG, "lis3dh");
8
9// g per LSB of the left-justified 16-bit sample, indexed by range. The same in every
10// operating mode, since the chip leaves the unused low bits at zero.
11static const float SCALE_G[] PROGMEM = {0.0625e-3f, 0.125e-3f, 0.25e-3f, 0.75e-3f};
12
13static const LogString *mode_to_str(LIS3DHOperatingMode mode) {
14 switch (mode) {
16 return LOG_STR("low power (8-bit)");
18 return LOG_STR("normal (10-bit)");
19 default:
20 return LOG_STR("high resolution (12-bit)");
21 }
22}
23
24// Output data rate in Hz, indexed by the ODR field minus one.
25static const uint16_t RATE_HZ[] PROGMEM = {1, 10, 25, 50, 100, 200, 400, 1620, 1344};
26
28 MotionComponent::setup();
29
30 uint8_t who_am_i = 0;
31 if (!this->read_byte(LIS3DH_REG_WHO_AM_I, &who_am_i)) {
32 this->mark_failed(LOG_STR("Failed to read chip ID - check wiring / address"));
33 return;
34 }
35 if (who_am_i != LIS3DH_WHO_AM_I_VALUE) {
36 ESP_LOGE(TAG, "Wrong chip ID: 0x%02X (expected 0x%02X)", who_am_i, LIS3DH_WHO_AM_I_VALUE);
37 this->mark_failed(LOG_STR("Wrong chip ID"));
38 return;
39 }
40
41 if (!this->setup_accelerometer_() || !this->setup_temperature_() || !this->setup_interrupt_()) {
42 this->mark_failed(LOG_STR("Failed to configure sensor"));
43 return;
44 }
45}
46
48 // CTRL_REG1: output data rate, low-power flag and axis enable.
49 uint8_t ctrl_reg1 = ((uint8_t) this->data_rate_ << 4) | LIS3DH_CTRL_REG1_AXES_EN;
51 ctrl_reg1 |= LIS3DH_CTRL_REG1_LPEN;
52 if (!this->write_byte(LIS3DH_REG_CTRL_REG1, ctrl_reg1))
53 return false;
54
55 // CTRL_REG4: block data update, full-scale range and high-resolution flag.
56 uint8_t ctrl_reg4 = LIS3DH_CTRL_REG4_BDU | ((uint8_t) this->range_ << 4);
58 ctrl_reg4 |= LIS3DH_CTRL_REG4_HR;
59 return this->write_byte(LIS3DH_REG_CTRL_REG4, ctrl_reg4);
60}
61
63 // Only power the ADC / temperature sensor when a temperature sensor is used.
64 uint8_t temp_cfg =
65 this->temperature_callback_.empty() ? 0x00 : (uint8_t) (LIS3DH_TEMP_CFG_ADC_EN | LIS3DH_TEMP_CFG_TEMP_EN);
66 return this->write_byte(LIS3DH_REG_TEMP_CFG, temp_cfg);
67}
68
70 // Runs even with no interrupt configured: the chip usually stays powered across resets,
71 // so this drops whatever the previous firmware left in the interrupt registers.
72 // High-pass filter the interrupt (IA1) input so the ~1 g of gravity is removed
73 // from the threshold comparison. The output data registers stay unfiltered
74 // (FDS = 0), so acceleration / pitch / roll still report the full gravity vector.
75 uint8_t ctrl_reg2 = this->interrupt_high_pass_ ? LIS3DH_CTRL_REG2_HP_IA1 : 0x00;
76 if (!this->write_byte(LIS3DH_REG_CTRL_REG2, ctrl_reg2))
77 return false;
78
79 if (!this->write_byte(LIS3DH_REG_INT1_CFG, this->interrupt_axes_cfg_) ||
80 !this->write_byte(LIS3DH_REG_INT1_THS, this->interrupt_threshold_) ||
81 !this->write_byte(LIS3DH_REG_INT1_DURATION, this->interrupt_duration_))
82 return false;
83
84 // Latch the request so a brief movement keeps the pad asserted until INT1_SRC is read.
85 uint8_t ctrl_reg5 = this->interrupt_latched_ ? LIS3DH_CTRL_REG5_LIR_INT1 : 0;
86 if (!this->write_byte(LIS3DH_REG_CTRL_REG5, ctrl_reg5))
87 return false;
88
89 // Route the IA1 engine to the chosen physical pad and set the pad polarity.
90 uint8_t ctrl_reg3 = 0;
91 uint8_t ctrl_reg6 = this->interrupt_active_high_ ? 0 : LIS3DH_CTRL_REG6_INT_POLARITY;
92 if (this->interrupt_axes_cfg_ != 0) {
94 ctrl_reg3 |= LIS3DH_CTRL_REG3_I1_IA1;
95 } else {
96 ctrl_reg6 |= LIS3DH_CTRL_REG6_I2_IA1;
97 }
98 }
99 if (!this->write_byte(LIS3DH_REG_CTRL_REG3, ctrl_reg3) || !this->write_byte(LIS3DH_REG_CTRL_REG6, ctrl_reg6))
100 return false;
101 if (this->interrupt_axes_cfg_ == 0)
102 return true;
103
104 // With the high-pass filter enabled, reading REFERENCE captures the current
105 // acceleration as the filter's zero point (removing the standing gravity bias).
106 if (this->interrupt_high_pass_) {
107 uint8_t reference = 0;
108 this->read_byte(LIS3DH_REG_REFERENCE, &reference);
109 }
110
111 // Clear any latched request left over from the motion that woke the device.
112 uint8_t src = 0;
113 this->read_byte(LIS3DH_REG_INT1_SRC, &src);
114 return true;
115}
116
118 ESP_LOGCONFIG(TAG, "LIS3DH:");
119 LOG_I2C_DEVICE(this);
120 if (this->is_failed())
121 return;
122
123 ESP_LOGCONFIG(TAG,
124 " Range: ±%ug\n"
125 " Operating mode: %s\n"
126 " Data rate: %uHz",
127 2u << this->range_, LOG_STR_ARG(mode_to_str(this->operating_mode_)),
128 (unsigned) progmem_read_uint16(&RATE_HZ[this->data_rate_ - 1]));
129 if (this->interrupt_axes_cfg_ != 0) {
130 ESP_LOGCONFIG(TAG,
131 " Motion interrupt: %s (%s%s%s)\n"
132 " Threshold: %u steps\n"
133 " Duration: %u samples",
134 this->interrupt_pin_ == LIS3DH_INT_PIN_INT1 ? LOG_STR_LITERAL("INT1") : LOG_STR_LITERAL("INT2"),
135 this->interrupt_active_high_ ? LOG_STR_LITERAL("active high") : LOG_STR_LITERAL("active low"),
136 this->interrupt_high_pass_ ? LOG_STR_LITERAL(", high-pass") : LOG_STR_LITERAL(""),
137 this->interrupt_latched_ ? LOG_STR_LITERAL(", latched") : LOG_STR_LITERAL(""),
139 }
140 MotionComponent::dump_config();
141}
142
144 // Clear a latched request from motion seen while awake, so it does not wake the device straight away.
145 if (this->interrupt_latched_ && this->interrupt_axes_cfg_ != 0 && !this->is_failed()) {
146 uint8_t src = 0;
147 this->read_byte(LIS3DH_REG_INT1_SRC, &src);
148 }
149}
150
152 if (this->is_failed())
153 return false;
154
155 uint8_t raw[6];
156 if (!this->read_bytes(LIS3DH_REG_OUT_X_L | LIS3DH_AUTO_INCREMENT, raw, 6)) {
157 this->status_set_warning(LOG_STR("Failed to read acceleration data"));
158 return false;
159 }
160
161 float scale;
162 progmem_memcpy(&scale, &SCALE_G[this->range_], sizeof(scale));
163
164 // Data is little-endian and left-justified in a signed 16-bit register.
165 int16_t raw_x = (int16_t) encode_uint16(raw[1], raw[0]);
166 int16_t raw_y = (int16_t) encode_uint16(raw[3], raw[2]);
167 int16_t raw_z = (int16_t) encode_uint16(raw[5], raw[4]);
168 ESP_LOGV(TAG, "Read raw accel data: %d, %d, %d", raw_x, raw_y, raw_z);
169 data.acceleration[motion::X_AXIS] = raw_x * scale;
170 data.acceleration[motion::Y_AXIS] = raw_y * scale;
171 data.acceleration[motion::Z_AXIS] = raw_z * scale;
172
173 if (this->temperature_callback_.empty() || this->publish_temperature_())
174 this->status_clear_warning();
175 return true;
176}
177
179 uint8_t raw[2];
180 if (!this->read_bytes(LIS3DH_REG_OUT_ADC3_L | LIS3DH_AUTO_INCREMENT, raw, 2)) {
181 this->status_set_warning(LOG_STR("Failed to read temperature data"));
182 return false;
183 }
184 // Signed, left-justified, relative value with 1 °C per count of the high byte; the
185 // low byte carries the fractional bits in the modes that have them.
186 float temperature = (int16_t) encode_uint16(raw[1], raw[0]) / 256.0f + LIS3DH_TEMP_REFERENCE_C;
187 this->temperature_callback_.call(temperature);
188 return true;
189}
190
191} // namespace esphome::lis3dh
BedjetMode mode
BedJet operating mode.
uint8_t raw[35]
Definition bl0939.h:0
void mark_failed()
Mark this component as failed.
bool is_failed() const
Definition component.h:274
void status_clear_warning()
Definition component.h:291
bool write_byte(uint8_t a_register, uint8_t data) const
Definition i2c.h:265
bool read_byte(uint8_t a_register, uint8_t *data)
Definition i2c.h:240
bool read_bytes(uint8_t a_register, uint8_t *data, uint8_t len)
Compat APIs All methods below have been added for compatibility reasons.
Definition i2c.h:217
LIS3DHInterruptPin interrupt_pin_
Definition lis3dh.h:124
LIS3DHOperatingMode operating_mode_
Definition lis3dh.h:121
LazyCallbackManager< void(float)> temperature_callback_
Definition lis3dh.h:132
bool update_data(motion::MotionData &data) override
Definition lis3dh.cpp:151
constexpr float BME680_GAS_LOOKUP_TABLE_1[16] PROGMEM
Definition bme680.cpp:26
@ LIS3DH_INT_PIN_INT1
Definition lis3dh.h:85
ESPHOME_LOG_TAG(TAG, "lis3dh")
@ LIS3DH_MODE_LOW_POWER
Definition lis3dh.h:78
@ LIS3DH_MODE_HIGH_RESOLUTION
Definition lis3dh.h:80
@ LIS3DH_MODE_NORMAL
Definition lis3dh.h:79
void progmem_memcpy(void *dst, const void *src, size_t len)
Definition hal.h:56
uint16_t progmem_read_uint16(const uint16_t *addr)
Definition hal.h:53
const void * src
Definition hal.h:68
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition helpers.h:980
uint16_t temperature
Definition sun_gtil2.cpp:12