summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-01-21 19:01:54 +1100
committerjacqueline <me@jacqueline.id.au>2023-01-21 19:01:54 +1100
commit8ed3d7e31f8b16a24593c01a480b19b14a513b48 (patch)
treef055abec7631f9682396ad5c3f125824d76cc95e /src
parentc7901ae4297d42d55bb3a06010198ecf14b3a7ba (diff)
downloadtangara-fw-8ed3d7e31f8b16a24593c01a480b19b14a513b48.tar.gz
Re-enable the parts of the audio pipeline that are working
Diffstat (limited to 'src')
-rw-r--r--src/audio/audio_playback.cpp2
-rw-r--r--src/audio/fatfs_audio_input.cpp9
-rw-r--r--src/drivers/dac.cpp83
-rw-r--r--src/drivers/include/dac.hpp18
-rw-r--r--src/main/main.cpp5
5 files changed, 70 insertions, 47 deletions
diff --git a/src/audio/audio_playback.cpp b/src/audio/audio_playback.cpp
index bcc3ad04..34ede950 100644
--- a/src/audio/audio_playback.cpp
+++ b/src/audio/audio_playback.cpp
@@ -43,9 +43,11 @@ auto AudioPlayback::create(drivers::GpioExpander* expander,
playback->ConnectElements(codec.get(), sink.get());
// Launch!
+ /*
playback->element_handles_.push_back(StartAudioTask("src", source));
playback->element_handles_.push_back(StartAudioTask("dec", codec));
playback->element_handles_.push_back(StartAudioTask("sink", sink));
+ */
return playback;
}
diff --git a/src/audio/fatfs_audio_input.cpp b/src/audio/fatfs_audio_input.cpp
index 3e501154..f0d4d751 100644
--- a/src/audio/fatfs_audio_input.cpp
+++ b/src/audio/fatfs_audio_input.cpp
@@ -106,6 +106,8 @@ auto FatfsAudioInput::ProcessIdle() -> cpp::result<void, AudioProcessingError> {
read_size = file_buffer_.begin() - file_buffer_write_pos_;
}
+ ESP_LOGI(kTag, "reading up to %d bytes", (int) read_size);
+
UINT bytes_read = 0;
FRESULT result =
f_read(&current_file_, std::addressof(file_buffer_write_pos_),
@@ -115,6 +117,8 @@ auto FatfsAudioInput::ProcessIdle() -> cpp::result<void, AudioProcessingError> {
return cpp::fail(IO_ERROR);
}
+ ESP_LOGI(kTag, "actual read size %d bytes", (int) bytes_read);
+
if (f_eof(&current_file_)) {
f_close(&current_file_);
is_file_open_ = false;
@@ -130,7 +134,8 @@ auto FatfsAudioInput::ProcessIdle() -> cpp::result<void, AudioProcessingError> {
}
// Now stream data into the output buffer until it's full.
- while (1) {
+ while (GetRingBufferDistance() > 0) {
+ ESP_LOGI(kTag, "writing up to %d bytes", (int) GetRingBufferDistance());
ChunkWriteResult result = chunk_writer_->WriteChunkToStream(
[&](cpp::span<std::byte> d) { return SendChunk(d); }, kServiceInterval);
@@ -146,6 +151,8 @@ auto FatfsAudioInput::ProcessIdle() -> cpp::result<void, AudioProcessingError> {
return cpp::fail(IO_ERROR);
}
}
+
+ return {};
}
auto FatfsAudioInput::SendChunk(cpp::span<std::byte> dest) -> size_t {
diff --git a/src/drivers/dac.cpp b/src/drivers/dac.cpp
index 78bf94c4..2c7b3e5b 100644
--- a/src/drivers/dac.cpp
+++ b/src/drivers/dac.cpp
@@ -4,9 +4,9 @@
#include "assert.h"
#include "driver/i2c.h"
-#include "driver/i2s.h"
+#include "driver/i2s_common.h"
+#include "driver/i2s_std.h"
#include "driver/i2s_types.h"
-#include "driver/i2s_types_legacy.h"
#include "esp_err.h"
#include "esp_log.h"
#include "hal/i2c_types.h"
@@ -28,45 +28,43 @@ static const AudioDac::BitsPerSample kDefaultBps = AudioDac::BPS_16;
auto AudioDac::create(GpioExpander* expander)
-> cpp::result<std::unique_ptr<AudioDac>, Error> {
+
+ // 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);
+ //
// First, instantiate the instance so it can do all of its power on
// configuration.
- std::unique_ptr<AudioDac> dac = std::make_unique<AudioDac>(expander);
+ std::unique_ptr<AudioDac> dac = std::make_unique<AudioDac>(expander, i2s_handle);
// Whilst we wait for the initial boot, we can work on installing the I2S
// driver.
- i2s_config_t i2s_config = {
- // static_cast bc esp-adf uses enums incorrectly
- .mode = static_cast<i2s_mode_t>(I2S_MODE_MASTER | I2S_MODE_TX),
- .sample_rate = 44100,
- .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
- .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
- .communication_format = I2S_COMM_FORMAT_STAND_I2S,
- .intr_alloc_flags = ESP_INTR_FLAG_LOWMED,
- // TODO(jacqueline): tune dma buffer size. this seems very smol.
- .dma_buf_count = 8,
- .dma_buf_len = 64,
- .use_apll = false,
- .tx_desc_auto_clear = false,
- .fixed_mclk = 0,
- .mclk_multiple = I2S_MCLK_MULTIPLE_512, // TODO: double check
- .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT,
+ i2s_std_config_t i2s_config = {
+ .clk_cfg = dac->clock_config_,
+ .slot_cfg = dac->slot_config_,
+ .gpio_cfg = {
+ .mclk = GPIO_NUM_0,
+ .bclk = GPIO_NUM_26,
+ .ws = GPIO_NUM_27,
+ .dout = GPIO_NUM_5,
+ .din = I2S_GPIO_UNUSED,
+ .invert_flags = {
+ .mclk_inv = false,
+ .bclk_inv = false,
+ .ws_inv = false,
+ }
+ },
};
- if (esp_err_t err =
- i2s_driver_install(kI2SPort, &i2s_config, 0, NULL) != ESP_OK) {
- ESP_LOGE(kTag, "failed to configure i2s pins %x", err);
+ if (esp_err_t err = i2s_channel_init_std_mode(i2s_handle, &i2s_config) != ESP_OK) {
+ ESP_LOGE(kTag, "failed to initialise i2s channel %x", err);
return cpp::fail(Error::FAILED_TO_INSTALL_I2S);
}
- i2s_pin_config_t pin_config = {.mck_io_num = GPIO_NUM_0,
- .bck_io_num = GPIO_NUM_26,
- .ws_io_num = GPIO_NUM_27,
- .data_out_num = GPIO_NUM_5,
- .data_in_num = I2S_PIN_NO_CHANGE};
- if (esp_err_t err = i2s_set_pin(kI2SPort, &pin_config) != ESP_OK) {
- ESP_LOGE(kTag, "failed to configure i2s pins %x", err);
- 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_);
// Now let's double check that the DAC itself came up whilst we we working.
bool is_booted = dac->WaitForPowerState(
@@ -92,13 +90,17 @@ auto AudioDac::create(GpioExpander* expander)
return dac;
}
-AudioDac::AudioDac(GpioExpander* gpio) : gpio_(gpio) {
+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, I2S_SLOT_MODE_STEREO)) {
gpio_->set_pin(GpioExpander::AUDIO_POWER_ENABLE, true);
gpio_->Write();
}
AudioDac::~AudioDac() {
- i2s_driver_uninstall(kI2SPort);
+ i2s_channel_disable(i2s_handle_);
+ i2s_del_channel(i2s_handle_);
gpio_->set_pin(GpioExpander::AUDIO_POWER_ENABLE, false);
gpio_->Write();
}
@@ -136,7 +138,7 @@ bool AudioDac::WaitForPowerState(
if (has_matched) {
break;
} else {
- ESP_LOGI(kTag, "Waiting for power state (was %d %x)", result.first,
+ ESP_LOGI(kTag, "Waiting for power state (was %d 0x%x)", result.first,
(uint8_t)result.second);
vTaskDelay(pdMS_TO_TICKS(1));
}
@@ -148,14 +150,23 @@ 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_set_clk(kI2SPort, rate, bps, I2S_CHANNEL_STEREO);
+ 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_);
+
+ // TODO: update mclk multiple as well if needed?
+ clock_config_.sample_rate_hz = rate;
+ i2s_channel_reconfig_std_clock(i2s_handle_, &clock_config_);
+
+ 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_write(kI2SPort, data.data(), data.size(), &res, max_wait);
+ i2s_channel_write(i2s_handle_, data.data(), data.size(), &res, max_wait);
return res;
}
diff --git a/src/drivers/include/dac.hpp b/src/drivers/include/dac.hpp
index 2d4e812f..8c49ce17 100644
--- a/src/drivers/include/dac.hpp
+++ b/src/drivers/include/dac.hpp
@@ -3,13 +3,15 @@
#include <stdint.h>
#include <functional>
+#include <memory>
+#include <utility>
+#include "driver/i2s_types.h"
#include "esp_err.h"
#include "freertos/portmacro.h"
-#include "hal/i2s_types.h"
#include "result.hpp"
#include "span.hpp"
-#include "driver/i2s_types_legacy.h"
+#include "driver/i2s_std.h"
#include "gpio_expander.hpp"
@@ -29,7 +31,7 @@ class AudioDac {
static auto create(GpioExpander* expander)
-> cpp::result<std::unique_ptr<AudioDac>, Error>;
- AudioDac(GpioExpander* gpio);
+ AudioDac(GpioExpander* gpio, i2s_chan_handle_t i2s_handle);
~AudioDac();
/**
@@ -54,9 +56,9 @@ class AudioDac {
std::pair<bool, PowerState> ReadPowerState();
enum BitsPerSample {
- BPS_16 = I2S_BITS_PER_SAMPLE_16BIT,
- BPS_24 = I2S_BITS_PER_SAMPLE_24BIT,
- BPS_32 = I2S_BITS_PER_SAMPLE_32BIT
+ BPS_16 = I2S_DATA_BIT_WIDTH_16BIT,
+ BPS_24 = I2S_DATA_BIT_WIDTH_24BIT,
+ BPS_32 = I2S_DATA_BIT_WIDTH_32BIT,
};
enum SampleRate {
SAMPLE_RATE_44_1 = 44100,
@@ -75,6 +77,10 @@ class AudioDac {
private:
GpioExpander* gpio_;
+ i2s_chan_handle_t i2s_handle_;
+
+ i2s_std_clk_config_t clock_config_;
+ i2s_std_slot_config_t slot_config_;
/*
* Pools the power state for up to 10ms, waiting for the given predicate to
diff --git a/src/main/main.cpp b/src/main/main.cpp
index 2f874bc7..82a51b8d 100644
--- a/src/main/main.cpp
+++ b/src/main/main.cpp
@@ -122,8 +122,6 @@ extern "C" void app_main(void) {
(void*)lvglArgs, 1, sLvglStack,
&sLvglTaskBuffer, 1);
- // TODO(jacqueline): re-enable this once our pipeline works.
- /*
ESP_LOGI(TAG, "Init audio pipeline");
auto playback_res = audio::AudioPlayback::create(expander, storage);
if (playback_res.has_error()) {
@@ -132,10 +130,9 @@ extern "C" void app_main(void) {
}
std::shared_ptr<audio::AudioPlayback> playback =
std::move(playback_res.value());
- */
ESP_LOGI(TAG, "Launch console");
- console::AppConsole console(nullptr);
+ console::AppConsole console(playback.get());
console.Launch();
while (1) {