summaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-07-28 13:01:18 +1000
committerjacqueline <me@jacqueline.id.au>2023-07-28 13:01:18 +1000
commit3670859d1620ca0fe3492cffb591bf29e5af849c (patch)
tree51efdf3f8c5fa9ff86dabbdddb8c64416b8703bb /src/drivers
parent72fe82ebc43b1e7bf10ebe72efec1723b3792afd (diff)
downloadtangara-fw-3670859d1620ca0fe3492cffb591bf29e5af849c.tar.gz
Volume control! Reasonable default volume! Hooray!
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/CMakeLists.txt2
-rw-r--r--src/drivers/i2s_dac.cpp64
-rw-r--r--src/drivers/include/wm8523.hpp31
-rw-r--r--src/drivers/wm8523.cpp51
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;
+}
+
+}
+}