ESPHome 2026.5.0b1
Loading...
Searching...
No Matches
es8311.cpp
Go to the documentation of this file.
1#include "es8311.h"
2#include "es8311_const.h"
3#include "esphome/core/hal.h"
4#include "esphome/core/log.h"
5#include <cinttypes>
6
7namespace esphome::es8311 {
8
9static const char *const TAG = "es8311";
10
11// Mark the component as failed; use only in setup
12#define ES8311_ERROR_FAILED(func) \
13 if (!(func)) { \
14 this->mark_failed(); \
15 return; \
16 }
17// Return false; use outside of setup
18#define ES8311_ERROR_CHECK(func) \
19 if (!(func)) { \
20 return false; \
21 }
22
24 // Reset
25 ES8311_ERROR_FAILED(this->write_byte(ES8311_REG00_RESET, 0x1F));
26 ES8311_ERROR_FAILED(this->write_byte(ES8311_REG00_RESET, 0x00));
27
28 ES8311_ERROR_FAILED(this->configure_clock_());
29 ES8311_ERROR_FAILED(this->configure_format_());
30 ES8311_ERROR_FAILED(this->configure_mic_());
31
32 // Set initial volume
33 this->set_volume(0.75); // 0.75 = 0xBF = 0dB
34
35 // Power up analog circuitry
36 ES8311_ERROR_FAILED(this->write_byte(ES8311_REG0D_SYSTEM, 0x01));
37 // Enable analog PGA, enable ADC modulator
38 ES8311_ERROR_FAILED(this->write_byte(ES8311_REG0E_SYSTEM, 0x02));
39 // Power up DAC
40 ES8311_ERROR_FAILED(this->write_byte(ES8311_REG12_SYSTEM, 0x00));
41 // Enable output to HP drive
42 ES8311_ERROR_FAILED(this->write_byte(ES8311_REG13_SYSTEM, 0x10));
43 // ADC Equalizer bypass, cancel DC offset in digital domain
44 ES8311_ERROR_FAILED(this->write_byte(ES8311_REG1C_ADC, 0x6A));
45 // Bypass DAC equalizer
46 ES8311_ERROR_FAILED(this->write_byte(ES8311_REG37_DAC, 0x08));
47 // Power On
48 ES8311_ERROR_FAILED(this->write_byte(ES8311_REG00_RESET, 0x80));
49}
50
52 ESP_LOGCONFIG(TAG,
53 "ES8311 Audio Codec:\n"
54 " Use MCLK: %s\n"
55 " Use Microphone: %s\n"
56 " DAC Bits per Sample: %" PRIu8 "\n"
57 " Sample Rate: %" PRIu32,
58 YESNO(this->use_mclk_), YESNO(this->use_mic_), this->resolution_out_, this->sample_frequency_);
59
60 if (this->is_failed()) {
61 ESP_LOGCONFIG(TAG, " Failed to initialize!");
62 return;
63 }
64}
65
66bool ES8311::set_volume(float volume) {
67 volume = clamp(volume, 0.0f, 1.0f);
68 uint8_t reg32 = remap<uint8_t, float>(volume, 0.0f, 1.0f, 0, 255);
69 return this->write_byte(ES8311_REG32_DAC, reg32);
70}
71
73 uint8_t reg32;
74 this->read_byte(ES8311_REG32_DAC, &reg32);
75 return remap<float, uint8_t>(reg32, 0, 255, 0.0f, 1.0f);
76}
77
79 switch (resolution) {
81 return (3 << 2);
83 return (2 << 2);
85 return (1 << 2);
87 return (0 << 2);
89 return (4 << 2);
90 default:
91 return 0;
92 }
93}
94
96 for (const auto &coefficient : ES8311_COEFFICIENTS) {
97 if (coefficient.mclk == mclk && coefficient.rate == rate)
98 return &coefficient;
99 }
100 return nullptr;
101}
102
104 // Register 0x01: select clock source for internal MCLK and determine its frequency
105 uint8_t reg01 = 0x3F; // Enable all clocks
106
107 uint32_t mclk_frequency = this->sample_frequency_ * this->mclk_multiple_;
108 if (!this->use_mclk_) {
109 reg01 |= BIT(7); // Use SCLK
110 mclk_frequency = this->sample_frequency_ * (int) this->resolution_out_ * 2;
111 }
112 if (this->mclk_inverted_) {
113 reg01 |= BIT(6); // Invert MCLK pin
114 }
115 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG01_CLK_MANAGER, reg01));
116
117 // Get clock coefficients from coefficient table
118 auto *coefficient = get_coefficient(mclk_frequency, this->sample_frequency_);
119 if (coefficient == nullptr) {
120 ESP_LOGE(TAG, "Unable to configure sample rate %" PRIu32 "Hz with %" PRIu32 "Hz MCLK", this->sample_frequency_,
121 mclk_frequency);
122 return false;
123 }
124
125 // Register 0x02
126 uint8_t reg02;
127 ES8311_ERROR_CHECK(this->read_byte(ES8311_REG02_CLK_MANAGER, &reg02));
128 reg02 &= 0x07;
129 reg02 |= (coefficient->pre_div - 1) << 5;
130 reg02 |= coefficient->pre_mult << 3;
131 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG02_CLK_MANAGER, reg02));
132
133 // Register 0x03
134 const uint8_t reg03 = (coefficient->fs_mode << 6) | coefficient->adc_osr;
135 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG03_CLK_MANAGER, reg03));
136
137 // Register 0x04
138 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG04_CLK_MANAGER, coefficient->dac_osr));
139
140 // Register 0x05
141 const uint8_t reg05 = ((coefficient->adc_div - 1) << 4) | (coefficient->dac_div - 1);
142 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG05_CLK_MANAGER, reg05));
143
144 // Register 0x06
145 uint8_t reg06;
146 ES8311_ERROR_CHECK(this->read_byte(ES8311_REG06_CLK_MANAGER, &reg06));
147 if (this->sclk_inverted_) {
148 reg06 |= BIT(5);
149 } else {
150 reg06 &= ~BIT(5);
151 }
152 reg06 &= 0xE0;
153 if (coefficient->bclk_div < 19) {
154 reg06 |= (coefficient->bclk_div - 1) << 0;
155 } else {
156 reg06 |= (coefficient->bclk_div) << 0;
157 }
158 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG06_CLK_MANAGER, reg06));
159
160 // Register 0x07
161 uint8_t reg07;
162 ES8311_ERROR_CHECK(this->read_byte(ES8311_REG07_CLK_MANAGER, &reg07));
163 reg07 &= 0xC0;
164 reg07 |= coefficient->lrck_h << 0;
165 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG07_CLK_MANAGER, reg07));
166
167 // Register 0x08
168 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG08_CLK_MANAGER, coefficient->lrck_l));
169
170 // Successfully configured the clock
171 return true;
172}
173
175 // Configure I2S mode and format
176 uint8_t reg00;
177 ES8311_ERROR_CHECK(this->read_byte(ES8311_REG00_RESET, &reg00));
178 reg00 &= 0xBF;
179 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG00_RESET, reg00));
180
181 // Configure SDP in resolution
182 uint8_t reg09 = calculate_resolution_value(this->resolution_in_);
183 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG09_SDPIN, reg09));
184
185 // Configure SDP out resolution
186 uint8_t reg0a = calculate_resolution_value(this->resolution_out_);
187 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG0A_SDPOUT, reg0a));
188
189 // Successfully configured the format
190 return true;
191}
192
194 uint8_t reg14 = 0x1A; // Enable analog MIC and max PGA gain
195 if (this->use_mic_) {
196 reg14 |= BIT(6); // Enable PDM digital microphone
197 }
198 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG14_SYSTEM, reg14));
199
200 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG16_ADC, this->mic_gain_)); // ADC gain scale up
201 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG17_ADC, 0xC8)); // Set ADC gain
202
203 // Successfully configured the microphones
204 return true;
205}
206
207bool ES8311::set_mute_state_(bool mute_state) {
208 uint8_t reg31;
209
210 this->is_muted_ = mute_state;
211
212 if (!this->read_byte(ES8311_REG31_DAC, &reg31)) {
213 return false;
214 }
215
216 if (mute_state) {
217 reg31 |= BIT(6) | BIT(5);
218 } else {
219 reg31 &= ~(BIT(6) | BIT(5));
220 }
221
222 return this->write_byte(ES8311_REG31_DAC, reg31);
223}
224
225} // namespace esphome::es8311
bool is_failed() const
Definition component.h:284
float volume() override
Gets the current volume out from the DAC.
Definition es8311.cpp:72
ES8311Resolution resolution_out_
Definition es8311.h:129
static const ES8311Coefficient * get_coefficient(uint32_t mclk, uint32_t rate)
Retrieves the appropriate registers values for the configured mclk and rate.
Definition es8311.cpp:95
ES8311Resolution resolution_in_
Definition es8311.h:128
uint32_t sample_frequency_
Definition es8311.h:127
uint32_t mclk_multiple_
Definition es8311.h:125
static uint8_t calculate_resolution_value(ES8311Resolution resolution)
Computes the register value for the configured resolution (bits per sample)
Definition es8311.cpp:78
void dump_config() override
Definition es8311.cpp:51
bool configure_format_()
Configures the ES8311 registers for the chosen bits per sample.
Definition es8311.cpp:174
bool configure_clock_()
Configures the ES8311 registers for the chosen sample rate.
Definition es8311.cpp:103
void setup() override
Definition es8311.cpp:23
bool configure_mic_()
Configures the ES8311 microphone registers.
Definition es8311.cpp:193
bool set_mute_state_(bool mute_state)
Mutes or unmute the DAC audio out.
Definition es8311.cpp:207
bool set_volume(float volume) override
Writes the volume out to the DAC.
Definition es8311.cpp:66
ES8311MicGain mic_gain_
Definition es8311.h:120
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
Resolution resolution
Definition msa3xx.h:1
@ ES8311_RESOLUTION_32
Definition es8311.h:27
@ ES8311_RESOLUTION_16
Definition es8311.h:23
@ ES8311_RESOLUTION_20
Definition es8311.h:25
@ ES8311_RESOLUTION_24
Definition es8311.h:26
@ ES8311_RESOLUTION_18
Definition es8311.h:24
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
static void uint32_t