configs/components/ads131m08/ads131m08.cpp

199 lines
7.8 KiB
C++

#include "ads131m08.h"
namespace esphome {
namespace ads131m08 {
static const char *const TAG = "ads131m08";
void ADS131M08Hub::setup()
{
// Initialize SPI with correct settings for ADS131M08
// SPI mode 1: CPOL=0, CPHA=1
this->spi_setup();
// not sure if next few lines are needed here or is it handled in spi_setup()
SPI.begin();
SPI.setDataMode(SPI_MODE1);
SPI.setBitOrder(MSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV8); // Adjust clock speed as needed
this->drdy_pin_->setup();
this->drdy_pin_->pin_mode(esphome::gpio::FLAG_INPUT | esphome::gpio::FLAG_PULLUP);
this->drdy_pin_->attach_interrupt(&ADS131M08Hub::isr, this, gpio::INTERRUPT_FALLING_EDGE);
this->initialize_ads131m08();
}
void ADS131M08Hub::initialize_ads131m08()
{
// Send RESET command
SPI.transfer(0x06);
delay(1);
// Send UNLOCK command
SPI.transfer(0x55);
SPI.transfer(0x55);
// Configure registers as needed (example: set gain, etc.)
// Write to MODE register for continuous conversion, disable internal reference (use external MAX6070AAUT12+T at 1.25V)
write_register(0x02, 0x0000); // MODE register, continuous mode, INTREF_EN = 0
// Wait for external reference to settle
delay(100);
// Start conversions
SPI.transfer(0x08); // START command
}
void ADS131M08Hub::write_register(uint8_t reg, uint16_t value)
{
SPI.transfer(0x40 | reg); // WREG command
SPI.transfer(0x00); // Number of registers - 1 (0 for one register)
SPI.transfer((value >> 8) & 0xFF);
SPI.transfer(value & 0xFF);
}
void IRAM_ATTR ADS131M08Hub::isr(ADS131M08Hub *arg)
{
arg->txf_init(); // implementing datasheet recommended TXF init in ISR
arg->data_ready_ = true;
}
void ADS131M08Hub::loop()
{
if (this->data_ready_) {
this->data_ready_ = false;
this->read_data_();
}
}
// ********************** from datasheet ************************
void ADS131M08Hub::txf_init()
{
if (firstRead) {
// Clear the ADC's 2-deep FIFO on the first read
for (int i = 0; i <numFrameWords; i++) {
SPI.write(spiDummyWord + i);
}
for(int i = 0; i < numFrameWords; i++) {
SPI.read();
}
firstRead = false; // Clear the flag
DMA.enable(); // Let the DMA start sending ADC data to memory
}
for (int i = 0; i < numFrameWords; i++) {// Send the dummy data to the ADC to get the ADC data
SPI.write(spiDummyWord + i);
}
}
/* adcRegisterWrite
Short function that writes one ADC register at a time.
Blocks return until SPI is idle.
Returns false if the word length is wrong.
param
addrMask: 16-bit register address mask
data: data to write adcWord
Length: word length which ADC expects. Either 16, 24 or 32.
return true if word length was valid false if not
*/
bool ADS131M08Hub::adcRegisterWrite(unsigned short addrMask, unsigned short data, unsigned char adcWordLength)
{
unsigned char shiftValue; // Stores the amount of bit shift based on ADC word length
if(adcWordLength == 16) {
shiftValue = 0; // If length is 16, no shift
}
else if(adcWordLength == 24) {
shiftValue = 8; // If length is 24, shift left by 8
}
else if(adcWordLength == 32) {
shiftValue = 16; // If length is 32, shift left by 16
} else {
return false; // If not, invalid length
}
SPI.write((CMD_WREG | addrMask) << shiftValue); // Write address and opcode; Shift to accommodate ADC word length
SPI.write(data << shiftValue); // Write register data
while(SPI.isBusy()); // Wait for data to complete sending
return true;
}
void ADS131M08Hub::initialize_ads131m08_datasheet()
{
// enableSupplies();
// GPIO.inputEnable('input'); // Enable GPIO connected to DRDY
// clkout.enable(8192000); // Enable 8.192 MHz clock to CLKIN
// SPI.enable(); // Enable SPI port
// SPI.wordLengthSet(24); // ADC default word length is 24 bits
// SPI.configCS(STAY_ASSERTED);// Configure CS to remain asserted until frame is complete
while(!GPIO.read()){} // Wait for DRDY to go high indicating it is ok to talk to ADC
adcRegisterWrite(REG_CLOCK, MASK_CLOCK_ALL_CH_DISABLE | OSR_1024 | PM_HIGH_RESOLUTION, 24); // Write CLOCK register; Turn off all channels so short frames can be written during config
// Re-write defaults for other bits in CLOCK register
adcRegisterWrite(REG_MODE, MODE_NO_RESET | DRDY_FMT_PULSE | WLENGTH_24_BITS | TIMEOUT_ENABLED, 24); // Write MODE register; Clear the RESET flag, make DRDY active low pulse
// Re-write defaults for other bits in MODE register
adcRegisterWrite(REG_GAIN1, PGAGAIN3_32 | PGAGAIN1_32, 24); // Write GAIN1 register; Set channels 1 and 3 PGA gain to 32 in this example
// Leave channels 0 and 2 at default gain of 1
adcRegisterWrite(REG_THRSHLD_LSB, 0x09, 24); // Write THRSHLD_LSB register; Set DCBLOCK filter to have a corner frequency of 622 mHz
DMA.triggerSet(SPI);// Configure DMA to trigger when data comes in on the MCU SPI port
DMA.txAddrSet(SPI.rxAddr());// Set the DMA to take from the incoming SPI port
DMA.rxAddrSet(&adcData);// Set the DMA to send ADC data to a predefined memory location
adcRegisterWrite(REG_MODE, WLENGTH_32_BITS_MSB_SIGN_EXTEND | DRDY_FMT_PULSE | TIMEOUT_ENABLED, 24); // Write MODE register; Make ADC word size 32 bits to accommodate DMA;
// Re-write other set bits in MODE register
SPI.wordLengthSet(32); // Set SPI word size to 32 bits to accomodate DMA
adcRegisterWrite(REG_CLOCK, MASK_CLOCK_ALL_CH_ENABLE | OSR_1024 | PM_HIGH_RESOLUTION, 32); // Write CLOCK register; Turn on all ADC channels; Re-write defaults for other bits in CLOCK register
GPIO.interuptEnable();// Enable DRDY interrupt and begin streaming data
}
// ********************** end of from datasheet ************************
/*
void ADS131M08::read_all_channels()
{
// Send RDATA command or read data directly
SPI.transfer(0x12); // RDATA command
// Read 24 bytes (3 bytes per channel for 8 channels)
for (int i = 0; i < 24; i++) {
data_buffer_[i] = SPI.transfer(0x00);
}
// Convert to voltages for all channels
//Sensor *channels[8] = {channel1, channel2, channel3, channel4, channel5, channel6, channel7, channel8};
for (int ch = 0; ch < 8; ch++) {
if (this->sensors_[ch] != nullptr) {
int offset = ch * 3;
int32_t raw = (data_buffer_[offset] << 16) | (data_buffer_[offset + 1] << 8) | data_buffer_[offset + 2];
if (raw & 0x800000)
raw |= 0xFF000000; // Sign extend
float v = (raw / 8388608.0) * this->reference_voltage_; // 2^23 = 8388608, Vref = 1.25V (MAX6070AAUT12+T)
this->sensors_[ch]->publish_state(v);
}
}
}
*/
void ADS131M08Hub::read_data_()
{
this->enable();
// ADS131M08 Frame: 1 Status Word + 8 Channel Words + 1 CRC Word (24-bit words)
uint8_t frame[30]; // 10 words * 3 bytes
this->read_array(frame, 30);
this->disable();
for (int i = 0; i < 8; i++) {
if (this->sensors_[i] != nullptr) {
// Convert 24-bit two's complement to float (Simplified)
int32_t raw = (frame[3+(i*3)] << 16) | (frame[4+(i*3)] << 8) | frame[5+(i*3)];
if (raw & 0x800000)
raw |= 0xFF000000; // Sign extend
this->sensors_[i]->publish_state(raw * (this->reference_voltage_ / 8388608.0)); // 2^23 = 8388608, Vref = 1.25V ( for MAX6070AAUT12+T )
}
}
}
void ADS131M08Hub::dump_config()
{
ESP_LOGCONFIG(TAG, "ADS131M08:");
LOG_PIN(" CS Pin:", this->cs_);
LOG_PIN(" DRDY Pin:", this->drdy_pin_);
ESP_LOGCONFIG(TAG, " Reference Voltage: %.2fV", this->reference_voltage_);
}
} // namespace ads131m08
} // namespace esphome