summaryrefslogtreecommitdiff
path: root/src/drivers/dac.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/dac.cpp')
-rw-r--r--src/drivers/dac.cpp117
1 files changed, 58 insertions, 59 deletions
diff --git a/src/drivers/dac.cpp b/src/drivers/dac.cpp
index 60679678..40663219 100644
--- a/src/drivers/dac.cpp
+++ b/src/drivers/dac.cpp
@@ -5,9 +5,7 @@
#include "assert.h"
#include "driver/i2c.h"
-#include "driver/i2s_common.h"
-#include "driver/i2s_std.h"
-#include "driver/i2s_types.h"
+#include "driver/i2s_types_legacy.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_log.h"
@@ -19,6 +17,7 @@
#include "gpio_expander.hpp"
#include "hal/i2s_types.h"
#include "i2c.hpp"
+#include "soc/clk_tree_defs.h"
#include "sys/_stdint.h"
namespace drivers {
@@ -38,6 +37,7 @@ auto AudioDac::create(GpioExpander* expander)
i2s_chan_handle_t i2s_handle;
i2s_chan_config_t channel_config =
I2S_CHANNEL_DEFAULT_CONFIG(kI2SPort, I2S_ROLE_MASTER);
+ channel_config.auto_clear = true;
ESP_ERROR_CHECK(i2s_new_channel(&channel_config, &i2s_handle, NULL));
//
@@ -84,20 +84,22 @@ auto AudioDac::create(GpioExpander* expander)
// The DAC should be booted but in power down mode, but it might not be if we
// didn't shut down cleanly. Reset it to ensure it is in a consistent state.
- dac->WriteRegister(Register::POWER_MODE, 1 << 4);
- dac->WriteRegister(Register::RESET, 0b10001);
+ dac->WriteRegister(pcm512x::POWER, 1 << 4);
+ dac->WriteRegister(pcm512x::RESET, 0b10001);
// Use BCK for the internal PLL.
// dac->WriteRegister(Register::PLL_CLOCK_SOURCE, 1 << 4);
+ // dac->WriteRegister(Register::DAC_CLOCK_SOURCE, 0b11 << 5);
- // dac->WriteRegister(Register::PLL_ENABLE, 0);
- dac->WriteRegister(Register::INTERPOLATION, 1 << 4);
+ //dac->WriteRegister(Register::PLL_ENABLE, 0);
+ //dac->WriteRegister(Register::DAC_CLOCK_SOURCE, 0b0110000);
+ //dac->WriteRegister(Register::CLOCK_ERRORS, 0b01000001);
+ //dac->WriteRegister(Register::I2S_FORMAT, 0b110000);
+ // dac->WriteRegister(Register::INTERPOLATION, 1 << 4);
dac->Reconfigure(BPS_16, SAMPLE_RATE_44_1);
- dac->WriteRegister(Register::POWER_MODE, 0);
// Now configure the DAC for standard auto-clock SCK mode.
- // dac->WriteRegister(Register::DAC_CLOCK_SOURCE, 0b11 << 5);
// Enable auto clocking, and do your best to carry on despite errors.
// dac->WriteRegister(Register::CLOCK_ERRORS, 0b1111101);
@@ -115,9 +117,11 @@ AudioDac::AudioDac(GpioExpander* gpio, i2s_chan_handle_t i2s_handle)
: gpio_(gpio),
i2s_handle_(i2s_handle),
i2s_active_(false),
+ active_page_(),
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)) {
+ slot_config_(I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT,
+ I2S_SLOT_MODE_STEREO)) {
+ clock_config_.clk_src = I2S_CLK_SRC_PLL_160M;
gpio_->set_pin(GpioExpander::AMP_EN, true);
gpio_->Write();
}
@@ -130,29 +134,14 @@ AudioDac::~AudioDac() {
}
void AudioDac::WriteVolume(uint8_t volume) {
- WriteRegister(Register::DIGITAL_VOLUME_L, volume);
- WriteRegister(Register::DIGITAL_VOLUME_R, volume);
+ // Left channel.
+ WriteRegister(pcm512x::DIGITAL_VOLUME_2, volume);
+ // Right channel.
+ WriteRegister(pcm512x::DIGITAL_VOLUME_3, volume);
}
std::pair<bool, AudioDac::PowerState> AudioDac::ReadPowerState() {
- uint8_t result = 0;
-
- I2CTransaction transaction;
- transaction.start()
- .write_addr(kPcm5122Address, I2C_MASTER_WRITE)
- .write_ack(DSP_BOOT_POWER_STATE)
- .start()
- .write_addr(kPcm5122Address, I2C_MASTER_READ)
- .read(&result, I2C_MASTER_NACK)
- .stop();
-
- esp_err_t err = transaction.Execute();
- if (err == ESP_ERR_TIMEOUT) {
- return std::pair(false, POWERDOWN);
- } else {
- }
- ESP_ERROR_CHECK(err);
-
+ uint8_t result = ReadRegister(pcm512x::POWER_STATE);
bool is_booted = result >> 7;
PowerState detail = (PowerState)(result & 0b1111);
return std::pair(is_booted, detail);
@@ -176,17 +165,17 @@ bool AudioDac::WaitForPowerState(
}
auto AudioDac::Reconfigure(BitsPerSample bps, SampleRate rate) -> void {
- WriteRegister(Register::RESYNC_REQUEST, 1);
if (i2s_active_) {
+ WriteRegister(pcm512x::POWER, 1 << 4);
i2s_channel_disable(i2s_handle_);
}
// I2S reconfiguration.
- slot_config_.slot_bit_width = (i2s_slot_bit_width_t)bps;
+ slot_config_.slot_bit_width = I2S_SLOT_BIT_WIDTH_16BIT;
ESP_ERROR_CHECK(i2s_channel_reconfig_std_slot(i2s_handle_, &slot_config_));
- clock_config_.sample_rate_hz = rate;
+ clock_config_.sample_rate_hz = 44100;
// If we have an MCLK/SCK, then it must be a multiple of both the sample rate
// and the bit clock. At 24 BPS, we therefore have to change the MCLK multiple
// to avoid issues at some sample rates. (e.g. 48KHz)
@@ -194,21 +183,19 @@ auto AudioDac::Reconfigure(BitsPerSample bps, SampleRate rate) -> void {
bps == BPS_24 ? I2S_MCLK_MULTIPLE_384 : I2S_MCLK_MULTIPLE_256;
ESP_ERROR_CHECK(i2s_channel_reconfig_std_clock(i2s_handle_, &clock_config_));
- // DAC reconfiguration.
- if (rate == SAMPLE_RATE_44_1) {
- WriteRegister(Register::DE_EMPHASIS, 1 << 4);
- } else {
- WriteRegister(Register::DE_EMPHASIS, 0);
- }
-
// TODO: base on BPS
- WriteRegister(Register::I2S_FORMAT, 0b00);
+ // WriteRegister(Register::I2S_FORMAT, 0b110000);
// Configuration is all done, so we can now bring the DAC and I2S stream back
// up. I2S first, since otherwise the DAC will see that there's no clocks and
// shut itself down.
- WriteRegister(Register::RESYNC_REQUEST, 0);
ESP_ERROR_CHECK(i2s_channel_enable(i2s_handle_));
+ WriteRegister(pcm512x::POWER, 0);
+ WriteRegister(pcm512x::SYNCHRONIZE, 1);
+ vTaskDelay(pdMS_TO_TICKS(10));
+ WriteRegister(pcm512x::SYNCHRONIZE, 0);
+ vTaskDelay(pdMS_TO_TICKS(10));
+ LogStatus();
i2s_active_ = true;
}
@@ -223,7 +210,7 @@ auto AudioDac::WriteData(const cpp::span<const std::byte>& data) -> void {
auto AudioDac::Stop() -> void {
LogStatus();
- WriteRegister(Register::POWER_MODE, 1 << 4);
+ WriteRegister(pcm512x::POWER, 1 << 4);
i2s_channel_disable(i2s_handle_);
}
@@ -237,35 +224,47 @@ auto AudioDac::Stop() -> void {
auto AudioDac::LogStatus() -> void {
uint8_t res;
- res = ReadRegister(Register::SAMPLE_RATE_DETECTION);
- ESP_LOGI(kTag, "detected sample rate (want 3): %u", (res >> 4) && 0b111);
+ res = ReadRegister(pcm512x::RATE_DET_1);
+ ESP_LOGI(kTag, "detected sample rate (want 3): %u", (res & 0b01110000) >> 4);
ESP_LOGI(kTag, "detected SCK ratio (want 6): %u", res && 0b1111);
- res = ReadRegister(Register::BCK_DETECTION);
+ res = ReadRegister(pcm512x::RATE_DET_3);
ESP_LOGI(kTag, "detected BCK (want... 16? 32?): %u", res);
- res = ReadRegister(Register::CLOCK_ERROR_STATE);
+ res = ReadRegister(pcm512x::RATE_DET_4);
ESP_LOGI(kTag, "clock errors (want zeroes): ");
ESP_LOGI(kTag, BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(res & 0b1111111));
- res = ReadRegister(Register::CLOCK_STATUS);
+ res = ReadRegister(pcm512x::CLOCK_STATUS);
ESP_LOGI(kTag, "clock status (want zeroes): ");
ESP_LOGI(kTag, BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(res & 0b10111));
- res = ReadRegister(Register::AUTO_MUTE_STATE);
- ESP_LOGI(kTag, "automute status (want 3): %u", res & 0b11);
-
- res = ReadRegister(Register::SOFT_MUTE_STATE);
- ESP_LOGI(kTag, "soft mute pin status (want 3): %u", res & 0b11);
-
- res = ReadRegister(Register::SAMPLE_RATE_STATE);
- ESP_LOGI(kTag, "detected sample speed mode (want 0): %u", res & 0b11);
+ res = ReadRegister(pcm512x::DIGITAL_MUTE_DET);
+ ESP_LOGI(kTag, "automute status (want 0): %u", res & 0b10001);
auto power = ReadPowerState();
ESP_LOGI(kTag, "current power state (want 5): %u", power.second);
}
-void AudioDac::WriteRegister(Register reg, uint8_t val) {
+void AudioDac::WriteRegister(pcm512x::Register r, uint8_t val) {
+ SelectPage(r.page);
+ WriteRegisterRaw(r.reg, val);
+}
+
+uint8_t AudioDac::ReadRegister(pcm512x::Register r) {
+ SelectPage(r.page);
+ return ReadRegisterRaw(r.reg);
+}
+
+void AudioDac::SelectPage(uint8_t page) {
+ if (active_page_ && active_page_ == page) {
+ return;
+ }
+ WriteRegisterRaw(0, page);
+ active_page_ = page;
+}
+
+void AudioDac::WriteRegisterRaw(uint8_t reg, uint8_t val) {
I2CTransaction transaction;
transaction.start()
.write_addr(kPcm5122Address, I2C_MASTER_WRITE)
@@ -275,7 +274,7 @@ void AudioDac::WriteRegister(Register reg, uint8_t val) {
transaction.Execute();
}
-uint8_t AudioDac::ReadRegister(Register reg) {
+uint8_t AudioDac::ReadRegisterRaw(uint8_t reg) {
uint8_t result = 0;
I2CTransaction transaction;
transaction.start()