From 00b1ba58f0efca59e1ef2acbeab21849db4faafe Mon Sep 17 00:00:00 2001 From: jacqueline Date: Fri, 14 Jun 2024 14:27:56 +1000 Subject: Improve DAC power+mute management to reduce clicks and pops --- src/drivers/gpios.cpp | 2 +- src/drivers/i2s_dac.cpp | 47 +++++++++++++-------------------- src/drivers/include/drivers/i2s_dac.hpp | 2 -- 3 files changed, 20 insertions(+), 31 deletions(-) (limited to 'src/drivers') diff --git a/src/drivers/gpios.cpp b/src/drivers/gpios.cpp index 64ba26a7..52b2b874 100644 --- a/src/drivers/gpios.cpp +++ b/src/drivers/gpios.cpp @@ -43,7 +43,7 @@ static const uint8_t kPortADefault = 0b00111110; // 6 - NC // 7 - NC // Default inputs high, amp off. -static const uint8_t kPortBDefault = 0b00001101; +static const uint8_t kPortBDefault = 0b00011111; /* * Convenience mehod for packing the port a and b bytes into a single 16 bit diff --git a/src/drivers/i2s_dac.cpp b/src/drivers/i2s_dac.cpp index b479d572..b1044896 100644 --- a/src/drivers/i2s_dac.cpp +++ b/src/drivers/i2s_dac.cpp @@ -137,54 +137,43 @@ I2SDac::I2SDac(IGpios& gpio, PcmBuffer& buf, i2s_chan_handle_t i2s_handle) I2S_SLOT_MODE_STEREO)) { clock_config_.clk_src = I2S_CLK_SRC_APLL; - // The amplifier's power rails ramp unevenly, with the negative rail coming - // up ~5ms after the positive rail. Ensure that headphone output is muted - // during this to avoid a loud pop during power up. - gpio_.WriteSync(IGpios::Pin::kAmplifierMute, true); - vTaskDelay(pdMS_TO_TICKS(1)); - - gpio_.WriteSync(IGpios::Pin::kAmplifierEnable, true); + // Power up the DAC. + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b01); // Reset all registers back to their default values. wm8523::WriteRegister(wm8523::Register::kReset, 1); - // Wait for DAC reset + analog rails ramp. + // Wait for DAC to reset. vTaskDelay(pdMS_TO_TICKS(10)); - wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b0); - // Use zero-cross detection for volume changes. - wm8523::WriteRegister(wm8523::Register::kDacCtrl, 0b10000); + // Enable zero-cross detection and ramping for volume changes. + wm8523::WriteRegister(wm8523::Register::kDacCtrl, 0b10011); + + // Ready to play! + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b10); } I2SDac::~I2SDac() { - Stop(); - i2s_del_channel(i2s_handle_); + if (i2s_active_) { + SetPaused(true); + } - gpio_.WriteSync(IGpios::Pin::kAmplifierMute, true); - vTaskDelay(pdMS_TO_TICKS(1)); - gpio_.WriteSync(IGpios::Pin::kAmplifierEnable, false); -} + // Power down the DAC. + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b01); + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b00); -auto I2SDac::Start() -> void { - std::lock_guard lock(configure_mutex_); - wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b11); -} - -auto I2SDac::Stop() -> void { - std::lock_guard lock(configure_mutex_); - set_channel(false); - wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b0); + i2s_del_channel(i2s_handle_); } auto I2SDac::SetPaused(bool paused) -> void { if (paused) { - gpio_.WriteSync(IGpios::Pin::kAmplifierUnmuteLegacy, false); + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b10); gpio_.WriteSync(IGpios::Pin::kAmplifierMute, true); set_channel(false); } else { set_channel(true); - gpio_.WriteSync(IGpios::Pin::kAmplifierUnmuteLegacy, true); gpio_.WriteSync(IGpios::Pin::kAmplifierMute, false); + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b11); } } @@ -250,6 +239,8 @@ auto I2SDac::Reconfigure(Channels ch, BitsPerSample bps, SampleRate rate) if (i2s_active_) { i2s_channel_enable(i2s_handle_); wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b11); + } else { + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b10); } } diff --git a/src/drivers/include/drivers/i2s_dac.hpp b/src/drivers/include/drivers/i2s_dac.hpp index 138a0c03..cf9258c0 100644 --- a/src/drivers/include/drivers/i2s_dac.hpp +++ b/src/drivers/include/drivers/i2s_dac.hpp @@ -45,8 +45,6 @@ class I2SDac { I2SDac(IGpios& gpio, PcmBuffer&, i2s_chan_handle_t i2s_handle); ~I2SDac(); - auto Start() -> void; - auto Stop() -> void; auto SetPaused(bool) -> void; enum Channels { -- cgit v1.2.3