From 678312a27dfc104c6603373f6d4618366ce1ca7b Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 2 May 2026 16:31:14 +0200 Subject: [PATCH] Added spiframe with DMA_ATTR to enable DMA transfers. Much quicker now. However, now plaque with what appears to be noise / errors on the channels. Will revert to direct publishing from main loop to see if it makes a difference. --- ads131m08/ads131m08.cpp | 225 ++++++++++++++++++++++------------- ads131m08/ads131m08.h | 25 ++-- ads131m08/ads131m08_defs.h | 20 +--- ads131m08/sensor/__init__.py | 2 +- 4 files changed, 163 insertions(+), 109 deletions(-) diff --git a/ads131m08/ads131m08.cpp b/ads131m08/ads131m08.cpp index 93c6941..d565a22 100644 --- a/ads131m08/ads131m08.cpp +++ b/ads131m08/ads131m08.cpp @@ -15,6 +15,11 @@ namespace esphome { namespace ads131m08 { static const char *const TAG = "ads131m08"; +static const char *const white_space = " \t\n\r\f\v"; // Defines whitespace + +//TODO: RREG might be longer than allocated frame size. work out max length and update following accordingly +DRAM_ATTR static spiframe tx_frame(ADS131M08Hub::numFrameWords * 4, 0); +DRAM_ATTR static spiframe rx_frame(ADS131M08Hub::numFrameWords * 4, 0); // ADS131M08Hub::ADS131M08Hub() // : base_frame(40, 0) @@ -76,7 +81,7 @@ void ADS131M08Hub::setup() { // cs_ctr_=1000; // SPIDevice::enable(); // leave CS low // Request a high loop() execution interval - // this->high_freq_.start(); + this->high_freq_.start(); } void ADS131M08Hub::dump_config() { @@ -150,6 +155,7 @@ float ADS131M08Hub::update_conversion_factor() { } return this->conversion_factor_; } + bool ADS131M08Hub::adc_initialize(uint8_t word_length) { this->adc_init_++; update_adc_word_length(); @@ -158,17 +164,19 @@ bool ADS131M08Hub::adc_initialize(uint8_t word_length) { 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)) { ESP_LOGE(TAG, "MODE register write / read to set word size to 24bits failed"); return false; } - // update_adc_word_length(); ESP_LOGV(TAG, "Written MODE register; Cleared the RESET flag, made DRDY active low pulse"); + if (!adc_register_write(REG_THRSHLD_LSB, 0x09)) { ESP_LOGE(TAG, "THRSHLD_LSB register write / read to set DBLOCK filter failed"); return false; } ESP_LOGV(TAG, "Written THRSHLD_LSB register; Set DCBLOCK filter to have a corner frequency of 622 mHz"); + if (!adc_set_word_length(word_length)) return false; // we leave should channels off, as the individual sensors should turn it on @@ -177,7 +185,6 @@ bool ADS131M08Hub::adc_initialize(uint8_t word_length) { return false; } - // ESP_LOGV(TAG, "Turned on all ADC channels; Re-wrote defaults for other bits in CLOCK register"); if (!drdy_pin_->digital_read()) { ESP_LOGE(TAG, "DRDY pin is low after initialization!"); return false; @@ -237,24 +244,28 @@ void ADS131M08Hub::disable(const char *txt) { // MUST be fast and non-blocking void ADS131M08Hub::isr_handler(ADS131M08Hub *arg) { { - InterruptLock lock; + // InterruptLock lock; if (arg != nullptr) { + arg->enable_loop_soon_any_context(); arg->isr_ctr_++; - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xSemaphoreGiveFromISR(arg->data_ready_semhandle, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken == pdTRUE) { - portYIELD_FROM_ISR(); // Switch to the waiting task immediately - } + // BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // xSemaphoreGiveFromISR(arg->data_ready_semhandle, &xHigherPriorityTaskWoken); + // if (xHigherPriorityTaskWoken == pdTRUE) { + // portYIELD_FROM_ISR(); // Switch to the waiting task immediately + // } } } } -void ADS131M08Hub::loop() { +void ADS131M08Hub::loop() +{ // Check the semaphore (0 timeout means non-blocking) - if (xSemaphoreTake(data_ready_semhandle, 0) == pdTRUE) { + //if (xSemaphoreTake(data_ready_semhandle, 0) == pdTRUE) { if (this->adc_init_ == 0) { uint32_t num_samples = 0; uint32_t crc_errors = 0; + uint32_t iterations = 0; + uint32_t not_ready = 0; { CHIP_SELECTx // Perform the read here safely outside of ISR @@ -262,15 +273,19 @@ void ADS131M08Hub::loop() { // this->txf_init(); // implementing datasheet recommended TXF init in ISR this->adc_sync(); if (rms_calc_req_) { - std::pair result = read_multi(); - num_samples = result.first; - crc_errors = result.second; + uint16_str result = read_multi(); + num_samples = result[0]; + crc_errors = result[1]; + iterations = result[2]; + not_ready = result[3]; uint64_t end = micros(); update_averages(SAMPLE_TIME_SENSOR, 1, static_cast(end - start) / 1000.0); update_averages(MAX_SAMPLES_SENSOR, 1, static_cast(num_samples)); update_averages(CRC_ERRORS_SENSOR, 1, static_cast(crc_errors)); uint16_t ctr = isr_ctr_; update_averages(ISR_COUNT_SENSOR, 1, static_cast(ctr)); + update_averages(ITERATIONS_SENSOR, 1, static_cast(iterations)); + update_averages(NOT_READY_SENSOR, 1, static_cast(not_ready)); // if(this->sensors_ac[SAMPLE_TIME_SENSOR] != nullptr) // this->sensors_ac[SAMPLE_TIME_SENSOR]->publish_state(static_cast(end - start)/1000.0); @@ -289,7 +304,8 @@ void ADS131M08Hub::loop() { } if (crc_errors > 30) { ESP_LOGW(TAG, "High CRC error rate."); - adc_set_word_length(DEFAULT_WORD_LENGTH); // for some reason the adc occasionally reverts to 24bits; this will + int i = 4; + while(i-- > 0 && !adc_set_word_length(DEFAULT_WORD_LENGTH)); // for some reason the adc occasionally reverts to 24bits; this will // reset the word length to what it should be // update_adc_word_length(); // spiframe recoverframe(40, 0); @@ -298,14 +314,15 @@ void ADS131M08Hub::loop() { } // ESP_LOGW(TAG, "%llu ms (%llu us), max samples: %u", (end - start)/1000, (end - start), num_samples); } - } + //} } /// @brief Set 16 bit frameword /// @param frame /// @param w_index /// @param data uint16_t denotes command or CRC /// @return -bool ADS131M08Hub::set_frame_word(spiframe &frame, int w_index, uint16_t data) { +bool ADS131M08Hub::set_frame_word(spiframe &frame, int w_index, uint16_t data) +{ size_t word_nbytes = adc_word_length_ >> 3; size_t frame_words = frame.size() / word_nbytes; int b_index = w_index * word_nbytes; @@ -334,7 +351,8 @@ bool ADS131M08Hub::set_frame_word(spiframe &frame, int w_index, uint16_t data) { return true; } -bool ADS131M08Hub::set_frame_word(spiframe &frame, int w_index, uint32_t data) { +bool ADS131M08Hub::set_frame_word(spiframe &frame, int w_index, uint32_t data) +{ size_t word_nbytes = adc_word_length_ >> 3; size_t frame_words = frame.size() / word_nbytes; int b_index = w_index * word_nbytes; @@ -364,7 +382,8 @@ bool ADS131M08Hub::set_frame_word(spiframe &frame, int w_index, uint32_t data) { } // index(i) = zero-reference, returns i'th word, LSB aligned -uint32_t ADS131M08Hub::get_unsigned_frame_word(const spiframe &frame, int w_index, bool force_16bits) { +uint32_t ADS131M08Hub::get_unsigned_frame_word(const spiframe &frame, int w_index, bool force_16bits) +{ uint32_t result = 0; size_t word_nbytes = adc_word_length_ >> 3; int b_index = w_index * word_nbytes; @@ -388,7 +407,8 @@ uint32_t ADS131M08Hub::get_unsigned_frame_word(const spiframe &frame, int w_inde return result; } -int32_t ADS131M08Hub::get_sign_ext_frame_word(const spiframe &frame, int w_index) { +int32_t ADS131M08Hub::get_sign_ext_frame_word(const spiframe &frame, int w_index) +{ int32_t result = 0; size_t word_nbytes = adc_word_length_ >> 3; int b_index = w_index * word_nbytes; @@ -396,27 +416,29 @@ int32_t ADS131M08Hub::get_sign_ext_frame_word(const spiframe &frame, int w_index ESP_LOGW(TAG, "Word index of %d out of bounds", w_index); return result; // invalid } - uint32_t raw = 0; switch (adc_word_length_) { case 32: - raw = (frame[b_index] << 24) | (frame[b_index + 1] << 16) | (frame[b_index + 2]) << 8 | frame[b_index + 3]; - result = static_cast(raw); + result = (frame[b_index] << 24) | (frame[b_index + 1] << 16) | (frame[b_index + 2]) << 8 | frame[b_index + 3]; break; case 24: - raw = (frame[b_index] << 16) | (frame[b_index + 1] << 8) | frame[b_index + 2]; - if (raw & 0x800000) - result = static_cast(raw | 0xFF000000); // Sign extend - else - result = static_cast(raw); + result = (frame[b_index] << 24) | (frame[b_index + 1] << 16) | (frame[b_index + 2] << 8); + result = result >> 8; break; case 16: - raw = ((frame[b_index] << 8) | frame[b_index + 1]); - result = static_cast(raw); + { + int16_t raw = (frame[b_index] << 8) | frame[b_index + 1]; + result = static_cast(raw); + } break; default: ESP_LOGW(TAG, "Invalid adc word length of %d", adc_word_length_); break; } + //if(w_index == 1 || w_index ==2) + //if(result > 7000000 || result < -7000000) { + //ESP_LOGD(TAG, "frame: %s", frame_to_string(rx_frame).c_str()); + // ESP_LOGD(TAG, "frame_word%d: %s result: [0x%08X] %d", w_index, frame_words_to_string(frame, w_index, 1).c_str(), result, result); + //} return result; } @@ -617,9 +639,7 @@ uint8_t ADS131M08Hub::read_byte() { void ADS131M08Hub::read_array(spiframe &frame) { CHIP_SELECT - for (size_t i = 0; i < frame.size(); i++) { - frame[i] = this->transfer_byte(0x00); // Send dummy byte to read data - } + this->transfer_array(frame.data(), frame.size()); } void ADS131M08Hub::write_array(const spiframe &frame) { @@ -629,15 +649,15 @@ void ADS131M08Hub::write_array(const spiframe &frame) { } } -void ADS131M08Hub::transfer_array(const spiframe &tx_frame, spiframe &rx_frame) { - CHIP_SELECT - auto frame_length = tx_frame.size(); - if (rx_frame.size() < frame_length) - rx_frame.resize(frame_length); - for (size_t i = 0; i < frame_length; i++) { - rx_frame[i] = this->transfer_byte(tx_frame[i]); - } -} +//void ADS131M08Hub::transfer_array(const spiframe &tx_frame, spiframe &rx_frame) { +// CHIP_SELECT +// auto frame_length = tx_frame.size(); +// if (rx_frame.size() < frame_length) +// rx_frame.resize(frame_length); +// for (size_t i = 0; i < frame_length; i++) { +// rx_frame[i] = this->transfer_byte(tx_frame[i]); +// } +//} bool ADS131M08Hub::set_measure_rms(uint8_t channel, bool enable) { if (channel >= MAX_CHANNELS) @@ -681,20 +701,20 @@ void ADS131M08Hub::read_single() { // hopefully reliably calculate RMS value, phase offsets, etc. the best the read_multi procedure does is to read about // 66x 16bit / 33x 32bit word frames in 40ms which is far from ideal Once we ge the ISR and loop setup to respond fast // enough, the following procedure should be completely re-designed -std::pair ADS131M08Hub::read_multi() { +uint16_str ADS131M08Hub::read_multi() { int32_t raw; float value; - std::pair result; - result.first = 0; - result.second = 0; + uint16_str result(4, 0); bool crc_ok, data_ready, ac_sensor_exist, dc_sensor_exist; uint16_t drdy_status, status; - int i, max_iters = 250; // going above 255 will result in overflows + int i, iteration = 0; // going above 255 will result in overflows uint32_t elapsed_time = 0; uint32_t loop_start_time = micros(); int word_nbytes = adc_word_length_ >> 3; int frame_length = numFrameWords * word_nbytes; - spiframe frame(frame_length, 0); + //spiframe frame(frame_length, 0); + tx_frame.resize(frame_length); + rx_frame.resize(frame_length); // integrate for rms values over #iterations or sample_time depending on what comes first for (int i = 0; i < ADC_CHANNELS; i++) { // last_publish_time_[i] = 0; @@ -702,29 +722,37 @@ std::pair ADS131M08Hub::read_multi() { sample_sum_[i] = 0; sample_squared_sum_[i] = 0; } - while (elapsed_time < this->sample_time_ && max_iters-- > 0) { - this->read_array(frame); - // ESP_LOGD(TAG, "max_iters: %d, frame: %s", max_iters, frame_to_string(frame).c_str()); - status = get_unsigned_frame_word(frame, 0, true); + + while (elapsed_time < this->sample_time_ && iteration++ < 1000) { + result[2] = iteration; + std::fill(rx_frame.begin(), rx_frame.end(), 0); + this->read_array(rx_frame); + //ESP_LOGD(TAG, "frame: %s", frame_to_string(rx_frame).c_str()); + //ESP_LOGD(TAG, "iteration: %d, frame: %s", iteration, frame_to_string(rx_frame).c_str()); + //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(frame); + crc_ok = check_crc(rx_frame); if (crc_ok) { // skip frame immediately afte resync if ((status & MASK_STATUS_RESYNC) == 0) { drdy_status = status & MASK_STATUS_DRDY; // sample channels + if(drdy_status == 0){ + result[3]++; + } for (i = 0; i < ADC_CHANNELS && drdy_status != 0; i++) { data_ready = drdy_status & 1; drdy_status = drdy_status >> 1; ac_sensor_exist = this->sensors_ac[i] != nullptr; dc_sensor_exist = this->sensors_dc[i] != nullptr; if (data_ready && (ac_sensor_exist || dc_sensor_exist)) { - raw = get_sign_ext_frame_word(frame, i + 1); + raw = get_sign_ext_frame_word(rx_frame, i + 1); value = this->conversion_factor_ * raw; this->sampled_values_[i] = value; if (this->rms_enabled_[i]) { (this->num_samples_[i])++; - (this->sample_sum_[i]) += static_cast(raw); + (this->sample_sum_[i]) += value; (this->sample_squared_sum_[i]) += value * value; } else { // if(ac_sensor_exist) @@ -737,8 +765,8 @@ std::pair ADS131M08Hub::read_multi() { } } } else { - result.second++; - // ESP_LOGW(TAG, "max_iters: %d, frame: %s CRC error", max_iters, frame_to_string(frame).c_str()); + result[1]++; + // ESP_LOGW(TAG, "iteration: %d, frame: %s CRC error", iteration, frame_to_string(frame).c_str()); } elapsed_time = micros() - loop_start_time; } @@ -748,20 +776,20 @@ std::pair ADS131M08Hub::read_multi() { ac_sensor_exist = this->sensors_ac[i] != nullptr; dc_sensor_exist = this->sensors_dc[i] != nullptr; auto num_samples = this->num_samples_[i]; - if (num_samples > result.first) { - result.first = num_samples; + if (num_samples > result[0]) { + result[0] = num_samples; } if (num_samples == 0) { - // should never happen, but let's play safe and avoid dividing by zero - ESP_LOGW(TAG, "Num samples: %d", num_samples); + // should not happen, but let's play safe and avoid dividing by zero + // ESP_LOGW(TAG, "Num samples: %d", num_samples); update_averages(i, NAN, NAN); // if(ac_sensor_exist) // this->sensors_ac[i]->publish_state(NAN); // if(dc_sensor_exist) // this->sensors_dc[i]->publish_state(NAN); } else { - int64_t sample_sum = sample_sum_[i]; - float rms_dc = this->conversion_factor_ * static_cast(sample_sum) / num_samples; + float sample_sum = sample_sum_[i]; + float rms_dc = sample_sum / num_samples; float rms_ac_squared = sample_squared_sum_[i] / num_samples - rms_dc * rms_dc; float rms_ac = 0; if (rms_ac_squared > 0) { @@ -791,30 +819,29 @@ bool ADS131M08Hub::update_averages(uint8_t channel, float rms_ac, float rms_dc) bool ac_sensor_exist = this->sensors_ac[channel] != nullptr; bool dc_sensor_exist = this->sensors_dc[channel] != nullptr; if (!ac_sensor_exist && !dc_sensor_exist) { - ESP_LOGW(TAG, "channel %d does not exist", channel); + //ESP_LOGW(TAG, "channel %d does not exist", channel); return false; } - // we treat update state as a critical resource that must not be clobbered + // we treat update_state as a critical resource that must not be clobbered if (xSemaphoreTake(update_avg, (TickType_t) 50) == pdTRUE) { uint8_t update_state = update_state_[channel]; + update_state_[channel] &= 0xF0; if (ac_sensor_exist) { // if this is the first value, then we just store it with no averaging if ((update_state & 0x0F) == 0) { avg_ac_[channel] = rms_ac; update_state |= 0x01; + update_state_[channel] = update_state; } else { // if we have NAN (no samples), we store it, but also also treat next valid value as the first if (rms_ac == NAN) { avg_ac_[channel] = NAN; - update_state &= 0xF0; } else { ESP_LOGI(TAG, "Setting AC avg: %f %f", avg_ac_[channel], rms_ac); avg_ac_[channel] = 0.5 * (avg_ac_[channel] + rms_ac); + update_state_[channel] = update_state; } } - update_state_[channel] = update_state; - } else { - update_state_[channel] &= 0xF0; } update_state = update_state_[channel]; if (dc_sensor_exist) { @@ -942,6 +969,14 @@ bool ADS131M08Hub::adc_register_write(uint16_t address, uint16_t data) { return adc_register_write(address, arg); } +/* +//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) { int nregs = data.size(); if (nregs == 0) { @@ -950,24 +985,25 @@ bool ADS131M08Hub::adc_register_write(uint16_t start_address, const uint16_str & int word_nbytes = adc_word_length_ >> 3; int wreg_framelength = word_nbytes * (2 + nregs); // ensure room for crc int rreg_resp_framelength = word_nbytes * (2 + (nregs == 1 ? -1 : nregs)); // add room for CRC if nregs > 1 - spiframe frame(wreg_framelength, 0); - spiframe rxframe(wreg_framelength, 0); + //spiframe frame(wreg_framelength, 0); + //spiframe rxframe(wreg_framelength, 0); 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)); + tx_frame.resize(wreg_framelength); + rx_frame.resize(wreg_framelength); { - CHIP_SELECT - set_frame_word(frame, 0, wreg_addr_opcode); + CHIP_SELECT set_frame_word(tx_frame, 0, wreg_addr_opcode); for (int i = 0; i < nregs; i++) { - set_frame_word(frame, i + 1, data[i]); + set_frame_word(tx_frame, i + 1, data[i]); } - add_crc(frame); - ESP_LOGVV(TAG, "%s\n", rwreg_command_frame_to_string(frame).c_str()); - transfer_array(frame, rxframe); // WREG + add_crc(tx_frame); + //ESP_LOGD(TAG, "%s\n", rwreg_command_frame_to_string(tx_frame).c_str()); + //ESP_LOGD(TAG, "Send Frame: %s", frame_to_string(tx_frame).c_str()); + transfer_array(tx_frame.data(), tx_frame.size()); // WREG } - ESP_LOGVV(TAG, "Sent Frame: %s", frame_to_string(frame).c_str()); if (has_mode_reg) { update_adc_word_length(); } @@ -977,7 +1013,9 @@ bool ADS131M08Hub::adc_register_write(uint16_t start_address, const uint16_str & for (int i = 0; i < rxdata.size() && verified; i++) { verified = rxdata[i] == data[i]; if (!verified) { - ESP_LOGE(TAG, "Write register failed: tx data= 0x%04X, rx data= 0x%04X", data[i], rxdata[i]); + 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()); } } delay_microseconds_safe(T_REGACQ); @@ -1033,7 +1071,6 @@ uint16_str ADS131M08Hub::adc_register_read(uint8_t address, uint8_t nregs) { if (nregs > 1) { offset = 1; rreg_ack = get_unsigned_frame_word(frame, 0, true); - ; } // uint16_t rreg_ack = (nregs == 1) ? rreg_addr_opcode : get_unsigned_frame_word(frame, 0, true); nregs = (rreg_ack & MASK_CMD_RW_REG_COUNT) + 1; @@ -1139,6 +1176,24 @@ bool ADS131M08Hub::set_channel_gain_calibration(uint8_t channel, uint32_t gain) } // for debug only - remove references, declarations and definitions before submitting for production +std::string ADS131M08Hub::frame_words_to_string(const spiframe &frame, int index, int count) { + std::string str; + char buffer[20]; + const std::string::size_type new_cap(768); + str.reserve(new_cap); + int word_nbytes = adc_word_length_ >> 3; + int frame_nwords = frame.size() / word_nbytes; + if(index >= frame_nwords) + return ""; + for (int w = index; w < (index + count) && w < frame_nwords; w++) { + for (int i = 0; i < word_nbytes; i++) { + snprintf(buffer, sizeof(buffer), " %02X", frame[w * word_nbytes + i]); + str += buffer; + } + } + return str; +} + std::string ADS131M08Hub::frame_to_string(const spiframe &frame) { std::string str; char buffer[20]; @@ -1189,12 +1244,10 @@ std::string ADS131M08Hub::rwreg_command_frame_to_string(const spiframe &frame) { int nregs = 1 + (cmdadr & MASK_CMD_RW_REG_COUNT); str = command_to_string(cmdadr); uint16_t command = (cmdadr & MASK_CMD_RW_REG) ? (cmdadr & MASK_CMD_RW_REG) : cmdadr; - const char *ws = " \t\n\r\f\v"; // Defines whitespace if (command == CMD_RREG) { str += " : regs "; for (int i = 0; i < nregs; i++) { str += reg_addr_to_string(address + i); - str.erase(str.find_last_not_of(ws) + 1); str += (i < (nregs - 1) ? ", " : ""); } } @@ -1209,14 +1262,18 @@ std::string ADS131M08Hub::rwreg_command_frame_to_string(const spiframe &frame) { uint16_t data = get_unsigned_frame_word(frame, i + 1, true); str += "\n "; str += reg_data_to_string(address + i, data); - str.erase(str.find_last_not_of(ws) + 1); str += (i < (nregs - 1) ? ", " : ""); } } return str; } -std::string ADS131M08Hub::reg_addr_to_string(int address) { return reg_data_to_string(address, 0, true); } +std::string ADS131M08Hub::reg_addr_to_string(int address) +{ + auto str = reg_data_to_string(address, 0, true); + str.erase(str.find_last_not_of(white_space) + 1); + return str; +} std::string ADS131M08Hub::reg_data_to_string(int address, uint16_t data, bool nameonly) { std::string str; diff --git a/ads131m08/ads131m08.h b/ads131m08/ads131m08.h index 7bdf5c3..0c8bc63 100644 --- a/ads131m08/ads131m08.h +++ b/ads131m08/ads131m08.h @@ -22,13 +22,16 @@ namespace esphome { namespace ads131m08 { -static const uint8_t DEFAULT_WORD_LENGTH = 32; -static const int MAX_CHANNELS = 12; // for debugging +static const uint8_t DEFAULT_WORD_LENGTH = 32; // we use 32 bit to allow for DMA transfers static const int ADC_CHANNELS = 8; + +static const int MAX_CHANNELS = 14; // for debugging static const int SAMPLE_TIME_SENSOR = 8; // for debugging static const int MAX_SAMPLES_SENSOR = 9; // for debugging static const int CRC_ERRORS_SENSOR = 10; // for debugging static const int ISR_COUNT_SENSOR = 11; // for debugging +static const int ITERATIONS_SENSOR = 12; // for debugging +static const int NOT_READY_SENSOR = 13; // for debugging // #define SET_IRAM IRAM_ATTR #define SET_IRAM @@ -46,18 +49,19 @@ class ADS131M08Hub : public Component, static constexpr uint16_t reg_clock_cfg = MASK_CLOCK_EXTREF_EN | OSR_1024 | PM_HIGH_RESOLUTION; 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_cfg16 = WLENGTH_16_BITS | DRDY_FMT_PULSE | TIMEOUT_ENABLED; - static constexpr uint16_t reg_mode_cfg24 = WLENGTH_24_BITS | DRDY_FMT_PULSE | TIMEOUT_ENABLED; - static constexpr uint16_t reg_mode_cfg32 = WLENGTH_32_BITS_MSB_SIGN_EXTEND | DRDY_FMT_PULSE | TIMEOUT_ENABLED; + static constexpr uint16_t reg_mode_cfg = DRDY_FMT_PULSE | TIMEOUT_ENABLED | CRC_REC_ENABLE | CRC_REG_ENABLE; + static constexpr uint16_t reg_mode_cfg16 = WLENGTH_16_BITS | reg_mode_cfg; + static constexpr uint16_t reg_mode_cfg24 = WLENGTH_24_BITS | reg_mode_cfg; + static constexpr uint16_t reg_mode_cfg32 = WLENGTH_32_BITS_MSB_SIGN_EXTEND | reg_mode_cfg; // masks for the above 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; + 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; // Semaphore handles SemaphoreHandle_t data_ready_semhandle = NULL; SemaphoreHandle_t update_avg = NULL; - const int numFrameWords = 10; // Number of words in a full ADS131M08 SPI frame + static constexpr int numFrameWords = 10; // Number of words in a full ADS131M08 SPI frame 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(); @@ -106,7 +110,7 @@ class ADS131M08Hub : public Component, uint8_t update_adc_word_length(); uint8_t update_adc_word_length(uint16_t status); void SET_IRAM read_single(); - std::pair SET_IRAM read_multi(); + uint16_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); @@ -122,7 +126,7 @@ class ADS131M08Hub : public Component, uint8_t read_byte(); void write_array(const spiframe &data); void SET_IRAM read_array(spiframe &buffer); - void transfer_array(const spiframe &data_out, spiframe &data_in); + //void transfer_array(const spiframe &data_out, spiframe &data_in); uint16_t SET_IRAM get_crc(const spiframe &frame); bool SET_IRAM check_crc(const spiframe &frame_with_crc); size_t SET_IRAM add_crc(spiframe &frame); @@ -165,12 +169,13 @@ class ADS131M08Hub : public Component, const uint32_t sample_time_ = 40000; // 250 ms float sps_{0.0f}; uint32_t num_samples_[ADC_CHANNELS]; - int64_t sample_sum_[ADC_CHANNELS]; + float sample_sum_[ADC_CHANNELS]; float sample_squared_sum_[ADC_CHANNELS]; float avg_dc_[MAX_CHANNELS]; float avg_ac_[MAX_CHANNELS]; // for debug only std::string frame_to_string(const spiframe &frame); + std::string frame_words_to_string(const spiframe &frame, int index, int count); std::string conversion_frame_to_string(const spiframe &frame); std::string command_to_string(uint16_t cmdadr); void print_command_response_to_string(uint16_t cmdadr_sent, const spiframe &frame); diff --git a/ads131m08/ads131m08_defs.h b/ads131m08/ads131m08_defs.h index 1b55eb0..d3f8725 100644 --- a/ads131m08/ads131m08_defs.h +++ b/ads131m08/ads131m08_defs.h @@ -67,25 +67,20 @@ enum ADC_DELAY { }; -// MODE Register -// enum ADC_RESET : uint16_t -//{ static constexpr uint16_t MODE_MASK_RESET_HAPPENED = ~0x0400; // DEFAULT static constexpr uint16_t MODE_RESET_HAPPENED = 0x0400; -//}; -enum ADC_CRC_TYPE : uint16_t { - CRC_CCITT_16BIT = 0x0000, // DEFAULT - CRC_ANSI_16BIT = 0x0800 +enum ADC_CRC: uint16_t { + CRC_TYPE_CCITT = 0x0000, // DEFAULT CRC type + CRC_TYPE_ANSI = 0x0800, + CRC_REC_ENABLE = 0x1000, + CRC_REG_ENABLE = 0x2000, }; -// enum ADC_WORD_LENGTH : uint16_t -//{ static constexpr uint16_t WLENGTH_16_BITS = 0x0000; static constexpr uint16_t WLENGTH_24_BITS = 0x0100; // DEFAULT static constexpr uint16_t WLENGTH_32_BITS_LSB_ZERO_PADDING = 0x0200; static constexpr uint16_t WLENGTH_32_BITS_MSB_SIGN_EXTEND = 0x0300; -//}; enum ADC_TIMEOUT : uint16_t { TIMEOUT_DISABLED = 0x0000, @@ -98,12 +93,9 @@ enum ADC_DRDY_SELECTION : uint16_t { DRDY_SEL_MOST_LEADING_CHAN = 0x0008, DRDY_SEL_MOST_LEADING_CHAN2 = 0x000C }; -// enum ADC_DRDY_FORMAT : uint16_t -//{ + static constexpr uint16_t DRDY_FMT_LEVEL = 0x0000; // Logic low (default) static constexpr uint16_t DRDY_FMT_PULSE = 0x0001; // Low pulse with a fixed duration -//}; -// end of MODE Register // Commands enum ADC_COMMANDS : uint16_t { diff --git a/ads131m08/sensor/__init__.py b/ads131m08/sensor/__init__.py index e68683f..0f7ba6c 100644 --- a/ads131m08/sensor/__init__.py +++ b/ads131m08/sensor/__init__.py @@ -9,12 +9,12 @@ AUTO_LOAD = [ "sensor", "voltage_sampler", ] +MAX_CHANNELS = 14 CONF_OFFSET_CALIBRATION = "offset_calibration" CONF_GAIN_CALIBRATION = "gain_calibration" CONF_PHASE_CALIBRATION = "phase_calibration" CONF_INPUT_SELECT = "input_select" ICON_CURRENT_DC = "mdi:current-dc" -MAX_CHANNELS = 12 DEPENDENCIES = ["ads131m08"]