Fixed osr calculation. Added DC block. With OSR = 512, sps = 8k, however noise is higher with values swinging wildly

This commit is contained in:
Chris Stuurman 2026-05-04 00:45:29 +02:00
parent d69d0b5dfb
commit a43256ac5e
6 changed files with 319 additions and 131 deletions

View File

@ -11,6 +11,15 @@
// using namespace esphome::spi;
/*
//https://github.com/espressif/esp-idf/blob/v6.0.1/examples/peripherals/spi_master/lcd/main/spi_master_example_main.c
//Allocate memory for the pixel buffers
for (int i = 0; i < 2; i++) {
lines[i] = spi_bus_dma_memory_alloc(LCD_HOST, 320 * PARALLEL_LINES * sizeof(uint16_t), mem_cap);
assert(lines[i] != NULL);
}
*/
namespace esphome {
namespace ads131m08 {
@ -100,10 +109,8 @@ void ADS131M08Hub::dump_config() {
} else {
ESP_LOGCONFIG(TAG, " Clock frequency: %.3fMHz", this->clock_frequency_ / 1000000);
}
uint16_t osr = 1 << (7 + this->osr_);
if (osr == 16384) {
osr = 16256;
}
uint16_t osr = convert_adc_osr_to_value(this->osr_);
ESP_LOGCONFIG(TAG, " Oversampling ratio: %" PRId32, osr);
ESP_LOGCONFIG(TAG, " Reference Voltage: %.2fV", this->reference_voltage_);
ESP_LOGCONFIG(TAG, " SPI Mode: %d", this->mode_);
@ -158,19 +165,19 @@ float ADS131M08Hub::update_conversion_factor() {
bool ADS131M08Hub::adc_initialize(uint8_t word_length) {
this->adc_init_++;
update_adc_word_length();
if (!adc_register_write(REG_CLOCK, reg_clock_allch_off)) {
if (!adc_register_write(REG_CLOCK, (reg_clock_allch_off | this->osr_ << 2), __LINE__)) {
ESP_LOGE(TAG, "CLOCK register write / read to turn off all channels failed");
return false;
}
ESP_LOGV(TAG, "Turned off all channels so short frames can be written during config");
if (!adc_register_write(REG_MODE, MODE_MASK_RESET_HAPPENED & reg_mode_cfg24)) {
if (!adc_register_write(REG_MODE, MODE_MASK_RESET_HAPPENED & reg_mode_cfg24, __LINE__)) {
ESP_LOGE(TAG, "MODE register write / read to set word size to 24bits failed");
return false;
}
ESP_LOGV(TAG, "Written MODE register; Cleared the RESET flag, made DRDY active low pulse");
if (!adc_register_write(REG_THRSHLD_LSB, 0x09)) {
if (!adc_register_write(REG_THRSHLD_LSB, 0x09, __LINE__)) {
ESP_LOGE(TAG, "THRSHLD_LSB register write / read to set DBLOCK filter failed");
return false;
}
@ -179,7 +186,7 @@ bool ADS131M08Hub::adc_initialize(uint8_t word_length) {
if (!adc_set_word_length(word_length))
return false;
// we leave should channels off, as the individual sensors should turn it on
if (!adc_register_write(REG_CLOCK, reg_clock_allch_off)) {
if (!adc_register_write(REG_CLOCK, (reg_clock_allch_off | this->osr_ << 2), __LINE__)) {
ESP_LOGE(TAG, "CLOCK register write / read to turn-off all channels failed");
return false;
}
@ -192,20 +199,44 @@ bool ADS131M08Hub::adc_initialize(uint8_t word_length) {
return true;
}
bool ADS131M08Hub::adc_restore_registers() {
uint8_t start_addr = REG_MODE;
uint16_str stored_regs(MAX_FRAME_SIZE - 2, 0);
bool success = true;
int j = 0;
success = adc_register_write(start_addr, settings.data[j], __LINE__, false);
j++;
start_addr++;
while(success && (j < sizeof(settings.data))) {
int i = 0;
stored_regs.resize(MAX_FRAME_SIZE - 2);
while((i < MAX_FRAME_SIZE - 2) && (j < sizeof(settings.data))) {
stored_regs[i++] = settings.data[j++];
}
stored_regs.resize(i);
success = adc_register_write(start_addr, stored_regs, __LINE__, false);
ESP_LOGD(TAG, "start_addr: %02X i: %02X", start_addr, i);
start_addr += i;
}
return success;
}
bool ADS131M08Hub::adc_set_word_length(uint8_t word_length) {
uint16_t setting;
uint16_t value;
switch (word_length) {
case 32:
setting = reg_mode_cfg32;
value = reg_mode_cfg32;
break;
case 16:
setting = reg_mode_cfg16;
value = reg_mode_cfg16;
break;
default:
setting = reg_mode_cfg24;
value = reg_mode_cfg24;
break;
}
if (!adc_register_write_masked(REG_MODE, setting, reg_mode_cfg_mask, __LINE__)) {
uint16_t mask = reg_mode_cfg_mask;
//ESP_LOGD(TAG, "WL: %d stored value: %04X / %04X new value: %04X masked value %04X mask: %04X", word_length, this->settings.reg.mode, this->settings.data[REG_MODE-2], value, value & mask, mask );
if (!adc_register_write_masked(REG_MODE, value, mask, __LINE__)) {
ESP_LOGE(TAG, "MODE register write / read to set word size to %ubits failed", word_length);
return false;
}
@ -269,8 +300,8 @@ void ADS131M08Hub::loop()
{
CHIP_SELECTx
uint64_t start = micros();
this->txf_init(); // implementing datasheet recommended TXF init
//this->adc_sync();
///this->txf_init(); // implementing datasheet recommended TXF init
this->adc_sync();
if (rms_calc_req_) {
float_str result = read_multi();
num_samples = result[0];
@ -449,28 +480,54 @@ int32_t ADS131M08Hub::get_sign_ext_frame_word(const spiframe &frame, int w_index
return result;
}
void ADS131M08Hub::adc_hard_reset() {
float cycle_micros = 1000000 / this->clock_frequency_; // one cycle duration in micro seconds
uint32_t reset_pulse_duration = static_cast<uint32_t>(
1.05 * 2048 * cycle_micros); // 2048 clock cycles converted to microseconds, multiplied by 1.05 to ensure we meet
// the minimum pulse duration requirement
if (reset_pulse_duration < 1) {
reset_pulse_duration = 1; // set it to 1 microsecond
}
uint32_t ADS131M08Hub::adc_hard_reset() {
uint32_t pulse_duration = convert_adc_clock_cycles_to_micros(2150);
sync_reset_pin_->digital_write(false); // Pull SYNC/RESET pin low to reset the ADC
delay_microseconds_safe(reset_pulse_duration); // Hold reset for the calculated duration
delay_microseconds_safe(pulse_duration); // Hold reset for the calculated duration
sync_reset_pin_->digital_write(true); // Set SYNC/RESET pin high to allow normal operation
return convert_adc_clock_cycles_to_micros(T_SETTLE_OSR1024);
}
void ADS131M08Hub::adc_sync() {
float cycle_micros = 1000000 / this->clock_frequency_; // one cycle duration in micro seconds
uint32_t sync_pulse_duration =
static_cast<uint32_t>(std::round(50 * cycle_micros)); // minimum is 1/clock freq, max = 2047/clock freq
if (sync_pulse_duration < 1) {
sync_pulse_duration = 1; // set it to 1 microsecond
}
uint32_t ADS131M08Hub::adc_sync() {
uint32_t pulse_duration = convert_adc_clock_cycles_to_micros(50);
sync_reset_pin_->digital_write(false); // Pull SYNC/RESET pin low to sync the ADC
delay_microseconds_safe(sync_pulse_duration); // Hold sync for the calculated duration
delay_microseconds_safe(pulse_duration); // Hold sync for the calculated duration
sync_reset_pin_->digital_write(true); // Set SYNC/RESET pin high to allow normal operation
return get_filter_settling_time();
}
uint32_t ADS131M08Hub::get_filter_settling_time() {
uint16_t cycles = T_SETTLE_OSR16384;
switch(this->osr_) {
case OSR_128:
cycles = T_SETTLE_OSR128;
break;
case OSR_256:
cycles = T_SETTLE_OSR256;
break;
case OSR_512:
cycles = T_SETTLE_OSR512;
break;
case OSR_1024:
cycles = T_SETTLE_OSR1024;
break;
case OSR_2048:
cycles = T_SETTLE_OSR2048;
break;
case OSR_4096:
cycles = T_SETTLE_OSR4096;
break;
case OSR_8192:
cycles = T_SETTLE_OSR8192;
break;
}
return convert_adc_clock_cycles_to_micros(cycles);
}
uint32_t ADS131M08Hub::convert_adc_clock_cycles_to_micros(uint32_t cycles)
{
float cycle_micros = 1000000 / this->clock_frequency_; // one cycle duration in micro seconds
return 1 + static_cast<uint32_t>(std::round(cycle_micros * cycles));
}
// ********************** from datasheet ************************
@ -496,7 +553,7 @@ bool ADS131M08Hub::adc_reset_retry() {
int i = 0;
while (i < sizeof(retry_wordlengths) && !reset_ok) {
adc_word_length_ = retry_wordlengths[i];
// ESP_LOGW(TAG, "ADC word length: %d", adc_word_length_);
ESP_LOGW(TAG, "ADC word length: %d", adc_word_length_);
reset_ok = adc_soft_reset();
i++;
}
@ -506,7 +563,7 @@ bool ADS131M08Hub::adc_reset_retry() {
i = 0;
while (i < sizeof(retry_wordlengths) && !reset_ok) {
adc_word_length_ = retry_wordlengths[i];
// ESP_LOGW(TAG, "ADC word length: %d", adc_word_length_);
ESP_LOGW(TAG, "ADC word length: %d", adc_word_length_);
reset_ok = adc_soft_reset();
i++;
}
@ -690,6 +747,7 @@ float_str ADS131M08Hub::read_multi() {
uint16_t drdy_status, status;
int i, iteration = 0;
uint32_t elapsed_time = 0;
uint32_t sample_time = this->sample_time_;
uint32_t loop_start_time = micros();
int word_nbytes = adc_word_length_ >> 3;
int frame_length = numFrameWords * word_nbytes;
@ -703,8 +761,8 @@ float_str ADS131M08Hub::read_multi() {
sample_sum_[i] = 0;
sample_squared_sum_[i] = 0;
}
while ((elapsed_time < this->sample_time_) && (iteration++ < 1000)) {
uint32_t settling_end_time = loop_start_time;
while ((elapsed_time < sample_time) && (iteration++ < 1000)) {
result[2] = iteration;
setup_frame(rx_frame, numFrameWords);
this->transfer_array(rx_frame);
@ -715,7 +773,17 @@ float_str ADS131M08Hub::read_multi() {
update_adc_word_length(status);
crc_ok = check_crc(rx_frame);
if (crc_ok) {
// skip frame immediately afte resync
if(status & MASK_STATUS_RESET) {
adc_reset_retry();
adc_restore_registers();
ESP_LOGW(TAG, "Mid data-read reset detected; restored registers");
return result;
}
else {
if(status & MASK_STATUS_RESYNC) {
settling_end_time = elapsed_time + get_filter_settling_time() + 50; // add 50us for good measure
}
if(elapsed_time > settling_end_time) {
if ((status & MASK_STATUS_RESYNC) == 0) {
drdy_status = status & MASK_STATUS_DRDY;
// sample channels
@ -747,7 +815,10 @@ float_str ADS131M08Hub::read_multi() {
}
}
}
} else {
}
}
}
else {
result[1]++;
// ESP_LOGW(TAG, "iteration: %d, frame: %s CRC error", iteration, frame_to_string(frame).c_str());
}
@ -917,9 +988,19 @@ bool ADS131M08Hub::adc_register_write_masked(uint8_t address, uint16_t value, ui
}
// ESP_LOGW(TAG, "1: reg contents: 0x%04X, address: 0x%02X, value: 0x%04X, mask: 0x%04X, caller: %d",
// reg_contents[0],address, value,mask, line );
reg_contents[0] = (reg_contents[0] & ~mask) | (value & mask);
// ESP_LOGW(TAG, "After applying mask - reg contents: 0x%04X, caller: %d", reg_contents[0], line );
return adc_register_write(address, reg_contents);
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);
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);
// 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
/// @param start_address - first register address
@ -943,34 +1024,54 @@ bool ADS131M08Hub::adc_register_write_masked(uint8_t start_address, const uint16
ESP_LOGW(TAG, "No contents read from adc. Expected %d values. Register write aborted.", nregs);
return false;
}
bool update_required = false;
for (int i = 0; i < nregs; i++) {
// ESP_LOGW(TAG, "Before change %d: reg contents: 0x%04X, address: 0x%02X, value: 0x%04X, mask: 0x%04X, caller: %d",
//ESP_LOGW(TAG, "Before change %d: reg contents: 0x%04X, address: 0x%02X, value: 0x%04X, mask: 0x%04X, caller: %d",
// i, reg_contents[i], start_address + i, values[i], masks[i], line);
reg_contents[i] = (reg_contents[i] & ~masks[i]) | (values[i] & masks[i]);
// ESP_LOGW(TAG, "After applying mask - reg contents: 0x%04X, caller: %d", reg_contents[i], line);
auto new_value = (reg_contents[i] & ~masks[i]) | (values[i] & masks[i]);
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);
}
return adc_register_write(start_address, reg_contents);
if(!update_required) {
ESP_LOGW(TAG, "2: No update needed. start reg: %02X first data: %04X Line: %d", start_address, values[0], line);
// we backup data irrespective
int bup_index = start_address - REG_MODE;
for(auto i = values.begin(); i != values.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);
settings.data[bup_index++] = *i;
}
return true;
}
return adc_register_write(start_address, reg_contents, line);
}
bool ADS131M08Hub::adc_register_write(uint16_t address, uint16_t data) {
bool ADS131M08Hub::adc_register_write(uint16_t address, uint16_t data, int line, bool backup_data) {
uint16_str arg;
arg += data;
return adc_register_write(address, arg);
return adc_register_write(address, arg, line, backup_data);
}
/*
//https://github.com/espressif/esp-idf/blob/v6.0.1/examples/peripherals/spi_master/lcd/main/spi_master_example_main.c
//Allocate memory for the pixel buffers
for (int i = 0; i < 2; i++) {
lines[i] = spi_bus_dma_memory_alloc(LCD_HOST, 320 * PARALLEL_LINES * sizeof(uint16_t), mem_cap);
assert(lines[i] != NULL);
}
*/
bool ADS131M08Hub::adc_register_write(uint16_t start_address, const uint16_str &data) {
bool ADS131M08Hub::adc_register_write(uint16_t start_address, const uint16_str &data, int line, bool backup_data) {
int nregs = data.size();
if (nregs == 0) {
return false; // invalid
}
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);
settings.data[bup_index++] = *i;
}
}
else {
int bup_index = start_address - REG_MODE;
for(auto i = data.begin(); i != data.end(); i++) {
ESP_LOGD(TAG, "Restoring: %-13s: data %04X stored val: %04X Line: %d", reg_addr_to_string(bup_index + REG_MODE).c_str(), *i, settings.data[bup_index], line);
bup_index++;
}
}
int wreg_nwords = 2 + nregs; // ensure room for crc
int rreg_resp_framelength = 2 + (nregs == 1 ? -1 : nregs); // add room for CRC if nregs > 1
//spiframe frame(wreg_nwords, 0);
@ -1010,7 +1111,7 @@ bool ADS131M08Hub::adc_register_write(uint16_t start_address, const uint16_str &
return verified;
}
// recommended not to read more than 20 registers at a time
// recommended not to read more than 8 registers at a time
uint16_str ADS131M08Hub::adc_register_read(uint8_t address, uint8_t nregs) {
uint16_str result;
if (nregs == 0) {
@ -1045,6 +1146,7 @@ uint16_str ADS131M08Hub::adc_register_read(uint8_t address, uint8_t nregs) {
if (nregs > 1) {
bool crc_ok = check_crc(rx_frame);
if (!crc_ok) {
ESP_LOGD(TAG, "Recv Frame: %s", frame_to_string(rx_frame).c_str());
ESP_LOGW(TAG, "CRC failed reading ADC registers!");
result.clear();
return result; // invalid
@ -1070,28 +1172,46 @@ uint16_str ADS131M08Hub::adc_register_read(uint8_t address, uint8_t nregs) {
}
bool ADS131M08Hub::set_reg_osr() {
uint16_t osr = 3; // default
if (this->osr_ <= 16256 && this->osr_ >= 128) {
if (this->osr_ == 16256)
osr = 7;
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__);
}
uint16_t ADS131M08Hub::convert_value_to_adc_osr(uint16_t osr_value) {
uint16_t adc_osr = OSR_1024; // default
if (osr_value <= 16256 && osr_value >= 128) {
if (osr_value == 16256)
adc_osr = OSR_16256;
else {
osr = 0;
auto tmp = this->osr_ / 128;
adc_osr = OSR_128;
auto tmp = osr_value / 128;
while (tmp >>= 1)
osr++;
adc_osr++;
}
}
return adc_register_write_masked(REG_CLOCK, osr << 2, MASK_CLOCK_OSR, __LINE__);
return adc_osr;
}
uint16_t ADS131M08Hub::convert_adc_osr_to_value(uint16_t adc_osr) {
uint16_t osr_value = 1 << (7 + adc_osr);
if (osr_value == 16384) {
osr_value = 16256;
}
return osr_value;
}
bool ADS131M08Hub::set_channel_enable(uint8_t channel, bool enable) {
if (channel >= ADC_CHANNELS)
return false;
uint16_t enable_mask = MASK_CLOCK_CH0 << channel;
uint16_t reg_value = (enable) ? enable_mask : 0;
// ESP_LOGD(TAG, "adc_register_write_masked(REG_CLOCK=%02X, reg_value=%04X, enable_mask=%04X, __LINE__)", REG_CLOCK,
// reg_value, enable_mask);
return adc_register_write_masked(REG_CLOCK, reg_value, enable_mask, __LINE__);
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__);
}
bool ADS131M08Hub::set_channel_gain(uint8_t channel, uint8_t gain) {
@ -1101,16 +1221,26 @@ 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__);
}
void ADS131M08Hub::set_global_chop(uint16_t global_chop) {
adc_register_write_masked(REG_CFG, global_chop << 8, MASK_CFG_GC_EN, __LINE__);
bool ADS131M08Hub::set_global_chop(uint16_t global_chop) {
uint16_t mask = MASK_CFG_GC_EN;
uint16_t value = global_chop << 8;
//this->settings.reg.cfg = value & mask;
return adc_register_write_masked(REG_CFG, value, mask, __LINE__);
}
void ADS131M08Hub::set_global_chop_delay(uint16_t delay) {
adc_register_write_masked(REG_CFG, delay << 9, MASK_CFG_GC_DLY, __LINE__);
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__);
}
bool ADS131M08Hub::set_channel_phase_calibration(uint8_t channel, int16_t phase_offset) {
@ -1119,22 +1249,31 @@ bool ADS131M08Hub::set_channel_phase_calibration(uint8_t channel, int16_t phase_
uint16_t reg_addr = 5 * channel + REG_CH0_CFG;
if (phase_offset < -512 || phase_offset > 511)
return false;
return adc_register_write_masked(reg_addr, (phase_offset << 6), MASK_CHX_CFG_PHASE, __LINE__);
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__);
}
bool ADS131M08Hub::set_dcblock_filter_disable(uint8_t channel, bool disable) {
if (channel > 7)
return false;
uint16_t reg_addr = 5 * channel + REG_CH0_CFG;
uint16_t reg_value = (disable) ? MASK_CHX_CFG_DCBLKX_DIS : 0;
return adc_register_write_masked(reg_addr, reg_value, MASK_CHX_CFG_DCBLKX_DIS, __LINE__);
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);
return adc_register_write_masked(reg_addr, value, mask, __LINE__);
}
bool ADS131M08Hub::set_channel_input_selection(uint8_t channel, ADC_INPUT_CHANNEL_MUX input) {
if (channel > 7)
return false;
uint16_t reg_addr = 5 * channel + REG_CH0_CFG;
return adc_register_write_masked(reg_addr, input, MASK_CHX_CFG_MUX, __LINE__);
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__);
}
bool ADS131M08Hub::set_channel_offset_calibration(uint8_t channel, int32_t offset) {
@ -1142,11 +1281,15 @@ bool ADS131M08Hub::set_channel_offset_calibration(uint8_t channel, int32_t offse
return false;
if (offset < -8388608 || offset > 8388607)
return false;
uint16_t MSB = offset >> 8;
uint16_t LSB = offset << 8;
uint16_t reg_addr = 5 * channel + REG_CH0_OCAL_MSB;
return adc_register_write_masked(reg_addr, {MSB, LSB}, {MASK_CHX_OCAL_MSB, MASK_CHX_OCAL_LSB}, __LINE__);
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__);
}
bool ADS131M08Hub::set_channel_gain_calibration(uint8_t channel, uint32_t gain) {
@ -1158,7 +1301,11 @@ bool ADS131M08Hub::set_channel_gain_calibration(uint8_t channel, uint32_t gain)
uint16_t MSB = gain >> 8;
uint8_t LSB = gain;
uint16_t reg_addr = 5 * channel + REG_CH0_GCAL_MSB;
return adc_register_write_masked(reg_addr, {MSB, LSB}, {MASK_CHX_GCAL_MSB, MASK_CHX_GCAL_LSB}, __LINE__);
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__);
}
// for debug only - remove references, declarations and definitions before submitting for production
@ -1336,10 +1483,11 @@ std::string ADS131M08Hub::reg_data_to_string(int address, uint16_t data, bool na
str += " / EXT VREF=";
str += ((data & MASK_CLOCK_EXTREF_EN) != 0) ? "EN" : "DIS";
{
uint16_t osr = 1 << (7 + ((data & MASK_CLOCK_OSR) >> 2));
if (osr == 16384) {
osr = 16256;
}
//uint16_t osr = 1 << (7 + ((data & MASK_CLOCK_OSR) >> 2));
//if (osr == 16384) {
// osr = 16256;
//}
uint16_t osr = convert_adc_osr_to_value((data & MASK_CLOCK_OSR) >> 2);
snprintf(buffer, sizeof(buffer), " / OSR=%d", osr);
str += buffer;
}

View File

@ -51,7 +51,7 @@ class ADS131M08Hub : public Component,
public:
// register config values used
static constexpr uint16_t reg_clock_cfg = MASK_CLOCK_EXTREF_EN | OSR_1024 | PM_HIGH_RESOLUTION;
static constexpr uint16_t reg_clock_cfg = MASK_CLOCK_EXTREF_EN | PM_HIGH_RESOLUTION; // OSR must be added
static constexpr uint16_t reg_clock_allch_on = MASK_CLOCK_ALLCH | reg_clock_cfg;
static constexpr uint16_t reg_clock_allch_off = ~MASK_CLOCK_ALLCH & reg_clock_cfg;
static constexpr uint16_t reg_mode_cfg = DRDY_FMT_PULSE | TIMEOUT_ENABLED | CRC_REC_ENABLE | CRC_REG_ENABLE;
@ -62,6 +62,29 @@ class ADS131M08Hub : public Component,
static constexpr uint16_t reg_clock_cfg_mask = MASK_CLOCK_EXTREF_EN | MASK_CLOCK_OSR | MASK_CLOCK_PWR;
static constexpr uint16_t reg_clock_allch_mask = MASK_CLOCK_ALLCH_OFF | reg_clock_cfg_mask;
static constexpr uint16_t reg_mode_cfg_mask = MASK_MODE_WLENGTH | MASK_MODE_DRDY_FMT | MASK_MODE_TIMEOUT | MASK_MODE_RX_CRC_EN | MASK_MODE_REG_CRC_EN;
struct adc_channel_settings {
uint16_t ch_cfg;
uint16_t ch_ocal_msb;
uint16_t ch_ocal_lsb;
uint16_t ch_gcal_msb;
uint16_t ch_gcal_lsb;
};
struct adc_register_settings {
uint16_t mode;
uint16_t clock;
uint16_t gain1;
uint16_t gain2;
uint16_t cfg;
uint16_t threshold_msb;
uint16_t threshold_lsb;
adc_channel_settings chan[8];
//uint16_t regmap_crc;
};
union regmap {
adc_register_settings reg;
uint16_t data[sizeof(adc_register_settings)/2];
};
// Semaphore handles
SemaphoreHandle_t data_ready_semhandle = NULL;
SemaphoreHandle_t update_avg = NULL;
@ -70,8 +93,10 @@ class ADS131M08Hub : public Component,
bool firstRead = true; // Flag to tell us if we are reading ADC data for the first time
// signed long adcData; // Location where DMA will store ADC data in memory, length defined elsewhere
// ADS131M08Hub();
regmap settings;
void txf_init();
bool adc_initialize(uint8_t word_length);
bool adc_restore_registers();
bool adc_set_word_length(uint8_t word_length);
void setup() override;
@ -86,8 +111,8 @@ class ADS131M08Hub : public Component,
void dump_config() override;
bool set_channel_enable(uint8_t channel, bool enable);
void set_global_chop(uint16_t global_chop);
void set_global_chop_delay(uint16_t delay);
bool set_global_chop(uint16_t global_chop);
bool set_global_chop_delay(uint16_t delay);
bool set_channel_input_selection(uint8_t channel, ADC_INPUT_CHANNEL_MUX input);
bool set_channel_offset_calibration(uint8_t channel, int32_t offset);
bool set_channel_gain_calibration(uint8_t channel, uint32_t gain);
@ -96,8 +121,12 @@ class ADS131M08Hub : public Component,
bool set_channel_gain(uint8_t channel, uint8_t gain);
bool set_measure_rms(uint8_t channel, bool enable);
float get_sampled_value(uint8_t channel) { return sampled_values_[channel]; }
uint32_t get_filter_settling_time();
//float get_average(uint8_t channel, bool read_ac);
bool set_reg_osr();
uint16_t convert_value_to_adc_osr(uint16_t osr_value);
uint16_t convert_adc_osr_to_value(uint16_t adc_osr);
uint32_t convert_adc_clock_cycles_to_micros(uint32_t cycles);
protected:
HighFrequencyLoopRequester high_freq_;
@ -117,15 +146,15 @@ class ADS131M08Hub : public Component,
void SET_IRAM read_single();
float_str SET_IRAM read_multi();
bool adc_lock(bool enable);
bool adc_register_write(uint16_t address, uint16_t data);
bool adc_register_write(uint16_t address, const uint16_str &data);
bool adc_register_write(uint16_t address, uint16_t data, int line, bool backup_date = true);
bool adc_register_write(uint16_t address, const uint16_str &data, int line, bool backup_date = true);
uint16_str adc_register_read(uint8_t address, uint8_t nregs);
bool adc_register_write_masked(uint8_t address, uint16_t value, uint16_t mask, int line);
bool adc_register_write_masked(uint8_t start_address, const uint16_str &values, const uint16_str &masks, int line);
bool adc_reset_retry();
bool adc_soft_reset();
void adc_hard_reset();
void adc_sync();
uint32_t adc_hard_reset();
uint32_t adc_sync();
void SET_IRAM transfer_array(spiframe &frame);
//void transfer_array(const spiframe &data_out, spiframe &data_in);
uint16_t SET_IRAM get_crc(const spiframe &frame);
@ -179,7 +208,7 @@ class ADS131M08Hub : public Component,
uint8_t update_state_[MAX_CHANNELS] = {0, 0, 0, 0, 0, 0, 0, 0};
uint8_t adc_word_length_{24};
float conversion_factor_{1.25 / 8388608.0}; // updated when word length changes
const uint32_t sample_time_ = 20000; // 250 ms
const uint32_t sample_time_ = 40000; // 40 ms
float sps_{0.0f};
uint32_t num_samples_[ADC_CHANNELS];
float sample_sum_[ADC_CHANNELS];

View File

@ -13,6 +13,7 @@ enum ADC_DRDY_STATE : uint8_t {
DS_HI_Z = 1
};
// no shift
enum ADC_POWERMODE : uint16_t {
PM_VERY_LOW_POWER = 0,
PM_LOW_POWER = 1,
@ -39,26 +40,27 @@ enum ADC_INPUT_CHANNEL_MUX : uint8_t {
ICM_NEGATIVE_DC_TEST_SIGNAL = 3,
};
// must be shifted << 2
enum ADC_OVERSAMPLING_RATIO : uint16_t {
OSR_128 = 0,
OSR_256 = 1,
OSR_512 = 2,
OSR_1024 = 3, // default
OSR_1024 = 3,
OSR_2048 = 4,
OSR_4096 = 5,
OSR_8192 = 6,
OSR_16256 = 7
};
enum ADC_WAIT_TIME : uint16_t {
WT_128 = 856,
WT_256 = 1112,
WT_512 = 1624,
WT_1024 = 2648,
WT_2048 = 4696,
WT_4096 = 8792,
WT_8192 = 16984,
WT_16384 = 33368
enum ADC_SETTLING_TIME : uint16_t {
T_SETTLE_OSR128 = 856,
T_SETTLE_OSR256 = 1112,
T_SETTLE_OSR512 = 1624,
T_SETTLE_OSR1024 = 2648,
T_SETTLE_OSR2048 = 4696,
T_SETTLE_OSR4096 = 8792,
T_SETTLE_OSR8192 = 16984,
T_SETTLE_OSR16384 = 33368,
};
// delays in microseconds
@ -67,6 +69,7 @@ enum ADC_DELAY {
};
static constexpr uint16_t MODE_MASK_RESET_HAPPENED = ~0x0400; // DEFAULT
static constexpr uint16_t MODE_RESET_HAPPENED = 0x0400;

View File

@ -14,8 +14,10 @@ CONF_OFFSET_CALIBRATION = "offset_calibration"
CONF_GAIN_CALIBRATION = "gain_calibration"
CONF_PHASE_CALIBRATION = "phase_calibration"
CONF_INPUT_SELECT = "input_select"
CONF_DC_BLOCK = "dc_block"
ICON_CURRENT_DC = "mdi:current-dc"
DEPENDENCIES = ["ads131m08"]
GAIN = ads131m08_ns.enum("ADC_PGA_GAIN")
@ -59,6 +61,7 @@ CONFIG_SCHEMA = CONFIG_SCHEMA_RMS_SENSORS.extend(
cv.Optional(CONF_GAIN_CALIBRATION, default=1): cv.float_range(min=0, max=2),
cv.Optional(CONF_PHASE_CALIBRATION, default=0): cv.int_range(min=-512, max=511), # should use degrees, but need to figure out conversion function first
cv.Optional(CONF_INPUT_SELECT, default='normal'): cv.enum(ALLOWED_MUX_INP, int=False),
cv.Optional(CONF_DC_BLOCK, default=False): cv.boolean,
}
).extend(
{
@ -84,6 +87,8 @@ async def to_code(config):
cg.add(channel_sensor.set_offset_calibration(offset_cal))
phase_cal = config[CONF_PHASE_CALIBRATION]
cg.add(channel_sensor.set_phase_calibration(phase_cal))
dc_block = config[CONF_DC_BLOCK]
cg.add(channel_sensor.set_dc_block(dc_block))
await cg.register_component(channel_sensor, config)
if dc_sensor := await to_code_dc(config):
await cg.register_parented(dc_sensor, channel_sensor)

View File

@ -5,7 +5,7 @@
namespace esphome {
namespace ads131m08 {
static const char *const TAG = "adsm131m08.sensor";
static const char *const TAG = "ads131m08.sensor";
void Channel::loop()
{
@ -16,7 +16,7 @@ void Channel::loop()
this->parent_->set_channel_phase_calibration(this->channel_, this->normalised_phase_calibration());
this->parent_->set_channel_offset_calibration(this->channel_, this->normalised_offset_calibration());
this->parent_->set_channel_gain_calibration(this->channel_, this->normalised_gain_calibration());
this->parent_->set_dcblock_filter_disable(this->channel_, true);
this->parent_->set_dcblock_filter_disable(this->channel_, !this->dc_block_);
this->parent_->set_channel_enable(this->channel_, true);
this->first_reading_ = false;
}
@ -53,6 +53,7 @@ void Channel::dump_config() {
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" \

View File

@ -25,6 +25,7 @@ class Channel : public sensor::Sensor,
void set_gain_calibration(float value) { this->gain_cal_ = value; }
void set_offset_calibration(int value) { this->offset_cal_ = value; }
void set_phase_calibration(int value) { this->phase_cal_ = value; }
void set_dc_block(bool enable) { this->dc_block_ = enable; }
bool set_calc_rms(bool enable) { this->calc_rms_ = enable; return this->parent_ != nullptr ? this->parent_->set_measure_rms(this->channel_, enable) : false; }
//float get_average(bool read_ac) { return this->parent_->get_average(this->channel_, read_ac); }
void set_mux_input(ADC_INPUT_CHANNEL_MUX value) { this->input_ = value; }
@ -38,6 +39,7 @@ class Channel : public sensor::Sensor,
int offset_cal_;
float gain_cal_;
bool calc_rms_;
bool dc_block_;
uint8_t gain_;
ADC_INPUT_CHANNEL_MUX input_;
bool first_reading_{true};