mirror of
https://github.com/esphome/esphome.git
synced 2024-12-02 11:44:13 +01:00
d1feaa935d
* Added MCP4728 output component. * Added tests to test1.yaml * Added codeowners * Lint fixes * Implemented code review changes * Lint fixes * Added i2c communication check on setup() * Fixed tests * Lint fix * Update esphome/components/mcp4728/mcp4728_output.cpp Changed log function Co-authored-by: Otto Winter <otto@otto-winter.com> Co-authored-by: Otto Winter <otto@otto-winter.com>
121 lines
3 KiB
C++
121 lines
3 KiB
C++
#include "mcp4728_output.h"
|
|
|
|
#include "esphome/core/helpers.h"
|
|
#include "esphome/core/log.h"
|
|
|
|
namespace esphome {
|
|
namespace mcp4728 {
|
|
|
|
static const char *const TAG = "mcp4728";
|
|
|
|
void MCP4728Component::setup() {
|
|
ESP_LOGCONFIG(TAG, "Setting up MCP4728 (0x%02X)...", this->address_);
|
|
auto err = this->write(nullptr, 0);
|
|
if (err != i2c::ERROR_OK) {
|
|
this->mark_failed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
void MCP4728Component::dump_config() {
|
|
ESP_LOGCONFIG(TAG, "MCP4728:");
|
|
LOG_I2C_DEVICE(this);
|
|
if (this->is_failed()) {
|
|
ESP_LOGE(TAG, "Communication with MCP4728 failed!");
|
|
}
|
|
}
|
|
|
|
void MCP4728Component::loop() {
|
|
if (this->update_) {
|
|
this->update_ = false;
|
|
if (this->store_in_eeprom_) {
|
|
if (!this->seq_write_()) {
|
|
this->status_set_error();
|
|
} else {
|
|
this->status_clear_error();
|
|
}
|
|
} else {
|
|
if (!this->multi_write_()) {
|
|
this->status_set_error();
|
|
} else {
|
|
this->status_clear_error();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MCP4728Component::set_channel_value_(MCP4728ChannelIdx channel, uint16_t value) {
|
|
uint8_t cn = 0;
|
|
if (channel == MCP4728_CHANNEL_A) {
|
|
cn = 'A';
|
|
} else if (channel == MCP4728_CHANNEL_B) {
|
|
cn = 'B';
|
|
} else if (channel == MCP4728_CHANNEL_C) {
|
|
cn = 'C';
|
|
} else {
|
|
cn = 'D';
|
|
}
|
|
ESP_LOGV(TAG, "Setting MCP4728 channel %c to %d!", cn, value);
|
|
reg_[channel].data = value;
|
|
this->update_ = true;
|
|
}
|
|
|
|
bool MCP4728Component::multi_write_() {
|
|
i2c::ErrorCode err[4];
|
|
for (uint8_t i = 0; i < 4; ++i) {
|
|
uint8_t wd[3];
|
|
wd[0] = ((uint8_t) CMD::MULTI_WRITE | (i << 1)) & 0xFE;
|
|
wd[1] = ((uint8_t) reg_[i].vref << 7) | ((uint8_t) reg_[i].pd << 5) | ((uint8_t) reg_[i].gain << 4) |
|
|
(reg_[i].data >> 8);
|
|
wd[2] = reg_[i].data & 0xFF;
|
|
err[i] = this->write(wd, sizeof(wd));
|
|
}
|
|
bool ok = true;
|
|
for (auto &e : err) {
|
|
if (e != i2c::ERROR_OK) {
|
|
ok = false;
|
|
break;
|
|
}
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
bool MCP4728Component::seq_write_() {
|
|
uint8_t wd[9];
|
|
wd[0] = (uint8_t) CMD::SEQ_WRITE;
|
|
for (uint8_t i = 0; i < 4; i++) {
|
|
wd[i * 2 + 1] = ((uint8_t) reg_[i].vref << 7) | ((uint8_t) reg_[i].pd << 5) | ((uint8_t) reg_[i].gain << 4) |
|
|
(reg_[i].data >> 8);
|
|
wd[i * 2 + 2] = reg_[i].data & 0xFF;
|
|
}
|
|
auto err = this->write(wd, sizeof(wd));
|
|
return err == i2c::ERROR_OK;
|
|
}
|
|
|
|
void MCP4728Component::select_vref_(MCP4728ChannelIdx channel, MCP4728Vref vref) {
|
|
reg_[channel].vref = vref;
|
|
|
|
this->update_ = true;
|
|
}
|
|
|
|
void MCP4728Component::select_power_down_(MCP4728ChannelIdx channel, MCP4728PwrDown pd) {
|
|
reg_[channel].pd = pd;
|
|
|
|
this->update_ = true;
|
|
}
|
|
|
|
void MCP4728Component::select_gain_(MCP4728ChannelIdx channel, MCP4728Gain gain) {
|
|
reg_[channel].gain = gain;
|
|
|
|
this->update_ = true;
|
|
}
|
|
|
|
void MCP4728Channel::write_state(float state) {
|
|
const uint16_t max_duty = 4095;
|
|
const float duty_rounded = roundf(state * max_duty);
|
|
auto duty = static_cast<uint16_t>(duty_rounded);
|
|
this->parent_->set_channel_value_(this->channel_, duty);
|
|
}
|
|
|
|
} // namespace mcp4728
|
|
} // namespace esphome
|