diff options
Diffstat (limited to 'src/drivers/dac.cpp')
| -rw-r--r-- | src/drivers/dac.cpp | 41 |
1 files changed, 25 insertions, 16 deletions
diff --git a/src/drivers/dac.cpp b/src/drivers/dac.cpp index 96a204a7..214feb28 100644 --- a/src/drivers/dac.cpp +++ b/src/drivers/dac.cpp @@ -1,6 +1,7 @@ #include "dac.hpp" #include <cstdint> +#include <cstring> #include "assert.h" #include "driver/i2c.h" @@ -31,8 +32,10 @@ auto AudioDac::create(GpioExpander* expander) // TODO: tune. i2s_chan_handle_t i2s_handle; i2s_chan_config_t channel_config = - I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER); - i2s_new_channel(&channel_config, &i2s_handle, NULL); + I2S_CHANNEL_DEFAULT_CONFIG(kI2SPort, I2S_ROLE_MASTER); + // Auto clear to trigger soft-mute when we run out of data. + channel_config.auto_clear = true; + ESP_ERROR_CHECK(i2s_new_channel(&channel_config, &i2s_handle, NULL)); // // First, instantiate the instance so it can do all of its power on // configuration. @@ -44,7 +47,7 @@ auto AudioDac::create(GpioExpander* expander) i2s_std_config_t i2s_config = { .clk_cfg = dac->clock_config_, .slot_cfg = dac->slot_config_, - .gpio_cfg = {.mclk = GPIO_NUM_0, + .gpio_cfg = {.mclk = I2S_GPIO_UNUSED, // PCM5122 is self-clocking .bclk = GPIO_NUM_26, .ws = GPIO_NUM_27, .dout = GPIO_NUM_5, @@ -63,9 +66,7 @@ auto AudioDac::create(GpioExpander* expander) return cpp::fail(Error::FAILED_TO_INSTALL_I2S); } - // TODO: does starting the channel mean the dac will boot into a more - // meaningful state? - i2s_channel_enable(dac->i2s_handle_); + ESP_ERROR_CHECK(i2s_channel_enable(dac->i2s_handle_)); // Now let's double check that the DAC itself came up whilst we we working. bool is_booted = dac->WaitForPowerState( @@ -79,10 +80,12 @@ auto AudioDac::create(GpioExpander* expander) dac->WriteRegister(Register::DE_EMPHASIS, 1 << 4); dac->WriteVolume(255); + // We already started the I2S channel with a default clock rate, but sending + // only zeros. The DAC should see this and automatically enter standby (if + // it's still waiting for the charge pump then that's also okay.) bool is_configured = dac->WaitForPowerState([](bool booted, PowerState state) { - return state == WAIT_FOR_CP || state == RAMP_UP || state == RUN || - state == STANDBY; + return state == STANDBY || state == WAIT_FOR_CP; }); if (!is_configured) { return cpp::fail(Error::FAILED_TO_CONFIGURE); @@ -94,8 +97,8 @@ auto AudioDac::create(GpioExpander* expander) AudioDac::AudioDac(GpioExpander* gpio, i2s_chan_handle_t i2s_handle) : gpio_(gpio), i2s_handle_(i2s_handle), - clock_config_(I2S_STD_CLK_DEFAULT_CONFIG(48000)), - slot_config_(I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, + clock_config_(I2S_STD_CLK_DEFAULT_CONFIG(44100)), + slot_config_(I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO)) { gpio_->set_pin(GpioExpander::AUDIO_POWER_ENABLE, true); gpio_->Write(); @@ -158,23 +161,29 @@ auto AudioDac::Reconfigure(BitsPerSample bps, SampleRate rate) -> bool { // TODO(jacqueline): investigate how reliable the auto-clocking of the dac // is. We might need to explicit reconfigure the dac here as well if it's not // good enough. - i2s_channel_disable(i2s_handle_); + ESP_ERROR_CHECK(i2s_channel_disable(i2s_handle_)); slot_config_.slot_bit_width = (i2s_slot_bit_width_t)bps; - i2s_channel_reconfig_std_slot(i2s_handle_, &slot_config_); + ESP_ERROR_CHECK(i2s_channel_reconfig_std_slot(i2s_handle_, &slot_config_)); - // TODO: update mclk multiple as well if needed? clock_config_.sample_rate_hz = rate; - i2s_channel_reconfig_std_clock(i2s_handle_, &clock_config_); + clock_config_.mclk_multiple = + bps == BPS_24 ? I2S_MCLK_MULTIPLE_384 : I2S_MCLK_MULTIPLE_256; + ESP_ERROR_CHECK(i2s_channel_reconfig_std_clock(i2s_handle_, &clock_config_)); - i2s_channel_enable(i2s_handle_); + ESP_ERROR_CHECK(i2s_channel_enable(i2s_handle_)); return true; } auto AudioDac::WriteData(const cpp::span<std::byte>& data, TickType_t max_wait) -> std::size_t { std::size_t res = 0; - i2s_channel_write(i2s_handle_, data.data(), data.size(), &res, max_wait); + esp_err_t err = + i2s_channel_write(i2s_handle_, data.data(), data.size(), &res, max_wait); + if (err == ESP_ERR_TIMEOUT) { + return res; + } + ESP_ERROR_CHECK(err); return res; } |
