From 8ed3d7e31f8b16a24593c01a480b19b14a513b48 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Sat, 21 Jan 2023 19:01:54 +1100 Subject: [PATCH] Re-enable the parts of the audio pipeline that are working --- src/audio/audio_playback.cpp | 2 + src/audio/fatfs_audio_input.cpp | 9 +++- src/drivers/dac.cpp | 83 +++++++++++++++++++-------------- src/drivers/include/dac.hpp | 18 ++++--- src/main/main.cpp | 5 +- 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 { 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(¤t_file_, std::addressof(file_buffer_write_pos_), @@ -115,6 +117,8 @@ auto FatfsAudioInput::ProcessIdle() -> cpp::result { return cpp::fail(IO_ERROR); } + ESP_LOGI(kTag, "actual read size %d bytes", (int) bytes_read); + if (f_eof(¤t_file_)) { f_close(¤t_file_); is_file_open_ = false; @@ -130,7 +134,8 @@ auto FatfsAudioInput::ProcessIdle() -> cpp::result { } // 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 d) { return SendChunk(d); }, kServiceInterval); @@ -146,6 +151,8 @@ auto FatfsAudioInput::ProcessIdle() -> cpp::result { return cpp::fail(IO_ERROR); } } + + return {}; } auto FatfsAudioInput::SendChunk(cpp::span 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, 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 dac = std::make_unique(expander); + std::unique_ptr dac = std::make_unique(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_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& 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 #include +#include +#include +#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, Error>; - AudioDac(GpioExpander* gpio); + AudioDac(GpioExpander* gpio, i2s_chan_handle_t i2s_handle); ~AudioDac(); /** @@ -54,9 +56,9 @@ class AudioDac { std::pair 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 playback = std::move(playback_res.value()); - */ ESP_LOGI(TAG, "Launch console"); - console::AppConsole console(nullptr); + console::AppConsole console(playback.get()); console.Launch(); while (1) {