Preliminary I2S Implementation

This commit is contained in:
bjoernQ 2022-11-03 14:11:22 +01:00 committed by Jesse Braham
parent d9135350e7
commit 4afa8fda92
20 changed files with 3452 additions and 114 deletions

View File

@ -119,6 +119,38 @@ macro_rules! impl_channel {
ret ret
} }
fn last_out_dscr_address() -> usize {
let dma = unsafe { &*crate::pac::DMA::PTR };
dma.[<out_eof_des_addr_ch $num>].read().out_eof_des_addr().bits() as usize
}
fn is_out_eof_interrupt_set() -> bool {
let dma = unsafe { &*crate::pac::DMA::PTR };
#[cfg(not(esp32s3))]
let ret = dma.[<int_raw_ch $num>].read().out_eof().bit();
#[cfg(esp32s3)]
let ret = dma.[<out_int_raw_ch $num>].read().out_eof().bit();
ret
}
fn reset_out_eof_interrupt() {
let dma = unsafe { &*crate::pac::DMA::PTR };
#[cfg(not(esp32s3))]
dma.[<int_clr_ch $num>].write(|w| {
w.out_eof()
.set_bit()
});
#[cfg(esp32s3)]
dma.[<out_int_clr_ch $num>].write(|w| {
w.out_eof()
.set_bit()
});
}
fn set_in_burstmode(burst_mode: bool) { fn set_in_burstmode(burst_mode: bool) {
let dma = unsafe { &*crate::pac::DMA::PTR }; let dma = unsafe { &*crate::pac::DMA::PTR };
@ -225,6 +257,11 @@ macro_rules! impl_channel {
ret ret
} }
fn last_in_dscr_address() -> usize {
let dma = unsafe { &*crate::pac::DMA::PTR };
dma.[<in_dscr_bf0_ch $num>].read().inlink_dscr_bf0().bits() as usize
}
} }
pub struct [<Channel $num TxImpl>] {} pub struct [<Channel $num TxImpl>] {}
@ -252,6 +289,12 @@ macro_rules! impl_channel {
descriptors: tx_descriptors, descriptors: tx_descriptors,
burst_mode, burst_mode,
tx_impl: tx_impl, tx_impl: tx_impl,
write_offset: 0,
write_descr_ptr: core::ptr::null(),
available: 0,
last_seen_handled_descriptor_ptr: core::ptr::null(),
buffer_start: core::ptr::null(),
buffer_len: 0,
_phantom: PhantomData::default(), _phantom: PhantomData::default(),
}; };
@ -262,6 +305,12 @@ macro_rules! impl_channel {
descriptors: rx_descriptors, descriptors: rx_descriptors,
burst_mode, burst_mode,
rx_impl: rx_impl, rx_impl: rx_impl,
read_offset: 0,
read_descr_ptr: core::ptr::null(),
available: 0,
last_seen_handled_descriptor_ptr: core::ptr::null(),
buffer_start: core::ptr::null(),
buffer_len: 0,
_phantom: PhantomData::default(), _phantom: PhantomData::default(),
}; };
@ -279,6 +328,9 @@ macro_rules! impl_channel {
// with GDMA every channel can be used for any peripheral // with GDMA every channel can be used for any peripheral
impl SpiPeripheral for [<SuitablePeripheral $num>] {} impl SpiPeripheral for [<SuitablePeripheral $num>] {}
impl Spi2Peripheral for [<SuitablePeripheral $num>] {} impl Spi2Peripheral for [<SuitablePeripheral $num>] {}
impl I2sPeripheral for [<SuitablePeripheral $num>] {}
impl I2s0Peripheral for [<SuitablePeripheral $num>] {}
impl I2s1Peripheral for [<SuitablePeripheral $num>] {}
} }
}; };
} }

View File

@ -9,6 +9,8 @@ pub mod gdma;
#[cfg(pdma)] #[cfg(pdma)]
pub mod pdma; pub mod pdma;
const CHUNK_SIZE: usize = 4092;
/// DMA Errors /// DMA Errors
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum DmaError { pub enum DmaError {
@ -16,6 +18,9 @@ pub enum DmaError {
OutOfDescriptors, OutOfDescriptors,
InvalidDescriptorSize, InvalidDescriptorSize,
DescriptorError, DescriptorError,
Overflow,
Exhausted,
BufferTooSmall,
} }
/// DMA Priorities /// DMA Priorities
@ -51,9 +56,9 @@ pub enum DmaPeripheral {
Spi3 = 1, Spi3 = 1,
#[cfg(any(esp32c3, esp32s3))] #[cfg(any(esp32c3, esp32s3))]
Uhci0 = 2, Uhci0 = 2,
#[cfg(any(esp32c3, esp32s3))] #[cfg(any(esp32, esp32s2, esp32c3, esp32s3))]
I2s0 = 3, I2s0 = 3,
#[cfg(esp32s3)] #[cfg(any(esp32, esp32s3))]
I2s1 = 4, I2s1 = 4,
#[cfg(esp32s3)] #[cfg(esp32s3)]
LcdCam = 5, LcdCam = 5,
@ -89,7 +94,6 @@ trait DmaLinkedListDw0 {
fn set_err_eof(&mut self, err_eof: bool); fn set_err_eof(&mut self, err_eof: bool);
#[cfg(not(esp32))] #[cfg(not(esp32))]
fn get_err_eof(&mut self) -> bool; fn get_err_eof(&mut self) -> bool;
#[cfg(not(esp32))]
fn set_suc_eof(&mut self, suc_eof: bool); fn set_suc_eof(&mut self, suc_eof: bool);
fn get_suc_eof(&mut self) -> bool; fn get_suc_eof(&mut self) -> bool;
fn set_owner(&mut self, owner: Owner); fn set_owner(&mut self, owner: Owner);
@ -134,7 +138,6 @@ impl DmaLinkedListDw0 for &mut u32 {
((**self & (mask << bit_s)) >> bit_s) != 0 ((**self & (mask << bit_s)) >> bit_s) != 0
} }
#[cfg(not(esp32))]
fn set_suc_eof(&mut self, suc_eof: bool) { fn set_suc_eof(&mut self, suc_eof: bool) {
let mask = 0b1; let mask = 0b1;
let bit_s = 30; let bit_s = 30;
@ -176,6 +179,15 @@ pub(crate) mod private {
#[cfg(any(esp32, esp32s2, esp32s3))] #[cfg(any(esp32, esp32s2, esp32s3))]
pub trait Spi3Peripheral: SpiPeripheral + PeripheralMarker {} pub trait Spi3Peripheral: SpiPeripheral + PeripheralMarker {}
/// Marks channels as useable for I2S
pub trait I2sPeripheral: PeripheralMarker {}
/// Marks channels as useable for I2S0
pub trait I2s0Peripheral: I2sPeripheral + PeripheralMarker {}
/// Marks channels as useable for I2S1
pub trait I2s1Peripheral: I2sPeripheral + PeripheralMarker {}
/// DMA Rx /// DMA Rx
/// ///
/// The functions here are not meant to be used outside the HAL and will be /// The functions here are not meant to be used outside the HAL and will be
@ -187,12 +199,17 @@ pub(crate) mod private {
fn prepare_transfer( fn prepare_transfer(
&mut self, &mut self,
circular: bool,
peri: DmaPeripheral, peri: DmaPeripheral,
data: *mut u8, data: *mut u8,
len: usize, len: usize,
) -> Result<(), DmaError>; ) -> Result<(), DmaError>;
fn is_done(&mut self) -> bool; fn is_done(&mut self) -> bool;
fn available(&mut self) -> usize;
fn pop(&mut self, data: &mut [u8]) -> Result<usize, DmaError>;
} }
pub trait RxChannel<R> pub trait RxChannel<R>
@ -207,6 +224,7 @@ pub(crate) mod private {
fn prepare_transfer( fn prepare_transfer(
&mut self, &mut self,
descriptors: &mut [u32], descriptors: &mut [u32],
circular: bool,
peri: DmaPeripheral, peri: DmaPeripheral,
data: *mut u8, data: *mut u8,
len: usize, len: usize,
@ -220,16 +238,14 @@ pub(crate) mod private {
let mut processed = 0; let mut processed = 0;
let mut descr = 0; let mut descr = 0;
loop { loop {
let chunk_size = usize::min(4092, len - processed); let chunk_size = usize::min(CHUNK_SIZE, len - processed);
let last = processed + chunk_size >= len; let last = processed + chunk_size >= len;
descriptors[descr + 1] = data as u32 + processed as u32; descriptors[descr + 1] = data as u32 + processed as u32;
let mut dw0 = &mut descriptors[descr]; let mut dw0 = &mut descriptors[descr];
#[cfg(not(esp32))] dw0.set_suc_eof(true);
dw0.set_suc_eof(last);
dw0.set_owner(Owner::Dma); dw0.set_owner(Owner::Dma);
dw0.set_size(chunk_size as u16); // align to 32 bits? dw0.set_size(chunk_size as u16); // align to 32 bits?
dw0.set_length(0); // actual size of the data!? dw0.set_length(0); // actual size of the data!?
@ -238,7 +254,11 @@ pub(crate) mod private {
descriptors[descr + 2] = descriptors[descr + 2] =
(&descriptors[descr + 3]) as *const _ as *const () as u32; (&descriptors[descr + 3]) as *const _ as *const () as u32;
} else { } else {
descriptors[descr + 2] = 0; descriptors[descr + 2] = if circular {
descriptors.as_ptr() as *const () as u32
} else {
0
};
} }
processed += chunk_size; processed += chunk_size;
@ -265,6 +285,10 @@ pub(crate) mod private {
fn is_done(&mut self) -> bool { fn is_done(&mut self) -> bool {
R::is_in_done() R::is_in_done()
} }
fn last_in_dscr_address(&self) -> usize {
R::last_in_dscr_address()
}
} }
pub struct ChannelRx<'a, T, R> pub struct ChannelRx<'a, T, R>
@ -275,6 +299,12 @@ pub(crate) mod private {
pub descriptors: &'a mut [u32], pub descriptors: &'a mut [u32],
pub burst_mode: bool, pub burst_mode: bool,
pub rx_impl: T, pub rx_impl: T,
pub read_offset: usize,
pub read_descr_ptr: *const u32,
pub available: usize,
pub last_seen_handled_descriptor_ptr: *const u32,
pub buffer_start: *const u8,
pub buffer_len: usize,
pub _phantom: PhantomData<R>, pub _phantom: PhantomData<R>,
} }
@ -289,6 +319,7 @@ pub(crate) mod private {
fn prepare_transfer( fn prepare_transfer(
&mut self, &mut self,
circular: bool,
peri: DmaPeripheral, peri: DmaPeripheral,
data: *mut u8, data: *mut u8,
len: usize, len: usize,
@ -297,7 +328,7 @@ pub(crate) mod private {
return Err(DmaError::InvalidDescriptorSize); return Err(DmaError::InvalidDescriptorSize);
} }
if self.descriptors.len() / 3 < len / 4092 { if self.descriptors.len() / 3 < len / CHUNK_SIZE {
return Err(DmaError::OutOfDescriptors); return Err(DmaError::OutOfDescriptors);
} }
@ -305,8 +336,19 @@ pub(crate) mod private {
return Err(DmaError::InvalidAlignment); return Err(DmaError::InvalidAlignment);
} }
if circular && len < CHUNK_SIZE * 2 {
return Err(DmaError::BufferTooSmall);
}
self.read_offset = 0;
self.available = 0;
self.read_descr_ptr = self.descriptors.as_ptr() as *const u32;
self.last_seen_handled_descriptor_ptr = core::ptr::null();
self.buffer_start = data;
self.buffer_len = len;
self.rx_impl self.rx_impl
.prepare_transfer(self.descriptors, peri, data, len)?; .prepare_transfer(self.descriptors, circular, peri, data, len)?;
Ok(()) Ok(())
} }
@ -317,6 +359,118 @@ pub(crate) mod private {
fn init_channel(&mut self) { fn init_channel(&mut self) {
R::init_channel(); R::init_channel();
} }
fn available(&mut self) -> usize {
let last_dscr = self.rx_impl.last_in_dscr_address() as *const u32;
if !last_dscr.is_null()
&& !self.last_seen_handled_descriptor_ptr.is_null()
&& self.last_seen_handled_descriptor_ptr != last_dscr
{
let descr_address = last_dscr;
if descr_address >= self.last_seen_handled_descriptor_ptr {
let mut ptr = self.last_seen_handled_descriptor_ptr as *const u32;
unsafe {
while ptr < descr_address as *const u32 {
let mut dw0 = &mut ptr.read_volatile();
self.available += dw0.get_length() as usize;
ptr = ptr.offset(3);
}
}
} else {
let mut ptr = self.last_seen_handled_descriptor_ptr as *const u32;
unsafe {
loop {
if ptr.offset(2).read_volatile() == 0 {
break;
}
let mut dw0 = &mut ptr.read_volatile();
self.available += dw0.get_length() as usize;
ptr = ptr.offset(3);
}
}
}
if self.available >= self.buffer_len {
unsafe {
let segment_len =
(&mut self.read_descr_ptr.read_volatile()).get_length() as usize;
self.available -= segment_len;
self.read_offset = (self.read_offset + segment_len) % self.buffer_len;
let next_descriptor =
self.read_descr_ptr.offset(2).read_volatile() as *const u32;
self.read_descr_ptr = if next_descriptor.is_null() {
self.descriptors.as_ptr() as *const u32
} else {
next_descriptor
}
}
}
self.last_seen_handled_descriptor_ptr = descr_address;
} else {
self.last_seen_handled_descriptor_ptr = last_dscr;
}
self.available
}
fn pop(&mut self, data: &mut [u8]) -> Result<usize, super::DmaError> {
let avail = self.available();
if avail < data.len() {
return Err(super::DmaError::Exhausted);
}
unsafe {
let dst = data.as_mut_ptr();
let src = self.buffer_start.offset(self.read_offset as isize) as *const u8;
let count = usize::min(data.len(), self.buffer_len - self.read_offset);
core::ptr::copy_nonoverlapping(src, dst, count);
}
if self.read_offset + data.len() >= self.buffer_len {
let remainder = (self.read_offset + data.len()) % self.buffer_len;
let src = self.buffer_start as *const u8;
unsafe {
let dst = data.as_mut_ptr().offset((data.len() - remainder) as isize);
core::ptr::copy_nonoverlapping(src, dst, remainder);
}
}
let mut forward = data.len();
loop {
unsafe {
let next_descriptor =
self.read_descr_ptr.offset(2).read_volatile() as *const u32;
let segment_len =
(&mut self.read_descr_ptr.read_volatile()).get_length() as usize;
self.read_descr_ptr = if next_descriptor.is_null() {
self.descriptors.as_ptr() as *const u32
} else {
next_descriptor
};
if forward <= segment_len {
break;
}
forward -= segment_len;
if forward == 0 {
break;
}
}
}
self.read_offset = (self.read_offset + data.len()) % self.buffer_len;
self.available -= data.len();
Ok(data.len())
}
} }
/// DMA Tx /// DMA Tx
@ -331,11 +485,16 @@ pub(crate) mod private {
fn prepare_transfer( fn prepare_transfer(
&mut self, &mut self,
peri: DmaPeripheral, peri: DmaPeripheral,
circular: bool,
data: *const u8, data: *const u8,
len: usize, len: usize,
) -> Result<(), DmaError>; ) -> Result<(), DmaError>;
fn is_done(&mut self) -> bool; fn is_done(&mut self) -> bool;
fn available(&mut self) -> usize;
fn push(&mut self, data: &[u8]) -> Result<usize, super::DmaError>;
} }
pub trait TxChannel<R> pub trait TxChannel<R>
@ -350,6 +509,7 @@ pub(crate) mod private {
fn prepare_transfer( fn prepare_transfer(
&mut self, &mut self,
descriptors: &mut [u32], descriptors: &mut [u32],
circular: bool,
peri: DmaPeripheral, peri: DmaPeripheral,
data: *const u8, data: *const u8,
len: usize, len: usize,
@ -363,16 +523,14 @@ pub(crate) mod private {
let mut processed = 0; let mut processed = 0;
let mut descr = 0; let mut descr = 0;
loop { loop {
let chunk_size = usize::min(4092, len - processed); let chunk_size = usize::min(CHUNK_SIZE, len - processed);
let last = processed + chunk_size >= len; let last = processed + chunk_size >= len;
descriptors[descr + 1] = data as u32 + processed as u32; descriptors[descr + 1] = data as u32 + processed as u32;
let mut dw0 = &mut descriptors[descr]; let mut dw0 = &mut descriptors[descr];
#[cfg(not(esp32))] dw0.set_suc_eof(true);
dw0.set_suc_eof(last);
dw0.set_owner(Owner::Dma); dw0.set_owner(Owner::Dma);
dw0.set_size(chunk_size as u16); // align to 32 bits? dw0.set_size(chunk_size as u16); // align to 32 bits?
dw0.set_length(chunk_size as u16); // actual size of the data!? dw0.set_length(chunk_size as u16); // actual size of the data!?
@ -381,7 +539,11 @@ pub(crate) mod private {
descriptors[descr + 2] = descriptors[descr + 2] =
(&descriptors[descr + 3]) as *const _ as *const () as u32; (&descriptors[descr + 3]) as *const _ as *const () as u32;
} else { } else {
descriptors[descr + 2] = 0; if !circular {
descriptors[descr + 2] = 0;
} else {
descriptors[descr + 2] = descriptors.as_ptr() as u32;
}
} }
processed += chunk_size; processed += chunk_size;
@ -408,6 +570,18 @@ pub(crate) mod private {
fn is_done(&mut self) -> bool { fn is_done(&mut self) -> bool {
R::is_out_done() R::is_out_done()
} }
fn descriptors_handled(&self) -> bool {
R::is_out_eof_interrupt_set()
}
fn reset_descriptors_handled(&self) {
R::reset_out_eof_interrupt();
}
fn last_out_dscr_address(&self) -> usize {
R::last_out_dscr_address()
}
} }
pub struct ChannelTx<'a, T, R> pub struct ChannelTx<'a, T, R>
@ -419,6 +593,12 @@ pub(crate) mod private {
#[allow(unused)] #[allow(unused)]
pub burst_mode: bool, pub burst_mode: bool,
pub tx_impl: T, pub tx_impl: T,
pub write_offset: usize,
pub write_descr_ptr: *const u32,
pub available: usize,
pub last_seen_handled_descriptor_ptr: *const u32,
pub buffer_start: *const u8,
pub buffer_len: usize,
pub _phantom: PhantomData<R>, pub _phantom: PhantomData<R>,
} }
@ -438,6 +618,7 @@ pub(crate) mod private {
fn prepare_transfer( fn prepare_transfer(
&mut self, &mut self,
peri: DmaPeripheral, peri: DmaPeripheral,
circular: bool,
data: *const u8, data: *const u8,
len: usize, len: usize,
) -> Result<(), DmaError> { ) -> Result<(), DmaError> {
@ -445,12 +626,23 @@ pub(crate) mod private {
return Err(DmaError::InvalidDescriptorSize); return Err(DmaError::InvalidDescriptorSize);
} }
if self.descriptors.len() / 3 < len / 4092 { if self.descriptors.len() / 3 < len / CHUNK_SIZE {
return Err(DmaError::OutOfDescriptors); return Err(DmaError::OutOfDescriptors);
} }
if circular && len < CHUNK_SIZE * 2 {
return Err(DmaError::BufferTooSmall);
}
self.write_offset = 0;
self.available = 0;
self.write_descr_ptr = self.descriptors.as_ptr() as *const u32;
self.last_seen_handled_descriptor_ptr = self.descriptors.as_ptr() as *const u32;
self.buffer_start = data;
self.buffer_len = len;
self.tx_impl self.tx_impl
.prepare_transfer(self.descriptors, peri, data, len)?; .prepare_transfer(self.descriptors, circular, peri, data, len)?;
Ok(()) Ok(())
} }
@ -458,6 +650,113 @@ pub(crate) mod private {
fn is_done(&mut self) -> bool { fn is_done(&mut self) -> bool {
self.tx_impl.is_done() self.tx_impl.is_done()
} }
fn available(&mut self) -> usize {
if self.tx_impl.descriptors_handled() {
self.tx_impl.reset_descriptors_handled();
let descr_address = self.tx_impl.last_out_dscr_address() as *const u32;
if descr_address >= self.last_seen_handled_descriptor_ptr {
let mut ptr = self.last_seen_handled_descriptor_ptr as *const u32;
unsafe {
while ptr < descr_address as *const u32 {
let mut dw0 = &mut ptr.read_volatile();
self.available += dw0.get_length() as usize;
ptr = ptr.offset(3);
}
}
} else {
let mut ptr = self.last_seen_handled_descriptor_ptr as *const u32;
unsafe {
loop {
if ptr.offset(2).read_volatile() == 0 {
break;
}
let mut dw0 = &mut ptr.read_volatile();
self.available += dw0.get_length() as usize;
ptr = ptr.offset(3);
}
}
}
if self.available >= self.buffer_len {
unsafe {
let segment_len =
(&mut self.write_descr_ptr.read_volatile()).get_length() as usize;
self.available -= segment_len;
self.write_offset = (self.write_offset + segment_len) % self.buffer_len;
let next_descriptor =
self.write_descr_ptr.offset(2).read_volatile() as *const u32;
self.write_descr_ptr = if next_descriptor.is_null() {
self.descriptors.as_ptr() as *const u32
} else {
next_descriptor
}
}
}
self.last_seen_handled_descriptor_ptr = descr_address;
}
self.available
}
fn push(&mut self, data: &[u8]) -> Result<usize, super::DmaError> {
let avail = self.available();
if avail < data.len() {
return Err(super::DmaError::Overflow);
}
unsafe {
let src = data.as_ptr();
let dst = self.buffer_start.offset(self.write_offset as isize) as *mut u8;
let count = usize::min(data.len(), self.buffer_len - self.write_offset);
core::ptr::copy_nonoverlapping(src, dst, count);
}
if self.write_offset + data.len() >= self.buffer_len {
let remainder = (self.write_offset + data.len()) % self.buffer_len;
let dst = self.buffer_start as *mut u8;
unsafe {
let src = data.as_ptr().offset((data.len() - remainder) as isize);
core::ptr::copy_nonoverlapping(src, dst, remainder);
}
}
let mut forward = data.len();
loop {
unsafe {
let next_descriptor =
self.write_descr_ptr.offset(2).read_volatile() as *const u32;
let segment_len =
(&mut self.write_descr_ptr.read_volatile()).get_length() as usize;
self.write_descr_ptr = if next_descriptor.is_null() {
self.descriptors.as_ptr() as *const u32
} else {
next_descriptor
};
if forward <= segment_len {
break;
}
forward -= segment_len;
if forward == 0 {
break;
}
}
}
self.write_offset = (self.write_offset + data.len()) % self.buffer_len;
self.available -= data.len();
Ok(data.len())
}
} }
pub trait RegisterAccess { pub trait RegisterAccess {
@ -471,6 +770,10 @@ pub(crate) mod private {
fn set_out_peripheral(peripheral: u8); fn set_out_peripheral(peripheral: u8);
fn start_out(); fn start_out();
fn is_out_done() -> bool; fn is_out_done() -> bool;
fn is_out_eof_interrupt_set() -> bool;
fn reset_out_eof_interrupt();
fn last_out_dscr_address() -> usize;
fn set_in_burstmode(burst_mode: bool); fn set_in_burstmode(burst_mode: bool);
fn set_in_priority(priority: DmaPriority); fn set_in_priority(priority: DmaPriority);
fn clear_in_interrupts(); fn clear_in_interrupts();
@ -480,6 +783,7 @@ pub(crate) mod private {
fn set_in_peripheral(peripheral: u8); fn set_in_peripheral(peripheral: u8);
fn start_in(); fn start_in();
fn is_in_done() -> bool; fn is_in_done() -> bool;
fn last_in_dscr_address() -> usize;
} }
} }

View File

@ -86,6 +86,24 @@ macro_rules! ImplSpiChannel {
spi.dma_int_raw.read().out_done_int_raw().bit() spi.dma_int_raw.read().out_done_int_raw().bit()
} }
fn last_out_dscr_address() -> usize {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.out_eof_des_addr.read().dma_out_eof_des_addr().bits() as usize
}
fn is_out_eof_interrupt_set() -> bool {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_int_raw.read().out_eof_int_raw().bit()
}
fn reset_out_eof_interrupt() {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_int_clr.write(|w| {
w.out_eof_int_clr()
.set_bit()
});
}
fn set_in_burstmode(burst_mode: bool) { fn set_in_burstmode(burst_mode: bool) {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR }; let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_conf spi.dma_conf
@ -138,6 +156,11 @@ macro_rules! ImplSpiChannel {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR }; let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.dma_int_raw.read().in_done_int_raw().bit() spi.dma_int_raw.read().in_done_int_raw().bit()
} }
fn last_in_dscr_address() -> usize {
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
spi.inlink_dscr_bf0.read().dma_inlink_dscr_bf0().bits() as usize
}
} }
pub struct [<Spi $num DmaChannelTxImpl>] {} pub struct [<Spi $num DmaChannelTxImpl>] {}
@ -169,6 +192,12 @@ macro_rules! ImplSpiChannel {
descriptors: tx_descriptors, descriptors: tx_descriptors,
burst_mode, burst_mode,
tx_impl: tx_impl, tx_impl: tx_impl,
write_offset: 0,
write_descr_ptr: core::ptr::null(),
available: 0,
last_seen_handled_descriptor_ptr: core::ptr::null(),
buffer_start: core::ptr::null(),
buffer_len: 0,
_phantom: PhantomData::default(), _phantom: PhantomData::default(),
}; };
@ -179,6 +208,12 @@ macro_rules! ImplSpiChannel {
descriptors: rx_descriptors, descriptors: rx_descriptors,
burst_mode, burst_mode,
rx_impl: rx_impl, rx_impl: rx_impl,
read_offset: 0,
read_descr_ptr: core::ptr::null(),
available: 0,
last_seen_handled_descriptor_ptr: core::ptr::null(),
buffer_start: core::ptr::null(),
buffer_len: 0,
_phantom: PhantomData::default(), _phantom: PhantomData::default(),
}; };
@ -193,7 +228,212 @@ macro_rules! ImplSpiChannel {
}; };
} }
/// Crate private implementatin details macro_rules! ImplI2sChannel {
($num: literal, $peripheral: literal) => {
paste::paste! {
pub struct [<I2s $num DmaChannel>] {}
impl RegisterAccess for [<I2s $num DmaChannel>] {
fn init_channel() {
// nothing to do
}
fn set_out_burstmode(burst_mode: bool) {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.lc_conf
.modify(|_, w| w.outdscr_burst_en().bit(burst_mode));
}
fn set_out_priority(_priority: DmaPriority) {}
fn clear_out_interrupts() {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.int_clr.write(|w| {
w.out_done_int_clr()
.set_bit()
.out_eof_int_clr()
.set_bit()
.out_total_eof_int_clr()
.set_bit()
.out_dscr_err_int_clr()
.set_bit()
});
}
fn reset_out() {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.lc_conf.modify(|_, w| w.out_rst().set_bit());
reg_block.lc_conf.modify(|_, w| w.out_rst().clear_bit());
}
fn set_out_descriptors(address: u32) {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.out_link
.modify(|_, w| unsafe { w.outlink_addr().bits(address) });
}
fn has_out_descriptor_error() -> bool {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.int_raw.read().out_dscr_err_int_raw().bit()
}
fn set_out_peripheral(_peripheral: u8) {
// no-op
}
fn start_out() {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.out_link.modify(|_, w| w.outlink_start().set_bit());
}
fn is_out_done() -> bool {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.int_raw.read().out_done_int_raw().bit()
}
fn last_out_dscr_address() -> usize {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.out_eof_des_addr.read().out_eof_des_addr().bits() as usize
}
fn is_out_eof_interrupt_set() -> bool {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.int_raw.read().out_eof_int_raw().bit()
}
fn reset_out_eof_interrupt() {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.int_clr.write(|w| {
w.out_eof_int_clr()
.set_bit()
});
}
fn set_in_burstmode(burst_mode: bool) {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.lc_conf
.modify(|_, w| w.indscr_burst_en().bit(burst_mode));
}
fn set_in_priority(_priority: DmaPriority) {}
fn clear_in_interrupts() {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.int_clr.write(|w| {
w.in_done_int_clr()
.set_bit()
.in_err_eof_int_clr()
.set_bit()
.in_suc_eof_int_clr()
.set_bit()
.in_dscr_err_int_clr()
.set_bit()
});
}
fn reset_in() {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.lc_conf.modify(|_, w| w.in_rst().set_bit());
reg_block.lc_conf.modify(|_, w| w.in_rst().clear_bit());
}
fn set_in_descriptors(address: u32) {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.in_link
.modify(|_, w| unsafe { w.inlink_addr().bits(address) });
}
fn has_in_descriptor_error() -> bool {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.int_raw.read().in_dscr_err_int_raw().bit()
}
fn set_in_peripheral(_peripheral: u8) {
// no-op
}
fn start_in() {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.in_link.modify(|_, w| w.inlink_start().set_bit());
}
fn is_in_done() -> bool {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.int_raw.read().in_done_int_raw().bit()
}
fn last_in_dscr_address() -> usize {
let reg_block = unsafe { &*crate::pac::[<$peripheral>]::PTR };
reg_block.inlink_dscr_bf0.read().inlink_dscr_bf0().bits() as usize
}
}
pub struct [<I2s $num DmaChannelTxImpl>] {}
impl<'a> TxChannel<[<I2s $num DmaChannel>]> for [<I2s $num DmaChannelTxImpl>] {}
pub struct [<I2s $num DmaChannelRxImpl>] {}
impl<'a> RxChannel<[<I2s $num DmaChannel>]> for [<I2s $num DmaChannelRxImpl>] {}
pub struct [<I2s $num DmaChannelCreator>] {}
impl [<I2s $num DmaChannelCreator>] {
pub fn configure<'a>(
self,
burst_mode: bool,
tx_descriptors: &'a mut [u32],
rx_descriptors: &'a mut [u32],
priority: DmaPriority,
) -> Channel<
ChannelTx<'a,[<I2s $num DmaChannelTxImpl>], [<I2s $num DmaChannel>]>,
ChannelRx<'a,[<I2s $num DmaChannelRxImpl>], [<I2s $num DmaChannel>]>,
[<I2s $num DmaSuitablePeripheral>],
> {
let mut tx_impl = [<I2s $num DmaChannelTxImpl>] {};
tx_impl.init(burst_mode, priority);
let tx_channel = ChannelTx {
descriptors: tx_descriptors,
burst_mode,
tx_impl: tx_impl,
write_offset: 0,
write_descr_ptr: core::ptr::null(),
available: 0,
last_seen_handled_descriptor_ptr: core::ptr::null(),
buffer_start: core::ptr::null(),
buffer_len: 0,
_phantom: PhantomData::default(),
};
let mut rx_impl = [<I2s $num DmaChannelRxImpl>] {};
rx_impl.init(burst_mode, priority);
let rx_channel = ChannelRx {
descriptors: rx_descriptors,
burst_mode,
rx_impl: rx_impl,
read_offset: 0,
read_descr_ptr: core::ptr::null(),
available: 0,
last_seen_handled_descriptor_ptr: core::ptr::null(),
buffer_start: core::ptr::null(),
buffer_len: 0,
_phantom: PhantomData::default(),
};
Channel {
tx: tx_channel,
rx: rx_channel,
_phantom: PhantomData::default(),
}
}
}
}
};
}
/// Crate private implementation details
pub(crate) mod private { pub(crate) mod private {
use crate::dma::{private::*, *}; use crate::dma::{private::*, *};
@ -209,6 +449,25 @@ pub(crate) mod private {
ImplSpiChannel!(2); ImplSpiChannel!(2);
ImplSpiChannel!(3); ImplSpiChannel!(3);
pub struct I2s0DmaSuitablePeripheral {}
impl PeripheralMarker for I2s0DmaSuitablePeripheral {}
impl I2sPeripheral for I2s0DmaSuitablePeripheral {}
impl I2s0Peripheral for I2s0DmaSuitablePeripheral {}
#[cfg(esp32)]
ImplI2sChannel!(0, "I2S0");
#[cfg(esp32s2)]
ImplI2sChannel!(0, "I2S");
pub struct I2s1DmaSuitablePeripheral {}
impl PeripheralMarker for I2s1DmaSuitablePeripheral {}
impl I2sPeripheral for I2s1DmaSuitablePeripheral {}
impl I2s1Peripheral for I2s1DmaSuitablePeripheral {}
#[cfg(esp32)]
ImplI2sChannel!(1, "I2S1");
} }
/// DMA Peripheral /// DMA Peripheral
@ -218,6 +477,9 @@ pub struct Dma {
_inner: crate::system::Dma, _inner: crate::system::Dma,
pub spi2channel: Spi2DmaChannelCreator, pub spi2channel: Spi2DmaChannelCreator,
pub spi3channel: Spi3DmaChannelCreator, pub spi3channel: Spi3DmaChannelCreator,
pub i2s0channel: I2s0DmaChannelCreator,
#[cfg(esp32)]
pub i2s1channel: I2s1DmaChannelCreator,
} }
impl Dma { impl Dma {
@ -232,6 +494,9 @@ impl Dma {
_inner: dma, _inner: dma,
spi2channel: Spi2DmaChannelCreator {}, spi2channel: Spi2DmaChannelCreator {},
spi3channel: Spi3DmaChannelCreator {}, spi3channel: Spi3DmaChannelCreator {},
i2s0channel: I2s0DmaChannelCreator {},
#[cfg(esp32)]
i2s1channel: I2s1DmaChannelCreator {},
} }
} }
} }

View File

@ -60,6 +60,7 @@ pub enum InputSignal {
SUBSPID = 128, SUBSPID = 128,
SUBSPIHD = 129, SUBSPIHD = 129,
SUBSPIWP = 130, SUBSPIWP = 130,
I2S0I_DATA_IN15 = 158,
SUBSPID4 = 167, SUBSPID4 = 167,
SUBSPID5 = 168, SUBSPID5 = 168,
SUBSPID6 = 169, SUBSPID6 = 169,
@ -73,95 +74,97 @@ pub enum InputSignal {
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(PartialEq, Copy, Clone)] #[derive(PartialEq, Copy, Clone)]
pub enum OutputSignal { pub enum OutputSignal {
SPIQ = 0, SPIQ = 0,
SPID = 1, SPID = 1,
SPIHD = 2, SPIHD = 2,
SPIWP = 3, SPIWP = 3,
SPICLK = 4, SPICLK = 4,
SPICS0 = 5, SPICS0 = 5,
SPICS1 = 6, SPICS1 = 6,
SPID4 = 7, SPID4 = 7,
SPID5 = 8, SPID5 = 8,
SPID6 = 9, SPID6 = 9,
SPID7 = 10, SPID7 = 10,
SPIDQS = 11, SPIDQS = 11,
U0TXD = 14, U0TXD = 14,
U0RTS = 15, U0RTS = 15,
U0DTR = 16, U0DTR = 16,
U1TXD = 17, U1TXD = 17,
U1RTS = 18, U1RTS = 18,
U1DTR = 21, U1DTR = 21,
I2S0O_BCK = 23, I2S0O_BCK = 23,
I2S0O_WS = 25, I2S0O_WS = 25,
I2S0I_BCK = 27, I2S0I_BCK = 27,
I2S0I_WS = 28, I2S0I_WS = 28,
I2CEXT0_SCL = 29, I2CEXT0_SCL = 29,
I2CEXT0_SDA = 30, I2CEXT0_SDA = 30,
SDIO_TOHOST_INT = 31, SDIO_TOHOST_INT = 31,
SPI3_CLK = 72, SPI3_CLK = 72,
SPI3_Q = 73, SPI3_Q = 73,
SPI3_D = 74, SPI3_D = 74,
SPI3_HD = 75, SPI3_HD = 75,
SPI3_CS0 = 76, SPI3_CS0 = 76,
SPI3_CS1 = 77, SPI3_CS1 = 77,
SPI3_CS2 = 78, SPI3_CS2 = 78,
LEDC_LS_SIG0 = 79, LEDC_LS_SIG0 = 79,
LEDC_LS_SIG1 = 80, LEDC_LS_SIG1 = 80,
LEDC_LS_SIG2 = 81, LEDC_LS_SIG2 = 81,
LEDC_LS_SIG3 = 82, LEDC_LS_SIG3 = 82,
LEDC_LS_SIG4 = 83, LEDC_LS_SIG4 = 83,
LEDC_LS_SIG5 = 84, LEDC_LS_SIG5 = 84,
LEDC_LS_SIG6 = 85, LEDC_LS_SIG6 = 85,
LEDC_LS_SIG7 = 86, LEDC_LS_SIG7 = 86,
RMT_SIG_OUT0 = 87, RMT_SIG_OUT0 = 87,
RMT_SIG_OUT1 = 88, RMT_SIG_OUT1 = 88,
RMT_SIG_OUT2 = 89, RMT_SIG_OUT2 = 89,
RMT_SIG_OUT3 = 90, RMT_SIG_OUT3 = 90,
I2CEXT1_SCL = 95, I2CEXT1_SCL = 95,
I2CEXT1_SDA = 96, I2CEXT1_SDA = 96,
GPIO_SD0 = 100, GPIO_SD0 = 100,
GPIO_SD1 = 101, GPIO_SD1 = 101,
GPIO_SD2 = 102, GPIO_SD2 = 102,
GPIO_SD3 = 103, GPIO_SD3 = 103,
GPIO_SD4 = 104, GPIO_SD4 = 104,
GPIO_SD5 = 105, GPIO_SD5 = 105,
GPIO_SD6 = 106, GPIO_SD6 = 106,
GPIO_SD7 = 107, GPIO_SD7 = 107,
FSPICLK = 108, FSPICLK = 108,
FSPIQ = 109, FSPIQ = 109,
FSPID = 110, FSPID = 110,
FSPIHD = 111, FSPIHD = 111,
FSPIWP = 112, FSPIWP = 112,
FSPIIO4 = 113, FSPIIO4 = 113,
FSPIIO5 = 114, FSPIIO5 = 114,
FSPIIO6 = 115, FSPIIO6 = 115,
FSPIIO7 = 116, FSPIIO7 = 116,
FSPICS0 = 117, FSPICS0 = 117,
FSPICS1 = 118, FSPICS1 = 118,
FSPICS2 = 119, FSPICS2 = 119,
FSPICS3 = 120, FSPICS3 = 120,
FSPICS4 = 121, FSPICS4 = 121,
FSPICS5 = 122, FSPICS5 = 122,
SUBSPICLK = 126, SUBSPICLK = 126,
SUBSPIQ = 127, SUBSPIQ = 127,
SUBSPID = 128, SUBSPID = 128,
SUBSPIHD = 129, SUBSPIHD = 129,
SUBSPIWP = 130, SUBSPIWP = 130,
SUBSPICS0 = 131, SUBSPICS0 = 131,
SUBSPICS1 = 132, SUBSPICS1 = 132,
FSPIDQS = 133, FSPIDQS = 133,
FSPI_HSYNC = 134, FSPI_HSYNC = 134,
FSPI_VSYNC = 135, FSPI_VSYNC = 135,
FSPI_DE = 136, FSPI_DE = 136,
FSPICD = 137, FSPICD = 137,
SPI3_CD = 139, SPI3_CD = 139,
SPI3_DQS = 140, SPI3_DQS = 140,
SUBSPID4 = 167, I2S0O_DATA_OUT23 = 166,
SUBSPID5 = 168, SUBSPID4 = 167,
SUBSPID6 = 169, SUBSPID5 = 168,
SUBSPID7 = 170, SUBSPID6 = 169,
SUBSPIDQS = 171, SUBSPID7 = 170,
PCMFSYNC = 209, SUBSPIDQS = 171,
PCMCLK = 210, PCMFSYNC = 209,
GPIO = 256, PCMCLK = 210,
CLK_I2S = 251,
GPIO = 256,
} }

1725
esp-hal-common/src/i2s.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -56,6 +56,10 @@ pub mod dma;
pub mod embassy; pub mod embassy;
pub mod gpio; pub mod gpio;
pub mod i2c; pub mod i2c;
#[cfg(any(esp32c3, esp32s3, esp32, esp32s2))]
pub mod i2s;
pub mod ledc; pub mod ledc;
#[cfg(usb_otg)] #[cfg(usb_otg)]
pub mod otg_fs; pub mod otg_fs;

View File

@ -1000,8 +1000,18 @@ where
self.enable_dma(); self.enable_dma();
self.update(); self.update();
tx.prepare_transfer(self.dma_peripheral(), write_buffer_ptr, write_buffer_len)?; tx.prepare_transfer(
rx.prepare_transfer(self.dma_peripheral(), read_buffer_ptr, read_buffer_len)?; self.dma_peripheral(),
false,
write_buffer_ptr,
write_buffer_len,
)?;
rx.prepare_transfer(
false,
self.dma_peripheral(),
read_buffer_ptr,
read_buffer_len,
)?;
self.clear_dma_interrupts(); self.clear_dma_interrupts();
@ -1033,7 +1043,7 @@ where
self.enable_dma(); self.enable_dma();
self.update(); self.update();
tx.prepare_transfer(self.dma_peripheral(), ptr, len)?; tx.prepare_transfer(self.dma_peripheral(), false, ptr, len)?;
self.clear_dma_interrupts(); self.clear_dma_interrupts();
@ -1054,7 +1064,7 @@ where
self.enable_dma(); self.enable_dma();
self.update(); self.update();
rx.prepare_transfer(self.dma_peripheral(), ptr, len)?; rx.prepare_transfer(false, self.dma_peripheral(), ptr, len)?;
self.clear_dma_interrupts(); self.clear_dma_interrupts();

View File

@ -34,6 +34,10 @@ pub enum Peripheral {
Gdma, Gdma,
#[cfg(pdma)] #[cfg(pdma)]
Dma, Dma,
#[cfg(not(esp32c2))]
I2s0,
#[cfg(not(any(esp32c2, esp32s2, esp32c3)))]
I2s1,
#[cfg(usb_otg)] #[cfg(usb_otg)]
Usb, Usb,
} }
@ -122,6 +126,22 @@ impl PeripheralClockControl {
perip_clk_en0.modify(|_, w| w.spi3_dma_clk_en().set_bit()); perip_clk_en0.modify(|_, w| w.spi3_dma_clk_en().set_bit());
perip_rst_en0.modify(|_, w| w.spi3_dma_rst().clear_bit()); perip_rst_en0.modify(|_, w| w.spi3_dma_rst().clear_bit());
} }
#[cfg(esp32c3)]
Peripheral::I2s0 => {
// on ESP32-C3 note that i2s1_clk_en / rst is really I2s0
perip_clk_en0.modify(|_, w| w.i2s1_clk_en().set_bit());
perip_rst_en0.modify(|_, w| w.i2s1_rst().clear_bit());
}
#[cfg(any(esp32s3, esp32, esp32s2))]
Peripheral::I2s0 => {
perip_clk_en0.modify(|_, w| w.i2s0_clk_en().set_bit());
perip_rst_en0.modify(|_, w| w.i2s0_rst().clear_bit());
}
#[cfg(any(esp32s3, esp32))]
Peripheral::I2s1 => {
perip_clk_en0.modify(|_, w| w.i2s1_clk_en().set_bit());
perip_rst_en0.modify(|_, w| w.i2s1_rst().clear_bit());
}
#[cfg(usb_otg)] #[cfg(usb_otg)]
Peripheral::Usb => { Peripheral::Usb => {
perip_clk_en0.modify(|_, w| w.usb_clk_en().set_bit()); perip_clk_en0.modify(|_, w| w.usb_clk_en().set_bit());

View File

@ -0,0 +1,94 @@
//! This shows how to continously receive data via I2S
//!
//! Pins used
//! BCLK GPIO12
//! WS GPIO13
//! DIN GPIO17
//!
//! Without an additional I2S source device you can connect 3V3 or GND to DIN to
//! read 0 or 0xFF or connect DIN to WS to read two different values
//!
//! You can also inspect the MCLK, BCLK and WS with a logic analyzer
#![no_std]
#![no_main]
use esp32_hal::{
clock::ClockControl,
dma::{DmaPriority},
pdma::Dma,
i2s::{DataFormat, I2s, NoMclk, Standard, I2s0New, PinsBclkWsDin, I2sReadDma},
pac::Peripherals,
prelude::*,
timer::TimerGroup,
Rtc,
IO,
};
use esp_backtrace as _;
use esp_println::println;
use xtensa_lx_rt::entry;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take().unwrap();
let mut system = peripherals.DPORT.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt = timer_group0.wdt;
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
// Disable MWDT and RWDT (Watchdog) flash boot protection
wdt.disable();
rtc.rwdt.disable();
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let dma = Dma::new(system.dma, &mut system.peripheral_clock_control);
let dma_channel = dma.i2s0channel;
let mut tx_descriptors = [0u32; 8 * 3];
let mut rx_descriptors = [0u32; 8 * 3];
let i2s = I2s::new(
peripherals.I2S0,
NoMclk {},
Standard::Philips,
DataFormat::Data16Channel16,
44100u32.Hz(),
dma_channel.configure(
false,
&mut tx_descriptors,
&mut rx_descriptors,
DmaPriority::Priority0,
),
&mut system.peripheral_clock_control,
&clocks,
);
let i2s_rx = i2s.i2s_rx.with_pins(PinsBclkWsDin {
bclk: io.pins.gpio12,
ws: io.pins.gpio13,
din: io.pins.gpio17,
});
let buffer = dma_buffer();
let mut transfer = i2s_rx.read_dma_circular(buffer).unwrap();
println!("Started transfer");
loop {
let avail = transfer.available();
if avail > 0 {
let mut rcv = [0u8; 5000];
transfer.pop(&mut rcv[..avail]).unwrap();
println!("Received {:x?}...", &rcv[..30]);
}
}
}
fn dma_buffer() -> &'static mut [u8; 4092 * 4] {
static mut BUFFER: [u8; 4092 * 4] = [0u8; 4092 * 4];
unsafe { &mut BUFFER }
}

View File

@ -0,0 +1,136 @@
//! This shows how to transmit data continously via I2S
//!
//! Pins used
//! BCLK GPIO12
//! WS GPIO13
//! DOUT GPIO14
//!
//! Without an additional I2S sink device you can inspect the MCLK, BCLK, WS and
//! DOUT with a logic analyzer
//!
//! You can also connect e.g. a PCM510x to hear an annoying loud sine tone (full
//! scale), so turn down the volume before running this example.
//!
//! Wiring is like this
//!
//! | Pin | Connected to |
//! |-------|-----------------|
//! | BCK | GPIO12 |
//! | DIN | GPIO14 |
//! | LRCK | GPIO13 |
//! | SCK | Gnd |
//! | GND | Gnd |
//! | VIN | +3V3 |
//! | FLT | Gnd |
//! | FMT | Gnd |
//! | DEMP | Gnd |
//! | XSMT | +3V3 |
#![no_std]
#![no_main]
use esp32_hal::{
clock::ClockControl,
dma::DmaPriority,
pdma::Dma,
i2s::{DataFormat, I2s, I2sWriteDma, NoMclk, PinsBclkWsDout, Standard, I2s0New},
pac::Peripherals,
prelude::*,
timer::TimerGroup,
Rtc,
IO,
};
use esp_backtrace as _;
use xtensa_lx_rt::entry;
const SINE: [i16; 64] = [
0, 3211, 6392, 9511, 12539, 15446, 18204, 20787, 23169, 25329, 27244, 28897, 30272, 31356,
32137, 32609, 32767, 32609, 32137, 31356, 30272, 28897, 27244, 25329, 23169, 20787, 18204,
15446, 12539, 9511, 6392, 3211, 0, -3211, -6392, -9511, -12539, -15446, -18204, -20787, -23169,
-25329, -27244, -28897, -30272, -31356, -32137, -32609, -32767, -32609, -32137, -31356, -30272,
-28897, -27244, -25329, -23169, -20787, -18204, -15446, -12539, -9511, -6392, -3211,
];
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take().unwrap();
let mut system = peripherals.DPORT.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt = timer_group0.wdt;
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
// Disable MWDT and RWDT (Watchdog) flash boot protection
wdt.disable();
rtc.rwdt.disable();
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let dma = Dma::new(system.dma, &mut system.peripheral_clock_control);
let dma_channel = dma.i2s0channel;
let mut tx_descriptors = [0u32; 20 * 3];
let mut rx_descriptors = [0u32; 8 * 3];
let i2s = I2s::new(
peripherals.I2S0,
NoMclk {},
Standard::Philips,
DataFormat::Data16Channel16,
44100u32.Hz(),
dma_channel.configure(
false,
&mut tx_descriptors,
&mut rx_descriptors,
DmaPriority::Priority0,
),
&mut system.peripheral_clock_control,
&clocks,
);
let i2s_tx = i2s.i2s_tx.with_pins(PinsBclkWsDout {
bclk: io.pins.gpio12,
ws: io.pins.gpio13,
dout: io.pins.gpio14,
});
let data =
unsafe { core::slice::from_raw_parts(&SINE as *const _ as *const u8, SINE.len() * 2) };
let buffer = dma_buffer();
let mut idx = 0;
for i in 0..usize::min(data.len(), buffer.len()) {
buffer[i] = data[idx];
idx += 1;
if idx >= data.len() {
idx = 0;
}
}
let mut filler = [0u8; 10000];
let mut transfer = i2s_tx.write_dma_circular(buffer).unwrap();
loop {
let avail = transfer.available();
if avail > 0 {
let avail = usize::min(10000, avail);
for bidx in 0..avail {
filler[bidx] = data[idx];
idx += 1;
if idx >= data.len() {
idx = 0;
}
}
transfer.push(&filler[0..avail]).unwrap();
}
}
}
fn dma_buffer() -> &'static mut [u8; 32000] {
static mut BUFFER: [u8; 32000] = [0u8; 32000];
unsafe { &mut BUFFER }
}

View File

@ -10,6 +10,7 @@ pub use esp_hal_common::{
efuse, efuse,
gpio as gpio_types, gpio as gpio_types,
i2c, i2c,
i2s,
interrupt, interrupt,
ledc, ledc,
macros, macros,

View File

@ -0,0 +1,101 @@
//! This shows how to continously receive data via I2S
//!
//! Pins used
//! MCLK GPIO4
//! BCLK GPIO1
//! WS GPIO2
//! DIN GPIO5
//!
//! Without an additional I2S source device you can connect 3V3 or GND to DIN to
//! read 0 or 0xFF or connect DIN to WS to read two different values
//!
//! You can also inspect the MCLK, BCLK and WS with a logic analyzer
#![no_std]
#![no_main]
use esp32c3_hal::{
clock::ClockControl,
dma::DmaPriority,
gdma::Gdma,
i2s::{DataFormat, I2s, I2sReadDma, MclkPin, PinsBclkWsDin, Standard, I2s0New},
pac::Peripherals,
prelude::*,
timer::TimerGroup,
Rtc,
IO,
};
use esp_backtrace as _;
use esp_println::println;
use riscv_rt::entry;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take().unwrap();
let mut system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt0 = timer_group0.wdt;
let timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
let mut wdt1 = timer_group1.wdt;
// Disable watchdog timers
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.disable();
wdt1.disable();
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let dma = Gdma::new(peripherals.DMA, &mut system.peripheral_clock_control);
let dma_channel = dma.channel0;
let mut tx_descriptors = [0u32; 8 * 3];
let mut rx_descriptors = [0u32; 8 * 3];
let i2s = I2s::new(
peripherals.I2S,
MclkPin {
mclk: io.pins.gpio4,
},
Standard::Philips,
DataFormat::Data16Channel16,
44100u32.Hz(),
dma_channel.configure(
false,
&mut tx_descriptors,
&mut rx_descriptors,
DmaPriority::Priority0,
),
&mut system.peripheral_clock_control,
&clocks,
);
let i2s_rx = i2s.i2s_rx.with_pins(PinsBclkWsDin {
bclk: io.pins.gpio1,
ws: io.pins.gpio2,
din: io.pins.gpio5,
});
let buffer = dma_buffer();
let mut transfer = i2s_rx.read_dma_circular(buffer).unwrap();
println!("Started transfer");
loop {
let avail = transfer.available();
if avail > 0 {
let mut rcv = [0u8; 5000];
transfer.pop(&mut rcv[..avail]).unwrap();
println!("Received {:x?}...", &rcv[..30]);
}
}
}
fn dma_buffer() -> &'static mut [u8; 4092 * 4] {
static mut BUFFER: [u8; 4092 * 4] = [0u8; 4092 * 4];
unsafe { &mut BUFFER }
}

View File

@ -0,0 +1,143 @@
//! This shows how to transmit data continously via I2S
//!
//! Pins used
//! MCLK GPIO4
//! BCLK GPIO1
//! WS GPIO2
//! DOUT GPIO3
//!
//! Without an additional I2S sink device you can inspect the MCLK, BCLK, WS and
//! DOUT with a logic analyzer
//!
//! You can also connect e.g. a PCM510x to hear an annoying loud sine tone (full
//! scale), so turn down the volume before running this example.
//!
//! Wiring is like this
//!
//! | Pin | Connected to |
//! |-------|-----------------|
//! | BCK | GPIO1 |
//! | DIN | GPIO3 |
//! | LRCK | GPIO2 |
//! | SCK | Gnd |
//! | GND | Gnd |
//! | VIN | +3V3 |
//! | FLT | Gnd |
//! | FMT | Gnd |
//! | DEMP | Gnd |
//! | XSMT | +3V3 |
#![no_std]
#![no_main]
use esp32c3_hal::{
clock::ClockControl,
dma::DmaPriority,
gdma::Gdma,
i2s::{DataFormat, I2s, I2sWriteDma, MclkPin, PinsBclkWsDout, Standard, I2s0New},
pac::Peripherals,
prelude::*,
timer::TimerGroup,
Rtc,
IO,
};
use esp_backtrace as _;
use riscv_rt::entry;
const SINE: [i16; 64] = [
0, 3211, 6392, 9511, 12539, 15446, 18204, 20787, 23169, 25329, 27244, 28897, 30272, 31356,
32137, 32609, 32767, 32609, 32137, 31356, 30272, 28897, 27244, 25329, 23169, 20787, 18204,
15446, 12539, 9511, 6392, 3211, 0, -3211, -6392, -9511, -12539, -15446, -18204, -20787, -23169,
-25329, -27244, -28897, -30272, -31356, -32137, -32609, -32767, -32609, -32137, -31356, -30272,
-28897, -27244, -25329, -23169, -20787, -18204, -15446, -12539, -9511, -6392, -3211,
];
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take().unwrap();
let mut system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt0 = timer_group0.wdt;
let timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
let mut wdt1 = timer_group1.wdt;
// Disable watchdog timers
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.disable();
wdt1.disable();
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let dma = Gdma::new(peripherals.DMA, &mut system.peripheral_clock_control);
let dma_channel = dma.channel0;
let mut tx_descriptors = [0u32; 20 * 3];
let mut rx_descriptors = [0u32; 8 * 3];
let i2s = I2s::new(
peripherals.I2S,
MclkPin {
mclk: io.pins.gpio4,
},
Standard::Philips,
DataFormat::Data16Channel16,
44100u32.Hz(),
dma_channel.configure(
false,
&mut tx_descriptors,
&mut rx_descriptors,
DmaPriority::Priority0,
),
&mut system.peripheral_clock_control,
&clocks,
);
let i2s_tx = i2s.i2s_tx.with_pins(PinsBclkWsDout {
bclk: io.pins.gpio1,
ws: io.pins.gpio2,
dout: io.pins.gpio3,
});
let data =
unsafe { core::slice::from_raw_parts(&SINE as *const _ as *const u8, SINE.len() * 2) };
let buffer = dma_buffer();
let mut idx = 0;
for i in 0..usize::min(data.len(), buffer.len()) {
buffer[i] = data[idx];
idx += 1;
if idx >= data.len() {
idx = 0;
}
}
let mut filler = [0u8; 10000];
let mut transfer = i2s_tx.write_dma_circular(buffer).unwrap();
loop {
let avail = transfer.available();
if avail > 0 {
let avail = usize::min(10000, avail);
for bidx in 0..avail {
filler[bidx] = data[idx];
idx += 1;
if idx >= data.len() {
idx = 0;
}
}
transfer.push(&filler[0..avail]).unwrap();
}
}
}
fn dma_buffer() -> &'static mut [u8; 32000] {
static mut BUFFER: [u8; 32000] = [0u8; 32000];
unsafe { &mut BUFFER }
}

View File

@ -13,6 +13,7 @@ pub use esp_hal_common::{
efuse, efuse,
gpio as gpio_types, gpio as gpio_types,
i2c, i2c,
i2s,
interrupt, interrupt,
ledc, ledc,
macros, macros,

View File

@ -0,0 +1,94 @@
//! This shows how to continously receive data via I2S
//!
//! Pins used
//! BCLK GPIO1
//! WS GPIO2
//! DIN GPIO5
//!
//! Without an additional I2S source device you can connect 3V3 or GND to DIN to
//! read 0 or 0xFF or connect DIN to WS to read two different values
//!
//! You can also inspect the MCLK, BCLK and WS with a logic analyzer
#![no_std]
#![no_main]
use esp32s2_hal::{
clock::ClockControl,
dma::{DmaPriority},
pdma::Dma,
i2s::{DataFormat, I2s, NoMclk, Standard, I2s0New, PinsBclkWsDin, I2sReadDma},
pac::Peripherals,
prelude::*,
timer::TimerGroup,
Rtc,
IO,
};
use esp_backtrace as _;
use esp_println::println;
use xtensa_lx_rt::entry;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take().unwrap();
let mut system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt = timer_group0.wdt;
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
// Disable MWDT and RWDT (Watchdog) flash boot protection
wdt.disable();
rtc.rwdt.disable();
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let dma = Dma::new(system.dma, &mut system.peripheral_clock_control);
let dma_channel = dma.i2s0channel;
let mut tx_descriptors = [0u32; 8 * 3];
let mut rx_descriptors = [0u32; 8 * 3];
let i2s = I2s::new(
peripherals.I2S,
NoMclk {},
Standard::Philips,
DataFormat::Data16Channel16,
44100u32.Hz(),
dma_channel.configure(
false,
&mut tx_descriptors,
&mut rx_descriptors,
DmaPriority::Priority0,
),
&mut system.peripheral_clock_control,
&clocks,
);
let i2s_rx = i2s.i2s_rx.with_pins(PinsBclkWsDin {
bclk: io.pins.gpio1,
ws: io.pins.gpio2,
din: io.pins.gpio5,
});
let buffer = dma_buffer();
let mut transfer = i2s_rx.read_dma_circular(buffer).unwrap();
println!("Started transfer");
loop {
let avail = transfer.available();
if avail > 0 {
let mut rcv = [0u8; 4092 * 4];
transfer.pop(&mut rcv[..avail]).unwrap();
println!("Received {:x?}...", &rcv[..30]);
}
}
}
fn dma_buffer() -> &'static mut [u8; 4092 * 4] {
static mut BUFFER: [u8; 4092 * 4] = [0u8; 4092 * 4];
unsafe { &mut BUFFER }
}

View File

@ -0,0 +1,139 @@
//! This shows how to transmit data continously via I2S
//!
//! Pins used
//! MCLK GPIO4
//! BCLK GPIO1
//! WS GPIO2
//! DOUT GPIO3
//!
//! Without an additional I2S sink device you can inspect the MCLK, BCLK, WS and
//! DOUT with a logic analyzer
//!
//! You can also connect e.g. a PCM510x to hear an annoying loud sine tone (full
//! scale), so turn down the volume before running this example.
//!
//! Wiring is like this
//!
//! | Pin | Connected to |
//! |-------|-----------------|
//! | BCK | GPIO1 |
//! | DIN | GPIO3 |
//! | LRCK | GPIO2 |
//! | SCK | Gnd |
//! | GND | Gnd |
//! | VIN | +3V3 |
//! | FLT | Gnd |
//! | FMT | Gnd |
//! | DEMP | Gnd |
//! | XSMT | +3V3 |
#![no_std]
#![no_main]
use esp32s2_hal::{
clock::ClockControl,
dma::DmaPriority,
pdma::Dma,
i2s::{DataFormat, I2s, I2sWriteDma, MclkPin, PinsBclkWsDout, Standard, I2s0New},
pac::Peripherals,
prelude::*,
timer::TimerGroup,
Rtc,
IO,
};
use esp_backtrace as _;
use xtensa_lx_rt::entry;
const SINE: [i16; 64] = [
0, 3211, 6392, 9511, 12539, 15446, 18204, 20787, 23169, 25329, 27244, 28897, 30272, 31356,
32137, 32609, 32767, 32609, 32137, 31356, 30272, 28897, 27244, 25329, 23169, 20787, 18204,
15446, 12539, 9511, 6392, 3211, 0, -3211, -6392, -9511, -12539, -15446, -18204, -20787, -23169,
-25329, -27244, -28897, -30272, -31356, -32137, -32609, -32767, -32609, -32137, -31356, -30272,
-28897, -27244, -25329, -23169, -20787, -18204, -15446, -12539, -9511, -6392, -3211,
];
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take().unwrap();
let mut system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt = timer_group0.wdt;
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
// Disable watchdog timer
wdt.disable();
rtc.rwdt.disable();
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let dma = Dma::new(system.dma, &mut system.peripheral_clock_control);
let dma_channel = dma.i2s0channel;
let mut tx_descriptors = [0u32; 20 * 3];
let mut rx_descriptors = [0u32; 8 * 3];
let i2s = I2s::new(
peripherals.I2S,
MclkPin {
mclk: io.pins.gpio4,
},
Standard::Philips,
DataFormat::Data16Channel16,
44100u32.Hz(),
dma_channel.configure(
false,
&mut tx_descriptors,
&mut rx_descriptors,
DmaPriority::Priority0,
),
&mut system.peripheral_clock_control,
&clocks,
);
let i2s_tx = i2s.i2s_tx.with_pins(PinsBclkWsDout {
bclk: io.pins.gpio1,
ws: io.pins.gpio2,
dout: io.pins.gpio3,
});
let data =
unsafe { core::slice::from_raw_parts(&SINE as *const _ as *const u8, SINE.len() * 2) };
let buffer = dma_buffer();
let mut idx = 0;
for i in 0..usize::min(data.len(), buffer.len()) {
buffer[i] = data[idx];
idx += 1;
if idx >= data.len() {
idx = 0;
}
}
let mut filler = [0u8; 10000];
let mut transfer = i2s_tx.write_dma_circular(buffer).unwrap();
loop {
let avail = transfer.available();
if avail > 0 {
let avail = usize::min(10000, avail);
for bidx in 0..avail {
filler[bidx] = data[idx];
idx += 1;
if idx >= data.len() {
idx = 0;
}
}
transfer.push(&filler[0..avail]).unwrap();
}
}
}
fn dma_buffer() -> &'static mut [u8; 32000] {
static mut BUFFER: [u8; 32000] = [0u8; 32000];
unsafe { &mut BUFFER }
}

View File

@ -8,6 +8,7 @@ pub use esp_hal_common::{
dma::pdma, dma::pdma,
efuse, efuse,
gpio as gpio_types, gpio as gpio_types,
i2s,
i2c::{self, I2C}, i2c::{self, I2C},
interrupt, interrupt,
ledc, ledc,

View File

@ -0,0 +1,101 @@
//! This shows how to continously receive data via I2S
//!
//! Pins used
//! MCLK GPIO4
//! BCLK GPIO1
//! WS GPIO2
//! DIN GPIO5
//!
//! Without an additional I2S source device you can connect 3V3 or GND to DIN to
//! read 0 or 0xFF or connect DIN to WS to read two different values
//!
//! You can also inspect the MCLK, BCLK and WS with a logic analyzer
#![no_std]
#![no_main]
use esp32s3_hal::{
clock::ClockControl,
dma::DmaPriority,
gdma::Gdma,
i2s::{DataFormat, I2s, I2sReadDma, MclkPin, PinsBclkWsDin, Standard, I2s0New},
pac::Peripherals,
prelude::*,
timer::TimerGroup,
Rtc,
IO,
};
use esp_backtrace as _;
use esp_println::println;
use xtensa_lx_rt::entry;
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take().unwrap();
let mut system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt0 = timer_group0.wdt;
let timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
let mut wdt1 = timer_group1.wdt;
// Disable watchdog timers
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.disable();
wdt1.disable();
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let dma = Gdma::new(peripherals.DMA, &mut system.peripheral_clock_control);
let dma_channel = dma.channel0;
let mut tx_descriptors = [0u32; 8 * 3];
let mut rx_descriptors = [0u32; 8 * 3];
let i2s = I2s::new(
peripherals.I2S0,
MclkPin {
mclk: io.pins.gpio4,
},
Standard::Philips,
DataFormat::Data16Channel16,
44100u32.Hz(),
dma_channel.configure(
false,
&mut tx_descriptors,
&mut rx_descriptors,
DmaPriority::Priority0,
),
&mut system.peripheral_clock_control,
&clocks,
);
let i2s_rx = i2s.i2s_rx.with_pins(PinsBclkWsDin {
bclk: io.pins.gpio1,
ws: io.pins.gpio2,
din: io.pins.gpio5,
});
let buffer = dma_buffer();
let mut transfer = i2s_rx.read_dma_circular(buffer).unwrap();
println!("Started transfer");
loop {
let avail = transfer.available();
if avail > 0 {
let mut rcv = [0u8; 5000];
transfer.pop(&mut rcv[..avail]).unwrap();
println!("Received {:x?}...", &rcv[..30]);
}
}
}
fn dma_buffer() -> &'static mut [u8; 4092 * 4] {
static mut BUFFER: [u8; 4092 * 4] = [0u8; 4092 * 4];
unsafe { &mut BUFFER }
}

View File

@ -0,0 +1,143 @@
//! This shows how to transmit data continously via I2S
//!
//! Pins used
//! MCLK GPIO4
//! BCLK GPIO1
//! WS GPIO2
//! DOUT GPIO3
//!
//! Without an additional I2S sink device you can inspect the MCLK, BCLK, WS and
//! DOUT with a logic analyzer
//!
//! You can also connect e.g. a PCM510x to hear an annoying loud sine tone (full
//! scale), so turn down the volume before running this example.
//!
//! Wiring is like this
//!
//! | Pin | Connected to |
//! |-------|-----------------|
//! | BCK | GPIO1 |
//! | DIN | GPIO3 |
//! | LRCK | GPIO2 |
//! | SCK | Gnd |
//! | GND | Gnd |
//! | VIN | +3V3 |
//! | FLT | Gnd |
//! | FMT | Gnd |
//! | DEMP | Gnd |
//! | XSMT | +3V3 |
#![no_std]
#![no_main]
use esp32s3_hal::{
clock::ClockControl,
dma::DmaPriority,
gdma::Gdma,
i2s::{DataFormat, I2s, I2sWriteDma, MclkPin, PinsBclkWsDout, Standard, I2s0New},
pac::Peripherals,
prelude::*,
timer::TimerGroup,
Rtc,
IO,
};
use esp_backtrace as _;
use xtensa_lx_rt::entry;
const SINE: [i16; 64] = [
0, 3211, 6392, 9511, 12539, 15446, 18204, 20787, 23169, 25329, 27244, 28897, 30272, 31356,
32137, 32609, 32767, 32609, 32137, 31356, 30272, 28897, 27244, 25329, 23169, 20787, 18204,
15446, 12539, 9511, 6392, 3211, 0, -3211, -6392, -9511, -12539, -15446, -18204, -20787, -23169,
-25329, -27244, -28897, -30272, -31356, -32137, -32609, -32767, -32609, -32137, -31356, -30272,
-28897, -27244, -25329, -23169, -20787, -18204, -15446, -12539, -9511, -6392, -3211,
];
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take().unwrap();
let mut system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt0 = timer_group0.wdt;
let timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
let mut wdt1 = timer_group1.wdt;
// Disable watchdog timers
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.disable();
wdt1.disable();
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let dma = Gdma::new(peripherals.DMA, &mut system.peripheral_clock_control);
let dma_channel = dma.channel0;
let mut tx_descriptors = [0u32; 20 * 3];
let mut rx_descriptors = [0u32; 8 * 3];
let i2s = I2s::new(
peripherals.I2S0,
MclkPin {
mclk: io.pins.gpio4,
},
Standard::Philips,
DataFormat::Data16Channel16,
44100u32.Hz(),
dma_channel.configure(
false,
&mut tx_descriptors,
&mut rx_descriptors,
DmaPriority::Priority0,
),
&mut system.peripheral_clock_control,
&clocks,
);
let i2s_tx = i2s.i2s_tx.with_pins(PinsBclkWsDout {
bclk: io.pins.gpio1,
ws: io.pins.gpio2,
dout: io.pins.gpio3,
});
let data =
unsafe { core::slice::from_raw_parts(&SINE as *const _ as *const u8, SINE.len() * 2) };
let buffer = dma_buffer();
let mut idx = 0;
for i in 0..usize::min(data.len(), buffer.len()) {
buffer[i] = data[idx];
idx += 1;
if idx >= data.len() {
idx = 0;
}
}
let mut filler = [0u8; 10000];
let mut transfer = i2s_tx.write_dma_circular(buffer).unwrap();
loop {
let avail = transfer.available();
if avail > 0 {
let avail = usize::min(10000, avail);
for bidx in 0..avail {
filler[bidx] = data[idx];
idx += 1;
if idx >= data.len() {
idx = 0;
}
}
transfer.push(&filler[0..avail]).unwrap();
}
}
}
fn dma_buffer() -> &'static mut [u8; 32000] {
static mut BUFFER: [u8; 32000] = [0u8; 32000];
unsafe { &mut BUFFER }
}

View File

@ -11,6 +11,7 @@ pub use esp_hal_common::{
efuse, efuse,
gpio as gpio_types, gpio as gpio_types,
i2c, i2c,
i2s,
interrupt, interrupt,
ledc, ledc,
macros, macros,