Trying to recover from spurious ADC resets. Not successful. TODO: implement polling method instead of interrupts with setting up of ADC on each poll. If it is too lengthy to execute, then will try only setting up on detection of resets.

This commit is contained in:
Chris Stuurman 2026-05-05 23:29:56 +02:00
parent 3ae00bdddd
commit 799407c6be
2 changed files with 84 additions and 77 deletions

View File

@ -18,7 +18,7 @@ ads131m08_ns = cg.esphome_ns.namespace("ads131m08")
ADS131M08Hub = ads131m08_ns.class_("ADS131M08Hub", cg.Component, spi.SPIDevice)
OSR = ads131m08_ns.enum("ADS131M08_OVERSAMPLING_RATIO")
ALLOWED_OSRS = {
OSRS = {
128: OSR.OSR_128,
256: OSR.OSR_256,
512: OSR.OSR_512,
@ -29,7 +29,7 @@ ALLOWED_OSRS = {
16256: OSR.OSR_16256,
}
ALLOWED_CLOCK_FREQUENCIES = {
CLOCK_FREQUENCIES = {
2048000: 2048000,
4096000: 4096000,
8192000: 8192000,
@ -48,10 +48,10 @@ CONFIG_SCHEMA = (
cv.Required(CONF_DRDY_PIN): pins.internal_gpio_input_pin_schema,
cv.Optional(CONF_SYNC_RESET_PIN): pins.internal_gpio_input_pin_schema,
cv.Optional(CONF_CLOCK_FREQUENCY, default="8192kHz"): cv.All(
cv.frequency, cv.one_of(*ALLOWED_CLOCK_FREQUENCIES.keys())
cv.frequency, cv.one_of(*CLOCK_FREQUENCIES.keys())
),
cv.Optional(CONF_OVERSAMPLING_RATIO, default=1024): cv.enum(
ALLOWED_OSRS, int=True
OSRS, int=True
),
cv.Optional(CONF_REFERENCE_VOLTAGE, default=1.2): cv.float_range(
min=1.1, max=1.3
@ -71,7 +71,7 @@ async def to_code(config):
if CONF_SYNC_RESET_PIN in config:
sync_reset = await cg.gpio_pin_expression(config[CONF_SYNC_RESET_PIN])
cg.add(var.set_sync_reset_pin(sync_reset))
clock_frequency = ALLOWED_CLOCK_FREQUENCIES[config[CONF_CLOCK_FREQUENCY]]
clock_frequency = CLOCK_FREQUENCIES[config[CONF_CLOCK_FREQUENCY]]
cg.add(var.set_clock_frequency(clock_frequency))
osr = config[CONF_OVERSAMPLING_RATIO]
cg.add(var.set_osr(osr))

View File

@ -9,6 +9,8 @@
#include "esp_system.h"
#include "spi_flash_mmap.h"
# include "driver/spi_master.h"
// using namespace esphome::spi;
/*
@ -226,6 +228,9 @@ bool ADS131M08Hub::adc_restore_registers() {
int j = 0;
int store_nwords = sizeof(settings.data) / sizeof(settings.data[0]);
success = adc_register_write(j + REG_MODE, settings.data[j], __LINE__, false);
if(!success) {
ESP_LOGD(TAG, "restoring %s reg: %04X failed", reg_addr_to_string(j + REG_MODE).c_str(), settings.data[j]);
}
j++;
while(success && (j < store_nwords)) {
int i = 0;
@ -322,6 +327,14 @@ void ADS131M08Hub::loop()
uint64_t start = micros();
///this->txf_init(); // implementing datasheet recommended TXF init
this->adc_sync();
int freq = 0;
//if(delegate_ != nullptr){
// esp_err_t ret = spi_device_get_actual_freq((SPIDelegateHw)delegate_->handle_, &freq);
// if (ret != ESP_OK) {
// ESP_LOGE(TAG, "SPI get actual frequency failed!");
// }
// ESP_LOGD(TAG, "spi_freq: %u", freq);
//}
if (rms_calc_req_) {
float_str result = read_multi();
num_samples = result[0];
@ -797,20 +810,38 @@ float_str ADS131M08Hub::read_multi() {
//ESP_LOGD(TAG, "frame_word%d: %s", 0, frame_words_to_string(rx_frame, 0, 1).c_str());
status = get_unsigned_frame_word(rx_frame, 0, true);
update_adc_word_length(status);
crc_ok = check_crc(rx_frame);
if (crc_ok) {
if(status & MASK_STATUS_RESET) {
if(adc_reset_retry()) {
if(adc_restore_registers()) {
ESP_LOGW(TAG, "Mid data-read reset detected; restored registers");
ESP_LOGI(TAG,"Reset frame: %s", frame_to_string(rx_frame).c_str());
ESP_LOGW(TAG, "ADC reset detected. Trying recover");
if (!adc_register_write(REG_MODE, MODE_MASK_RESET_HAPPENED & reg_mode_cfg32, __LINE__)) {
ESP_LOGE(TAG, "MODE register write / read to set word size to 32bits failed");
return result;
}
this->set_timeout("reset detected", 250, [this, result]() {
ESP_LOGE(TAG, "ADC reset detected. Trying to restore registers");
if(this->adc_restore_registers()) {
ESP_LOGW(TAG, "Mid data-read reset detected; restored registers");
//delay_microseconds_safe(get_filter_settling_time() + 50);
txf_init();
return result;
}
ESP_LOGE(TAG, "ADC reset detected. Unable to recover");
this->mark_failed(LOG_STR("ADC reset detected. Recovery failed"));
//this->mark_failed(LOG_STR("ADC reset detected. Recovery failed"));
return result;
});
//if(adc_reset_retry()) {
// if(adc_restore_registers()) {
// ESP_LOGW(TAG, "Mid data-read reset detected; restored registers");
// return result;
// }
//}
//ESP_LOGE(TAG, "ADC reset detected. Unable to recover");
//this->mark_failed(LOG_STR("ADC reset detected. Recovery failed"));
//ESP_LOGE(TAG, "ADC reset detected");
return result;
}
else {
crc_ok = check_crc(rx_frame);
if (crc_ok) {
if(status & MASK_STATUS_RESYNC) {
settling_end_time = elapsed_time + get_filter_settling_time() + 50; // add 50us for good measure
}
@ -848,7 +879,6 @@ float_str ADS131M08Hub::read_multi() {
}
}
}
}
else {
result[1]++;
// ESP_LOGW(TAG, "iteration: %d, frame: %s CRC error", iteration, frame_to_string(frame).c_str());
@ -1021,16 +1051,14 @@ bool ADS131M08Hub::adc_register_write_masked(uint8_t address, uint16_t value, ui
// reg_contents[0],address, value,mask, line );
auto new_value = (reg_contents[0] & ~mask) | (value & mask);
if(new_value == reg_contents[0]) {
ESP_LOGW(TAG, "1: No update needed. reg: %02X data: %04X / %04X Line: %d", address, value, new_value, line);
//ESP_LOGW(TAG, "No updt: %-13s: newv %04X old regval %04X mskd %04X Line: %d", reg_addr_to_string(address).c_str(), value, reg_contents[0], new_value, line);
int bup_index = address - REG_MODE;
ESP_LOGW(TAG, "Storing: %-13s: data %04X stored val: %04X Line: %d", reg_addr_to_string(bup_index + REG_MODE).c_str(), value, settings.data[bup_index], line);
//ESP_LOGW(TAG, "Storing: %-13s: data %04X stored val %04X Line %d", reg_addr_to_string(address).c_str(), value, settings.data[bup_index], line);
// we backup data irrespective
settings.data[bup_index] = value;
return true; // no need for an adc reg update
}
reg_contents[0] = new_value;
//ESP_LOGW(TAG, "After applying mask - reg contents: 0x%04X, caller: %d", reg_contents[0], line );
//ESP_LOGD(TAG, "adc_register_write_masked: address: %02X value: %04X reg_contents: %04X mask: %04X new value: %04X Line:%d", address, value, reg_contents[0], mask, new_value, line);
return adc_register_write(address, reg_contents, line);
}
/// @brief
@ -1063,7 +1091,6 @@ bool ADS131M08Hub::adc_register_write_masked(uint8_t start_address, const uint16
if(reg_contents[i] != new_value)
update_required = true;
reg_contents[i] = new_value;
//ESP_LOGW(TAG, "After applying mask - reg contents: 0x%04X, caller: %d", reg_contents[i], line);
}
if(!update_required) {
//ESP_LOGW(TAG, "2: No update needed. start reg: %02X first data: %04X Line: %d", start_address, values[0], line);
@ -1092,7 +1119,7 @@ bool ADS131M08Hub::adc_register_write(uint16_t start_address, const uint16_str &
if(backup_data) {
int bup_index = start_address - REG_MODE;
for(auto i = data.begin(); i != data.end(); i++) {
ESP_LOGW(TAG, "Storing: %-13s: data %04X stored val: %04X Line: %d", reg_addr_to_string(bup_index + REG_MODE).c_str(), *i, settings.data[bup_index], line);
//ESP_LOGW(TAG, "Storing: %-13s: data %04X stored val: %04X Line: %d", reg_addr_to_string(bup_index + REG_MODE).c_str(), *i, settings.data[bup_index], line);
settings.data[bup_index++] = *i;
}
}
@ -1120,7 +1147,7 @@ bool ADS131M08Hub::adc_register_write(uint16_t start_address, const uint16_str &
set_frame_word(rx_frame, i + 1, data[i]);
}
add_crc(rx_frame);
//ESP_LOGD(TAG, "%s\n", rwreg_command_frame_to_string(rx_frame).c_str());
ESP_LOGD(TAG, "%s\n", rwreg_command_frame_to_string(rx_frame).c_str());
//ESP_LOGD(TAG, "Send Frame: %s", frame_to_string(rx_frame).c_str());
transfer_array(rx_frame); // WREG
}
@ -1135,7 +1162,7 @@ bool ADS131M08Hub::adc_register_write(uint16_t start_address, const uint16_str &
if (!verified) {
ESP_LOGE(TAG, "Write \'%s\' register failed: tx data: 0x%04X, rx data: 0x%04X", reg_addr_to_string(start_address + i).c_str(), data[i], rxdata[i]);
// ESP_LOGE(TAG, "Write: %s", reg_data_to_string(start_address + i, data[i]).c_str());
// ESP_LOGE(TAG, "Ack : %s", reg_data_to_string(start_address + i, rxdata[i]).c_str());
ESP_LOGE(TAG, "Ack : %s", reg_data_to_string(start_address + i, rxdata[i]).c_str());
}
}
delay_microseconds_safe(T_REGACQ);
@ -1191,7 +1218,6 @@ uint16_str ADS131M08Hub::adc_register_read(uint8_t address, uint8_t nregs) {
offset = 1;
rreg_ack = get_unsigned_frame_word(rx_frame, 0, true);
}
// uint16_t rreg_ack = (nregs == 1) ? rreg_addr_opcode : get_unsigned_frame_word(rx_frame, 0, true);
nregs = (rreg_ack & MASK_CMD_RW_REG_COUNT) + 1;
uint16_t start_addr = (rreg_ack & MASK_CMD_RW_REG_ADDRESS) >> 7;
@ -1206,9 +1232,6 @@ uint16_str ADS131M08Hub::adc_register_read(uint8_t address, uint8_t nregs) {
bool ADS131M08Hub::set_reg_osr() {
uint16_t mask = MASK_CLOCK_OSR;
uint16_t value = this->osr_ << 2;
// ESP_LOGD(TAG, "adc_register_write_masked(REG_CLOCK=%02X, value=%04X, mask=%04X, __LINE__)", REG_CLOCK,
// value, mask);
//this->settings.reg.clock = value & mask;
return adc_register_write_masked(REG_CLOCK, value, mask, __LINE__);
}
@ -1240,9 +1263,6 @@ bool ADS131M08Hub::set_channel_enable(uint8_t channel, bool enable) {
return false;
uint16_t mask = MASK_CLOCK_CH0 << channel;
uint16_t value = (enable) ? mask : 0;
// ESP_LOGD(TAG, "adc_register_write_masked(REG_CLOCK=%02X, value=%04X, mask=%04X, __LINE__)", REG_CLOCK,
// value, mask);
//this->settings.reg.clock = value & mask;
return adc_register_write_masked(REG_CLOCK, value, mask, __LINE__);
}
@ -1253,11 +1273,6 @@ bool ADS131M08Hub::set_channel_gain(uint8_t channel, uint8_t gain) {
uint8_t shift = (channel % 4) << 2;
uint16_t mask = MASK_GAIN_PGAGAIN0 << shift;
uint16_t value = gain << shift;
//if(reg == REG_GAIN1)
//this->settings.reg.gain1 = value & mask;
//else
//this->settings.reg.gain2 = value & mask;
// ESP_LOGW(TAG, "Ch%d: Set Gain: reg: %02X pga: %04X mask: %04X ", channel, reg, value, mask);
return adc_register_write_masked(reg, value, mask, __LINE__);
}
@ -1271,7 +1286,6 @@ bool ADS131M08Hub::set_global_chop(uint16_t global_chop) {
bool ADS131M08Hub::set_global_chop_delay(uint16_t delay) {
uint16_t mask = MASK_CFG_GC_DLY;
uint16_t value = delay << 9;
//this->settings.reg.cfg = value & mask;
return adc_register_write_masked(REG_CFG, value, mask, __LINE__);
}
@ -1283,7 +1297,6 @@ bool ADS131M08Hub::set_channel_phase_calibration(uint8_t channel, int16_t phase_
return false;
uint16_t mask = MASK_CHX_CFG_PHASE;
uint16_t value = phase_offset << 6;
////this->settings.reg.chan[channel].ch_cfg = value & mask;
return adc_register_write_masked(reg_addr, value, mask, __LINE__);
}
@ -1293,8 +1306,7 @@ bool ADS131M08Hub::set_dcblock_filter_disable(uint8_t channel, bool disable) {
uint16_t reg_addr = 5 * channel + REG_CH0_CFG;
uint16_t mask = MASK_CHX_CFG_DCBLKX_DIS;
uint16_t value = (disable) ? mask : 0;
////this->settings.reg.chan[channel].ch_cfg = value & mask;
ESP_LOGI(TAG, "Setting DC BLOCK of Ch%d reg:%02X to %s [%04X]", channel, reg_addr, (disable ? "disable" : "enable"), value);
//ESP_LOGI(TAG, "Setting DC BLOCK of Ch%d reg:%02X to %s [%04X]", channel, reg_addr, (disable ? "disable" : "enable"), value);
return adc_register_write_masked(reg_addr, value, mask, __LINE__);
}
@ -1304,7 +1316,6 @@ bool ADS131M08Hub::set_channel_input_selection(uint8_t channel, ADC_INPUT_CHANNE
uint16_t reg_addr = 5 * channel + REG_CH0_CFG;
uint16_t mask = MASK_CHX_CFG_MUX;
uint16_t value = input;
////this->settings.reg.chan[channel].ch_cfg = value & mask;
return adc_register_write_masked(reg_addr, value, mask, __LINE__);
}
@ -1319,8 +1330,6 @@ bool ADS131M08Hub::set_channel_offset_calibration(uint8_t channel, int32_t offse
uint16_str masks = {MASK_CHX_OCAL_MSB, MASK_CHX_OCAL_LSB};
uint16_str values = {MSB, LSB};
////this->settings.reg.chan[channel].ch_ocal_msb = values[0] & masks[0];
//this->settings.reg.chan[channel].ch_ocal_lsb = values[1] & masks[1];
return adc_register_write_masked(reg_addr, values, masks, __LINE__);
}
@ -1335,8 +1344,6 @@ bool ADS131M08Hub::set_channel_gain_calibration(uint8_t channel, uint32_t gain)
uint16_t reg_addr = 5 * channel + REG_CH0_GCAL_MSB;
uint16_str masks = {MASK_CHX_GCAL_MSB, MASK_CHX_GCAL_LSB};
uint16_str values = {MSB, LSB};
//this->settings.reg.chan[channel].ch_gcal_msb = values[0] & masks[0];
//this->settings.reg.chan[channel].ch_gcal_lsb = values[1] & masks[1];
return adc_register_write_masked(reg_addr, values, masks, __LINE__);
}