ESPHome 2025.5.0
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, "Setting up ES8311...");
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, "ES8311 Audio Codec:");
56 ESP_LOGCONFIG(TAG, " Use MCLK: %s", YESNO(this->use_mclk_));
57 ESP_LOGCONFIG(TAG, " Use Microphone: %s", YESNO(this->use_mic_));
58 ESP_LOGCONFIG(TAG, " DAC Bits per Sample: %" PRIu8, this->resolution_out_);
59 ESP_LOGCONFIG(TAG, " Sample Rate: %" PRIu32, this->sample_frequency_);
60
61 if (this->is_failed()) {
62 ESP_LOGCONFIG(TAG, " Failed to initialize!");
63 return;
64 }
65}
66
67bool ES8311::set_volume(float volume) {
68 volume = clamp(volume, 0.0f, 1.0f);
69 uint8_t reg32 = remap<uint8_t, float>(volume, 0.0f, 1.0f, 0, 255);
70 return this->write_byte(ES8311_REG32_DAC, reg32);
71}
72
74 uint8_t reg32;
75 this->read_byte(ES8311_REG32_DAC, &reg32);
76 return remap<float, uint8_t>(reg32, 0, 255, 0.0f, 1.0f);
77}
78
80 switch (resolution) {
82 return (3 << 2);
84 return (2 << 2);
86 return (1 << 2);
88 return (0 << 2);
90 return (4 << 2);
91 default:
92 return 0;
93 }
94}
95
96const ES8311Coefficient *ES8311::get_coefficient(uint32_t mclk, uint32_t rate) {
97 for (const auto &coefficient : ES8311_COEFFICIENTS) {
98 if (coefficient.mclk == mclk && coefficient.rate == rate)
99 return &coefficient;
100 }
101 return nullptr;
102}
103
105 // Register 0x01: select clock source for internal MCLK and determine its frequency
106 uint8_t reg01 = 0x3F; // Enable all clocks
107
108 uint32_t mclk_frequency = this->sample_frequency_ * this->mclk_multiple_;
109 if (!this->use_mclk_) {
110 reg01 |= BIT(7); // Use SCLK
111 mclk_frequency = this->sample_frequency_ * (int) this->resolution_out_ * 2;
112 }
113 if (this->mclk_inverted_) {
114 reg01 |= BIT(6); // Invert MCLK pin
115 }
116 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG01_CLK_MANAGER, reg01));
117
118 // Get clock coefficients from coefficient table
119 auto *coefficient = get_coefficient(mclk_frequency, this->sample_frequency_);
120 if (coefficient == nullptr) {
121 ESP_LOGE(TAG, "Unable to configure sample rate %" PRIu32 "Hz with %" PRIu32 "Hz MCLK", this->sample_frequency_,
122 mclk_frequency);
123 return false;
124 }
125
126 // Register 0x02
127 uint8_t reg02;
128 ES8311_ERROR_CHECK(this->read_byte(ES8311_REG02_CLK_MANAGER, &reg02));
129 reg02 &= 0x07;
130 reg02 |= (coefficient->pre_div - 1) << 5;
131 reg02 |= coefficient->pre_mult << 3;
132 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG02_CLK_MANAGER, reg02));
133
134 // Register 0x03
135 const uint8_t reg03 = (coefficient->fs_mode << 6) | coefficient->adc_osr;
136 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG03_CLK_MANAGER, reg03));
137
138 // Register 0x04
139 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG04_CLK_MANAGER, coefficient->dac_osr));
140
141 // Register 0x05
142 const uint8_t reg05 = ((coefficient->adc_div - 1) << 4) | (coefficient->dac_div - 1);
143 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG05_CLK_MANAGER, reg05));
144
145 // Register 0x06
146 uint8_t reg06;
147 ES8311_ERROR_CHECK(this->read_byte(ES8311_REG06_CLK_MANAGER, &reg06));
148 if (this->sclk_inverted_) {
149 reg06 |= BIT(5);
150 } else {
151 reg06 &= ~BIT(5);
152 }
153 reg06 &= 0xE0;
154 if (coefficient->bclk_div < 19) {
155 reg06 |= (coefficient->bclk_div - 1) << 0;
156 } else {
157 reg06 |= (coefficient->bclk_div) << 0;
158 }
159 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG06_CLK_MANAGER, reg06));
160
161 // Register 0x07
162 uint8_t reg07;
163 ES8311_ERROR_CHECK(this->read_byte(ES8311_REG07_CLK_MANAGER, &reg07));
164 reg07 &= 0xC0;
165 reg07 |= coefficient->lrck_h << 0;
166 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG07_CLK_MANAGER, reg07));
167
168 // Register 0x08
169 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG08_CLK_MANAGER, coefficient->lrck_l));
170
171 // Successfully configured the clock
172 return true;
173}
174
176 // Configure I2S mode and format
177 uint8_t reg00;
178 ES8311_ERROR_CHECK(this->read_byte(ES8311_REG00_RESET, &reg00));
179 reg00 &= 0xBF;
180 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG00_RESET, reg00));
181
182 // Configure SDP in resolution
183 uint8_t reg09 = calculate_resolution_value(this->resolution_in_);
184 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG09_SDPIN, reg09));
185
186 // Configure SDP out resolution
187 uint8_t reg0a = calculate_resolution_value(this->resolution_out_);
188 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG0A_SDPOUT, reg0a));
189
190 // Successfully configured the format
191 return true;
192}
193
195 uint8_t reg14 = 0x1A; // Enable analog MIC and max PGA gain
196 if (this->use_mic_) {
197 reg14 |= BIT(6); // Enable PDM digital microphone
198 }
199 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG14_SYSTEM, reg14));
200
201 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG16_ADC, this->mic_gain_)); // ADC gain scale up
202 ES8311_ERROR_CHECK(this->write_byte(ES8311_REG17_ADC, 0xC8)); // Set ADC gain
203
204 // Successfully configured the microphones
205 return true;
206}
207
208bool ES8311::set_mute_state_(bool mute_state) {
209 uint8_t reg31;
210
211 this->is_muted_ = mute_state;
212
213 if (!this->read_byte(ES8311_REG31_DAC, &reg31)) {
214 return false;
215 }
216
217 if (mute_state) {
218 reg31 |= BIT(6) | BIT(5);
219 } else {
220 reg31 &= ~(BIT(6) | BIT(5));
221 }
222
223 return this->write_byte(ES8311_REG31_DAC, reg31);
224}
225
226} // namespace es8311
227} // namespace esphome
bool is_failed() const
float volume() override
Gets the current volume out from the DAC.
Definition es8311.cpp:73
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:96
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:79
void dump_config() override
Definition es8311.cpp:54
bool configure_format_()
Configures the ES8311 registers for the chosen bits per sample.
Definition es8311.cpp:175
bool configure_clock_()
Configures the ES8311 registers for the chosen sample rate.
Definition es8311.cpp:104
void setup() override
Definition es8311.cpp:24
bool configure_mic_()
Configures the ES8311 microphone registers.
Definition es8311.cpp:194
bool set_mute_state_(bool mute_state)
Mutes or unmute the DAC audio out.
Definition es8311.cpp:208
bool set_volume(float volume) override
Writes the volume out to the DAC.
Definition es8311.cpp:67
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:162
constexpr const T & clamp(const T &v, const T &lo, const T &hi, Compare comp)
Definition helpers.h:101