From 853d81c6ddb7d9d11e04156707a83451214c7356 Mon Sep 17 00:00:00 2001 From: Mark Veinot Date: Wed, 11 Oct 2023 22:27:36 -0300 Subject: [PATCH] As3935 calibration (#5366) --- esphome/components/as3935/__init__.py | 6 ++ esphome/components/as3935/as3935.cpp | 89 +++++++++++++++++++++++++++ esphome/components/as3935/as3935.h | 14 +++++ esphome/const.py | 1 + 4 files changed, 110 insertions(+) diff --git a/esphome/components/as3935/__init__.py b/esphome/components/as3935/__init__.py index 5cec1bfaba..2ec7c50859 100644 --- a/esphome/components/as3935/__init__.py +++ b/esphome/components/as3935/__init__.py @@ -8,6 +8,8 @@ from esphome.const import ( CONF_IRQ_PIN, CONF_LIGHTNING_THRESHOLD, CONF_MASK_DISTURBER, + CONF_CALIBRATION, + CONF_TUNE_ANTENNA, CONF_NOISE_LEVEL, CONF_SPIKE_REJECTION, CONF_WATCHDOG_THRESHOLD, @@ -34,6 +36,8 @@ AS3935_SCHEMA = cv.Schema( cv.Optional(CONF_MASK_DISTURBER, default=False): cv.boolean, cv.Optional(CONF_DIV_RATIO, default=0): cv.one_of(0, 16, 32, 64, 128, int=True), cv.Optional(CONF_CAPACITANCE, default=0): cv.int_range(min=0, max=15), + cv.Optional(CONF_TUNE_ANTENNA, default=False): cv.boolean, + cv.Optional(CONF_CALIBRATION, default=True): cv.boolean, } ) @@ -51,3 +55,5 @@ async def setup_as3935(var, config): cg.add(var.set_mask_disturber(config[CONF_MASK_DISTURBER])) cg.add(var.set_div_ratio(config[CONF_DIV_RATIO])) cg.add(var.set_capacitance(config[CONF_CAPACITANCE])) + cg.add(var.set_tune_antenna(config[CONF_TUNE_ANTENNA])) + cg.add(var.set_calibration(config[CONF_CALIBRATION])) diff --git a/esphome/components/as3935/as3935.cpp b/esphome/components/as3935/as3935.cpp index c5651caee3..29fc6ee685 100644 --- a/esphome/components/as3935/as3935.cpp +++ b/esphome/components/as3935/as3935.cpp @@ -21,6 +21,14 @@ void AS3935Component::setup() { this->write_mask_disturber(this->mask_disturber_); this->write_div_ratio(this->div_ratio_); this->write_capacitance(this->capacitance_); + + // Handle setting up tuning or auto-calibration + if (this->tune_antenna_) { + ESP_LOGCONFIG(TAG, " Antenna tuning: ENABLED - lightning detection will not function in this mode"); + this->tune_antenna(); + } else if (this->calibration_) { + this->calibrate_oscillator(); + } } void AS3935Component::dump_config() { @@ -227,6 +235,87 @@ uint32_t AS3935Component::get_lightning_energy_() { return pure_light; } +// REG0x03, bit [7:6], manufacturer default: 0 (16 division ratio). +// This function returns the current division ratio of the resonance frequency. +// The antenna resonance frequency should be within 3.5 percent of 500kHz, and +// so when modifying the resonance frequency with the internal capacitors +// (tuneCap()) it's important to keep in mind that the displayed frequency on +// the IRQ pin is divided by this number. +uint8_t AS3935Component::read_div_ratio() { + ESP_LOGV(TAG, "Calling read_div_ratio"); + uint8_t reg_val = this->read_register_(INT_MASK_ANT, DIV_MASK); + reg_val >>= 6; // Front of the line. + + if (reg_val == 0) { + return 16; + } else if (reg_val == 1) { + return 32; + } else if (reg_val == 2) { + return 64; + } else if (reg_val == 3) { + return 128; + } + ESP_LOGW(TAG, "Unknown response received for div_ratio"); + return 0; +} + +uint8_t AS3935Component::read_capacitance() { + ESP_LOGV(TAG, "Calling read_capacitance"); + uint8_t reg_val = this->read_register_(FREQ_DISP_IRQ, CAP_MASK) * 8; + return (reg_val); +} + +// REG0x08, bits [5,6,7], manufacturer default: 0. +// This will send the frequency of the oscillators to the IRQ pin. +// _osc 1, bit[5] = TRCO - System RCO at 32.768kHz +// _osc 2, bit[6] = SRCO - Timer RCO Oscillators 1.1MHz +// _osc 3, bit[7] = LCO - Frequency of the Antenna +void AS3935Component::display_oscillator(bool state, uint8_t osc) { + if ((osc < 1) || (osc > 3)) + return; + + this->write_register(FREQ_DISP_IRQ, OSC_MASK, state, 4 + osc); +} + +// REG0x3D, bits[7:0] +// This function calibrates both internal oscillators The oscillators are tuned +// based on the resonance frequency of the antenna and so it should be trimmed +// before the calibration is done. +bool AS3935Component::calibrate_oscillator() { + ESP_LOGI(TAG, "Starting oscillators calibration..."); + this->write_register(CALIB_RCO, WIPE_ALL, DIRECT_COMMAND, 0); // Send command to calibrate the oscillators + + this->display_oscillator(true, 2); + delay(2); // Give time for the internal oscillators to start up. + this->display_oscillator(false, 2); + + // Check it they were calibrated successfully. + uint8_t reg_val_srco = this->read_register_(CALIB_SRCO, CALIB_MASK_NOK); + uint8_t reg_val_trco = this->read_register_(CALIB_TRCO, CALIB_MASK_NOK); + + // reg_val_srco &= CALIB_MASK; + // reg_val_srco >>= 6; + // reg_val_trco &= CALIB_MASK; + // reg_val_trco >>= 6; + if (!reg_val_srco && !reg_val_trco) { // Zero upon success + ESP_LOGI(TAG, "Calibration was succesful"); + return true; + } else { + ESP_LOGW(TAG, "Calibration was NOT succesful"); + return false; + } +} + +void AS3935Component::tune_antenna() { + ESP_LOGI(TAG, "Starting antenna tuning..."); + uint8_t div_ratio = this->read_div_ratio(); + uint8_t tune_val = this->read_capacitance(); + ESP_LOGI(TAG, "Division Ratio is set to: %d", div_ratio); + ESP_LOGI(TAG, "Internal Capacitor is set to: %d", tune_val); + ESP_LOGI(TAG, "Displaying oscillator on INT pin. Measure its frequency - multiply value by Division Ratio"); + this->display_oscillator(true, ANTFREQ); +} + uint8_t AS3935Component::read_register_(uint8_t reg, uint8_t mask) { uint8_t value = this->read_register(reg); value &= (~mask); diff --git a/esphome/components/as3935/as3935.h b/esphome/components/as3935/as3935.h index a8af703a59..dc590c268e 100644 --- a/esphome/components/as3935/as3935.h +++ b/esphome/components/as3935/as3935.h @@ -13,6 +13,9 @@ namespace esphome { namespace as3935 { +static const uint8_t DIRECT_COMMAND = 0x96; +static const uint8_t ANTFREQ = 3; + enum AS3935RegisterNames { AFE_GAIN = 0x00, THRESHOLD, @@ -30,6 +33,7 @@ enum AS3935RegisterNames { }; enum AS3935RegisterMasks { + WIPE_ALL = 0x0, GAIN_MASK = 0x3E, SPIKE_MASK = 0xF, IO_MASK = 0xC1, @@ -44,6 +48,7 @@ enum AS3935RegisterMasks { NOISE_FLOOR_MASK = 0x70, OSC_MASK = 0xE0, CALIB_MASK = 0x7F, + CALIB_MASK_NOK = 0xBF, DIV_MASK = 0x3F }; @@ -90,6 +95,13 @@ class AS3935Component : public Component { void write_div_ratio(uint8_t div_ratio); void set_capacitance(uint8_t capacitance) { capacitance_ = capacitance; } void write_capacitance(uint8_t capacitance); + uint8_t read_div_ratio(); + uint8_t read_capacitance(); + bool calibrate_oscillator(); + void display_oscillator(bool state, uint8_t osc); + void tune_antenna(); + void set_tune_antenna(bool tune_antenna) { tune_antenna_ = tune_antenna; } + void set_calibration(bool calibration) { calibration_ = calibration; } protected: uint8_t read_interrupt_register_(); @@ -112,6 +124,8 @@ class AS3935Component : public Component { bool mask_disturber_; uint8_t div_ratio_; uint8_t capacitance_; + bool tune_antenna_; + bool calibration_; }; } // namespace as3935 diff --git a/esphome/const.py b/esphome/const.py index 01555c35ec..fc67651193 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -783,6 +783,7 @@ CONF_TRACES = "traces" CONF_TRANSITION_LENGTH = "transition_length" CONF_TRIGGER_ID = "trigger_id" CONF_TRIGGER_PIN = "trigger_pin" +CONF_TUNE_ANTENNA = "tune_antenna" CONF_TURN_OFF_ACTION = "turn_off_action" CONF_TURN_ON_ACTION = "turn_on_action" CONF_TVOC = "tvoc"