mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	| @@ -3,3 +3,4 @@ include README.md | ||||
| include esphome/dashboard/templates/*.html | ||||
| recursive-include esphome/dashboard/static *.ico *.js *.css *.woff* LICENSE | ||||
| recursive-include esphome *.cpp *.h *.tcc | ||||
| recursive-include esphome LICENSE.txt | ||||
|   | ||||
| @@ -208,5 +208,30 @@ void I2CDevice::set_i2c_parent(I2CComponent *parent) { this->parent_ = parent; } | ||||
| uint8_t next_i2c_bus_num_ = 0; | ||||
| #endif | ||||
|  | ||||
| I2CRegister &I2CRegister::operator=(uint8_t value) { | ||||
|   this->parent_->write_byte(this->register_, value); | ||||
|   return *this; | ||||
| } | ||||
|  | ||||
| I2CRegister &I2CRegister::operator&=(uint8_t value) { | ||||
|   this->parent_->write_byte(this->register_, this->get() & value); | ||||
|   return *this; | ||||
| } | ||||
|  | ||||
| I2CRegister &I2CRegister::operator|=(uint8_t value) { | ||||
|   this->parent_->write_byte(this->register_, this->get() | value); | ||||
|   return *this; | ||||
| } | ||||
|  | ||||
| uint8_t I2CRegister::get() { | ||||
|   uint8_t value = 0x00; | ||||
|   this->parent_->read_byte(this->register_, &value); | ||||
|   return value; | ||||
| } | ||||
| I2CRegister &I2CRegister::operator=(const std::vector<uint8_t> &value) { | ||||
|   this->parent_->write_bytes(this->register_, value); | ||||
|   return *this; | ||||
| } | ||||
|  | ||||
| }  // namespace i2c | ||||
| }  // namespace esphome | ||||
|   | ||||
| @@ -134,6 +134,24 @@ class I2CComponent : public Component { | ||||
| extern uint8_t next_i2c_bus_num_; | ||||
| #endif | ||||
|  | ||||
| class I2CDevice; | ||||
|  | ||||
| class I2CRegister { | ||||
|  public: | ||||
|   I2CRegister(I2CDevice *parent, uint8_t a_register) : parent_(parent), register_(a_register) {} | ||||
|  | ||||
|   I2CRegister &operator=(uint8_t value); | ||||
|   I2CRegister &operator=(const std::vector<uint8_t> &value); | ||||
|   I2CRegister &operator&=(uint8_t value); | ||||
|   I2CRegister &operator|=(uint8_t value); | ||||
|  | ||||
|   uint8_t get(); | ||||
|  | ||||
|  protected: | ||||
|   I2CDevice *parent_; | ||||
|   uint8_t register_; | ||||
| }; | ||||
|  | ||||
| /** All components doing communication on the I2C bus should subclass I2CDevice. | ||||
|  * | ||||
|  * This class stores 1. the address of the i2c device and has a helper function to allow | ||||
| @@ -153,6 +171,8 @@ class I2CDevice { | ||||
|   /// Manually set the parent i2c bus for this device. | ||||
|   void set_i2c_parent(I2CComponent *parent); | ||||
|  | ||||
|   I2CRegister reg(uint8_t a_register) { return {this, a_register}; } | ||||
|  | ||||
|   /** Read len amount of bytes from a register into data. Optionally with a conversion time after | ||||
|    * writing the register value to the bus. | ||||
|    * | ||||
|   | ||||
							
								
								
									
										80
									
								
								esphome/components/vl53l0x/LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								esphome/components/vl53l0x/LICENSE.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| Most of the code in this integration is based on the VL53L0x library | ||||
| by Pololu (Pololu Corporation), which in turn is based on the VL53L0X | ||||
| API from ST. The code has been adapted to work with ESPHome's i2c APIs. | ||||
| Please see the top-level LICENSE.txt for information about ESPHome's license. | ||||
| The licenses for Pololu's and ST's software are included below. | ||||
| Orignally taken from https://github.com/pololu/vl53l0x-arduino (accessed 20th october 2019). | ||||
|  | ||||
| ================================================================= | ||||
|  | ||||
| Copyright (c) 2017 Pololu Corporation.  For more information, see | ||||
|  | ||||
| https://www.pololu.com/ | ||||
| https://forum.pololu.com/ | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person | ||||
| obtaining a copy of this software and associated documentation | ||||
| files (the "Software"), to deal in the Software without | ||||
| restriction, including without limitation the rights to use, | ||||
| copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the | ||||
| Software is furnished to do so, subject to the following | ||||
| conditions: | ||||
|  | ||||
| The above copyright notice and this permission notice shall be | ||||
| included in all copies or substantial portions of the Software. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||||
| OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||
| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||||
| HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||||
| WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||||
| OTHER DEALINGS IN THE SOFTWARE. | ||||
|  | ||||
| ================================================================= | ||||
|  | ||||
| Most of the functionality of this library is based on the VL53L0X | ||||
| API provided by ST (STSW-IMG005), and some of the explanatory | ||||
| comments are quoted or paraphrased from the API source code, API | ||||
| user manual (UM2039), and the VL53L0X datasheet. | ||||
|  | ||||
| The following applies to source code reproduced or derived from | ||||
| the API: | ||||
|  | ||||
| ----------------------------------------------------------------- | ||||
|  | ||||
| Copyright © 2016, STMicroelectronics International N.V.  All | ||||
| rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or | ||||
| without modification, are permitted provided that the following | ||||
| conditions are met: | ||||
| * Redistributions of source code must retain the above copyright | ||||
| notice, this list of conditions and the following disclaimer. | ||||
| * Redistributions in binary form must reproduce the above | ||||
| copyright notice, this list of conditions and the following | ||||
| disclaimer in the documentation and/or other materials provided | ||||
| with the distribution. | ||||
| * Neither the name of STMicroelectronics nor the | ||||
| names of its contributors may be used to endorse or promote | ||||
| products derived from this software without specific prior | ||||
| written permission. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND | ||||
| CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, | ||||
| INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||||
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND | ||||
| NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED. | ||||
| IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE | ||||
| FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT | ||||
| OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | ||||
| OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||||
| LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | ||||
| USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||||
| DAMAGE. | ||||
|  | ||||
| ----------------------------------------------------------------- | ||||
							
								
								
									
										0
									
								
								esphome/components/vl53l0x/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								esphome/components/vl53l0x/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										24
									
								
								esphome/components/vl53l0x/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								esphome/components/vl53l0x/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import i2c, sensor | ||||
| from esphome.const import CONF_ID, UNIT_METER, ICON_ARROW_EXPAND_VERTICAL | ||||
|  | ||||
| DEPENDENCIES = ['i2c'] | ||||
|  | ||||
| vl53l0x_ns = cg.esphome_ns.namespace('vl53l0x') | ||||
| VL53L0XSensor = vl53l0x_ns.class_('VL53L0XSensor', sensor.Sensor, cg.PollingComponent, | ||||
|                                   i2c.I2CDevice) | ||||
|  | ||||
| CONF_SIGNAL_RATE_LIMIT = 'signal_rate_limit' | ||||
| CONFIG_SCHEMA = sensor.sensor_schema(UNIT_METER, ICON_ARROW_EXPAND_VERTICAL, 2).extend({ | ||||
|     cv.GenerateID(): cv.declare_id(VL53L0XSensor), | ||||
|     cv.Optional(CONF_SIGNAL_RATE_LIMIT, default=0.25): cv.float_range( | ||||
|         min=0.0, max=512.0, min_included=False, max_included=False) | ||||
| }).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x29)) | ||||
|  | ||||
|  | ||||
| def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     yield cg.register_component(var, config) | ||||
|     yield sensor.register_sensor(var, config) | ||||
|     yield i2c.register_i2c_device(var, config) | ||||
							
								
								
									
										249
									
								
								esphome/components/vl53l0x/vl53l0x_sensor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								esphome/components/vl53l0x/vl53l0x_sensor.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,249 @@ | ||||
| #include "vl53l0x_sensor.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| /* | ||||
|  * Most of the code in this integration is based on the VL53L0x library | ||||
|  * by Pololu (Pololu Corporation), which in turn is based on the VL53L0X | ||||
|  * API from ST. | ||||
|  * | ||||
|  * For more information about licensing, please view the included LICENSE.txt file | ||||
|  * in the vl53l0x integration directory. | ||||
|  */ | ||||
|  | ||||
| namespace esphome { | ||||
| namespace vl53l0x { | ||||
|  | ||||
| static const char *TAG = "vl53l0x"; | ||||
|  | ||||
| void VL53L0XSensor::dump_config() { | ||||
|   LOG_SENSOR("", "VL53L0X", this); | ||||
|   LOG_UPDATE_INTERVAL(this); | ||||
|   LOG_I2C_DEVICE(this); | ||||
| } | ||||
| void VL53L0XSensor::setup() { | ||||
|   reg(0x89) |= 0x01; | ||||
|   reg(0x88) = 0x00; | ||||
|  | ||||
|   reg(0x80) = 0x01; | ||||
|   reg(0xFF) = 0x01; | ||||
|   reg(0x00) = 0x00; | ||||
|   stop_variable_ = reg(0x91).get(); | ||||
|  | ||||
|   reg(0x00) = 0x01; | ||||
|   reg(0xFF) = 0x00; | ||||
|   reg(0x80) = 0x00; | ||||
|   reg(0x60) |= 0x12; | ||||
|  | ||||
|   auto rate_value = static_cast<uint16_t>(signal_rate_limit_ * 128); | ||||
|   write_byte_16(0x44, rate_value); | ||||
|  | ||||
|   reg(0x01) = 0xFF; | ||||
|  | ||||
|   // getSpadInfo() | ||||
|   reg(0x80) = 0x01; | ||||
|   reg(0xFF) = 0x01; | ||||
|   reg(0x00) = 0x00; | ||||
|   reg(0xFF) = 0x06; | ||||
|   reg(0x83) |= 0x04; | ||||
|   reg(0xFF) = 0x07; | ||||
|   reg(0x81) = 0x01; | ||||
|   reg(0x80) = 0x01; | ||||
|   reg(0x94) = 0x6B; | ||||
|   reg(0x83) = 0x00; | ||||
|  | ||||
|   while (reg(0x83).get() == 0x00) | ||||
|     yield(); | ||||
|  | ||||
|   reg(0x83) = 0x01; | ||||
|   uint8_t tmp = reg(0x92).get(); | ||||
|   uint8_t spad_count = tmp & 0x7F; | ||||
|   bool spad_type_is_aperture = tmp & 0x80; | ||||
|  | ||||
|   reg(0x81) = 0x00; | ||||
|   reg(0xFF) = 0x06; | ||||
|   reg(0x83) &= ~0x04; | ||||
|   reg(0xFF) = 0x01; | ||||
|   reg(0x00) = 0x01; | ||||
|   reg(0xFF) = 0x00; | ||||
|   reg(0x80) = 0x00; | ||||
|  | ||||
|   uint8_t ref_spad_map[6]; | ||||
|   this->read_bytes(0xB0, ref_spad_map, 6); | ||||
|  | ||||
|   reg(0xFF) = 0x01; | ||||
|   reg(0x4F) = 0x00; | ||||
|   reg(0x4E) = 0x2C; | ||||
|   reg(0xFF) = 0x00; | ||||
|   reg(0xB6) = 0xB4; | ||||
|  | ||||
|   uint8_t first_spad_to_enable = spad_type_is_aperture ? 12 : 0; | ||||
|   uint8_t spads_enabled = 0; | ||||
|   for (int i = 0; i < 48; i++) { | ||||
|     uint8_t &val = ref_spad_map[i / 8]; | ||||
|     uint8_t mask = 1 << (i % 8); | ||||
|  | ||||
|     if (i < first_spad_to_enable || spads_enabled == spad_count) | ||||
|       val &= ~mask; | ||||
|     else if (val & mask) | ||||
|       spads_enabled += 1; | ||||
|   } | ||||
|  | ||||
|   this->write_bytes(0xB0, ref_spad_map, 6); | ||||
|  | ||||
|   reg(0xFF) = 0x01; | ||||
|   reg(0x00) = 0x00; | ||||
|   reg(0xFF) = 0x00; | ||||
|   reg(0x09) = 0x00; | ||||
|   reg(0x10) = 0x00; | ||||
|   reg(0x11) = 0x00; | ||||
|   reg(0x24) = 0x01; | ||||
|   reg(0x25) = 0xFF; | ||||
|   reg(0x75) = 0x00; | ||||
|   reg(0xFF) = 0x01; | ||||
|   reg(0x4E) = 0x2C; | ||||
|   reg(0x48) = 0x00; | ||||
|   reg(0x30) = 0x20; | ||||
|   reg(0xFF) = 0x00; | ||||
|   reg(0x30) = 0x09; | ||||
|   reg(0x54) = 0x00; | ||||
|   reg(0x31) = 0x04; | ||||
|   reg(0x32) = 0x03; | ||||
|   reg(0x40) = 0x83; | ||||
|   reg(0x46) = 0x25; | ||||
|   reg(0x60) = 0x00; | ||||
|   reg(0x27) = 0x00; | ||||
|   reg(0x50) = 0x06; | ||||
|   reg(0x51) = 0x00; | ||||
|   reg(0x52) = 0x96; | ||||
|   reg(0x56) = 0x08; | ||||
|   reg(0x57) = 0x30; | ||||
|   reg(0x61) = 0x00; | ||||
|   reg(0x62) = 0x00; | ||||
|   reg(0x64) = 0x00; | ||||
|   reg(0x65) = 0x00; | ||||
|   reg(0x66) = 0xA0; | ||||
|   reg(0xFF) = 0x01; | ||||
|   reg(0x22) = 0x32; | ||||
|   reg(0x47) = 0x14; | ||||
|   reg(0x49) = 0xFF; | ||||
|   reg(0x4A) = 0x00; | ||||
|   reg(0xFF) = 0x00; | ||||
|   reg(0x7A) = 0x0A; | ||||
|   reg(0x7B) = 0x00; | ||||
|   reg(0x78) = 0x21; | ||||
|   reg(0xFF) = 0x01; | ||||
|   reg(0x23) = 0x34; | ||||
|   reg(0x42) = 0x00; | ||||
|   reg(0x44) = 0xFF; | ||||
|   reg(0x45) = 0x26; | ||||
|   reg(0x46) = 0x05; | ||||
|   reg(0x40) = 0x40; | ||||
|   reg(0x0E) = 0x06; | ||||
|   reg(0x20) = 0x1A; | ||||
|   reg(0x43) = 0x40; | ||||
|   reg(0xFF) = 0x00; | ||||
|   reg(0x34) = 0x03; | ||||
|   reg(0x35) = 0x44; | ||||
|   reg(0xFF) = 0x01; | ||||
|   reg(0x31) = 0x04; | ||||
|   reg(0x4B) = 0x09; | ||||
|   reg(0x4C) = 0x05; | ||||
|   reg(0x4D) = 0x04; | ||||
|   reg(0xFF) = 0x00; | ||||
|   reg(0x44) = 0x00; | ||||
|   reg(0x45) = 0x20; | ||||
|   reg(0x47) = 0x08; | ||||
|   reg(0x48) = 0x28; | ||||
|   reg(0x67) = 0x00; | ||||
|   reg(0x70) = 0x04; | ||||
|   reg(0x71) = 0x01; | ||||
|   reg(0x72) = 0xFE; | ||||
|   reg(0x76) = 0x00; | ||||
|   reg(0x77) = 0x00; | ||||
|   reg(0xFF) = 0x01; | ||||
|   reg(0x0D) = 0x01; | ||||
|   reg(0xFF) = 0x00; | ||||
|   reg(0x80) = 0x01; | ||||
|   reg(0x01) = 0xF8; | ||||
|   reg(0xFF) = 0x01; | ||||
|   reg(0x8E) = 0x01; | ||||
|   reg(0x00) = 0x01; | ||||
|   reg(0xFF) = 0x00; | ||||
|   reg(0x80) = 0x00; | ||||
|  | ||||
|   reg(0x0A) = 0x04; | ||||
|   reg(0x84) &= ~0x10; | ||||
|   reg(0x0B) = 0x01; | ||||
|  | ||||
|   measurement_timing_budget_us_ = get_measurement_timing_budget_(); | ||||
|   reg(0x01) = 0xE8; | ||||
|   set_measurement_timing_budget_(measurement_timing_budget_us_); | ||||
|   reg(0x01) = 0x01; | ||||
|  | ||||
|   if (!perform_single_ref_calibration_(0x40)) { | ||||
|     ESP_LOGW(TAG, "1st reference calibration failed!"); | ||||
|     this->mark_failed(); | ||||
|     return; | ||||
|   } | ||||
|   reg(0x01) = 0x02; | ||||
|   if (!perform_single_ref_calibration_(0x00)) { | ||||
|     ESP_LOGW(TAG, "2nd reference calibration failed!"); | ||||
|     this->mark_failed(); | ||||
|     return; | ||||
|   } | ||||
|   reg(0x01) = 0xE8; | ||||
| } | ||||
| void VL53L0XSensor::update() { | ||||
|   if (this->initiated_read_ || this->waiting_for_interrupt_) { | ||||
|     this->publish_state(NAN); | ||||
|     this->status_set_warning(); | ||||
|   } | ||||
|  | ||||
|   // initiate single shot measurement | ||||
|   reg(0x80) = 0x01; | ||||
|   reg(0xFF) = 0x01; | ||||
|  | ||||
|   reg(0x00) = 0x00; | ||||
|   reg(0x91) = stop_variable_; | ||||
|   reg(0x00) = 0x01; | ||||
|   reg(0xFF) = 0x00; | ||||
|   reg(0x80) = 0x00; | ||||
|  | ||||
|   reg(0x00) = 0x01; | ||||
|   this->waiting_for_interrupt_ = false; | ||||
|   this->initiated_read_ = true; | ||||
|   // wait for timeout | ||||
| } | ||||
| void VL53L0XSensor::loop() { | ||||
|   if (this->initiated_read_) { | ||||
|     if (reg(0x00).get() & 0x01) { | ||||
|       // waiting | ||||
|     } else { | ||||
|       // done | ||||
|       // wait until reg(0x13) & 0x07 is set | ||||
|       this->initiated_read_ = false; | ||||
|       this->waiting_for_interrupt_ = true; | ||||
|     } | ||||
|   } | ||||
|   if (this->waiting_for_interrupt_) { | ||||
|     if (reg(0x13).get() & 0x07) { | ||||
|       uint16_t range_mm; | ||||
|       this->read_byte_16(0x14 + 10, &range_mm); | ||||
|       reg(0x0B) = 0x01; | ||||
|       this->waiting_for_interrupt_ = false; | ||||
|  | ||||
|       if (range_mm >= 8190) { | ||||
|         ESP_LOGW(TAG, "'%s' - Distance is out of range, please move the target closer", this->name_.c_str()); | ||||
|         this->publish_state(NAN); | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       float range_m = range_mm / 1e3f; | ||||
|       ESP_LOGD(TAG, "'%s' - Got distance %.3f m", this->name_.c_str(), range_m); | ||||
|       this->publish_state(range_m); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| }  // namespace vl53l0x | ||||
| }  // namespace esphome | ||||
							
								
								
									
										257
									
								
								esphome/components/vl53l0x/vl53l0x_sensor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								esphome/components/vl53l0x/vl53l0x_sensor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,257 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/sensor/sensor.h" | ||||
| #include "esphome/components/i2c/i2c.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace vl53l0x { | ||||
|  | ||||
| struct SequenceStepEnables { | ||||
|   bool tcc, msrc, dss, pre_range, final_range; | ||||
| }; | ||||
|  | ||||
| struct SequenceStepTimeouts { | ||||
|   uint16_t pre_range_vcsel_period_pclks, final_range_vcsel_period_pclks; | ||||
|  | ||||
|   uint16_t msrc_dss_tcc_mclks, pre_range_mclks, final_range_mclks; | ||||
|   uint32_t msrc_dss_tcc_us, pre_range_us, final_range_us; | ||||
| }; | ||||
|  | ||||
| class VL53L0XSensor : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice { | ||||
|  public: | ||||
|   void setup() override; | ||||
|  | ||||
|   void dump_config() override; | ||||
|   float get_setup_priority() const override { return setup_priority::DATA; } | ||||
|   void update() override; | ||||
|  | ||||
|   void loop() override; | ||||
|  | ||||
|   void set_signal_rate_limit(float signal_rate_limit) { signal_rate_limit_ = signal_rate_limit; } | ||||
|  | ||||
|  protected: | ||||
|   uint32_t get_measurement_timing_budget_() { | ||||
|     SequenceStepEnables enables{}; | ||||
|     SequenceStepTimeouts timeouts{}; | ||||
|  | ||||
|     uint16_t start_overhead = 1910; | ||||
|     uint16_t end_overhead = 960; | ||||
|     uint16_t msrc_overhead = 660; | ||||
|     uint16_t tcc_overhead = 590; | ||||
|     uint16_t dss_overhead = 690; | ||||
|     uint16_t pre_range_overhead = 660; | ||||
|     uint16_t final_range_overhead = 550; | ||||
|  | ||||
|     // "Start and end overhead times always present" | ||||
|     uint32_t budget_us = start_overhead + end_overhead; | ||||
|  | ||||
|     get_sequence_step_enables_(&enables); | ||||
|     get_sequence_step_timeouts_(&enables, &timeouts); | ||||
|  | ||||
|     if (enables.tcc) | ||||
|       budget_us += (timeouts.msrc_dss_tcc_us + tcc_overhead); | ||||
|  | ||||
|     if (enables.dss) | ||||
|       budget_us += 2 * (timeouts.msrc_dss_tcc_us + dss_overhead); | ||||
|     else if (enables.msrc) | ||||
|       budget_us += (timeouts.msrc_dss_tcc_us + msrc_overhead); | ||||
|  | ||||
|     if (enables.pre_range) | ||||
|       budget_us += (timeouts.pre_range_us + pre_range_overhead); | ||||
|  | ||||
|     if (enables.final_range) | ||||
|       budget_us += (timeouts.final_range_us + final_range_overhead); | ||||
|  | ||||
|     measurement_timing_budget_us_ = budget_us;  // store for internal reuse | ||||
|     return budget_us; | ||||
|   } | ||||
|  | ||||
|   bool set_measurement_timing_budget_(uint32_t budget_us) { | ||||
|     SequenceStepEnables enables{}; | ||||
|     SequenceStepTimeouts timeouts{}; | ||||
|  | ||||
|     uint16_t start_overhead = 1320;  // note that this is different than the value in get_ | ||||
|     uint16_t end_overhead = 960; | ||||
|     uint16_t msrc_overhead = 660; | ||||
|     uint16_t tcc_overhead = 590; | ||||
|     uint16_t dss_overhead = 690; | ||||
|     uint16_t pre_range_overhead = 660; | ||||
|     uint16_t final_range_overhead = 550; | ||||
|  | ||||
|     uint32_t min_timing_budget = 20000; | ||||
|  | ||||
|     if (budget_us < min_timing_budget) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     uint32_t used_budget_us = start_overhead + end_overhead; | ||||
|  | ||||
|     get_sequence_step_enables_(&enables); | ||||
|     get_sequence_step_timeouts_(&enables, &timeouts); | ||||
|  | ||||
|     if (enables.tcc) { | ||||
|       used_budget_us += (timeouts.msrc_dss_tcc_us + tcc_overhead); | ||||
|     } | ||||
|  | ||||
|     if (enables.dss) { | ||||
|       used_budget_us += 2 * (timeouts.msrc_dss_tcc_us + dss_overhead); | ||||
|     } else if (enables.msrc) { | ||||
|       used_budget_us += (timeouts.msrc_dss_tcc_us + msrc_overhead); | ||||
|     } | ||||
|  | ||||
|     if (enables.pre_range) { | ||||
|       used_budget_us += (timeouts.pre_range_us + pre_range_overhead); | ||||
|     } | ||||
|  | ||||
|     if (enables.final_range) { | ||||
|       used_budget_us += final_range_overhead; | ||||
|  | ||||
|       // "Note that the final range timeout is determined by the timing | ||||
|       // budget and the sum of all other timeouts within the sequence. | ||||
|       // If there is no room for the final range timeout, then an error | ||||
|       // will be set. Otherwise the remaining time will be applied to | ||||
|       // the final range." | ||||
|  | ||||
|       if (used_budget_us > budget_us) { | ||||
|         // "Requested timeout too big." | ||||
|         return false; | ||||
|       } | ||||
|  | ||||
|       uint32_t final_range_timeout_us = budget_us - used_budget_us; | ||||
|  | ||||
|       // set_sequence_step_timeout() begin | ||||
|       // (SequenceStepId == VL53L0X_SEQUENCESTEP_FINAL_RANGE) | ||||
|  | ||||
|       // "For the final range timeout, the pre-range timeout | ||||
|       //  must be added. To do this both final and pre-range | ||||
|       //  timeouts must be expressed in macro periods MClks | ||||
|       //  because they have different vcsel periods." | ||||
|  | ||||
|       uint16_t final_range_timeout_mclks = | ||||
|           timeout_microseconds_to_mclks_(final_range_timeout_us, timeouts.final_range_vcsel_period_pclks); | ||||
|  | ||||
|       if (enables.pre_range) { | ||||
|         final_range_timeout_mclks += timeouts.pre_range_mclks; | ||||
|       } | ||||
|  | ||||
|       write_byte_16(0x71, encode_timeout_(final_range_timeout_mclks)); | ||||
|  | ||||
|       // set_sequence_step_timeout() end | ||||
|  | ||||
|       measurement_timing_budget_us_ = budget_us;  // store for internal reuse | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   void get_sequence_step_enables_(SequenceStepEnables *enables) { | ||||
|     uint8_t sequence_config = reg(0x01).get(); | ||||
|     enables->tcc = (sequence_config >> 4) & 0x1; | ||||
|     enables->dss = (sequence_config >> 3) & 0x1; | ||||
|     enables->msrc = (sequence_config >> 2) & 0x1; | ||||
|     enables->pre_range = (sequence_config >> 6) & 0x1; | ||||
|     enables->final_range = (sequence_config >> 7) & 0x1; | ||||
|   } | ||||
|  | ||||
|   enum VcselPeriodType { VCSEL_PERIOD_PRE_RANGE, VCSEL_PERIOD_FINAL_RANGE }; | ||||
|  | ||||
|   void get_sequence_step_timeouts_(SequenceStepEnables const *enables, SequenceStepTimeouts *timeouts) { | ||||
|     timeouts->pre_range_vcsel_period_pclks = get_vcsel_pulse_period_(VCSEL_PERIOD_PRE_RANGE); | ||||
|  | ||||
|     timeouts->msrc_dss_tcc_mclks = reg(0x46).get() + 1; | ||||
|     timeouts->msrc_dss_tcc_us = | ||||
|         timeout_mclks_to_microseconds_(timeouts->msrc_dss_tcc_mclks, timeouts->pre_range_vcsel_period_pclks); | ||||
|  | ||||
|     uint16_t value; | ||||
|     read_byte_16(0x51, &value); | ||||
|     timeouts->pre_range_mclks = decode_timeout_(value); | ||||
|     timeouts->pre_range_us = | ||||
|         timeout_mclks_to_microseconds_(timeouts->pre_range_mclks, timeouts->pre_range_vcsel_period_pclks); | ||||
|  | ||||
|     timeouts->final_range_vcsel_period_pclks = get_vcsel_pulse_period_(VCSEL_PERIOD_FINAL_RANGE); | ||||
|  | ||||
|     read_byte_16(0x71, &value); | ||||
|     timeouts->final_range_mclks = decode_timeout_(value); | ||||
|  | ||||
|     if (enables->pre_range) { | ||||
|       timeouts->final_range_mclks -= timeouts->pre_range_mclks; | ||||
|     } | ||||
|  | ||||
|     timeouts->final_range_us = | ||||
|         timeout_mclks_to_microseconds_(timeouts->final_range_mclks, timeouts->final_range_vcsel_period_pclks); | ||||
|   } | ||||
|  | ||||
|   uint8_t get_vcsel_pulse_period_(VcselPeriodType type) { | ||||
|     uint8_t vcsel; | ||||
|     if (type == VCSEL_PERIOD_PRE_RANGE) | ||||
|       vcsel = reg(0x50).get(); | ||||
|     else if (type == VCSEL_PERIOD_FINAL_RANGE) | ||||
|       vcsel = reg(0x70).get(); | ||||
|     else | ||||
|       return 255; | ||||
|  | ||||
|     return (vcsel + 1) << 1; | ||||
|   } | ||||
|  | ||||
|   uint32_t get_macro_period_(uint8_t vcsel_period_pclks) { | ||||
|     return ((2304UL * vcsel_period_pclks * 1655UL) + 500UL) / 1000UL; | ||||
|   } | ||||
|  | ||||
|   uint32_t timeout_mclks_to_microseconds_(uint16_t timeout_period_mclks, uint8_t vcsel_period_pclks) { | ||||
|     uint32_t macro_period_ns = get_macro_period_(vcsel_period_pclks); | ||||
|     return ((timeout_period_mclks * macro_period_ns) + (macro_period_ns / 2)) / 1000; | ||||
|   } | ||||
|   uint32_t timeout_microseconds_to_mclks_(uint32_t timeout_period_us, uint8_t vcsel_period_pclks) { | ||||
|     uint32_t macro_period_ns = get_macro_period_(vcsel_period_pclks); | ||||
|     return (((timeout_period_us * 1000) + (macro_period_ns / 2)) / macro_period_ns); | ||||
|   } | ||||
|  | ||||
|   uint16_t decode_timeout_(uint16_t reg_val) { | ||||
|     // format: "(LSByte * 2^MSByte) + 1" | ||||
|     uint8_t msb = (reg_val >> 8) & 0xFF; | ||||
|     uint8_t lsb = (reg_val >> 0) & 0xFF; | ||||
|     return (uint16_t(lsb) << msb) + 1; | ||||
|   } | ||||
|   uint16_t encode_timeout_(uint16_t timeout_mclks) { | ||||
|     // format: "(LSByte * 2^MSByte) + 1" | ||||
|     uint32_t ls_byte = 0; | ||||
|     uint16_t ms_byte = 0; | ||||
|  | ||||
|     if (timeout_mclks <= 0) | ||||
|       return 0; | ||||
|  | ||||
|     ls_byte = timeout_mclks - 1; | ||||
|  | ||||
|     while ((ls_byte & 0xFFFFFF00) > 0) { | ||||
|       ls_byte >>= 1; | ||||
|       ms_byte++; | ||||
|     } | ||||
|  | ||||
|     return (ms_byte << 8) | (ls_byte & 0xFF); | ||||
|   } | ||||
|  | ||||
|   bool perform_single_ref_calibration_(uint8_t vhv_init_byte) { | ||||
|     reg(0x00) = 0x01 | vhv_init_byte;  // VL53L0X_REG_SYSRANGE_MODE_START_STOP | ||||
|  | ||||
|     uint32_t start = millis(); | ||||
|     while ((reg(0x13).get() & 0x07) == 0) { | ||||
|       if (millis() - start > 1000) | ||||
|         return false; | ||||
|       yield(); | ||||
|     } | ||||
|  | ||||
|     reg(0x0B) = 0x01; | ||||
|     reg(0x00) = 0x00; | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   float signal_rate_limit_; | ||||
|   uint32_t measurement_timing_budget_us_; | ||||
|   bool initiated_read_{false}; | ||||
|   bool waiting_for_interrupt_{false}; | ||||
|   uint8_t stop_variable_; | ||||
| }; | ||||
|  | ||||
| }  // namespace vl53l0x | ||||
| }  // namespace esphome | ||||
		Reference in New Issue
	
	Block a user