ESPHome  2022.12.8
max9611.cpp
Go to the documentation of this file.
1 #include "max9611.h"
2 #include "esphome/core/log.h"
4 namespace esphome {
5 namespace max9611 {
6 using namespace esphome::i2c;
7 // Sign extend
8 // http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend
9 template<typename T, unsigned B> inline T signextend(const T x) {
10  struct {
11  T x : B;
12  } s;
13  return s.x = x;
14 }
15 // Map the gain register to in uV/LSB
17  float lsb = 0.0;
18  if (gain == MAX9611_MULTIPLEXER_CSA_GAIN1) {
19  lsb = 107.50;
20  } else if (gain == MAX9611_MULTIPLEXER_CSA_GAIN4) {
21  lsb = 26.88;
22  } else if (gain == MAX9611_MULTIPLEXER_CSA_GAIN8) {
23  lsb = 13.44;
24  }
25  return lsb;
26 }
27 static const char *const TAG = "max9611";
28 static const uint8_t SETUP_DELAY = 4; // Wait 2 integration periods.
29 static const float VOUT_LSB = 14.0 / 1000.0; // 14mV/LSB
30 static const float TEMP_LSB = 0.48; // 0.48C/LSB
31 static const float MICRO_VOLTS_PER_VOLT = 1000000.0;
33  ESP_LOGCONFIG(TAG, "Setting up max9611...");
34  // Perform dummy-read
35  uint8_t value;
36  this->read(&value, 1);
37  // Configuration Stage.
38  // First send an integration request with the specified gain
39  const uint8_t setup_dat[] = {CONTROL_REGISTER_1_ADRR, static_cast<uint8_t>(gain_)};
40  // Then send a request that samples all channels as fast as possible, using the last provided gain
42 
43  if (this->write(reinterpret_cast<const uint8_t *>(&setup_dat), sizeof(setup_dat)) != ErrorCode::ERROR_OK) {
44  ESP_LOGE(TAG, "Failed to setup Max9611 during GAIN SET");
45  return;
46  }
47  delay(SETUP_DELAY);
48  if (this->write(reinterpret_cast<const uint8_t *>(&fast_mode_dat), sizeof(fast_mode_dat)) != ErrorCode::ERROR_OK) {
49  ESP_LOGE(TAG, "Failed to setup Max9611 during FAST MODE SET");
50  return;
51  }
52 }
54  ESP_LOGCONFIG(TAG, "Dump Config max9611...");
55  ESP_LOGCONFIG(TAG, " CSA Gain Register: %x", gain_);
56  LOG_I2C_DEVICE(this);
57 }
59  // Setup read from 0x0 register base
60  const uint8_t reg_base = 0x0;
61  const ErrorCode write_result = this->write(&reg_base, 1);
62  // Just read the entire register map in a bulk read, faster than individually querying register.
63  const ErrorCode read_result = this->read(register_map_, sizeof(register_map_));
64  if (write_result != ErrorCode::ERROR_OK || read_result != ErrorCode::ERROR_OK) {
65  ESP_LOGW(TAG, "MAX9611 Update FAILED!");
66  return;
67  }
68  uint16_t csa_register = ((register_map_[CSA_DATA_BYTE_MSB_ADRR] << 8) | (register_map_[CSA_DATA_BYTE_LSB_ADRR])) >> 4;
69  uint16_t rs_register = ((register_map_[RS_DATA_BYTE_MSB_ADRR] << 8) | (register_map_[RS_DATA_BYTE_LSB_ADRR])) >> 4;
70  uint16_t t_register = ((register_map_[TEMP_DATA_BYTE_MSB_ADRR] << 8) | (register_map_[TEMP_DATA_BYTE_LSB_ADRR])) >> 7;
71  float voltage = rs_register * VOUT_LSB;
72  float shunt_voltage = (csa_register * gain_to_lsb(gain_)) / MICRO_VOLTS_PER_VOLT;
73  float temp = signextend<signed int, 9>(t_register) * TEMP_LSB;
74  float amps = shunt_voltage / current_resistor_;
75  float watts = amps * voltage;
76 
77  if (voltage_sensor_ != nullptr) {
78  voltage_sensor_->publish_state(voltage);
79  }
80  if (current_sensor_ != nullptr) {
81  current_sensor_->publish_state(amps);
82  }
83  if (watt_sensor_ != nullptr) {
84  watt_sensor_->publish_state(watts);
85  }
86  if (temperature_sensor_ != nullptr) {
87  temperature_sensor_->publish_state(temp);
88  }
89 
90  ESP_LOGD(TAG, "V: %f, A: %f, W: %f, Deg C: %f", voltage, amps, watts, temp);
91 }
92 } // namespace max9611
93 } // namespace esphome
float gain_to_lsb(MAX9611Multiplexer gain)
Definition: max9611.cpp:16
T signextend(const T x)
Definition: max9611.cpp:9
Definition: a4988.cpp:4
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:27