mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-10-01 22:31:23 +00:00
Preliminary I2S Implementation
This commit is contained in:
parent
d9135350e7
commit
4afa8fda92
@ -119,6 +119,38 @@ macro_rules! impl_channel {
|
||||
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) {
|
||||
let dma = unsafe { &*crate::pac::DMA::PTR };
|
||||
|
||||
@ -225,6 +257,11 @@ macro_rules! impl_channel {
|
||||
|
||||
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>] {}
|
||||
@ -252,6 +289,12 @@ macro_rules! impl_channel {
|
||||
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(),
|
||||
};
|
||||
|
||||
@ -262,6 +305,12 @@ macro_rules! impl_channel {
|
||||
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(),
|
||||
};
|
||||
|
||||
@ -279,6 +328,9 @@ macro_rules! impl_channel {
|
||||
// with GDMA every channel can be used for any peripheral
|
||||
impl SpiPeripheral for [<SuitablePeripheral $num>] {}
|
||||
impl Spi2Peripheral for [<SuitablePeripheral $num>] {}
|
||||
impl I2sPeripheral for [<SuitablePeripheral $num>] {}
|
||||
impl I2s0Peripheral for [<SuitablePeripheral $num>] {}
|
||||
impl I2s1Peripheral for [<SuitablePeripheral $num>] {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ pub mod gdma;
|
||||
#[cfg(pdma)]
|
||||
pub mod pdma;
|
||||
|
||||
const CHUNK_SIZE: usize = 4092;
|
||||
|
||||
/// DMA Errors
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum DmaError {
|
||||
@ -16,6 +18,9 @@ pub enum DmaError {
|
||||
OutOfDescriptors,
|
||||
InvalidDescriptorSize,
|
||||
DescriptorError,
|
||||
Overflow,
|
||||
Exhausted,
|
||||
BufferTooSmall,
|
||||
}
|
||||
|
||||
/// DMA Priorities
|
||||
@ -51,9 +56,9 @@ pub enum DmaPeripheral {
|
||||
Spi3 = 1,
|
||||
#[cfg(any(esp32c3, esp32s3))]
|
||||
Uhci0 = 2,
|
||||
#[cfg(any(esp32c3, esp32s3))]
|
||||
#[cfg(any(esp32, esp32s2, esp32c3, esp32s3))]
|
||||
I2s0 = 3,
|
||||
#[cfg(esp32s3)]
|
||||
#[cfg(any(esp32, esp32s3))]
|
||||
I2s1 = 4,
|
||||
#[cfg(esp32s3)]
|
||||
LcdCam = 5,
|
||||
@ -89,7 +94,6 @@ trait DmaLinkedListDw0 {
|
||||
fn set_err_eof(&mut self, err_eof: bool);
|
||||
#[cfg(not(esp32))]
|
||||
fn get_err_eof(&mut self) -> bool;
|
||||
#[cfg(not(esp32))]
|
||||
fn set_suc_eof(&mut self, suc_eof: bool);
|
||||
fn get_suc_eof(&mut self) -> bool;
|
||||
fn set_owner(&mut self, owner: Owner);
|
||||
@ -134,7 +138,6 @@ impl DmaLinkedListDw0 for &mut u32 {
|
||||
((**self & (mask << bit_s)) >> bit_s) != 0
|
||||
}
|
||||
|
||||
#[cfg(not(esp32))]
|
||||
fn set_suc_eof(&mut self, suc_eof: bool) {
|
||||
let mask = 0b1;
|
||||
let bit_s = 30;
|
||||
@ -176,6 +179,15 @@ pub(crate) mod private {
|
||||
#[cfg(any(esp32, esp32s2, esp32s3))]
|
||||
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
|
||||
///
|
||||
/// 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(
|
||||
&mut self,
|
||||
circular: bool,
|
||||
peri: DmaPeripheral,
|
||||
data: *mut u8,
|
||||
len: usize,
|
||||
) -> Result<(), DmaError>;
|
||||
|
||||
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>
|
||||
@ -207,6 +224,7 @@ pub(crate) mod private {
|
||||
fn prepare_transfer(
|
||||
&mut self,
|
||||
descriptors: &mut [u32],
|
||||
circular: bool,
|
||||
peri: DmaPeripheral,
|
||||
data: *mut u8,
|
||||
len: usize,
|
||||
@ -220,16 +238,14 @@ pub(crate) mod private {
|
||||
let mut processed = 0;
|
||||
let mut descr = 0;
|
||||
loop {
|
||||
let chunk_size = usize::min(4092, len - processed);
|
||||
let chunk_size = usize::min(CHUNK_SIZE, len - processed);
|
||||
let last = processed + chunk_size >= len;
|
||||
|
||||
descriptors[descr + 1] = data as u32 + processed as u32;
|
||||
|
||||
let mut dw0 = &mut descriptors[descr];
|
||||
|
||||
#[cfg(not(esp32))]
|
||||
dw0.set_suc_eof(last);
|
||||
|
||||
dw0.set_suc_eof(true);
|
||||
dw0.set_owner(Owner::Dma);
|
||||
dw0.set_size(chunk_size as u16); // align to 32 bits?
|
||||
dw0.set_length(0); // actual size of the data!?
|
||||
@ -238,7 +254,11 @@ pub(crate) mod private {
|
||||
descriptors[descr + 2] =
|
||||
(&descriptors[descr + 3]) as *const _ as *const () as u32;
|
||||
} else {
|
||||
descriptors[descr + 2] = 0;
|
||||
descriptors[descr + 2] = if circular {
|
||||
descriptors.as_ptr() as *const () as u32
|
||||
} else {
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
processed += chunk_size;
|
||||
@ -265,6 +285,10 @@ pub(crate) mod private {
|
||||
fn is_done(&mut self) -> bool {
|
||||
R::is_in_done()
|
||||
}
|
||||
|
||||
fn last_in_dscr_address(&self) -> usize {
|
||||
R::last_in_dscr_address()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ChannelRx<'a, T, R>
|
||||
@ -275,6 +299,12 @@ pub(crate) mod private {
|
||||
pub descriptors: &'a mut [u32],
|
||||
pub burst_mode: bool,
|
||||
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>,
|
||||
}
|
||||
|
||||
@ -289,6 +319,7 @@ pub(crate) mod private {
|
||||
|
||||
fn prepare_transfer(
|
||||
&mut self,
|
||||
circular: bool,
|
||||
peri: DmaPeripheral,
|
||||
data: *mut u8,
|
||||
len: usize,
|
||||
@ -297,7 +328,7 @@ pub(crate) mod private {
|
||||
return Err(DmaError::InvalidDescriptorSize);
|
||||
}
|
||||
|
||||
if self.descriptors.len() / 3 < len / 4092 {
|
||||
if self.descriptors.len() / 3 < len / CHUNK_SIZE {
|
||||
return Err(DmaError::OutOfDescriptors);
|
||||
}
|
||||
|
||||
@ -305,8 +336,19 @@ pub(crate) mod private {
|
||||
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
|
||||
.prepare_transfer(self.descriptors, peri, data, len)?;
|
||||
.prepare_transfer(self.descriptors, circular, peri, data, len)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -317,6 +359,118 @@ pub(crate) mod private {
|
||||
fn init_channel(&mut self) {
|
||||
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
|
||||
@ -331,11 +485,16 @@ pub(crate) mod private {
|
||||
fn prepare_transfer(
|
||||
&mut self,
|
||||
peri: DmaPeripheral,
|
||||
circular: bool,
|
||||
data: *const u8,
|
||||
len: usize,
|
||||
) -> Result<(), DmaError>;
|
||||
|
||||
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>
|
||||
@ -350,6 +509,7 @@ pub(crate) mod private {
|
||||
fn prepare_transfer(
|
||||
&mut self,
|
||||
descriptors: &mut [u32],
|
||||
circular: bool,
|
||||
peri: DmaPeripheral,
|
||||
data: *const u8,
|
||||
len: usize,
|
||||
@ -363,16 +523,14 @@ pub(crate) mod private {
|
||||
let mut processed = 0;
|
||||
let mut descr = 0;
|
||||
loop {
|
||||
let chunk_size = usize::min(4092, len - processed);
|
||||
let chunk_size = usize::min(CHUNK_SIZE, len - processed);
|
||||
let last = processed + chunk_size >= len;
|
||||
|
||||
descriptors[descr + 1] = data as u32 + processed as u32;
|
||||
|
||||
let mut dw0 = &mut descriptors[descr];
|
||||
|
||||
#[cfg(not(esp32))]
|
||||
dw0.set_suc_eof(last);
|
||||
|
||||
dw0.set_suc_eof(true);
|
||||
dw0.set_owner(Owner::Dma);
|
||||
dw0.set_size(chunk_size as u16); // align to 32 bits?
|
||||
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 + 3]) as *const _ as *const () as u32;
|
||||
} else {
|
||||
descriptors[descr + 2] = 0;
|
||||
if !circular {
|
||||
descriptors[descr + 2] = 0;
|
||||
} else {
|
||||
descriptors[descr + 2] = descriptors.as_ptr() as u32;
|
||||
}
|
||||
}
|
||||
|
||||
processed += chunk_size;
|
||||
@ -408,6 +570,18 @@ pub(crate) mod private {
|
||||
fn is_done(&mut self) -> bool {
|
||||
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>
|
||||
@ -419,6 +593,12 @@ pub(crate) mod private {
|
||||
#[allow(unused)]
|
||||
pub burst_mode: bool,
|
||||
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>,
|
||||
}
|
||||
|
||||
@ -438,6 +618,7 @@ pub(crate) mod private {
|
||||
fn prepare_transfer(
|
||||
&mut self,
|
||||
peri: DmaPeripheral,
|
||||
circular: bool,
|
||||
data: *const u8,
|
||||
len: usize,
|
||||
) -> Result<(), DmaError> {
|
||||
@ -445,12 +626,23 @@ pub(crate) mod private {
|
||||
return Err(DmaError::InvalidDescriptorSize);
|
||||
}
|
||||
|
||||
if self.descriptors.len() / 3 < len / 4092 {
|
||||
if self.descriptors.len() / 3 < len / CHUNK_SIZE {
|
||||
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
|
||||
.prepare_transfer(self.descriptors, peri, data, len)?;
|
||||
.prepare_transfer(self.descriptors, circular, peri, data, len)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -458,6 +650,113 @@ pub(crate) mod private {
|
||||
fn is_done(&mut self) -> bool {
|
||||
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 {
|
||||
@ -471,6 +770,10 @@ pub(crate) mod private {
|
||||
fn set_out_peripheral(peripheral: u8);
|
||||
fn start_out();
|
||||
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_priority(priority: DmaPriority);
|
||||
fn clear_in_interrupts();
|
||||
@ -480,6 +783,7 @@ pub(crate) mod private {
|
||||
fn set_in_peripheral(peripheral: u8);
|
||||
fn start_in();
|
||||
fn is_in_done() -> bool;
|
||||
fn last_in_dscr_address() -> usize;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,6 +86,24 @@ macro_rules! ImplSpiChannel {
|
||||
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) {
|
||||
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
|
||||
spi.dma_conf
|
||||
@ -138,6 +156,11 @@ macro_rules! ImplSpiChannel {
|
||||
let spi = unsafe { &*crate::pac::[<SPI $num>]::PTR };
|
||||
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>] {}
|
||||
@ -169,6 +192,12 @@ macro_rules! ImplSpiChannel {
|
||||
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(),
|
||||
};
|
||||
|
||||
@ -179,6 +208,12 @@ macro_rules! ImplSpiChannel {
|
||||
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(),
|
||||
};
|
||||
|
||||
@ -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 {
|
||||
use crate::dma::{private::*, *};
|
||||
|
||||
@ -209,6 +449,25 @@ pub(crate) mod private {
|
||||
|
||||
ImplSpiChannel!(2);
|
||||
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
|
||||
@ -218,6 +477,9 @@ pub struct Dma {
|
||||
_inner: crate::system::Dma,
|
||||
pub spi2channel: Spi2DmaChannelCreator,
|
||||
pub spi3channel: Spi3DmaChannelCreator,
|
||||
pub i2s0channel: I2s0DmaChannelCreator,
|
||||
#[cfg(esp32)]
|
||||
pub i2s1channel: I2s1DmaChannelCreator,
|
||||
}
|
||||
|
||||
impl Dma {
|
||||
@ -232,6 +494,9 @@ impl Dma {
|
||||
_inner: dma,
|
||||
spi2channel: Spi2DmaChannelCreator {},
|
||||
spi3channel: Spi3DmaChannelCreator {},
|
||||
i2s0channel: I2s0DmaChannelCreator {},
|
||||
#[cfg(esp32)]
|
||||
i2s1channel: I2s1DmaChannelCreator {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ pub enum InputSignal {
|
||||
SUBSPID = 128,
|
||||
SUBSPIHD = 129,
|
||||
SUBSPIWP = 130,
|
||||
I2S0I_DATA_IN15 = 158,
|
||||
SUBSPID4 = 167,
|
||||
SUBSPID5 = 168,
|
||||
SUBSPID6 = 169,
|
||||
@ -73,95 +74,97 @@ pub enum InputSignal {
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(PartialEq, Copy, Clone)]
|
||||
pub enum OutputSignal {
|
||||
SPIQ = 0,
|
||||
SPID = 1,
|
||||
SPIHD = 2,
|
||||
SPIWP = 3,
|
||||
SPICLK = 4,
|
||||
SPICS0 = 5,
|
||||
SPICS1 = 6,
|
||||
SPID4 = 7,
|
||||
SPID5 = 8,
|
||||
SPID6 = 9,
|
||||
SPID7 = 10,
|
||||
SPIDQS = 11,
|
||||
U0TXD = 14,
|
||||
U0RTS = 15,
|
||||
U0DTR = 16,
|
||||
U1TXD = 17,
|
||||
U1RTS = 18,
|
||||
U1DTR = 21,
|
||||
I2S0O_BCK = 23,
|
||||
I2S0O_WS = 25,
|
||||
I2S0I_BCK = 27,
|
||||
I2S0I_WS = 28,
|
||||
I2CEXT0_SCL = 29,
|
||||
I2CEXT0_SDA = 30,
|
||||
SDIO_TOHOST_INT = 31,
|
||||
SPI3_CLK = 72,
|
||||
SPI3_Q = 73,
|
||||
SPI3_D = 74,
|
||||
SPI3_HD = 75,
|
||||
SPI3_CS0 = 76,
|
||||
SPI3_CS1 = 77,
|
||||
SPI3_CS2 = 78,
|
||||
LEDC_LS_SIG0 = 79,
|
||||
LEDC_LS_SIG1 = 80,
|
||||
LEDC_LS_SIG2 = 81,
|
||||
LEDC_LS_SIG3 = 82,
|
||||
LEDC_LS_SIG4 = 83,
|
||||
LEDC_LS_SIG5 = 84,
|
||||
LEDC_LS_SIG6 = 85,
|
||||
LEDC_LS_SIG7 = 86,
|
||||
RMT_SIG_OUT0 = 87,
|
||||
RMT_SIG_OUT1 = 88,
|
||||
RMT_SIG_OUT2 = 89,
|
||||
RMT_SIG_OUT3 = 90,
|
||||
I2CEXT1_SCL = 95,
|
||||
I2CEXT1_SDA = 96,
|
||||
GPIO_SD0 = 100,
|
||||
GPIO_SD1 = 101,
|
||||
GPIO_SD2 = 102,
|
||||
GPIO_SD3 = 103,
|
||||
GPIO_SD4 = 104,
|
||||
GPIO_SD5 = 105,
|
||||
GPIO_SD6 = 106,
|
||||
GPIO_SD7 = 107,
|
||||
FSPICLK = 108,
|
||||
FSPIQ = 109,
|
||||
FSPID = 110,
|
||||
FSPIHD = 111,
|
||||
FSPIWP = 112,
|
||||
FSPIIO4 = 113,
|
||||
FSPIIO5 = 114,
|
||||
FSPIIO6 = 115,
|
||||
FSPIIO7 = 116,
|
||||
FSPICS0 = 117,
|
||||
FSPICS1 = 118,
|
||||
FSPICS2 = 119,
|
||||
FSPICS3 = 120,
|
||||
FSPICS4 = 121,
|
||||
FSPICS5 = 122,
|
||||
SUBSPICLK = 126,
|
||||
SUBSPIQ = 127,
|
||||
SUBSPID = 128,
|
||||
SUBSPIHD = 129,
|
||||
SUBSPIWP = 130,
|
||||
SUBSPICS0 = 131,
|
||||
SUBSPICS1 = 132,
|
||||
FSPIDQS = 133,
|
||||
FSPI_HSYNC = 134,
|
||||
FSPI_VSYNC = 135,
|
||||
FSPI_DE = 136,
|
||||
FSPICD = 137,
|
||||
SPI3_CD = 139,
|
||||
SPI3_DQS = 140,
|
||||
SUBSPID4 = 167,
|
||||
SUBSPID5 = 168,
|
||||
SUBSPID6 = 169,
|
||||
SUBSPID7 = 170,
|
||||
SUBSPIDQS = 171,
|
||||
PCMFSYNC = 209,
|
||||
PCMCLK = 210,
|
||||
GPIO = 256,
|
||||
SPIQ = 0,
|
||||
SPID = 1,
|
||||
SPIHD = 2,
|
||||
SPIWP = 3,
|
||||
SPICLK = 4,
|
||||
SPICS0 = 5,
|
||||
SPICS1 = 6,
|
||||
SPID4 = 7,
|
||||
SPID5 = 8,
|
||||
SPID6 = 9,
|
||||
SPID7 = 10,
|
||||
SPIDQS = 11,
|
||||
U0TXD = 14,
|
||||
U0RTS = 15,
|
||||
U0DTR = 16,
|
||||
U1TXD = 17,
|
||||
U1RTS = 18,
|
||||
U1DTR = 21,
|
||||
I2S0O_BCK = 23,
|
||||
I2S0O_WS = 25,
|
||||
I2S0I_BCK = 27,
|
||||
I2S0I_WS = 28,
|
||||
I2CEXT0_SCL = 29,
|
||||
I2CEXT0_SDA = 30,
|
||||
SDIO_TOHOST_INT = 31,
|
||||
SPI3_CLK = 72,
|
||||
SPI3_Q = 73,
|
||||
SPI3_D = 74,
|
||||
SPI3_HD = 75,
|
||||
SPI3_CS0 = 76,
|
||||
SPI3_CS1 = 77,
|
||||
SPI3_CS2 = 78,
|
||||
LEDC_LS_SIG0 = 79,
|
||||
LEDC_LS_SIG1 = 80,
|
||||
LEDC_LS_SIG2 = 81,
|
||||
LEDC_LS_SIG3 = 82,
|
||||
LEDC_LS_SIG4 = 83,
|
||||
LEDC_LS_SIG5 = 84,
|
||||
LEDC_LS_SIG6 = 85,
|
||||
LEDC_LS_SIG7 = 86,
|
||||
RMT_SIG_OUT0 = 87,
|
||||
RMT_SIG_OUT1 = 88,
|
||||
RMT_SIG_OUT2 = 89,
|
||||
RMT_SIG_OUT3 = 90,
|
||||
I2CEXT1_SCL = 95,
|
||||
I2CEXT1_SDA = 96,
|
||||
GPIO_SD0 = 100,
|
||||
GPIO_SD1 = 101,
|
||||
GPIO_SD2 = 102,
|
||||
GPIO_SD3 = 103,
|
||||
GPIO_SD4 = 104,
|
||||
GPIO_SD5 = 105,
|
||||
GPIO_SD6 = 106,
|
||||
GPIO_SD7 = 107,
|
||||
FSPICLK = 108,
|
||||
FSPIQ = 109,
|
||||
FSPID = 110,
|
||||
FSPIHD = 111,
|
||||
FSPIWP = 112,
|
||||
FSPIIO4 = 113,
|
||||
FSPIIO5 = 114,
|
||||
FSPIIO6 = 115,
|
||||
FSPIIO7 = 116,
|
||||
FSPICS0 = 117,
|
||||
FSPICS1 = 118,
|
||||
FSPICS2 = 119,
|
||||
FSPICS3 = 120,
|
||||
FSPICS4 = 121,
|
||||
FSPICS5 = 122,
|
||||
SUBSPICLK = 126,
|
||||
SUBSPIQ = 127,
|
||||
SUBSPID = 128,
|
||||
SUBSPIHD = 129,
|
||||
SUBSPIWP = 130,
|
||||
SUBSPICS0 = 131,
|
||||
SUBSPICS1 = 132,
|
||||
FSPIDQS = 133,
|
||||
FSPI_HSYNC = 134,
|
||||
FSPI_VSYNC = 135,
|
||||
FSPI_DE = 136,
|
||||
FSPICD = 137,
|
||||
SPI3_CD = 139,
|
||||
SPI3_DQS = 140,
|
||||
I2S0O_DATA_OUT23 = 166,
|
||||
SUBSPID4 = 167,
|
||||
SUBSPID5 = 168,
|
||||
SUBSPID6 = 169,
|
||||
SUBSPID7 = 170,
|
||||
SUBSPIDQS = 171,
|
||||
PCMFSYNC = 209,
|
||||
PCMCLK = 210,
|
||||
CLK_I2S = 251,
|
||||
GPIO = 256,
|
||||
}
|
||||
|
1725
esp-hal-common/src/i2s.rs
Normal file
1725
esp-hal-common/src/i2s.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -56,6 +56,10 @@ pub mod dma;
|
||||
pub mod embassy;
|
||||
pub mod gpio;
|
||||
pub mod i2c;
|
||||
|
||||
#[cfg(any(esp32c3, esp32s3, esp32, esp32s2))]
|
||||
pub mod i2s;
|
||||
|
||||
pub mod ledc;
|
||||
#[cfg(usb_otg)]
|
||||
pub mod otg_fs;
|
||||
|
@ -1000,8 +1000,18 @@ where
|
||||
self.enable_dma();
|
||||
self.update();
|
||||
|
||||
tx.prepare_transfer(self.dma_peripheral(), write_buffer_ptr, write_buffer_len)?;
|
||||
rx.prepare_transfer(self.dma_peripheral(), read_buffer_ptr, read_buffer_len)?;
|
||||
tx.prepare_transfer(
|
||||
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();
|
||||
|
||||
@ -1033,7 +1043,7 @@ where
|
||||
self.enable_dma();
|
||||
self.update();
|
||||
|
||||
tx.prepare_transfer(self.dma_peripheral(), ptr, len)?;
|
||||
tx.prepare_transfer(self.dma_peripheral(), false, ptr, len)?;
|
||||
|
||||
self.clear_dma_interrupts();
|
||||
|
||||
@ -1054,7 +1064,7 @@ where
|
||||
self.enable_dma();
|
||||
self.update();
|
||||
|
||||
rx.prepare_transfer(self.dma_peripheral(), ptr, len)?;
|
||||
rx.prepare_transfer(false, self.dma_peripheral(), ptr, len)?;
|
||||
|
||||
self.clear_dma_interrupts();
|
||||
|
||||
|
@ -34,6 +34,10 @@ pub enum Peripheral {
|
||||
Gdma,
|
||||
#[cfg(pdma)]
|
||||
Dma,
|
||||
#[cfg(not(esp32c2))]
|
||||
I2s0,
|
||||
#[cfg(not(any(esp32c2, esp32s2, esp32c3)))]
|
||||
I2s1,
|
||||
#[cfg(usb_otg)]
|
||||
Usb,
|
||||
}
|
||||
@ -122,6 +126,22 @@ impl PeripheralClockControl {
|
||||
perip_clk_en0.modify(|_, w| w.spi3_dma_clk_en().set_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)]
|
||||
Peripheral::Usb => {
|
||||
perip_clk_en0.modify(|_, w| w.usb_clk_en().set_bit());
|
||||
|
94
esp32-hal/examples/i2s_read.rs
Normal file
94
esp32-hal/examples/i2s_read.rs
Normal 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 }
|
||||
}
|
136
esp32-hal/examples/i2s_sound.rs
Normal file
136
esp32-hal/examples/i2s_sound.rs
Normal 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 }
|
||||
}
|
@ -10,6 +10,7 @@ pub use esp_hal_common::{
|
||||
efuse,
|
||||
gpio as gpio_types,
|
||||
i2c,
|
||||
i2s,
|
||||
interrupt,
|
||||
ledc,
|
||||
macros,
|
||||
|
101
esp32c3-hal/examples/i2s_read.rs
Normal file
101
esp32c3-hal/examples/i2s_read.rs
Normal 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 }
|
||||
}
|
143
esp32c3-hal/examples/i2s_sound.rs
Normal file
143
esp32c3-hal/examples/i2s_sound.rs
Normal 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 }
|
||||
}
|
@ -13,6 +13,7 @@ pub use esp_hal_common::{
|
||||
efuse,
|
||||
gpio as gpio_types,
|
||||
i2c,
|
||||
i2s,
|
||||
interrupt,
|
||||
ledc,
|
||||
macros,
|
||||
|
94
esp32s2-hal/examples/i2s_read.rs
Normal file
94
esp32s2-hal/examples/i2s_read.rs
Normal 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 }
|
||||
}
|
139
esp32s2-hal/examples/i2s_sound.rs
Normal file
139
esp32s2-hal/examples/i2s_sound.rs
Normal 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 }
|
||||
}
|
@ -8,6 +8,7 @@ pub use esp_hal_common::{
|
||||
dma::pdma,
|
||||
efuse,
|
||||
gpio as gpio_types,
|
||||
i2s,
|
||||
i2c::{self, I2C},
|
||||
interrupt,
|
||||
ledc,
|
||||
|
101
esp32s3-hal/examples/i2s_read.rs
Normal file
101
esp32s3-hal/examples/i2s_read.rs
Normal 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 }
|
||||
}
|
143
esp32s3-hal/examples/i2s_sound.rs
Normal file
143
esp32s3-hal/examples/i2s_sound.rs
Normal 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 }
|
||||
}
|
@ -11,6 +11,7 @@ pub use esp_hal_common::{
|
||||
efuse,
|
||||
gpio as gpio_types,
|
||||
i2c,
|
||||
i2s,
|
||||
interrupt,
|
||||
ledc,
|
||||
macros,
|
||||
|
Loading…
x
Reference in New Issue
Block a user