diff options
| author | jacqueline <me@jacqueline.id.au> | 2023-07-28 13:01:18 +1000 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2023-07-28 13:01:18 +1000 |
| commit | 3670859d1620ca0fe3492cffb591bf29e5af849c (patch) | |
| tree | 51efdf3f8c5fa9ff86dabbdddb8c64416b8703bb /src/drivers | |
| parent | 72fe82ebc43b1e7bf10ebe72efec1723b3792afd (diff) | |
| download | tangara-fw-3670859d1620ca0fe3492cffb591bf29e5af849c.tar.gz | |
Volume control! Reasonable default volume! Hooray!
Diffstat (limited to 'src/drivers')
| -rw-r--r-- | src/drivers/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/drivers/i2s_dac.cpp | 64 | ||||
| -rw-r--r-- | src/drivers/include/wm8523.hpp | 31 | ||||
| -rw-r--r-- | src/drivers/wm8523.cpp | 51 |
4 files changed, 109 insertions, 39 deletions
diff --git a/src/drivers/CMakeLists.txt b/src/drivers/CMakeLists.txt index 151a3afc..40cd0c4f 100644 --- a/src/drivers/CMakeLists.txt +++ b/src/drivers/CMakeLists.txt @@ -4,7 +4,7 @@ idf_component_register( SRCS "touchwheel.cpp" "i2s_dac.cpp" "gpios.cpp" "battery.cpp" "storage.cpp" "i2c.cpp" - "spi.cpp" "display.cpp" "display_init.cpp" "samd.cpp" "relative_wheel.cpp" + "spi.cpp" "display.cpp" "display_init.cpp" "samd.cpp" "relative_wheel.cpp" "wm8523.cpp" INCLUDE_DIRS "include" REQUIRES "esp_adc" "fatfs" "result" "lvgl" "span" "tasks") target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/drivers/i2s_dac.cpp b/src/drivers/i2s_dac.cpp index dd454db3..e4e782c2 100644 --- a/src/drivers/i2s_dac.cpp +++ b/src/drivers/i2s_dac.cpp @@ -28,6 +28,7 @@ #include "hal/i2c_types.h" #include "gpios.hpp" +#include "wm8523.hpp" #include "hal/i2s_types.h" #include "i2c.hpp" #include "soc/clk_tree_defs.h" @@ -36,28 +37,6 @@ namespace drivers { static const char* kTag = "i2s_dac"; static const i2s_port_t kI2SPort = I2S_NUM_0; -static const uint8_t kWm8523Address = 0b0011010; - -enum Register { - kReset = 0, - kRevision = 1, - kPsCtrl = 2, - kAifCtrl1 = 3, - kAifCtrl2 = 4, - kDacCtrl = 5, - kDacGainLeft = 6, - kDacGainRight = 7, - kZeroDetect = 8, -}; - -auto write_register(Register reg, uint8_t msb, uint8_t lsb) -> esp_err_t { - I2CTransaction transaction; - transaction.start() - .write_addr(kWm8523Address, I2C_MASTER_WRITE) - .write_ack(reg, msb, lsb) - .stop(); - return transaction.Execute(); -} auto I2SDac::create(IGpios* expander) -> std::optional<I2SDac*> { i2s_chan_handle_t i2s_handle; @@ -110,17 +89,11 @@ I2SDac::I2SDac(IGpios* gpio, i2s_chan_handle_t i2s_handle) gpio_->WriteSync(IGpios::Pin::kAmplifierEnable, false); // Reset all registers back to their default values. - write_register(kReset, 0, 1); + wm8523::WriteRegister(wm8523::Register::kReset, 1); vTaskDelay(pdMS_TO_TICKS(10)); // Power up the charge pump. - write_register(kPsCtrl, 0, 0b01); - - // TODO: testing - // write_register(kDacGainLeft, 0b01, 0x50); - // write_register(kDacGainRight, 0b11, 0x50); - write_register(kDacGainLeft, 0b01, 0x0); - write_register(kDacGainRight, 0b11, 0x0); + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b01); } I2SDac::~I2SDac() { @@ -130,15 +103,23 @@ I2SDac::~I2SDac() { auto I2SDac::Start() -> void { gpio_->WriteSync(IGpios::Pin::kAmplifierEnable, true); + vTaskDelay(pdMS_TO_TICKS(1)); + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b10); - i2s_channel_enable(i2s_handle_); - write_register(kPsCtrl, 0, 0b11); + uint8_t zeroes[256] {0}; + size_t bytes_loaded = 0; + esp_err_t res = ESP_OK; + do { + res = i2s_channel_preload_data(i2s_handle_, zeroes, 256, &bytes_loaded); + } while (bytes_loaded > 0 && res == ESP_OK); + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b11); + i2s_channel_enable(i2s_handle_); i2s_active_ = true; } auto I2SDac::Stop() -> void { - write_register(kPsCtrl, 0, 0b01); + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b01); i2s_channel_disable(i2s_handle_); gpio_->WriteSync(IGpios::Pin::kAmplifierEnable, false); @@ -148,8 +129,15 @@ auto I2SDac::Stop() -> void { auto I2SDac::Reconfigure(Channels ch, BitsPerSample bps, SampleRate rate) -> void { - write_register(kPsCtrl, 0, 0b01); - i2s_channel_disable(i2s_handle_); + if (i2s_active_) { + // Ramp down into mute instead of just outright stopping to minimise any + // clicks and pops. + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b10); + vTaskDelay(pdMS_TO_TICKS(1)); + + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b01); + i2s_channel_disable(i2s_handle_); + } switch (ch) { case CHANNELS_MONO: @@ -190,13 +178,13 @@ auto I2SDac::Reconfigure(Channels ch, BitsPerSample bps, SampleRate rate) ESP_ERROR_CHECK(i2s_channel_reconfig_std_clock(i2s_handle_, &clock_config_)); // Set the correct word size, and set the input format to I2S-justified. - write_register(kAifCtrl1, 0, (word_length << 3) | 0b10); + wm8523::WriteRegister(wm8523::Register::kAifCtrl1, (word_length << 3) | 0b10); // Tell the DAC the clock ratio instead of waiting for it to auto detect. - // write_register(kAifCtrl2, 0, bps == BPS_24 ? 0b100 : 0b011); + wm8523::WriteRegister(wm8523::Register::kAifCtrl2, bps == BPS_24 ? 0b100 : 0b011); if (i2s_active_) { i2s_channel_enable(i2s_handle_); - write_register(kPsCtrl, 0, 0b11); + wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b11); } } diff --git a/src/drivers/include/wm8523.hpp b/src/drivers/include/wm8523.hpp new file mode 100644 index 00000000..8b20eda0 --- /dev/null +++ b/src/drivers/include/wm8523.hpp @@ -0,0 +1,31 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ +#pragma once + +#include <cstdint> +#include <optional> + +namespace drivers { +namespace wm8523 { + +enum class Register : uint8_t { + kReset = 0, + kRevision = 1, + kPsCtrl = 2, + kAifCtrl1 = 3, + kAifCtrl2 = 4, + kDacCtrl = 5, + kDacGainLeft = 6, + kDacGainRight = 7, + kZeroDetect = 8, +}; + +auto ReadRegister(Register reg) -> std::optional<uint16_t>; +auto WriteRegister(Register reg, uint16_t data) -> bool; +auto WriteRegister(Register reg, uint8_t msb, uint8_t lsb) -> bool; + +} +} diff --git a/src/drivers/wm8523.cpp b/src/drivers/wm8523.cpp new file mode 100644 index 00000000..dbd4a88e --- /dev/null +++ b/src/drivers/wm8523.cpp @@ -0,0 +1,51 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ +#include "wm8523.hpp" + +#include <cstdint> + +#include "esp_err.h" + +#include "hal/i2c_types.h" +#include "i2c.hpp" + +namespace drivers { +namespace wm8523 { + +static const uint8_t kAddress = 0b0011010; + +auto ReadRegister(Register reg) -> std::optional<uint16_t> { + uint8_t msb, lsb; + I2CTransaction transaction; + transaction.start() + .write_addr(kAddress, I2C_MASTER_WRITE) + .write_ack(static_cast<uint8_t>(reg)) + .start() + .write_addr(kAddress, I2C_MASTER_READ) + .read(&msb, I2C_MASTER_ACK) + .read(&lsb, I2C_MASTER_LAST_NACK) + .stop(); + if (transaction.Execute() != ESP_OK) { + return {}; + } + return (msb << 8) & lsb; +} + +auto WriteRegister(Register reg, uint16_t data) -> bool { + return WriteRegister(reg, (data >> 8) & 0xFF, data & 0xFF); +} + +auto WriteRegister(Register reg, uint8_t msb, uint8_t lsb) -> bool { + I2CTransaction transaction; + transaction.start() + .write_addr(kAddress, I2C_MASTER_WRITE) + .write_ack(static_cast<uint8_t>(reg), msb, lsb) + .stop(); + return transaction.Execute() == ESP_OK; +} + +} +} |
