ESPHome 2026.6.2
Loading...
Searching...
No Matches
pcm5122.cpp
Go to the documentation of this file.
1#include "pcm5122.h"
2
4#include "esphome/core/log.h"
5
6#include <cmath>
7
8namespace esphome::pcm5122 {
9
10static const char *const TAG = "pcm5122";
11
13 // Select page 0 and verify chip presence via I2C ACK
14 if (!this->select_page_(0)) {
15 ESP_LOGE(TAG, "Write failed");
16 this->status_set_error(LOG_STR("Write failed"));
17 this->mark_failed();
18 return;
19 }
20
21 // Reset audio modules
22 this->reg(PCM5122_REG_RESET) = PCM5122_RESET_MODULES;
23 delay(20);
24 this->reg(PCM5122_REG_RESET) = 0x00;
25
26 // Ignore clock halt detection; enable clock divider autoset
27 optional<uint8_t> err_detect = this->read_byte(PCM5122_REG_ERROR_DETECT);
28 if (!err_detect.has_value()) {
29 ESP_LOGE(TAG, "Failed to read ERROR_DETECT");
30 this->mark_failed();
31 return;
32 }
33 uint8_t err_detect_val = err_detect.value();
34 err_detect_val |= PCM5122_ERROR_DETECT_IGNORE_CLKHALT;
35 err_detect_val &= ~PCM5122_ERROR_DETECT_DISABLE_DIV_AUTOSET;
36 this->reg(PCM5122_REG_ERROR_DETECT) = err_detect_val;
37
38 // I2S format with the configured word length
39 uint8_t alen;
40 switch (this->bits_per_sample_) {
42 alen = PCM5122_AUDIO_FORMAT_ALEN_16BIT;
43 break;
45 alen = PCM5122_AUDIO_FORMAT_ALEN_24BIT;
46 break;
48 default:
49 alen = PCM5122_AUDIO_FORMAT_ALEN_32BIT;
50 break;
51 }
52 this->reg(PCM5122_REG_AUDIO_FORMAT) = PCM5122_AUDIO_FORMAT_I2S | alen;
53
54 // PLL reference clock: BCK
55 optional<uint8_t> pll_ref = this->read_byte(PCM5122_REG_PLL_REF);
56 if (!pll_ref.has_value()) {
57 ESP_LOGE(TAG, "Failed to read PLL_REF");
58 this->mark_failed();
59 return;
60 }
61 uint8_t pll_ref_val = pll_ref.value();
62 pll_ref_val &= ~PCM5122_PLL_REF_MASK;
63 pll_ref_val |= PCM5122_PLL_REF_SOURCE_BCK;
64 this->reg(PCM5122_REG_PLL_REF) = pll_ref_val;
65
66 if (!this->set_mute_on() || !this->set_volume(this->volume_)) {
67 this->mark_failed();
68 return;
69 }
70}
71
73 ESP_LOGCONFIG(TAG, "Audio DAC:");
74 LOG_I2C_DEVICE(this);
75 ESP_LOGCONFIG(TAG,
76 " Bits per sample: %u\n"
77 " Muted: %s",
78 this->bits_per_sample_, YESNO(this->is_muted_));
79}
80
82 this->is_muted_ = false;
83 return this->write_mute_();
84}
85
87 this->is_muted_ = true;
88 return this->write_mute_();
89}
90
91bool PCM5122::set_volume(float volume) {
92 this->volume_ = clamp<float>(volume, 0.0f, 1.0f);
93 return this->write_volume_();
94}
95
96bool PCM5122::is_muted() { return this->is_muted_; }
97
98float PCM5122::volume() { return this->volume_; }
99
100bool PCM5122::select_page_(uint8_t page) {
101 if (this->current_page_ == page)
102 return true;
103 if (!this->write_byte(PCM5122_REG_PAGE_SELECT, page)) {
104 this->current_page_ = -1;
105 return false;
106 }
107 this->current_page_ = page;
108 return true;
109}
110
112 uint8_t mute_byte = this->is_muted() ? 0x11 : 0x00;
113 if (!this->select_page_(0) || !this->write_byte(PCM5122_REG_MUTE, mute_byte)) {
114 ESP_LOGE(TAG, "Writing mute failed");
115 return false;
116 }
117 return true;
118}
119
121 // DVOL register: 0x00 = +24 dB, 0x30 = 0 dB, 0xFF = mute (-0.5 dB/step).
122 // Note: volume=0.0 maps to -52.5 dB (still audible), not true silence.
123 // Use set_mute_on() for silence.
124 const uint8_t dvol_max_volume = 0x30; // 0 dB at full scale
125 const uint8_t dvol_min_volume = 0x99; // -52.5 dB at minimum
126
127 const uint8_t volume_byte =
128 dvol_max_volume + static_cast<uint8_t>(lroundf((1.0f - this->volume_) * (dvol_min_volume - dvol_max_volume)));
129
130 ESP_LOGV(TAG, "Setting volume to 0x%.2x", volume_byte);
131
132 if (!this->select_page_(0) || !this->write_byte(PCM5122_REG_DVOL_LEFT, volume_byte) ||
133 !this->write_byte(PCM5122_REG_DVOL_RIGHT, volume_byte)) {
134 ESP_LOGE(TAG, "Writing volume failed");
135 return false;
136 }
137 return true;
138}
139
140} // namespace esphome::pcm5122
void mark_failed()
Mark this component as failed.
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
void setup() override
Definition pcm5122.cpp:12
bool set_volume(float volume) override
Definition pcm5122.cpp:91
bool is_muted() override
Definition pcm5122.cpp:96
bool set_mute_on() override
Definition pcm5122.cpp:86
float volume() override
Definition pcm5122.cpp:98
bool set_mute_off() override
Definition pcm5122.cpp:81
void dump_config() override
Definition pcm5122.cpp:72
bool select_page_(uint8_t page)
Definition pcm5122.cpp:100
PCM5122BitsPerSample bits_per_sample_
Definition pcm5122.h:69
@ PCM5122_BITS_PER_SAMPLE_16
Definition pcm5122.h:39
@ PCM5122_BITS_PER_SAMPLE_32
Definition pcm5122.h:41
@ PCM5122_BITS_PER_SAMPLE_24
Definition pcm5122.h:40
void HOT delay(uint32_t ms)
Definition hal.cpp:85