Publishing directly to sensors from component (hub) loop. Appears to be aorund 4000sps. DC stable, but AC still fluctuating a lot. 20ms sample time. Will try loop sampling instead of ISR sampling next.

This commit is contained in:
Chris Stuurman 2026-05-03 00:06:23 +02:00
parent 477f05a524
commit d69d0b5dfb
6 changed files with 181 additions and 182 deletions

View File

@ -17,8 +17,8 @@ namespace ads131m08 {
static const char *const TAG = "ads131m08"; static const char *const TAG = "ads131m08";
static const char *const white_space = " \t\n\r\f\v"; // Defines whitespace static const char *const white_space = " \t\n\r\f\v"; // Defines whitespace
DRAM_ATTR static spiframe tx_frame(ADS131M08Hub::numFrameWords * 4, 0); DRAM_ATTR static spiframe tx_frame(ADS131M08Hub::numFrameWords * 4, 0);
DRAM_ATTR static spiframe rx_frame(ADS131M08Hub::numFrameWords * 4, 0); DRAM_ATTR static spiframe rx_frame(ADS131M08Hub::numFrameWords * 4, 0);
// ADS131M08Hub::ADS131M08Hub() // ADS131M08Hub::ADS131M08Hub()
// : base_frame(40, 0) // : base_frame(40, 0)
@ -114,11 +114,11 @@ void ADS131M08Hub::dump_config() {
} }
uint8_t ADS131M08Hub::update_adc_word_length() { uint8_t ADS131M08Hub::update_adc_word_length() {
int word_nbytes = this->adc_word_length_ >> 3; setup_frame(rx_frame, 2);
spiframe frame(2 * word_nbytes, 0); // prepare with CMD_NULL; always cater for crc transfer_array(rx_frame); // write CMD_NULL to ADC to retrieve status
write_array(frame); // write CMD_NULL to ADC to retrieve status zero_fill(rx_frame);
read_array(frame); transfer_array(rx_frame);
uint16_t status = frame[0] << 8 | frame[1]; uint16_t status = rx_frame[0] << 8 | rx_frame[1];
// print_command_response_to_string(CMD_NULL, frame).c_str(); // print_command_response_to_string(CMD_NULL, frame).c_str();
return update_adc_word_length(status); return update_adc_word_length(status);
} }
@ -261,41 +261,49 @@ void ADS131M08Hub::loop()
// Check the semaphore (0 timeout means non-blocking) // 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) { if (this->adc_init_ == 0) {
uint32_t num_samples = 0; float num_samples = 0;
uint32_t crc_errors = 0; float crc_errors = 0;
uint32_t iterations = 0; float iterations = 0;
uint32_t not_ready = 0; float not_ready = 0;
float sps = 0;
{ {
CHIP_SELECTx CHIP_SELECTx
// Perform the read here safely outside of ISR uint64_t start = micros();
uint64_t start = micros(); this->txf_init(); // implementing datasheet recommended TXF init
// this->txf_init(); // implementing datasheet recommended TXF init in ISR //this->adc_sync();
this->adc_sync();
if (rms_calc_req_) { if (rms_calc_req_) {
uint16_str result = read_multi(); float_str result = read_multi();
num_samples = result[0]; num_samples = result[0];
crc_errors = result[1]; crc_errors = result[1];
iterations = result[2]; iterations = result[2];
not_ready = result[3]; not_ready = result[3];
sps = result[4];
uint64_t end = micros(); uint64_t end = micros();
update_averages(SAMPLE_TIME_SENSOR, 1, static_cast<float>(end - start) / 1000.0); //update_averages(SAMPLE_TIME_SENSOR, 1, static_cast<float>(end - start) / 1000.0);
update_averages(MAX_SAMPLES_SENSOR, 1, static_cast<float>(num_samples)); //update_averages(MAX_SAMPLES_SENSOR, 1, static_cast<float>(num_samples));
update_averages(CRC_ERRORS_SENSOR, 1, static_cast<float>(crc_errors)); //update_averages(CRC_ERRORS_SENSOR, 1, static_cast<float>(crc_errors));
uint16_t ctr = isr_ctr_; //uint16_t ctr = isr_ctr_;
update_averages(ISR_COUNT_SENSOR, 1, static_cast<float>(ctr)); //update_averages(ISR_COUNT_SENSOR, 1, static_cast<float>(ctr));
update_averages(ITERATIONS_SENSOR, 1, static_cast<float>(iterations)); //update_averages(ITERATIONS_SENSOR, 1, static_cast<float>(iterations));
update_averages(NOT_READY_SENSOR, 1, static_cast<float>(not_ready)); //update_averages(NOT_READY_SENSOR, 1, static_cast<float>(not_ready));
if(this->sensors_dc[SAMPLE_TIME_SENSOR] != nullptr)
this->sensors_dc[SAMPLE_TIME_SENSOR]->publish_state((end - start)/1000.0);
if(this->sensors_dc[MAX_SAMPLES_SENSOR] != nullptr)
this->sensors_dc[MAX_SAMPLES_SENSOR]->publish_state(num_samples);
if(this->sensors_dc[CRC_ERRORS_SENSOR] != nullptr)
this->sensors_dc[CRC_ERRORS_SENSOR]->publish_state(crc_errors);
if(this->sensors_dc[ISR_COUNT_SENSOR] != nullptr) {
uint16_t ctr = isr_ctr_;
this->sensors_dc[ISR_COUNT_SENSOR]->publish_state(ctr);
}
if(this->sensors_dc[ITERATIONS_SENSOR] != nullptr)
this->sensors_dc[ITERATIONS_SENSOR]->publish_state(iterations);
if(this->sensors_dc[NOT_READY_SENSOR] != nullptr)
this->sensors_dc[NOT_READY_SENSOR]->publish_state(not_ready);
if(this->sensors_dc[SPS_SENSOR] != nullptr)
this->sensors_dc[SPS_SENSOR]->publish_state(sps);
// if(this->sensors_ac[SAMPLE_TIME_SENSOR] != nullptr)
// this->sensors_ac[SAMPLE_TIME_SENSOR]->publish_state(static_cast<float>(end - start)/1000.0);
// if(this->sensors_ac[MAX_SAMPLES_SENSOR] != nullptr)
// this->sensors_ac[MAX_SAMPLES_SENSOR]->publish_state(static_cast<float>(num_samples));
// if(this->sensors_ac[CRC_ERRORS_SENSOR] != nullptr)
// this->sensors_ac[CRC_ERRORS_SENSOR]->publish_state(static_cast<float>(crc_errors));
// if(this->sensors_ac[ISR_COUNT_SENSOR] != nullptr) {
// uint16_t ctr = isr_ctr_;
// this->sensors_ac[ISR_COUNT_SENSOR]->publish_state(static_cast<float>(ctr));
// }
} else { } else {
read_single(); read_single();
} }
@ -468,23 +476,17 @@ void ADS131M08Hub::adc_sync() {
// ********************** from datasheet ************************ // ********************** from datasheet ************************
void ADS131M08Hub::txf_init() { void ADS131M08Hub::txf_init() {
CHIP_SELECT CHIP_SELECT
setup_frame(rx_frame, numFrameWords);
if (firstRead) { if (firstRead) {
// Clear the ADC's 2-deep FIFO on the first read // Clear the ADC's 2-deep FIFO on the first read
for (int i = 0; i < numFrameWords * adc_word_length_; i++) { this->transfer_array(rx_frame);
this->write_byte(0); zero_fill(rx_frame);
} this->transfer_array(rx_frame);
for (int i = 0; i < numFrameWords; i++) {
this->read_byte(); // should perhaps read dwords instead of bytes, but we just want to clear the FIFO so it
// doesn't matter much?
}
firstRead = false; // Clear the flag firstRead = false; // Clear the flag
// we will do this later, after sorting out basic communication
// DMA.enable(); // Let the DMA start sending ADC data to memory
}
// Send the dummy data to the ADC to get the ADC data
for (int i = 0; i < numFrameWords * adc_word_length_; i++) {
this->write_byte(0);
} }
// Send the nulls to the ADC to get the current ADC data
zero_fill(rx_frame);
this->transfer_array(rx_frame);
} }
bool ADS131M08Hub::adc_reset_retry() { bool ADS131M08Hub::adc_reset_retry() {
@ -518,36 +520,34 @@ bool ADS131M08Hub::adc_soft_reset() {
uint16_t reset_response; uint16_t reset_response;
uint16_t cmd = 0; uint16_t cmd = 0;
update_adc_word_length(); update_adc_word_length();
size_t word_nbytes = adc_word_length_ >> 3; auto framelength = numFrameWords * (adc_word_length_ >> 3);
int framelength = numFrameWords * word_nbytes;
spiframe frame(framelength, 0);
size_t frame_len; size_t frame_len;
// curly braces confine chip select scope // curly braces confine chip select scope
{ {
CHIP_SELECTx cmd = CMD_RESET; CHIP_SELECTx cmd = CMD_RESET;
set_frame_word(frame, 0, cmd); setup_frame(rx_frame, 2);
frame.resize(2 * word_nbytes); set_frame_word(rx_frame, 0, cmd);
frame_len = add_crc(frame); frame_len = add_crc(rx_frame);
frame.resize(framelength); rx_frame.resize(framelength);
index += frame_len; index += frame_len;
for (; index < framelength; index++) { for (; index < framelength; index++) {
frame[index] = 0; rx_frame[index] = 0;
} }
write_array(frame); ESP_LOGVV(TAG, "Sent Frame: %s", frame_to_string(rx_frame).c_str());
ESP_LOGVV(TAG, "Sent Frame: %s", frame_to_string(frame).c_str()); transfer_array(rx_frame);
} }
delay_microseconds_safe(T_REGACQ); delay_microseconds_safe(T_REGACQ);
update_adc_word_length(WLENGTH_24_BITS); // should be 24 after reset update_adc_word_length(WLENGTH_24_BITS); // should be 24 after reset
word_nbytes = adc_word_length_ >> 3; setup_frame(rx_frame, numFrameWords);
frame.resize(numFrameWords * word_nbytes);
{ {
CHIP_SELECTx read_array(frame); CHIP_SELECTx
reset_response = get_unsigned_frame_word(frame, 0, true); transfer_array(rx_frame);
bool crc_ok = check_crc(frame); reset_response = get_unsigned_frame_word(rx_frame, 0, true);
ESP_LOGVV(TAG, "Read Frame: %s CRC: %s", frame_to_string(frame).c_str(), (crc_ok ? "OK" : "FAIL")); bool crc_ok = check_crc(rx_frame);
ESP_LOGVV(TAG, "Read Frame: %s CRC: %s", frame_to_string(rx_frame).c_str(), (crc_ok ? "OK" : "FAIL"));
} }
bool result = reset_response == RSP_RESET_OK; bool result = reset_response == RSP_RESET_OK;
ESP_LOGVV(TAG, "Reset response: [0x%04X] %s", reset_response, (result ? "OK" : "FAIL")); ESP_LOGV(TAG, "Reset response: [0x%04X] %s", reset_response, (result ? "OK" : "FAIL"));
return result; return result;
} }
@ -625,27 +625,9 @@ uint16_t ADS131M08Hub::crc(uint16_t crc_register, uint8_t data) {
return crc_result; return crc_result;
} }
void ADS131M08Hub::write_byte(uint8_t byte) { void ADS131M08Hub::transfer_array(spiframe &frame) {
CHIP_SELECT CHIP_SELECT
this->transfer_byte(byte); Base::transfer_array(frame.data(), (size_t)frame.size());
}
uint8_t ADS131M08Hub::read_byte() {
CHIP_SELECT
uint8_t result = this->transfer_byte(0x00); // Send dummy byte to read data
return result;
}
void ADS131M08Hub::read_array(spiframe &frame) {
CHIP_SELECT
this->transfer_array(frame.data(), frame.size());
}
void ADS131M08Hub::write_array(const spiframe &frame) {
CHIP_SELECT
for (size_t i = 0; i < frame.size(); i++) {
this->transfer_byte(frame[i]);
}
} }
//void ADS131M08Hub::transfer_array(const spiframe &tx_frame, spiframe &rx_frame) { //void ADS131M08Hub::transfer_array(const spiframe &tx_frame, spiframe &rx_frame) {
@ -667,28 +649,28 @@ bool ADS131M08Hub::set_measure_rms(uint8_t channel, bool enable) {
} }
void ADS131M08Hub::read_single() { void ADS131M08Hub::read_single() {
int word_nbytes = adc_word_length_ >> 3; setup_frame(rx_frame, numFrameWords);
int frame_length = numFrameWords * word_nbytes; this->transfer_array(rx_frame);
spiframe frame(frame_length, 0); bool crc_ok = check_crc(rx_frame);
this->read_array(frame); uint16_t drdy_status = get_unsigned_frame_word(rx_frame, 0, true) & MASK_STATUS_DRDY;
bool crc_ok = check_crc(frame);
uint16_t drdy_status = get_unsigned_frame_word(frame, 0, true) & MASK_STATUS_DRDY;
// data_ready = crc_ok && (drdy_status != 0); // data_ready = crc_ok && (drdy_status != 0);
if (crc_ok) { if (crc_ok) {
// sample channels // sample channels
for (int i = 0; i < ADC_CHANNELS; i++) { for (int i = 0; i < ADC_CHANNELS; i++) {
bool channel_ready = drdy_status & 1; bool channel_ready = drdy_status & 1;
drdy_status = drdy_status >> 1; drdy_status = drdy_status >> 1;
bool ac_sensor_exist = this->sensors_ac[i] != nullptr; if (channel_ready) {
bool dc_sensor_exist = this->sensors_dc[i] != nullptr; int32_t raw = get_sign_ext_frame_word(rx_frame, i + 1);
if (channel_ready && (ac_sensor_exist || dc_sensor_exist)) {
int32_t raw = get_sign_ext_frame_word(frame, i + 1);
float value = this->conversion_factor_ * raw; float value = this->conversion_factor_ * raw;
this->sampled_values_[i] = value; this->sampled_values_[i] = value;
if (ac_sensor_exist) bool ac_sensor_exist = this->sensors_ac[i] != nullptr;
this->sensors_ac[i]->publish_state(value); bool dc_sensor_exist = this->sensors_dc[i] != nullptr;
if (dc_sensor_exist) if (ac_sensor_exist || dc_sensor_exist) {
this->sensors_dc[i]->publish_state(value); if (ac_sensor_exist)
this->sensors_ac[i]->publish_state(value);
if (dc_sensor_exist)
this->sensors_dc[i]->publish_state(value);
}
} }
} }
} }
@ -700,13 +682,13 @@ void ADS131M08Hub::read_single() {
// hopefully reliably calculate RMS value, phase offsets, etc. the best the read_multi procedure does is to read about // 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 // 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 // enough, the following procedure should be completely re-designed
uint16_str ADS131M08Hub::read_multi() { float_str ADS131M08Hub::read_multi() {
int32_t raw; int32_t raw;
float value; float value;
uint16_str result(4, 0); float_str result(5, 0.0);
bool crc_ok, data_ready, ac_sensor_exist, dc_sensor_exist; bool crc_ok, data_ready, ac_sensor_exist, dc_sensor_exist;
uint16_t drdy_status, status; uint16_t drdy_status, status;
int i, iteration = 0; // going above 255 will result in overflows int i, iteration = 0;
uint32_t elapsed_time = 0; uint32_t elapsed_time = 0;
uint32_t loop_start_time = micros(); uint32_t loop_start_time = micros();
int word_nbytes = adc_word_length_ >> 3; int word_nbytes = adc_word_length_ >> 3;
@ -722,10 +704,10 @@ uint16_str ADS131M08Hub::read_multi() {
sample_squared_sum_[i] = 0; sample_squared_sum_[i] = 0;
} }
while (elapsed_time < this->sample_time_ && iteration++ < 1000) { while ((elapsed_time < this->sample_time_) && (iteration++ < 1000)) {
result[2] = iteration; result[2] = iteration;
std::fill(rx_frame.begin(), rx_frame.end(), 0); setup_frame(rx_frame, numFrameWords);
this->read_array(rx_frame); this->transfer_array(rx_frame);
//ESP_LOGD(TAG, "frame: %s", frame_to_string(rx_frame).c_str()); //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, "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()); //ESP_LOGD(TAG, "frame_word%d: %s", 0, frame_words_to_string(rx_frame, 0, 1).c_str());
@ -743,22 +725,24 @@ uint16_str ADS131M08Hub::read_multi() {
for (i = 0; i < ADC_CHANNELS && drdy_status != 0; i++) { for (i = 0; i < ADC_CHANNELS && drdy_status != 0; i++) {
data_ready = drdy_status & 1; data_ready = drdy_status & 1;
drdy_status = drdy_status >> 1; drdy_status = drdy_status >> 1;
ac_sensor_exist = this->sensors_ac[i] != nullptr; if (data_ready) {
dc_sensor_exist = this->sensors_dc[i] != nullptr;
if (data_ready && (ac_sensor_exist || dc_sensor_exist)) {
raw = get_sign_ext_frame_word(rx_frame, i + 1);
value = this->conversion_factor_ * raw;
this->sampled_values_[i] = value; this->sampled_values_[i] = value;
if (this->rms_enabled_[i]) { ac_sensor_exist = this->sensors_ac[i] != nullptr;
(this->num_samples_[i])++; dc_sensor_exist = this->sensors_dc[i] != nullptr;
(this->sample_sum_[i]) += value; if (ac_sensor_exist || dc_sensor_exist) {
(this->sample_squared_sum_[i]) += value * value; raw = get_sign_ext_frame_word(rx_frame, i + 1);
} else { value = this->conversion_factor_ * raw;
// if(ac_sensor_exist) if (this->rms_enabled_[i]) {
// this->sensors_ac[i]->publish_state(value); (this->num_samples_[i])++;
// if(dc_sensor_exist) (this->sample_sum_[i]) += value;
// this->sensors_dc[i]->publish_state(value); (this->sample_squared_sum_[i]) += value * value;
update_averages(i, value, value); } else {
if(ac_sensor_exist)
this->sensors_ac[i]->publish_state(value);
if(dc_sensor_exist)
this->sensors_dc[i]->publish_state(value);
//update_averages(i, value, value);
}
} }
} }
} }
@ -781,11 +765,11 @@ uint16_str ADS131M08Hub::read_multi() {
if (num_samples == 0) { if (num_samples == 0) {
// should not happen, but let's play safe and avoid dividing by zero // should not happen, but let's play safe and avoid dividing by zero
// ESP_LOGW(TAG, "Num samples: %d", num_samples); // ESP_LOGW(TAG, "Num samples: %d", num_samples);
update_averages(i, NAN, NAN); //update_averages(i, NAN, NAN);
// if(ac_sensor_exist) if(ac_sensor_exist)
// this->sensors_ac[i]->publish_state(NAN); this->sensors_ac[i]->publish_state(NAN);
// if(dc_sensor_exist) if(dc_sensor_exist)
// this->sensors_dc[i]->publish_state(NAN); this->sensors_dc[i]->publish_state(NAN);
} else { } else {
float sample_sum = sample_sum_[i]; float sample_sum = sample_sum_[i];
float rms_dc = sample_sum / num_samples; float rms_dc = sample_sum / num_samples;
@ -794,16 +778,22 @@ uint16_str ADS131M08Hub::read_multi() {
if (rms_ac_squared > 0) { if (rms_ac_squared > 0) {
rms_ac = std::sqrtf(rms_ac_squared); rms_ac = std::sqrtf(rms_ac_squared);
} }
this->sps_ = (1e6 * (float) num_samples) / elapsed_time; if(ac_sensor_exist)
update_averages(i, rms_ac, rms_dc); this->sensors_ac[i]->publish_state(rms_ac);
if(dc_sensor_exist)
this->sensors_dc[i]->publish_state(rms_dc);
//update_averages(i, rms_ac, rms_dc);
} }
this->num_samples_[i] = 0; this->num_samples_[i] = 0;
this->sample_sum_[i] = 0.0f; this->sample_sum_[i] = 0.0f;
this->sample_squared_sum_[i] = 0.0f; this->sample_squared_sum_[i] = 0.0f;
} }
} }
this->sps_ = (1e6 * (float) result[0]) / elapsed_time;
result[4] = this->sps_;
return result; return result;
} }
/*
/// @brief Updates rolling averages for rms_ac and rms_dc. Window = 2 /// @brief Updates rolling averages for rms_ac and rms_dc. Window = 2
/// @param channel /// @param channel
/// @param rms_ac /// @param rms_ac
@ -897,20 +887,20 @@ float ADS131M08Hub::get_average(uint8_t channel, bool read_ac) {
} }
return result; return result;
} }
*/
bool ADS131M08Hub::adc_lock(bool enable) { bool ADS131M08Hub::adc_lock(bool enable) {
int word_nbytes = adc_word_length_ >> 3; setup_frame(rx_frame, 2);
spiframe frame(word_nbytes * 2, 0);
uint16_t command = CMD_UNLOCK; uint16_t command = CMD_UNLOCK;
if (enable) { if (enable) {
command = CMD_LOCK; command = CMD_LOCK;
} }
set_frame_word(frame, 0, command); set_frame_word(rx_frame, 0, command);
add_crc(frame); add_crc(rx_frame);
write_array(frame); transfer_array(rx_frame);
delay_microseconds_safe(T_REGACQ); delay_microseconds_safe(T_REGACQ);
read_array(frame); zero_fill(rx_frame);
auto ack = get_unsigned_frame_word(frame, 0, true); transfer_array(rx_frame);
auto ack = get_unsigned_frame_word(rx_frame, 0, true);
return ack == command; return ack == command;
} }
@ -981,27 +971,26 @@ bool ADS131M08Hub::adc_register_write(uint16_t start_address, const uint16_str &
if (nregs == 0) { if (nregs == 0) {
return false; // invalid return false; // invalid
} }
int word_nbytes = adc_word_length_ >> 3; int wreg_nwords = 2 + nregs; // ensure room for crc
int wreg_framelength = word_nbytes * (2 + nregs); // ensure room for crc int rreg_resp_framelength = 2 + (nregs == 1 ? -1 : nregs); // add room for CRC if nregs > 1
int rreg_resp_framelength = word_nbytes * (2 + (nregs == 1 ? -1 : nregs)); // add room for CRC if nregs > 1 //spiframe frame(wreg_nwords, 0);
//spiframe frame(wreg_framelength, 0); //spiframe rxframe(wreg_nwords, 0);
//spiframe rxframe(wreg_framelength, 0);
uint16_t addr_regcnt_mask = (start_address << 7) | ((nregs - 1) & MASK_CMD_RW_REG_COUNT); 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 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 uint16_t rreg_addr_opcode = CMD_RREG | addr_regcnt_mask; // Combine RREG command, start_address and register count
bool has_mode_reg = bool has_mode_reg =
(start_address == REG_MODE) || ((start_address < REG_MODE) && ((start_address + nregs) > REG_MODE)); (start_address == REG_MODE) || ((start_address < REG_MODE) && ((start_address + nregs) > REG_MODE));
tx_frame.resize(wreg_framelength); setup_frame(rx_frame, wreg_nwords);
rx_frame.resize(wreg_framelength);
{ {
CHIP_SELECT set_frame_word(tx_frame, 0, wreg_addr_opcode); CHIP_SELECT
set_frame_word(rx_frame, 0, wreg_addr_opcode);
for (int i = 0; i < nregs; i++) { for (int i = 0; i < nregs; i++) {
set_frame_word(tx_frame, i + 1, data[i]); set_frame_word(rx_frame, i + 1, data[i]);
} }
add_crc(tx_frame); add_crc(rx_frame);
//ESP_LOGD(TAG, "%s\n", rwreg_command_frame_to_string(tx_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(tx_frame).c_str()); //ESP_LOGD(TAG, "Send Frame: %s", frame_to_string(rx_frame).c_str());
transfer_array(tx_frame.data(), tx_frame.size()); // WREG transfer_array(rx_frame); // WREG
} }
if (has_mode_reg) { if (has_mode_reg) {
update_adc_word_length(); update_adc_word_length();
@ -1032,31 +1021,29 @@ uint16_str ADS131M08Hub::adc_register_read(uint8_t address, uint8_t nregs) {
ESP_LOGE(TAG, "Trying to read %d registers. This exceeds maximum register read count of %d!", nregs, MAX_FRAME_SIZE - 2); ESP_LOGE(TAG, "Trying to read %d registers. This exceeds maximum register read count of %d!", nregs, MAX_FRAME_SIZE - 2);
return result; // invalid return result; // invalid
} }
int word_nbytes = adc_word_length_ >> 3; int rreg_nwords = 2; // ensure room for crc
int request_framelength = 2 * word_nbytes; // ensure room for crc int response_nwords = 2 + (nregs == 1 ? -1 : nregs); // add room for CRC if nregs > 1
int response_framelength = word_nbytes * (2 + (nregs == 1 ? -1 : nregs)); // add room for CRC if nregs > 1
spiframe frame(response_framelength, 0);
uint16_t rreg_addr_opcode = uint16_t rreg_addr_opcode =
CMD_RREG | (address << 7) | CMD_RREG | (address << 7) |
((nregs - 1) & MASK_CMD_RW_REG_COUNT); // Combine RREG command, address and register count ((nregs - 1) & MASK_CMD_RW_REG_COUNT); // Combine RREG command, address and register count
{ {
CHIP_SELECT CHIP_SELECT
frame.resize(request_framelength); setup_frame(rx_frame, rreg_nwords);
set_frame_word(frame, 0, rreg_addr_opcode); set_frame_word(rx_frame, 0, rreg_addr_opcode);
add_crc(frame); add_crc(rx_frame);
write_array(frame); // send RREG transfer_array(rx_frame); // send RREG
} }
ESP_LOGVV(TAG, "%s\n", rwreg_command_frame_to_string(frame).c_str()); ESP_LOGVV(TAG, "%s\n", rwreg_command_frame_to_string(rx_frame).c_str());
ESP_LOGVV(TAG, "Sent Frame: %s", frame_to_string(frame).c_str()); ESP_LOGVV(TAG, "Sent Frame: %s", frame_to_string(rx_frame).c_str());
delay_microseconds_safe(T_REGACQ); delay_microseconds_safe(T_REGACQ);
{ {
CHIP_SELECT CHIP_SELECT
frame.resize(response_framelength); setup_frame(rx_frame, response_nwords);
read_array(frame); transfer_array(rx_frame);
} }
ESP_LOGVV(TAG, "Recv Frame: %s", frame_to_string(frame).c_str()); ESP_LOGVV(TAG, "Recv Frame: %s", frame_to_string(rx_frame).c_str());
if (nregs > 1) { if (nregs > 1) {
bool crc_ok = check_crc(frame); bool crc_ok = check_crc(rx_frame);
if (!crc_ok) { if (!crc_ok) {
ESP_LOGW(TAG, "CRC failed reading ADC registers!"); ESP_LOGW(TAG, "CRC failed reading ADC registers!");
result.clear(); result.clear();
@ -1069,15 +1056,15 @@ uint16_str ADS131M08Hub::adc_register_read(uint8_t address, uint8_t nregs) {
// pretend this is the ack // pretend this is the ack
if (nregs > 1) { if (nregs > 1) {
offset = 1; offset = 1;
rreg_ack = get_unsigned_frame_word(frame, 0, true); rreg_ack = get_unsigned_frame_word(rx_frame, 0, true);
} }
// uint16_t rreg_ack = (nregs == 1) ? rreg_addr_opcode : get_unsigned_frame_word(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; nregs = (rreg_ack & MASK_CMD_RW_REG_COUNT) + 1;
uint16_t start_addr = (rreg_ack & MASK_CMD_RW_REG_ADDRESS) >> 7; uint16_t start_addr = (rreg_ack & MASK_CMD_RW_REG_ADDRESS) >> 7;
for (int i = 0; i < nregs; i++) { for (int i = 0; i < nregs; i++) {
result[i] = get_unsigned_frame_word(frame, i + offset, true); result[i] = get_unsigned_frame_word(rx_frame, i + offset, true);
} }
print_command_response_to_string(rreg_addr_opcode, frame); print_command_response_to_string(rreg_addr_opcode, rx_frame);
delay_microseconds_safe(1); delay_microseconds_safe(1);
return result; return result;
} }

View File

@ -25,23 +25,28 @@ namespace ads131m08 {
static const uint8_t DEFAULT_WORD_LENGTH = 32; // we use 32 bit to allow for DMA transfers 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 ADC_CHANNELS = 8;
static const int MAX_CHANNELS = 14; // for debugging static const int MAX_CHANNELS = 15; // for debugging
static const int SAMPLE_TIME_SENSOR = 8; // for debugging static const int SAMPLE_TIME_SENSOR = 8; // for debugging
static const int MAX_SAMPLES_SENSOR = 9; // for debugging static const int MAX_SAMPLES_SENSOR = 9; // for debugging
static const int CRC_ERRORS_SENSOR = 10; // for debugging static const int CRC_ERRORS_SENSOR = 10; // for debugging
static const int ISR_COUNT_SENSOR = 11; // for debugging static const int ISR_COUNT_SENSOR = 11; // for debugging
static const int ITERATIONS_SENSOR = 12; // for debugging static const int ITERATIONS_SENSOR = 12; // for debugging
static const int NOT_READY_SENSOR = 13; // for debugging static const int NOT_READY_SENSOR = 13; // for debugging
static const int SPS_SENSOR = 14; // for debugging
// #define SET_IRAM IRAM_ATTR // #define SET_IRAM IRAM_ATTR
#define SET_IRAM #define SET_IRAM
typedef std::vector<uint8_t> spiframe; typedef std::vector<uint8_t> spiframe;
typedef uint_str<uint16_t>::Ty_string uint16_str; // we want to use the stack to pass small arrays typedef uint_str<uint16_t>::Ty_string uint16_str; // we want to use the stack to pass small arrays
typedef uint_str<float>::Ty_string float_str; // we want to use the stack to pass small arrays
class ADS131M08Hub : public Component, class ADS131M08Hub : public Component,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_TRAILING, public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_TRAILING,
spi::DATA_RATE_8MHZ> { spi::DATA_RATE_8MHZ> {
using Base = spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_TRAILING, spi::DATA_RATE_8MHZ>;
friend class ads131m08_select; friend class ads131m08_select;
public: public:
@ -91,7 +96,7 @@ class ADS131M08Hub : public Component,
bool set_channel_gain(uint8_t channel, uint8_t gain); bool set_channel_gain(uint8_t channel, uint8_t gain);
bool set_measure_rms(uint8_t channel, bool enable); bool set_measure_rms(uint8_t channel, bool enable);
float get_sampled_value(uint8_t channel) { return sampled_values_[channel]; } float get_sampled_value(uint8_t channel) { return sampled_values_[channel]; }
float get_average(uint8_t channel, bool read_ac); //float get_average(uint8_t channel, bool read_ac);
bool set_reg_osr(); bool set_reg_osr();
protected: protected:
@ -110,7 +115,7 @@ class ADS131M08Hub : public Component,
uint8_t update_adc_word_length(); uint8_t update_adc_word_length();
uint8_t update_adc_word_length(uint16_t status); uint8_t update_adc_word_length(uint16_t status);
void SET_IRAM read_single(); void SET_IRAM read_single();
uint16_str SET_IRAM read_multi(); float_str SET_IRAM read_multi();
bool adc_lock(bool enable); bool adc_lock(bool enable);
bool adc_register_write(uint16_t address, uint16_t data); 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, const uint16_str &data);
@ -121,11 +126,7 @@ class ADS131M08Hub : public Component,
bool adc_soft_reset(); bool adc_soft_reset();
void adc_hard_reset(); void adc_hard_reset();
void adc_sync(); void adc_sync();
void write_byte(uint8_t byte); void SET_IRAM transfer_array(spiframe &frame);
bool write(uint32_t data, uint8_t adcWordLength);
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); uint16_t SET_IRAM get_crc(const spiframe &frame);
bool SET_IRAM check_crc(const spiframe &frame_with_crc); bool SET_IRAM check_crc(const spiframe &frame_with_crc);
@ -137,7 +138,7 @@ class ADS131M08Hub : public Component,
bool SET_IRAM set_frame_word(spiframe &frame, int w_index, uint32_t data); bool SET_IRAM set_frame_word(spiframe &frame, int w_index, uint32_t data);
uint32_t SET_IRAM get_unsigned_frame_word(const spiframe &frame, int w_index, bool force_16bits = false); uint32_t SET_IRAM get_unsigned_frame_word(const spiframe &frame, int w_index, bool force_16bits = false);
int32_t SET_IRAM get_sign_ext_frame_word(const spiframe &frame, int w_index); 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); //bool update_averages(uint8_t channel, float rms_ac, float rms_dc);
std::atomic<int> adc_init_{0}; std::atomic<int> adc_init_{0};
std::atomic<int> cs_ctr_{ std::atomic<int> cs_ctr_{
0}; // Counter to track nested CS enable/disable calls for proper handling of multiple transfers in a row 0}; // Counter to track nested CS enable/disable calls for proper handling of multiple transfers in a row
@ -161,12 +162,24 @@ class ADS131M08Hub : public Component,
} }
}; };
float update_conversion_factor(); float update_conversion_factor();
//DRAM_ATTR static spiframe rx_frame;
inline void zero_fill(spiframe& frame) {
std::fill(frame.begin(), frame.end(), 0);
}
inline size_t setup_frame(spiframe& frame, uint8_t word_count) {
int word_nbytes = this->adc_word_length_ >> 3;
frame.resize(word_nbytes * word_count);
zero_fill(frame);
return frame.size();
}
private: private:
uint8_t update_state_[MAX_CHANNELS] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t update_state_[MAX_CHANNELS] = {0, 0, 0, 0, 0, 0, 0, 0};
uint8_t adc_word_length_{24}; uint8_t adc_word_length_{24};
float conversion_factor_{1.2 / 8388608.0}; // updated when word length changes float conversion_factor_{1.25 / 8388608.0}; // updated when word length changes
const uint32_t sample_time_ = 40000; // 250 ms const uint32_t sample_time_ = 20000; // 250 ms
float sps_{0.0f}; float sps_{0.0f};
uint32_t num_samples_[ADC_CHANNELS]; uint32_t num_samples_[ADC_CHANNELS];
float sample_sum_[ADC_CHANNELS]; float sample_sum_[ADC_CHANNELS];

View File

@ -9,7 +9,7 @@ AUTO_LOAD = [
"sensor", "voltage_sampler", "sensor", "voltage_sampler",
] ]
MAX_CHANNELS = 14 MAX_CHANNELS = 15
CONF_OFFSET_CALIBRATION = "offset_calibration" CONF_OFFSET_CALIBRATION = "offset_calibration"
CONF_GAIN_CALIBRATION = "gain_calibration" CONF_GAIN_CALIBRATION = "gain_calibration"
CONF_PHASE_CALIBRATION = "phase_calibration" CONF_PHASE_CALIBRATION = "phase_calibration"

View File

@ -73,10 +73,10 @@ void RMS_Sensor::loop()
} }
} }
} }
else { //else {
float value = this->parent_->get_average(this->calc_rms_); // float value = this->parent_->get_average(this->calc_rms_);
publish_state(value); // publish_state(value);
} //}
} }
void RMS_Sensor::dump_config() void RMS_Sensor::dump_config()

View File

@ -26,7 +26,7 @@ class Channel : public sensor::Sensor,
void set_offset_calibration(int value) { this->offset_cal_ = value; } void set_offset_calibration(int value) { this->offset_cal_ = value; }
void set_phase_calibration(int value) { this->phase_cal_ = value; } void set_phase_calibration(int value) { this->phase_cal_ = value; }
bool set_calc_rms(bool enable) { this->calc_rms_ = enable; return this->parent_ != nullptr ? this->parent_->set_measure_rms(this->channel_, enable) : false; } 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); } //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; } void set_mux_input(ADC_INPUT_CHANNEL_MUX value) { this->input_ = value; }
uint32_t normalised_gain_calibration() const; uint32_t normalised_gain_calibration() const;
uint32_t normalised_offset_calibration() const; uint32_t normalised_offset_calibration() const;

View File

@ -14,7 +14,6 @@ from .. import CONF_ADS131M08_ID, ads131m08_ns
CONF_AC = "ac" CONF_AC = "ac"
CONF_DC = "dc" CONF_DC = "dc"
ICON_CURRENT_DC = "mdi:current-dc" ICON_CURRENT_DC = "mdi:current-dc"
MAX_CHANNELS = 12
AUTO_LOAD = ["sensor",] AUTO_LOAD = ["sensor",]
DEPENDENCIES = ["ads131m08"] DEPENDENCIES = ["ads131m08"]