ESPHome 2026.5.0b1
Loading...
Searching...
No Matches
emc2101.cpp
Go to the documentation of this file.
1// Implementation based on:
2// - Adafruit_EMC2101: https://github.com/adafruit/Adafruit_EMC2101
3// - Official Datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/2101.pdf
4
5#include "esphome/core/log.h"
6#include "emc2101.h"
7
8namespace esphome::emc2101 {
9
10static const char *const TAG = "EMC2101";
11
12static const uint8_t EMC2101_CHIP_ID = 0x16; // EMC2101 default device id from part id
13static const uint8_t EMC2101_ALT_CHIP_ID = 0x28; // EMC2101 alternate device id from part id
14
15// EMC2101 registers from the datasheet. We only define what we use.
16static const uint8_t EMC2101_REGISTER_INTERNAL_TEMP = 0x00; // The internal temperature register
17static const uint8_t EMC2101_REGISTER_EXTERNAL_TEMP_MSB = 0x01; // high byte for the external temperature reading
18static const uint8_t EMC2101_REGISTER_DAC_CONV_RATE = 0x04; // DAC convesion rate config
19static const uint8_t EMC2101_REGISTER_EXTERNAL_TEMP_LSB = 0x10; // low byte for the external temperature reading
20static const uint8_t EMC2101_REGISTER_CONFIG = 0x03; // configuration register
21static const uint8_t EMC2101_REGISTER_TACH_LSB = 0x46; // Tach RPM data low byte
22static const uint8_t EMC2101_REGISTER_TACH_MSB = 0x47; // Tach RPM data high byte
23static const uint8_t EMC2101_REGISTER_FAN_CONFIG = 0x4A; // General fan config register
24static const uint8_t EMC2101_REGISTER_FAN_SETTING = 0x4C; // Fan speed for non-LUT settings
25static const uint8_t EMC2101_REGISTER_PWM_FREQ = 0x4D; // PWM frequency setting
26static const uint8_t EMC2101_REGISTER_PWM_DIV = 0x4E; // PWM frequency divisor
27static const uint8_t EMC2101_REGISTER_WHOAMI = 0xFD; // Chip ID register
28
29// EMC2101 configuration bits from the datasheet. We only define what we use.
30
31// Determines the funcionallity of the ALERT/TACH pin.
32// 0 (default): The ALERT/TECH pin will function as an open drain, active low interrupt.
33// 1: The ALERT/TECH pin will function as a high impedance TACH input. This may require an
34// external pull-up resistor to set the proper signaling levels.
35static const uint8_t EMC2101_ALT_TCH_BIT = 1 << 2;
36
37// Determines the FAN output mode.
38// 0 (default): PWM output enabled at FAN pin.
39// 1: DAC output enabled at FAN ping.
40static const uint8_t EMC2101_DAC_BIT = 1 << 4;
41
42// Overrides the CLK_SEL bit and uses the Frequency Divide Register to determine
43// the base PWM frequency. It is recommended that this bit be set for maximum PWM resolution.
44// 0 (default): The base clock frequency for the PWM is determined by the CLK_SEL bit.
45// 1 (recommended): The base clock that is used to determine the PWM frequency is set by the
46// Frequency Divide Register
47static const uint8_t EMC2101_CLK_OVR_BIT = 1 << 2;
48
49// Sets the polarity of the Fan output driver.
50// 0 (default): The polarity of the Fan output driver is non-inverted. A '00h' setting will
51// correspond to a 0% duty cycle or a minimum DAC output voltage.
52// 1: The polarity of the Fan output driver is inverted. A '00h' setting will correspond to a
53// 100% duty cycle or a maximum DAC output voltage.
54static const uint8_t EMC2101_POLARITY_BIT = 1 << 4;
55
57
59 // make sure we're talking to the right chip
60 uint8_t chip_id = reg(EMC2101_REGISTER_WHOAMI).get();
61 if ((chip_id != EMC2101_CHIP_ID) && (chip_id != EMC2101_ALT_CHIP_ID)) {
62 ESP_LOGE(TAG, "Wrong chip ID %02X", chip_id);
63 this->mark_failed();
64 return;
65 }
66
67 // Configure EMC2101
68 i2c::I2CRegister config = reg(EMC2101_REGISTER_CONFIG);
69 config |= EMC2101_ALT_TCH_BIT;
70 if (this->dac_mode_) {
71 config |= EMC2101_DAC_BIT;
72 }
73 if (this->inverted_) {
74 reg(EMC2101_REGISTER_FAN_CONFIG) |= EMC2101_POLARITY_BIT;
75 }
76
77 if (this->dac_mode_) { // DAC mode configurations
78 // set DAC conversion rate
79 reg(EMC2101_REGISTER_DAC_CONV_RATE) = this->dac_conversion_rate_;
80 } else { // PWM mode configurations
81 // set PWM divider
82 reg(EMC2101_REGISTER_FAN_CONFIG) |= EMC2101_CLK_OVR_BIT;
83 reg(EMC2101_REGISTER_PWM_DIV) = this->pwm_divider_;
84
85 // set PWM resolution
86 reg(EMC2101_REGISTER_PWM_FREQ) = this->pwm_resolution_;
87 }
88}
89
91 ESP_LOGCONFIG(TAG, "Emc2101 component:");
92 LOG_I2C_DEVICE(this);
93 if (this->is_failed()) {
94 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
95 }
96 ESP_LOGCONFIG(TAG, " Mode: %s", this->dac_mode_ ? "DAC" : "PWM");
97 if (this->dac_mode_) {
98 ESP_LOGCONFIG(TAG, " DAC Conversion Rate: %X", this->dac_conversion_rate_);
99 } else {
100 ESP_LOGCONFIG(TAG,
101 " PWM Resolution: %02X\n"
102 " PWM Divider: %02X",
103 this->pwm_resolution_, this->pwm_divider_);
104 }
105 ESP_LOGCONFIG(TAG, " Inverted: %s", YESNO(this->inverted_));
106}
107
109 uint8_t duty_cycle = remap(value, 0.0f, 1.0f, (uint8_t) 0, this->max_output_value_);
110 ESP_LOGD(TAG, "Setting duty fan setting to %02X", duty_cycle);
111 if (!this->write_byte(EMC2101_REGISTER_FAN_SETTING, duty_cycle)) {
112 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
113 this->status_set_warning();
114 return;
115 }
116}
117
119 uint8_t duty_cycle;
120 if (!this->read_byte(EMC2101_REGISTER_FAN_SETTING, &duty_cycle)) {
121 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
122 this->status_set_warning();
123 return NAN;
124 }
125 return remap(duty_cycle, (uint8_t) 0, this->max_output_value_, 0.0f, 1.0f);
126}
127
129 uint8_t temperature;
130 if (!this->read_byte(EMC2101_REGISTER_INTERNAL_TEMP, &temperature)) {
131 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
132 this->status_set_warning();
133 return NAN;
134 }
135 return temperature;
136}
137
139 // Read **MSB** first to match 'Data Read Interlock' behavior from 6.1 of datasheet
140 uint8_t lsb, msb;
141 if (!this->read_byte(EMC2101_REGISTER_EXTERNAL_TEMP_MSB, &msb) ||
142 !this->read_byte(EMC2101_REGISTER_EXTERNAL_TEMP_LSB, &lsb)) {
143 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
144 this->status_set_warning();
145 return NAN;
146 }
147
148 // join msb and lsb (5 least significant bits are not used)
149 uint16_t raw = (msb << 8 | lsb) >> 5;
150 return raw * 0.125;
151}
152
154 // Read **LSB** first to match 'Data Read Interlock' behavior from 6.1 of datasheet
155 uint8_t lsb, msb;
156 if (!this->read_byte(EMC2101_REGISTER_TACH_LSB, &lsb) || !this->read_byte(EMC2101_REGISTER_TACH_MSB, &msb)) {
157 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
158 this->status_set_warning();
159 return NAN;
160 }
161
162 // calculate RPMs
163 uint16_t tach = msb << 8 | lsb;
164 return tach == 0xFFFF ? 0.0f : 5400000.0f / tach;
165}
166
167} // namespace esphome::emc2101
uint8_t raw[35]
Definition bl0939.h:0
void mark_failed()
Mark this component as failed.
bool is_failed() const
Definition component.h:284
void setup() override
Used by ESPHome framework.
Definition emc2101.cpp:58
float get_duty_cycle()
Gets the Fan output duty cycle.
Definition emc2101.cpp:118
void dump_config() override
Used by ESPHome framework.
Definition emc2101.cpp:90
float get_setup_priority() const override
Used by ESPHome framework.
Definition emc2101.cpp:56
float get_speed()
Gets the tachometer speed sensor reading.
Definition emc2101.cpp:153
float get_internal_temperature()
Gets the internal temperature sensor reading.
Definition emc2101.cpp:128
float get_external_temperature()
Gets the external temperature sensor reading.
Definition emc2101.cpp:138
Emc2101DACConversionRate dac_conversion_rate_
Definition emc2101.h:110
void set_duty_cycle(float value)
Sets the Fan output duty cycle.
Definition emc2101.cpp:108
bool write_byte(uint8_t a_register, uint8_t data) const
Definition i2c.h:265
bool read_byte(uint8_t a_register, uint8_t *data)
Definition i2c.h:240
I2CRegister reg(uint8_t a_register)
calls the I2CRegister constructor
Definition i2c.h:152
This class is used to create I2CRegister objects that act as proxies to read/write internal registers...
Definition i2c.h:32
uint8_t get() const
returns the register value
Definition i2c.cpp:84
constexpr float HARDWARE
For components that deal with hardware and are very important like GPIO switch.
Definition component.h:41
T remap(U value, U min, U max, T min_out, T max_out)
Remap value from the range (min, max) to (min_out, max_out).
Definition helpers.h:765
uint16_t temperature
Definition sun_gtil2.cpp:12