ESPHome  2022.6.3
vl53l0x_sensor.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <list>
4 
6 #include "esphome/core/hal.h"
9 
10 namespace esphome {
11 namespace vl53l0x {
12 
15 };
16 
18  uint16_t pre_range_vcsel_period_pclks, final_range_vcsel_period_pclks;
19 
20  uint16_t msrc_dss_tcc_mclks, pre_range_mclks, final_range_mclks;
21  uint32_t msrc_dss_tcc_us, pre_range_us, final_range_us;
22 };
23 
25  public:
26  VL53L0XSensor();
27 
28  void setup() override;
29 
30  void dump_config() override;
31  float get_setup_priority() const override { return setup_priority::DATA; }
32  void update() override;
33 
34  void loop() override;
35 
36  void set_signal_rate_limit(float signal_rate_limit) { signal_rate_limit_ = signal_rate_limit; }
37  void set_long_range(bool long_range) { long_range_ = long_range; }
38  void set_timeout_us(uint32_t timeout_us) { this->timeout_us_ = timeout_us; }
39  void set_enable_pin(GPIOPin *enable) { this->enable_pin_ = enable; }
40 
41  protected:
43  SequenceStepEnables enables{};
44  SequenceStepTimeouts timeouts{};
45 
46  uint16_t start_overhead = 1910;
47  uint16_t end_overhead = 960;
48  uint16_t msrc_overhead = 660;
49  uint16_t tcc_overhead = 590;
50  uint16_t dss_overhead = 690;
51  uint16_t pre_range_overhead = 660;
52  uint16_t final_range_overhead = 550;
53 
54  // "Start and end overhead times always present"
55  uint32_t budget_us = start_overhead + end_overhead;
56 
57  get_sequence_step_enables_(&enables);
58  get_sequence_step_timeouts_(&enables, &timeouts);
59 
60  if (enables.tcc)
61  budget_us += (timeouts.msrc_dss_tcc_us + tcc_overhead);
62 
63  if (enables.dss) {
64  budget_us += 2 * (timeouts.msrc_dss_tcc_us + dss_overhead);
65  } else if (enables.msrc) {
66  budget_us += (timeouts.msrc_dss_tcc_us + msrc_overhead);
67  }
68 
69  if (enables.pre_range)
70  budget_us += (timeouts.pre_range_us + pre_range_overhead);
71 
72  if (enables.final_range)
73  budget_us += (timeouts.final_range_us + final_range_overhead);
74 
75  measurement_timing_budget_us_ = budget_us; // store for internal reuse
76  return budget_us;
77  }
78 
79  bool set_measurement_timing_budget_(uint32_t budget_us) {
80  SequenceStepEnables enables{};
81  SequenceStepTimeouts timeouts{};
82 
83  uint16_t start_overhead = 1320; // note that this is different than the value in get_
84  uint16_t end_overhead = 960;
85  uint16_t msrc_overhead = 660;
86  uint16_t tcc_overhead = 590;
87  uint16_t dss_overhead = 690;
88  uint16_t pre_range_overhead = 660;
89  uint16_t final_range_overhead = 550;
90 
91  uint32_t min_timing_budget = 20000;
92 
93  if (budget_us < min_timing_budget) {
94  return false;
95  }
96 
97  uint32_t used_budget_us = start_overhead + end_overhead;
98 
99  get_sequence_step_enables_(&enables);
100  get_sequence_step_timeouts_(&enables, &timeouts);
101 
102  if (enables.tcc) {
103  used_budget_us += (timeouts.msrc_dss_tcc_us + tcc_overhead);
104  }
105 
106  if (enables.dss) {
107  used_budget_us += 2 * (timeouts.msrc_dss_tcc_us + dss_overhead);
108  } else if (enables.msrc) {
109  used_budget_us += (timeouts.msrc_dss_tcc_us + msrc_overhead);
110  }
111 
112  if (enables.pre_range) {
113  used_budget_us += (timeouts.pre_range_us + pre_range_overhead);
114  }
115 
116  if (enables.final_range) {
117  used_budget_us += final_range_overhead;
118 
119  // "Note that the final range timeout is determined by the timing
120  // budget and the sum of all other timeouts within the sequence.
121  // If there is no room for the final range timeout, then an error
122  // will be set. Otherwise the remaining time will be applied to
123  // the final range."
124 
125  if (used_budget_us > budget_us) {
126  // "Requested timeout too big."
127  return false;
128  }
129 
130  uint32_t final_range_timeout_us = budget_us - used_budget_us;
131 
132  // set_sequence_step_timeout() begin
133  // (SequenceStepId == VL53L0X_SEQUENCESTEP_FINAL_RANGE)
134 
135  // "For the final range timeout, the pre-range timeout
136  // must be added. To do this both final and pre-range
137  // timeouts must be expressed in macro periods MClks
138  // because they have different vcsel periods."
139 
140  uint16_t final_range_timeout_mclks =
141  timeout_microseconds_to_mclks_(final_range_timeout_us, timeouts.final_range_vcsel_period_pclks);
142 
143  if (enables.pre_range) {
144  final_range_timeout_mclks += timeouts.pre_range_mclks;
145  }
146 
147  write_byte_16(0x71, encode_timeout_(final_range_timeout_mclks));
148 
149  // set_sequence_step_timeout() end
150 
151  measurement_timing_budget_us_ = budget_us; // store for internal reuse
152  }
153  return true;
154  }
155 
157  uint8_t sequence_config = reg(0x01).get();
158  enables->tcc = (sequence_config >> 4) & 0x1;
159  enables->dss = (sequence_config >> 3) & 0x1;
160  enables->msrc = (sequence_config >> 2) & 0x1;
161  enables->pre_range = (sequence_config >> 6) & 0x1;
162  enables->final_range = (sequence_config >> 7) & 0x1;
163  }
164 
165  enum VcselPeriodType { VCSEL_PERIOD_PRE_RANGE, VCSEL_PERIOD_FINAL_RANGE };
166 
168  timeouts->pre_range_vcsel_period_pclks = get_vcsel_pulse_period_(VCSEL_PERIOD_PRE_RANGE);
169 
170  timeouts->msrc_dss_tcc_mclks = reg(0x46).get() + 1;
171  timeouts->msrc_dss_tcc_us =
172  timeout_mclks_to_microseconds_(timeouts->msrc_dss_tcc_mclks, timeouts->pre_range_vcsel_period_pclks);
173 
174  uint16_t value;
175  read_byte_16(0x51, &value);
176  timeouts->pre_range_mclks = decode_timeout_(value);
177  timeouts->pre_range_us =
178  timeout_mclks_to_microseconds_(timeouts->pre_range_mclks, timeouts->pre_range_vcsel_period_pclks);
179 
180  timeouts->final_range_vcsel_period_pclks = get_vcsel_pulse_period_(VCSEL_PERIOD_FINAL_RANGE);
181 
182  read_byte_16(0x71, &value);
183  timeouts->final_range_mclks = decode_timeout_(value);
184 
185  if (enables->pre_range) {
186  timeouts->final_range_mclks -= timeouts->pre_range_mclks;
187  }
188 
189  timeouts->final_range_us =
190  timeout_mclks_to_microseconds_(timeouts->final_range_mclks, timeouts->final_range_vcsel_period_pclks);
191  }
192 
194  uint8_t vcsel;
195  if (type == VCSEL_PERIOD_PRE_RANGE) {
196  vcsel = reg(0x50).get();
197  } else if (type == VCSEL_PERIOD_FINAL_RANGE) {
198  vcsel = reg(0x70).get();
199  } else {
200  return 255;
201  }
202 
203  return (vcsel + 1) << 1;
204  }
205 
206  uint32_t get_macro_period_(uint8_t vcsel_period_pclks) {
207  return ((2304UL * vcsel_period_pclks * 1655UL) + 500UL) / 1000UL;
208  }
209 
210  uint32_t timeout_mclks_to_microseconds_(uint16_t timeout_period_mclks, uint8_t vcsel_period_pclks) {
211  uint32_t macro_period_ns = get_macro_period_(vcsel_period_pclks);
212  return ((timeout_period_mclks * macro_period_ns) + (macro_period_ns / 2)) / 1000;
213  }
214  uint32_t timeout_microseconds_to_mclks_(uint32_t timeout_period_us, uint8_t vcsel_period_pclks) {
215  uint32_t macro_period_ns = get_macro_period_(vcsel_period_pclks);
216  return (((timeout_period_us * 1000) + (macro_period_ns / 2)) / macro_period_ns);
217  }
218 
219  uint16_t decode_timeout_(uint16_t reg_val) {
220  // format: "(LSByte * 2^MSByte) + 1"
221  uint8_t msb = (reg_val >> 8) & 0xFF;
222  uint8_t lsb = (reg_val >> 0) & 0xFF;
223  return (uint16_t(lsb) << msb) + 1;
224  }
225  uint16_t encode_timeout_(uint16_t timeout_mclks) {
226  // format: "(LSByte * 2^MSByte) + 1"
227  uint32_t ls_byte = 0;
228  uint16_t ms_byte = 0;
229 
230  if (timeout_mclks <= 0)
231  return 0;
232 
233  ls_byte = timeout_mclks - 1;
234 
235  while ((ls_byte & 0xFFFFFF00) > 0) {
236  ls_byte >>= 1;
237  ms_byte++;
238  }
239 
240  return (ms_byte << 8) | (ls_byte & 0xFF);
241  }
242 
243  bool perform_single_ref_calibration_(uint8_t vhv_init_byte) {
244  reg(0x00) = 0x01 | vhv_init_byte; // VL53L0X_REG_SYSRANGE_MODE_START_STOP
245 
246  uint32_t start = millis();
247  while ((reg(0x13).get() & 0x07) == 0) {
248  if (millis() - start > 1000)
249  return false;
250  yield();
251  }
252 
253  reg(0x0B) = 0x01;
254  reg(0x00) = 0x00;
255 
256  return true;
257  }
258 
261  GPIOPin *enable_pin_{nullptr};
263  bool initiated_read_{false};
264  bool waiting_for_interrupt_{false};
265  uint8_t stop_variable_;
266 
268  uint16_t timeout_us_{};
269 
270  static std::list<VL53L0XSensor *> vl53_sensors; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
271  static bool enable_pin_setup_complete; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
272 };
273 
274 } // namespace vl53l0x
275 } // namespace esphome
void setup()
void loop()
const float DATA
For components that import data from directly connected sensors like DHT.
Definition: component.cpp:18
uint32_t get_macro_period_(uint8_t vcsel_period_pclks)
uint32_t timeout_mclks_to_microseconds_(uint16_t timeout_period_mclks, uint8_t vcsel_period_pclks)
bool set_measurement_timing_budget_(uint32_t budget_us)
uint16_t decode_timeout_(uint16_t reg_val)
This class simplifies creating components that periodically check a state.
Definition: component.h:266
void set_signal_rate_limit(float signal_rate_limit)
uint32_t IRAM_ATTR HOT millis()
Definition: core.cpp:26
void set_timeout_us(uint32_t timeout_us)
uint8_t type
uint32_t timeout_microseconds_to_mclks_(uint32_t timeout_period_us, uint8_t vcsel_period_pclks)
void get_sequence_step_enables_(SequenceStepEnables *enables)
static std::list< VL53L0XSensor * > vl53_sensors
bool perform_single_ref_calibration_(uint8_t vhv_init_byte)
void IRAM_ATTR HOT yield()
Definition: core.cpp:25
void set_enable_pin(GPIOPin *enable)
Definition: a4988.cpp:4
float get_setup_priority() const override
void set_long_range(bool long_range)
uint8_t get_vcsel_pulse_period_(VcselPeriodType type)
Base-class for all sensors.
Definition: sensor.h:47
uint16_t encode_timeout_(uint16_t timeout_mclks)
void get_sequence_step_timeouts_(SequenceStepEnables const *enables, SequenceStepTimeouts *timeouts)