Skip to content

Commit 8644c05

Browse files
committed
feat: add i2s transfer with driver mode
1 parent 51bc882 commit 8644c05

File tree

1 file changed

+123
-114
lines changed

1 file changed

+123
-114
lines changed

esp-hal/src/i2s/master.rs

Lines changed: 123 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@
6969
//!
7070
//! - Only TDM Philips standard is supported.
7171
72+
use core::{
73+
mem::ManuallyDrop,
74+
ops::{Deref, DerefMut},
75+
};
76+
7277
use enumset::{EnumSet, EnumSetType};
7378
use private::*;
7479

@@ -86,13 +91,12 @@ use crate::{
8691
DmaError,
8792
DmaTransferRx,
8893
DmaTransferRxCircular,
89-
DmaTransferTx,
90-
DmaTransferTxCircular,
94+
DmaTxBuffer,
9195
PeripheralRxChannel,
9296
PeripheralTxChannel,
93-
ReadBuffer,
9497
WriteBuffer,
95-
dma_private::{DmaSupport, DmaSupportRx, DmaSupportTx},
98+
asynch::DmaTxDoneChFuture,
99+
dma_private::{DmaSupport, DmaSupportRx},
96100
},
97101
gpio::{OutputConfig, interconnect::PeripheralOutput},
98102
i2s::AnyI2s,
@@ -416,6 +420,39 @@ where
416420
}
417421
}
418422

423+
impl<'d, Dm> I2sTx<'d, Dm>
424+
where
425+
Dm: DriverMode,
426+
{
427+
/// Starts a DMA transfer to write data to the I2S transmitter.
428+
pub fn write<TXBUF: DmaTxBuffer>(
429+
mut self,
430+
mut buf: TXBUF,
431+
) -> Result<I2sWriteDmaTransfer<'d, Dm, TXBUF>, Error> {
432+
// Reset TX unit and TX FIFO
433+
self.i2s.reset_tx();
434+
435+
// Enable corresponding interrupts if needed
436+
437+
// configure DMA outlink
438+
unsafe {
439+
self.tx_channel
440+
.prepare_transfer(self.i2s.dma_peripheral(), &mut buf)
441+
.and_then(|_| self.tx_channel.start_transfer())?;
442+
}
443+
444+
// set I2S_TX_STOP_EN if needed
445+
446+
// start: set I2S_TX_START
447+
self.i2s.tx_start();
448+
449+
Ok(I2sWriteDmaTransfer {
450+
i2s_tx: ManuallyDrop::new(self),
451+
buffer_view: ManuallyDrop::new(buf.into_view()),
452+
})
453+
}
454+
}
455+
419456
/// I2S RX channel
420457
pub struct I2sRx<'d, Dm>
421458
where
@@ -556,6 +593,88 @@ where
556593
}
557594
}
558595

596+
/// An in-progress async circular DMA write transfer.
597+
pub struct I2sWriteDmaTransfer<'d, Dm: DriverMode, BUFFER: DmaTxBuffer> {
598+
i2s_tx: ManuallyDrop<I2sTx<'d, Dm>>,
599+
buffer_view: ManuallyDrop<BUFFER::View>,
600+
}
601+
602+
impl<'d, Dm: DriverMode, BUFFER: DmaTxBuffer> Deref for I2sWriteDmaTransfer<'d, Dm, BUFFER> {
603+
type Target = BUFFER::View;
604+
605+
fn deref(&self) -> &Self::Target {
606+
&self.buffer_view
607+
}
608+
}
609+
610+
impl<'d, Dm: DriverMode, BUFFER: DmaTxBuffer> DerefMut for I2sWriteDmaTransfer<'d, Dm, BUFFER> {
611+
fn deref_mut(&mut self) -> &mut Self::Target {
612+
&mut self.buffer_view
613+
}
614+
}
615+
616+
impl<'d, Dm: DriverMode, BUFFER: DmaTxBuffer> Drop for I2sWriteDmaTransfer<'d, Dm, BUFFER> {
617+
fn drop(&mut self) {
618+
self.stop_peripheral();
619+
// SAFETY: This is Drop, we know that self.i2s_tx and self.buffer_view
620+
// won't be touched again.
621+
unsafe {
622+
ManuallyDrop::drop(&mut self.i2s_tx);
623+
ManuallyDrop::drop(&mut self.buffer_view);
624+
}
625+
}
626+
}
627+
628+
impl<'d, Dm: DriverMode, BUFFER: DmaTxBuffer> I2sWriteDmaTransfer<'d, Dm, BUFFER> {
629+
/// Stops the DMA transfer and returns the I2S transmitter and buffer.
630+
pub fn stop(mut self) -> (I2sTx<'d, Dm>, BUFFER) {
631+
self.stop_peripheral();
632+
let (i2s_tx, view) = self.release();
633+
(i2s_tx, BUFFER::from_view(view))
634+
}
635+
636+
/// Checks if the DMA transfer is done.
637+
pub fn is_done(&self) -> bool {
638+
self.i2s_tx.tx_channel.is_done()
639+
}
640+
641+
/// Stops and restarts the DMA transfer.
642+
pub fn restart(self) -> Result<Self, Error> {
643+
let (i2s, buf) = self.stop();
644+
i2s.write(buf)
645+
}
646+
647+
/// Checks if the DMA transfer has an error.
648+
pub fn has_error(&self) -> bool {
649+
self.i2s_tx.tx_channel.has_error()
650+
}
651+
652+
fn release(mut self) -> (I2sTx<'d, Dm>, BUFFER::View) {
653+
// SAFETY: Since forget is called on self, we know that self.i2s_tx and
654+
// self.buffer_view won't be touched again.
655+
let result = unsafe {
656+
(
657+
ManuallyDrop::take(&mut self.i2s_tx),
658+
ManuallyDrop::take(&mut self.buffer_view),
659+
)
660+
};
661+
core::mem::forget(self);
662+
result
663+
}
664+
665+
fn stop_peripheral(&mut self) {
666+
self.i2s_tx.i2s.tx_stop();
667+
}
668+
}
669+
670+
impl<BUFFER: DmaTxBuffer> I2sWriteDmaTransfer<'_, Async, BUFFER> {
671+
/// Waits for any DMA process to be made.
672+
pub async fn process(&mut self) -> Result<(), Error> {
673+
DmaTxDoneChFuture::new(&mut self.i2s_tx.tx_channel).await?;
674+
Ok(())
675+
}
676+
}
677+
559678
/// A peripheral singleton compatible with the I2S master driver.
560679
pub trait Instance: RegisterAccessPrivate + super::IntoAnyI2s {}
561680
impl Instance for crate::peripherals::I2S0<'_> {}
@@ -1710,116 +1829,6 @@ pub mod asynch {
17101829
},
17111830
};
17121831

1713-
impl<'d> I2sTx<'d, Async> {
1714-
/// Continuously write to I2S. Returns [I2sWriteDmaTransferAsync]
1715-
pub fn write<TXBUF: DmaTxBuffer>(
1716-
mut self,
1717-
mut buf: TXBUF,
1718-
) -> Result<I2sWriteDmaTransferAsync<'d, TXBUF>, Error> {
1719-
// Reset TX unit and TX FIFO
1720-
self.i2s.reset_tx();
1721-
1722-
// Enable corresponding interrupts if needed
1723-
1724-
// configure DMA outlink
1725-
unsafe {
1726-
self.tx_channel
1727-
.prepare_transfer(self.i2s.dma_peripheral(), &mut buf)
1728-
.and_then(|_| self.tx_channel.start_transfer())?;
1729-
}
1730-
1731-
// set I2S_TX_STOP_EN if needed
1732-
1733-
// start: set I2S_TX_START
1734-
self.i2s.tx_start();
1735-
1736-
Ok(I2sWriteDmaTransferAsync {
1737-
i2s_tx: ManuallyDrop::new(self),
1738-
buffer_view: ManuallyDrop::new(buf.into_view()),
1739-
})
1740-
}
1741-
}
1742-
1743-
/// An in-progress async circular DMA write transfer.
1744-
pub struct I2sWriteDmaTransferAsync<'d, BUFFER: DmaTxBuffer> {
1745-
i2s_tx: ManuallyDrop<I2sTx<'d, Async>>,
1746-
buffer_view: ManuallyDrop<BUFFER::View>,
1747-
}
1748-
1749-
impl<'d, BUFFER: DmaTxBuffer> Deref for I2sWriteDmaTransferAsync<'d, BUFFER> {
1750-
type Target = BUFFER::View;
1751-
1752-
fn deref(&self) -> &Self::Target {
1753-
&self.buffer_view
1754-
}
1755-
}
1756-
1757-
impl<'d, BUFFER: DmaTxBuffer> DerefMut for I2sWriteDmaTransferAsync<'d, BUFFER> {
1758-
fn deref_mut(&mut self) -> &mut Self::Target {
1759-
&mut self.buffer_view
1760-
}
1761-
}
1762-
1763-
impl<'d, BUFFER: DmaTxBuffer> Drop for I2sWriteDmaTransferAsync<'d, BUFFER> {
1764-
fn drop(&mut self) {
1765-
self.stop_peripheral();
1766-
// SAFETY: This is Drop, we know that self.i2s_tx and self.buffer_view
1767-
// won't be touched again.
1768-
unsafe {
1769-
ManuallyDrop::drop(&mut self.i2s_tx);
1770-
ManuallyDrop::drop(&mut self.buffer_view);
1771-
}
1772-
}
1773-
}
1774-
1775-
impl<'d, BUFFER: DmaTxBuffer> I2sWriteDmaTransferAsync<'d, BUFFER> {
1776-
/// Stops the DMA transfer and returns the I2S transmitter and buffer.
1777-
pub fn stop(mut self) -> (I2sTx<'d, Async>, BUFFER) {
1778-
self.stop_peripheral();
1779-
let (i2s_tx, view) = self.release();
1780-
(i2s_tx, BUFFER::from_view(view))
1781-
}
1782-
1783-
/// Checks if the DMA transfer is done.
1784-
pub fn is_done(&self) -> bool {
1785-
self.i2s_tx.tx_channel.is_done()
1786-
}
1787-
1788-
/// Stops and restarts the DMA transfer.
1789-
pub fn restart(self) -> Result<Self, Error> {
1790-
let (i2s, buf) = self.stop();
1791-
i2s.write(buf)
1792-
}
1793-
1794-
/// Checks if the DMA transfer has an error.
1795-
pub fn has_error(&self) -> bool {
1796-
self.i2s_tx.tx_channel.has_error()
1797-
}
1798-
1799-
/// Waits for any DMA process to be made.
1800-
pub async fn process(&mut self) -> Result<(), Error> {
1801-
DmaTxDoneChFuture::new(&mut self.i2s_tx.tx_channel).await?;
1802-
Ok(())
1803-
}
1804-
1805-
fn release(mut self) -> (I2sTx<'d, Async>, BUFFER::View) {
1806-
// SAFETY: Since forget is called on self, we know that self.i2s_tx and
1807-
// self.buffer_view won't be touched again.
1808-
let result = unsafe {
1809-
(
1810-
ManuallyDrop::take(&mut self.i2s_tx),
1811-
ManuallyDrop::take(&mut self.buffer_view),
1812-
)
1813-
};
1814-
core::mem::forget(self);
1815-
result
1816-
}
1817-
1818-
fn stop_peripheral(&mut self) {
1819-
self.i2s_tx.i2s.tx_stop();
1820-
}
1821-
}
1822-
18231832
impl<'d> I2sRx<'d, Async> {
18241833
/// One-shot read I2S.
18251834
pub async fn read_dma_async(&mut self, words: &mut [u8]) -> Result<(), Error> {

0 commit comments

Comments
 (0)