use esp_hal::{
dma_buffers,
gpio::interconnect::PeripheralOutput,
i2s::master::{Config, I2s},
peripherals::{DMA_CH0, I2S0},
};
#[cfg(feature = "blocking")]
type DriveMode = esp_hal::Blocking;
#[cfg(feature = "async")]
type DriveMode = esp_hal::Async;
pub type I2sTx<'d> = esp_hal::i2s::master::I2sTx<'d, DriveMode>;
pub const DEFAULT_DMA_TX_BUF_SIZE: usize = 4 * 4096;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum I2sInitError {
PeripheralInitFailed,
}
impl I2sInitError {
pub const fn as_str(self) -> &'static str {
match self {
Self::PeripheralInitFailed => "I2S init failed",
}
}
}
pub enum TDMStandart {
Phillips,
MSB,
PCM,
PCM_Long,
}
macro_rules! tdm_config {
($standard:expr, $cfg:ident => $($method:tt)*) => {
match $standard {
TDMStandart::Phillips => Config::new_tdm_philips()$($method)*,
TDMStandart::MSB => Config::new_tdm_msb()$($method)*,
TDMStandart::PCM => Config::new_tdm_pcm_short()$($method)*,
TDMStandart::PCM_Long => Config::new_tdm_pcm_long()$($method)*,
}
};
}
pub struct I2sTxConfig {
pub sample_rate: esp_hal::time::Rate,
pub channels: esp_hal::i2s::master::Channels,
pub data_format: esp_hal::i2s::master::DataFormat,
pub tdm_standard: TDMStandart,
}
impl Default for I2sTxConfig {
fn default() -> Self {
Self {
sample_rate: esp_hal::time::Rate::from_hz(44100),
channels: esp_hal::i2s::master::Channels::STEREO,
data_format: esp_hal::i2s::master::DataFormat::Data16Channel16,
tdm_standard: TDMStandart::Phillips,
}
}
}
pub fn init_i2s_tx<'d>(
config: I2sTxConfig,
bclk: impl PeripheralOutput<'d>,
dout: impl PeripheralOutput<'d>,
lrck: impl PeripheralOutput<'d>,
i2s0: I2S0<'d>,
dma_channel: DMA_CH0<'d>,
) -> Result<I2sTx<'d>, I2sInitError> {
let i2s = I2s::new(
i2s0,
dma_channel,
tdm_config!(config.tdm_standard, cfg => .with_sample_rate(config.sample_rate).with_channels(config.channels).with_data_format(config.data_format))
)
.map_err(|_| I2sInitError::PeripheralInitFailed)?;
let (_, _, _tx_buf, tx_desc) = dma_buffers!(0, DEFAULT_DMA_TX_BUF_SIZE);
#[cfg(feature = "async")]
let i2s = i2s.into_async();
let i2stx = i2s
.i2s_tx
.with_bclk(bclk)
.with_ws(lrck)
.with_dout(dout)
.build(tx_desc);
Ok(i2stx)
}