TSL2591 automatic gain control (#3071)

This commit is contained in:
Nicholas Peters
2022-01-26 04:48:51 -05:00
committed by GitHub
parent 511c8de6f3
commit c5974b8833
3 changed files with 101 additions and 19 deletions
+66 -6
View File
@@ -43,6 +43,8 @@ void TSL2591Component::disable_if_power_saving_() {
}
void TSL2591Component::setup() {
if (this->component_gain_ == TSL2591_CGAIN_AUTO)
this->gain_ = TSL2591_GAIN_MED;
uint8_t address = this->address_;
ESP_LOGI(TAG, "Setting up TSL2591 sensor at I2C address 0x%02X", address);
uint8_t id;
@@ -73,26 +75,30 @@ void TSL2591Component::dump_config() {
}
ESP_LOGCONFIG(TAG, " Name: %s", this->name_);
TSL2591Gain raw_gain = this->gain_;
TSL2591ComponentGain raw_gain = this->component_gain_;
int gain = 0;
std::string gain_word = "unknown";
switch (raw_gain) {
case TSL2591_GAIN_LOW:
case TSL2591_CGAIN_LOW:
gain = 1;
gain_word = "low";
break;
case TSL2591_GAIN_MED:
case TSL2591_CGAIN_MED:
gain = 25;
gain_word = "medium";
break;
case TSL2591_GAIN_HIGH:
case TSL2591_CGAIN_HIGH:
gain = 400;
gain_word = "high";
break;
case TSL2591_GAIN_MAX:
case TSL2591_CGAIN_MAX:
gain = 9500;
gain_word = "maximum";
break;
case TSL2591_CGAIN_AUTO:
gain = -1;
gain_word = "auto";
break;
}
ESP_LOGCONFIG(TAG, " Gain: %dx (%s)", gain, gain_word.c_str());
TSL2591IntegrationTime raw_timing = this->integration_time_;
@@ -129,6 +135,9 @@ void TSL2591Component::process_update_() {
if (this->calculated_lux_sensor_ != nullptr) {
this->calculated_lux_sensor_->publish_state(lux);
}
if (this->component_gain_ == TSL2591_CGAIN_AUTO) {
this->automatic_gain_update(full);
}
this->status_clear_warning();
}
@@ -183,7 +192,7 @@ void TSL2591Component::set_integration_time(TSL2591IntegrationTime integration_t
this->integration_time_ = integration_time;
}
void TSL2591Component::set_gain(TSL2591Gain gain) { this->gain_ = gain; }
void TSL2591Component::set_gain(TSL2591ComponentGain gain) { this->component_gain_ = gain; }
void TSL2591Component::set_device_and_glass_attenuation_factors(float device_factor, float glass_attenuation_factor) {
this->device_factor_ = device_factor;
@@ -366,5 +375,56 @@ float TSL2591Component::get_calculated_lux(uint16_t full_spectrum, uint16_t infr
return std::max(lux, 0.0F);
}
/** Calculates and updates the sensor gain setting, trying to keep the full spectrum counts near
* the middle of the range
*
* It's hard to tell how far down to turn the gain when it's at the top of the scale, so decrease
* the gain by up to 2 steps if it's near the top to be sure we get a good reading next time.
* Increase gain by max 2 steps per reading.
*
* If integration time is 100 MS, divide the upper thresholds by 2 to account for ADC saturation
*
* @param full_spectrum The ADC reading for TSL2591 channel 0.
*
* 1/3 FS = 21,845
*/
void TSL2591Component::automatic_gain_update(uint16_t full_spectrum) {
TSL2591Gain new_gain = this->gain_;
uint fs_divider = (this->integration_time_ == TSL2591_INTEGRATION_TIME_100MS) ? 2 : 1;
switch (this->gain_) {
case TSL2591_GAIN_LOW:
if (full_spectrum < 54) // 1/3 FS / GAIN_HIGH
new_gain = TSL2591_GAIN_HIGH;
else if (full_spectrum < 875) // 1/3 FS / GAIN_MED
new_gain = TSL2591_GAIN_MED;
break;
case TSL2591_GAIN_MED:
if (full_spectrum < 57) // 1/3 FS / (GAIN_MAX/GAIN_MED)
new_gain = TSL2591_GAIN_MAX;
else if (full_spectrum < 1365) // 1/3 FS / (GAIN_HIGH/GAIN_MED)
new_gain = TSL2591_GAIN_HIGH;
else if (full_spectrum > 62000 / fs_divider) // 2/3 FS / (GAIN_LOW/GAIN_MED) clipped to 95% FS
new_gain = TSL2591_GAIN_LOW;
break;
case TSL2591_GAIN_HIGH:
if (full_spectrum < 920) // 1/3 FS / (GAIN_MAX/GAIN_HIGH)
new_gain = TSL2591_GAIN_MAX;
else if (full_spectrum > 62000 / fs_divider) // 2/3 FS / (GAIN_MED/GAIN_HIGH) clipped to 95% FS
new_gain = TSL2591_GAIN_LOW;
break;
case TSL2591_GAIN_MAX:
if (full_spectrum > 62000 / fs_divider) // 2/3 FS / (GAIN_MED/GAIN_HIGH) clipped to 95% FS
new_gain = TSL2591_GAIN_MED;
break;
}
if (this->gain_ != new_gain) {
this->gain_ = new_gain;
this->set_integration_time_and_gain(this->integration_time_, this->gain_);
}
ESP_LOGD(TAG, "Gain setting: %d", this->gain_);
}
} // namespace tsl2591
} // namespace esphome