Slowed down refresh rate of ac rms sensors with sliding_window_moving_average filter in yaml file. Added sample limit on rms sensor in read_multi procedure. Updated README.md file.

This commit is contained in:
Chris Stuurman 2026-05-11 22:28:13 +02:00
parent 2184825302
commit 40c7cf58e6
4 changed files with 106 additions and 55 deletions

View File

@ -15,12 +15,6 @@ substitutions:
ADC_CS_PIN: GPIO41
ADC_DRDY_PIN: GPIO42
external_components:
- source:
type: local
path: components # Path relative to this YAML file
components: [ ads131m08 ]
spi:
- id: spi_bus0
clk_pin: ${ESP32_S3_SPI0_SCK}
@ -29,15 +23,25 @@ spi:
interface: hardware
ads131m08:
id: highres_adc
- id: highres_adc
spi_id: spi_bus0
cs_pin: ${ADC_CS_PIN}
drdy_pin: ${ADC_DRDY_PIN}
sync_reset_pin: ${ADC_SYNC_RESET_PIN}
reference_voltage: 1.25
data_rate: 10MHz
reference_voltage: 1.248 #1.25
data_rate: 5MHz
clock_frequency: 8192kHz
oversampling_ratio: 512
spi_mode: MODE1
dcblock_filter: 5 # 10Hz
power_mode: high
global_chop: no
global_chop_delay: 1024
current_detect: disable
current_detect_all: no
current_detect_number: 16
current_detect_length: 768
current_detect_threshold: -500
sensor:
- platform: ads131m08
@ -49,11 +53,14 @@ sensor:
offset_calibration: 0
gain_calibration: 0.986
ac:
name: "Channel 0 AC"
id: ads_ch0_ac
dc:
name: "Channel 0 DC"
id: ads_ch0_dc
name: "ac_ch0"
id: ac_ch0
filters:
- multiply: 2884
- sliding_window_moving_average:
window_size: 50
send_every: 25
send_first_at: 10
- platform: ads131m08
ads131m08_id: highres_adc
@ -64,17 +71,34 @@ sensor:
offset_calibration: 0
gain_calibration: 0.986
ac:
name: "Channel 1 AC"
id: ads_ch1_ac
accuracy_decimals: 6
state_class: measurement
device_class: voltage
dc:
name: "Channel 1 DC"
id: ads_ch1_dc
accuracy_decimals: 6
state_class: measurement
device_class: voltage
name: "ac_ch1"
id: ac_ch1
filters:
- multiply: 2884
- sliding_window_moving_average:
window_size: 50
send_every: 25
send_first_at: 10
- platform: ads131m08
ads131m08_id: highres_adc
channel: 2
id: ads_ch2
gain: 1
input_select: normal
offset_calibration: 0
gain_calibration: 1.36153846
dc_block: enable
ac:
name: "ac_ch2"
id: ac_ch2
device_class: current
filters:
- multiply: 62.97
- sliding_window_moving_average:
window_size: 50
send_every: 25
send_first_at: 10
```
For more information, visit the [ESPHome documentation](https://esphome.io/).

View File

@ -122,19 +122,30 @@ void ADS131M08Hub::dump_config() {
this->power_mode_ == VERY_LOW_POWER ? "'very low power'"
: this->power_mode_ == LOW_POWER ? "'low power'"
: "'high resolution'");
ESP_LOGCONFIG(TAG, " Global Chop: %s", this->global_chop_enable_ ? "enable" : "disable");
ESP_LOGCONFIG(TAG, " Global Chop Delay: %u", 1 << (1 + this->global_chop_delay_));
ESP_LOGCONFIG(TAG, " Current Detect: %s", this->current_detect_enable_ ? "enable" : "disable");
ESP_LOGCONFIG(TAG, " Current Detect All: %s", this->current_detect_all_enable_ ? "YES" : "NO");
ESP_LOGCONFIG(TAG, " Current Detect Number: %u", 1 << this->current_detect_number_);
ESP_LOGCONFIG(TAG, " Current Detect Length: %u", convert_adc_cd_len_to_value(this->current_detect_length_));
ESP_LOGCONFIG(TAG, " Current Detect Threshold: %ld", this->current_detect_threshold_);
std::string str =" Global Chop";
ESP_LOGCONFIG(TAG, "%s: %s", str.c_str(), this->global_chop_enable_ ? "enable" : "disable");
ESP_LOGCONFIG(TAG, "%s Delay: %u", str.c_str(), 1 << (1 + this->global_chop_delay_));
str = " Current Detect";
ESP_LOGCONFIG(TAG, "%s: %s", str.c_str(), this->current_detect_enable_ ? "enable" : "disable");
ESP_LOGCONFIG(TAG, "%s All: %s", str.c_str(), this->current_detect_all_enable_ ? "YES" : "NO");
ESP_LOGCONFIG(TAG, "%s Number: %u", str.c_str(), 1 << this->current_detect_number_);
ESP_LOGCONFIG(TAG, "%s Length: %u", str.c_str(), convert_adc_cd_len_to_value(this->current_detect_length_));
ESP_LOGCONFIG(TAG, "%s Threshold: %ld", str.c_str(), this->current_detect_threshold_);
str =" DC Block Filter";
if(this->dcblock_filter_ == 0) {
ESP_LOGCONFIG(TAG, "%s: 0 (disabled)", str.c_str());
}
else if(this->dcblock_filter_ > 15) {
ESP_LOGCONFIG(TAG, "%s: %u (invalid)", str.c_str(), this->dcblock_filter_);
}
else {
ESP_LOGCONFIG(TAG, "%s('a'): %u (1/%u)", str.c_str(), this->dcblock_filter_, convert_adc_dc_block_to_value(this->dcblock_filter_));
}
ESP_LOGCONFIG(TAG, " SPI Mode: %d", this->mode_);
ESP_LOGCONFIG(TAG, " Bit Order: %s",
this->bit_order_ == spi::BIT_ORDER_MSB_FIRST ? "msb_first"
: this->bit_order_ == spi::BIT_ORDER_LSB_FIRST ? "lsb_first"
: "unknown");
// TODO: add new configs
: "invalid");
}
uint8_t ADS131M08Hub::update_adc_word_length() {
@ -835,7 +846,7 @@ void ADS131M08Hub::read_single() {
}
// do not like what the following procedure does at all (it blocks for +-40ms), but at the moment do not know how to get
// DRDY interrupt / ISR / loop setup to respond fast enough to read multiple frames with no or the minimum possible
// missed frames in quick succession idealy would want to read +- 200 24/32bit in 40ms. Gor now, this seems to be the
// missed frames in quick succession idealy would want to read +- 200 24/32bit in 40ms. For now, this seems to be the
// only way to do it.
float_str ADS131M08Hub::read_multi() {
int32_t raw;
@ -861,7 +872,11 @@ float_str ADS131M08Hub::read_multi() {
}
CHIP_SELECTx
uint32_t settling_end_time = loop_start_time;
while ((elapsed_time < sample_time) && (iteration++ < 1000)) {
uint32_t samples_per_second = 8000; // for osr of 512
uint32_t sample_target = (sample_time * samples_per_second) / 1000000; // sample_time is in microseconds
//ESP_LOGI(TAG,"sample_target: %lu active_channel_count_: %d", sample_target, this->active_channel_count_);
int nchannels_sampled = 0;
while ((elapsed_time < sample_time) && (nchannels_sampled < this->active_channel_count_) && (iteration++ < 1000)) {
result[2] = iteration;
setup_frame(rx_frame, numFrameWords);
this->transfer_array(rx_frame);
@ -890,7 +905,8 @@ float_str ADS131M08Hub::read_multi() {
if(drdy_status == 0){
result[3]++;
}
for (i = 0; i < ADC_CHANNELS && drdy_status != 0; i++) {
nchannels_sampled = 0;
for (i = 0; (i < ADC_CHANNELS) && (drdy_status != 0); i++) {
data_ready = drdy_status & 1;
drdy_status = drdy_status >> 1;
if (data_ready) {
@ -901,9 +917,15 @@ float_str ADS131M08Hub::read_multi() {
raw = get_sign_ext_frame_word(rx_frame, i + 1);
value = this->conversion_factor_ * raw;
if (this->rms_enabled_[i]) {
if(this->num_samples_[i] < sample_target) {
(this->num_samples_[i])++;
(this->sample_sum_[i]) += value;
(this->sample_squared_sum_[i]) += value * value;
}
else {
nchannels_sampled++;
//ESP_LOGI(TAG,"target: %lu ac_cnt: %d it: %d sampled: %d time: %lu", sample_target, this->active_channel_count_, iteration, nchannels_sampled, elapsed_time);
}
} else {
if(ac_sensor_exist)
this->sensors_ac[i]->publish_state(value);
@ -1190,8 +1212,7 @@ bool ADS131M08Hub::adc_register_write(uint16_t start_address, const uint16_str &
uint16_t addr_regcnt_mask = (start_address << 7) | ((nregs - 1) & MASK_CMD_RW_REG_COUNT);
uint16_t wreg_addr_opcode = CMD_WREG | addr_regcnt_mask; // Combine WREG command, start_address and register count
uint16_t rreg_addr_opcode = CMD_RREG | addr_regcnt_mask; // Combine RREG command, start_address and register count
bool has_mode_reg =
(start_address == REG_MODE) || ((start_address < REG_MODE) && ((start_address + nregs) > REG_MODE));
bool has_mode_reg = (start_address == REG_MODE) || ((start_address < REG_MODE) && ((start_address + nregs) > REG_MODE));
setup_frame(rx_frame, wreg_nwords);
{
CHIP_SELECT
@ -1217,6 +1238,11 @@ bool ADS131M08Hub::adc_register_write(uint16_t start_address, const uint16_str &
//ESP_LOGW(TAG, "Write: %s", reg_data_to_string(start_address + i, data[i]).c_str());
//ESP_LOGW(TAG, "Ack : %s", reg_data_to_string(start_address + i, rxdata[i]).c_str());
}
if((start_address + i) == REG_CLOCK) {
// count the number of channels that were enabled
uint16_t clock_reg_data = data[i] & MASK_CLOCK_ALLCH;
this->active_channel_count_ = std::popcount(clock_reg_data);
}
}
delay_microseconds_safe(T_REGACQ);
return verified;

View File

@ -150,6 +150,7 @@ class ADS131M08Hub : public Component,
uint32_t convert_adc_clock_cycles_to_micros(uint32_t cycles);
uint16_t convert_adc_osr_to_value(uint16_t adc_osr) { auto osr = 1 << (7 + adc_osr); return (osr == 16384) ? 16256 : osr; }
uint16_t convert_adc_cd_len_to_value(uint16_t adc_cd_len) { return adc_cd_len >= sizeof(current_detect_lengths) ? 0 : current_detect_lengths[adc_cd_len]; }
uint16_t convert_adc_dc_block_to_value(uint16_t dcblock) { return dcblock > 15 ? 0 : (1 << (dcblock + 1)); } // returns denominator of 'a' coefficient
protected:
std::string id_;
@ -165,6 +166,7 @@ class ADS131M08Hub : public Component,
float sampled_values_[ADC_CHANNELS];
bool rms_enabled_[MAX_CHANNELS];
bool rms_calc_req_{false};
int active_channel_count_{0};
uint16_t osr_{3};
uint16_t global_chop_delay_{16};
bool global_chop_enable_{false};
@ -203,8 +205,7 @@ class ADS131M08Hub : public Component,
int32_t SET_IRAM get_sign_ext_frame_word(const spiframe &frame, int w_index);
//bool update_averages(uint8_t channel, float rms_ac, float rms_dc);
std::atomic<int> adc_init_{0};
std::atomic<int> cs_ctr_{
0}; // Counter to track nested CS enable/disable calls for proper handling of multiple transfers in a row
std::atomic<int> cs_ctr_{0}; // Counter to track nested CS enable/disable calls
std::atomic<uint16_t> isr_ctr_{0};
void enable(const char *txt);
void disable(const char *txt);

View File

@ -70,16 +70,16 @@ int16_t Channel::normalised_phase_calibration() const
void Channel::dump_config() {
ESP_LOGCONFIG(TAG, "Channel %" PRIu8 ":", this->channel_);
ESP_LOGCONFIG(TAG, " Gain: %" PRIu8, 1 << this->gain_);
ESP_LOGCONFIG(TAG, " Gain calibration: %f", this->gain_cal_);
ESP_LOGCONFIG(TAG, " Offset calibration: %" PRIu32, this->offset_cal_);
ESP_LOGCONFIG(TAG, " Phase calibration: %" PRId32, this->phase_cal_);
ESP_LOGCONFIG(TAG, " DC block: %s", this->dc_block_ ? "YES" : "NO");
ESP_LOGCONFIG(TAG, " Input select: %s", (this->input_ == ICM_AIN0P_AIN0N) ? "normal" \
: (this->input_ == ICM_INPUT_SHORTED) ? "shorted" \
: (this->input_ == ICM_POSITIVE_DC_TEST_SIGNAL) ? "positive_dc" \
: (this->input_ == ICM_NEGATIVE_DC_TEST_SIGNAL) ? "negative_dc" \
: "invalid");
ESP_LOGCONFIG(TAG, " Gain: %" PRIu8, 1 << this->gain_);
ESP_LOGCONFIG(TAG, " Gain calibration: %f", this->gain_cal_);
ESP_LOGCONFIG(TAG, " Offset calibration: %" PRIu32, this->offset_cal_);
ESP_LOGCONFIG(TAG, " Phase calibration: %" PRId32, this->phase_cal_);
ESP_LOGCONFIG(TAG, " DC block: %s", this->dc_block_ ? "YES" : "NO");
}
void RMS_Sensor::loop()