|
|
|
@ -33,7 +33,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; |
|
|
|
|
// channel_config.auto_clear = true;
|
|
|
|
|
|
|
|
|
|
ESP_ERROR_CHECK(i2s_new_channel(&channel_config, &i2s_handle, NULL)); |
|
|
|
|
//
|
|
|
|
@ -115,7 +115,7 @@ AudioDac::AudioDac(GpioExpander* gpio, i2s_chan_handle_t 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, |
|
|
|
|
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); |
|
|
|
@ -192,8 +192,8 @@ 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_)); |
|
|
|
|
|
|
|
|
|
WriteRegister(pcm512x::I2S_1, (0b11 << 4) | bps_bits); |
|
|
|
|
WriteRegister(pcm512x::I2S_2, 0); |
|
|
|
|
WriteRegister(pcm512x::I2S_1, bps_bits); |
|
|
|
|
// WriteRegister(pcm512x::I2S_2, 0);
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
@ -212,31 +212,35 @@ auto AudioDac::WriteData(const cpp::span<const std::byte>& data) -> void { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
IRAM_ATTR auto callback(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx) -> bool { |
|
|
|
|
extern "C" IRAM_ATTR auto callback(i2s_chan_handle_t handle, |
|
|
|
|
i2s_event_data_t* event, |
|
|
|
|
void* user_ctx) -> bool { |
|
|
|
|
if (event == nullptr || user_ctx == nullptr) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
if (event->data == nullptr || event->size == 0) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
StreamBufferHandle_t *src = reinterpret_cast<StreamBufferHandle_t*>(user_ctx); |
|
|
|
|
uint8_t** buf = reinterpret_cast<uint8_t**>(event->data); |
|
|
|
|
StreamBufferHandle_t src = reinterpret_cast<StreamBufferHandle_t>(user_ctx); |
|
|
|
|
BaseType_t ret = false; |
|
|
|
|
std::size_t bytes_received = xStreamBufferReceiveFromISR(*src, event->data, event->size, &ret); |
|
|
|
|
std::size_t bytes_received = |
|
|
|
|
xStreamBufferReceiveFromISR(src, *buf, event->size, &ret); |
|
|
|
|
if (bytes_received < event->size) { |
|
|
|
|
// TODO(jacqueline): zero-pad.
|
|
|
|
|
memset(*buf + bytes_received, 0, event->size - bytes_received); |
|
|
|
|
} |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
auto AudioDac::SetSource(StreamBufferHandle_t *buffer) -> void { |
|
|
|
|
auto AudioDac::SetSource(StreamBufferHandle_t buffer) -> void { |
|
|
|
|
if (i2s_active_) { |
|
|
|
|
ESP_ERROR_CHECK(i2s_channel_disable(i2s_handle_)); |
|
|
|
|
} |
|
|
|
|
i2s_event_callbacks_t callbacks { |
|
|
|
|
.on_recv = NULL, |
|
|
|
|
.on_recv_q_ovf = NULL, |
|
|
|
|
.on_sent = NULL, |
|
|
|
|
.on_send_q_ovf = NULL, |
|
|
|
|
i2s_event_callbacks_t callbacks{ |
|
|
|
|
.on_recv = NULL, |
|
|
|
|
.on_recv_q_ovf = NULL, |
|
|
|
|
.on_sent = NULL, |
|
|
|
|
.on_send_q_ovf = NULL, |
|
|
|
|
}; |
|
|
|
|
if (buffer != nullptr) { |
|
|
|
|
callbacks.on_sent = &callback; |
|
|
|
|