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.
This commit is contained in:
parent
c100502519
commit
678312a27d
@ -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<uint32_t, uint32_t> 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<float>(end - start) / 1000.0);
|
||||
update_averages(MAX_SAMPLES_SENSOR, 1, static_cast<float>(num_samples));
|
||||
update_averages(CRC_ERRORS_SENSOR, 1, static_cast<float>(crc_errors));
|
||||
uint16_t ctr = isr_ctr_;
|
||||
update_averages(ISR_COUNT_SENSOR, 1, static_cast<float>(ctr));
|
||||
update_averages(ITERATIONS_SENSOR, 1, static_cast<float>(iterations));
|
||||
update_averages(NOT_READY_SENSOR, 1, static_cast<float>(not_ready));
|
||||
|
||||
// if(this->sensors_ac[SAMPLE_TIME_SENSOR] != nullptr)
|
||||
// this->sensors_ac[SAMPLE_TIME_SENSOR]->publish_state(static_cast<float>(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<int32_t>(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<int32_t>(raw | 0xFF000000); // Sign extend
|
||||
else
|
||||
result = static_cast<int32_t>(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]);
|
||||
{
|
||||
int16_t raw = (frame[b_index] << 8) | frame[b_index + 1];
|
||||
result = static_cast<int16_t>(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<uint32_t, uint32_t> ADS131M08Hub::read_multi() {
|
||||
uint16_str ADS131M08Hub::read_multi() {
|
||||
int32_t raw;
|
||||
float value;
|
||||
std::pair<uint32_t, uint32_t> 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<uint32_t, uint32_t> 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<int64_t>(raw);
|
||||
(this->sample_sum_[i]) += value;
|
||||
(this->sample_squared_sum_[i]) += value * value;
|
||||
} else {
|
||||
// if(ac_sensor_exist)
|
||||
@ -737,8 +765,8 @@ std::pair<uint32_t, uint32_t> 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<uint32_t, uint32_t> 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<float>(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;
|
||||
} 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;
|
||||
|
||||
@ -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<uint32_t, uint32_t> 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);
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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"]
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user