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