Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use DMA Transfer API in I2S module #209

Merged
merged 5 commits into from
Sep 4, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions examples/i2s-peripheral-demo/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ const RED: [u8; 9] = [0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x10, 0xFF];
const APP: () = {
struct Resources {
rgb: Spim<SPIM0>,
transfer: Option<Transfer<&'static mut [i16]>>,
transfer: Option<Transfer<&'static mut [i16; 128]>>,
}

#[init]
fn init(ctx: init::Context) -> init::LateResources {
static mut RX_BUF: [i16; 128] = [0i16; 128];
static mut RX_BUF: [i16; 128] = [0; 128];

let _clocks = hal::clocks::Clocks::new(ctx.device.CLOCK).enable_ext_hfosc();
rtt_init_print!();
Expand Down Expand Up @@ -78,7 +78,7 @@ const APP: () = {
);
init::LateResources {
rgb,
transfer: i2s.rx(&mut RX_BUF[..]).ok(),
transfer: i2s.rx(RX_BUF).ok(),
}
}

Expand All @@ -87,7 +87,7 @@ const APP: () = {
let (rx_buf, i2s) = ctx.resources.transfer.take().unwrap().wait();
if i2s.is_event_triggered(I2SEvent::RxPtrUpdated) {
i2s.reset_event(I2SEvent::RxPtrUpdated);
// Calculate mono summed average of received buffer
//Calculate mono summed average of received buffer
let avg = (rx_buf.iter().map(|x| (*x).abs() as u32).sum::<u32>() / rx_buf.len() as u32)
as u16;
let color = match avg {
Expand Down
5 changes: 1 addition & 4 deletions nrf-hal-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,7 @@ nb = "1.0.0"
fixed = "1.0.0"
rand_core = "0.5.1"
cfg-if = "0.1.10"

[dependencies.stable_deref_trait]
version = "1.2.0"
default-features = false
embedded-dma = "0.1.1"

[dependencies.void]
default-features = false
Expand Down
228 changes: 34 additions & 194 deletions nrf-hal-common/src/i2s.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@ use crate::{
pac::generic::Reg,
target_constants::{SRAM_LOWER, SRAM_UPPER},
};
use core::{
ops::{Deref, DerefMut},
sync::atomic::{compiler_fence, Ordering},
};
pub use stable_deref_trait::StableDeref;
use core::sync::atomic::{compiler_fence, Ordering};
use embedded_dma::*;

use i2s::{_EVENTS_RXPTRUPD, _EVENTS_STOPPED, _EVENTS_TXPTRUPD, _TASKS_START, _TASKS_STOP};

Expand All @@ -23,7 +20,7 @@ pub struct I2S {
}

// I2S EasyDMA MAXCNT bit length = 14
const MAX_DMA_MAXCNT: u32 = 16_384;
const MAX_DMA_MAXCNT: u32 = 1 << 14;

impl I2S {
/// Takes ownership of the raw I2S peripheral, returning a safe wrapper in controller mode.
Expand Down Expand Up @@ -265,23 +262,20 @@ impl I2S {
/// Receives data into the given `buffer` until it's filled.
/// Returns a value that represents the in-progress DMA transfer.
#[allow(unused_mut)]
pub fn rx<Word, B>(mut self, mut buffer: B) -> Result<Transfer<B>, Error>
pub fn rx<W, B>(mut self, mut buffer: B) -> Result<Transfer<B>, Error>
where
Word: SupportedWordSize,
B: DerefMut + StableDeref + 'static + I2SBuffer,
B::Target: AsMut<[Word]>,
B: WriteBuffer<Word = W>,
{
if buffer.maxcnt() > MAX_DMA_MAXCNT {
let (ptr, len) = unsafe { buffer.write_buffer() };
let maxcnt = (len / (core::mem::size_of::<u32>() / core::mem::size_of::<W>())) as u32;
if maxcnt > MAX_DMA_MAXCNT {
return Err(Error::BufferTooLong);
}
self.i2s
.rxd
.ptr
.write(|w| unsafe { w.ptr().bits(buffer.ptr()) });
self.i2s
.rxtxd
.maxcnt
.write(|w| unsafe { w.bits(buffer.maxcnt()) });
.write(|w| unsafe { w.ptr().bits(ptr as u32) });
self.i2s.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) });
Ok(Transfer {
inner: Some(Inner { buffer, i2s: self }),
})
Expand All @@ -292,42 +286,37 @@ impl I2S {
/// into the given `rx_buffer` until it is filled. The buffers must be of equal size.
/// Returns a value that represents the in-progress DMA transfer.
#[allow(unused_mut)]
pub fn transfer<Word, TxB, RxB>(
pub fn transfer<W, TxB, RxB>(
mut self,
tx_buffer: TxB,
mut rx_buffer: RxB,
) -> Result<TransferFullDuplex<TxB, RxB>, Error>
where
Word: SupportedWordSize,
TxB: Deref + StableDeref + 'static + I2SBuffer,
TxB::Target: AsRef<[Word]>,
RxB: DerefMut + StableDeref + 'static + I2SBuffer,
RxB::Target: AsMut<[Word]>,
TxB: ReadBuffer<Word = W>,
RxB: WriteBuffer<Word = W>,
{
if (tx_buffer.ptr() as usize) < SRAM_LOWER || (tx_buffer.ptr() as usize) > SRAM_UPPER {
return Err(Error::DMABufferNotInDataMemory);
}
if tx_buffer.maxcnt() != rx_buffer.maxcnt() {
let (rx_ptr, rx_len) = unsafe { rx_buffer.write_buffer() };
let (tx_ptr, tx_len) = unsafe { tx_buffer.read_buffer() };
let maxcnt = (tx_len / (core::mem::size_of::<u32>() / core::mem::size_of::<W>())) as u32;
if tx_len != rx_len {
return Err(Error::BuffersDontMatch);
}
if tx_buffer.maxcnt() > MAX_DMA_MAXCNT {
if maxcnt > MAX_DMA_MAXCNT {
return Err(Error::BufferTooLong);
}
if (tx_ptr as usize) < SRAM_LOWER || (tx_ptr as usize) > SRAM_UPPER {
return Err(Error::DMABufferNotInDataMemory);
}

self.i2s
.txd
.ptr
.write(|w| unsafe { w.ptr().bits(tx_buffer.ptr()) });
.write(|w| unsafe { w.ptr().bits(tx_ptr as u32) });
self.i2s
.rxd
.ptr
.write(|w| unsafe { w.ptr().bits(rx_buffer.ptr()) });
self.i2s
.rxtxd
.maxcnt
.write(|w| unsafe { w.bits(rx_buffer.maxcnt()) });

self.start();
.write(|w| unsafe { w.ptr().bits(rx_ptr as u32) });
self.i2s.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) });

Ok(TransferFullDuplex {
inner: Some(InnerFullDuplex {
Expand All @@ -341,28 +330,24 @@ impl I2S {
/// Transmits the given `tx_buffer`.
/// Returns a value that represents the in-progress DMA transfer.
#[allow(unused_mut)]
pub fn tx<Word, B>(mut self, buffer: B) -> Result<Transfer<B>, Error>
pub fn tx<W, B>(mut self, buffer: B) -> Result<Transfer<B>, Error>
where
Word: SupportedWordSize,
B: Deref + StableDeref + 'static + I2SBuffer,
B::Target: AsRef<[Word]>,
B: ReadBuffer<Word = W>,
{
if (buffer.ptr() as usize) < SRAM_LOWER || (buffer.ptr() as usize) > SRAM_UPPER {
return Err(Error::DMABufferNotInDataMemory);
}

if buffer.maxcnt() > MAX_DMA_MAXCNT {
let (ptr, len) = unsafe { buffer.read_buffer() };
let maxcnt = (len / (core::mem::size_of::<u32>() / core::mem::size_of::<W>())) as u32;
if maxcnt > MAX_DMA_MAXCNT {
return Err(Error::BufferTooLong);
}
if (ptr as usize) < SRAM_LOWER || (ptr as usize) > SRAM_UPPER {
jonas-schievink marked this conversation as resolved.
Show resolved Hide resolved
return Err(Error::DMABufferNotInDataMemory);
}

self.i2s
.txd
.ptr
.write(|w| unsafe { w.ptr().bits(buffer.ptr()) });
self.i2s
.rxtxd
.maxcnt
.write(|w| unsafe { w.bits(buffer.maxcnt()) });
.write(|w| unsafe { w.ptr().bits(ptr as u32) });
self.i2s.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) });

Ok(Transfer {
inner: Some(Inner { buffer, i2s: self }),
Expand Down Expand Up @@ -598,132 +583,6 @@ pub enum I2SEvent {
Stopped,
}

/// Trait to represent valid sample buffers.
pub trait I2SBuffer: private::Sealed {
fn ptr(&self) -> u32;
fn maxcnt(&self) -> u32;
}

impl private::Sealed for &[i8] {}
impl I2SBuffer for &[i8] {
fn ptr(&self) -> u32 {
self.as_ptr() as u32
}
fn maxcnt(&self) -> u32 {
self.len() as u32 / 4
}
}

impl private::Sealed for &[i16] {}
impl I2SBuffer for &[i16] {
fn ptr(&self) -> u32 {
self.as_ptr() as u32
}
fn maxcnt(&self) -> u32 {
self.len() as u32 / 2
}
}

impl private::Sealed for &[i32] {}
impl I2SBuffer for &[i32] {
fn ptr(&self) -> u32 {
self.as_ptr() as u32
}
fn maxcnt(&self) -> u32 {
self.len() as u32
}
}

impl private::Sealed for &[u8] {}
impl I2SBuffer for &[u8] {
fn ptr(&self) -> u32 {
self.as_ptr() as u32
}
fn maxcnt(&self) -> u32 {
self.len() as u32 / 8
}
}

impl private::Sealed for &[u16] {}
impl I2SBuffer for &[u16] {
fn ptr(&self) -> u32 {
self.as_ptr() as u32
}
fn maxcnt(&self) -> u32 {
self.len() as u32 / 4
}
}

impl private::Sealed for &[u32] {}
impl I2SBuffer for &[u32] {
fn ptr(&self) -> u32 {
self.as_ptr() as u32
}
fn maxcnt(&self) -> u32 {
self.len() as u32 / 2
}
}

impl private::Sealed for &mut [i8] {}
impl I2SBuffer for &mut [i8] {
fn ptr(&self) -> u32 {
self.as_ptr() as u32
}
fn maxcnt(&self) -> u32 {
self.len() as u32 / 4
}
}

impl private::Sealed for &mut [i16] {}
impl I2SBuffer for &mut [i16] {
fn ptr(&self) -> u32 {
self.as_ptr() as u32
}
fn maxcnt(&self) -> u32 {
self.len() as u32 / 2
}
}

impl private::Sealed for &mut [i32] {}
impl I2SBuffer for &mut [i32] {
fn ptr(&self) -> u32 {
self.as_ptr() as u32
}
fn maxcnt(&self) -> u32 {
self.len() as u32
}
}

impl private::Sealed for &mut [u8] {}
impl I2SBuffer for &mut [u8] {
fn ptr(&self) -> u32 {
self.as_ptr() as u32
}
fn maxcnt(&self) -> u32 {
self.len() as u32 / 8
}
}

impl private::Sealed for &mut [u16] {}
impl I2SBuffer for &mut [u16] {
fn ptr(&self) -> u32 {
self.as_ptr() as u32
}
fn maxcnt(&self) -> u32 {
self.len() as u32 / 4
}
}

impl private::Sealed for &mut [u32] {}
impl I2SBuffer for &mut [u32] {
fn ptr(&self) -> u32 {
self.as_ptr() as u32
}
fn maxcnt(&self) -> u32 {
self.len() as u32 / 2
}
}

/// A DMA transfer
pub struct Transfer<B> {
inner: Option<Inner<B>>,
Expand Down Expand Up @@ -791,22 +650,3 @@ impl<TxB, RxB> Drop for TransferFullDuplex<TxB, RxB> {
}
}
}

pub trait SupportedWordSize: private::Sealed {}
impl private::Sealed for i8 {}
impl SupportedWordSize for i8 {}
impl private::Sealed for i16 {}
impl SupportedWordSize for i16 {}
impl private::Sealed for i32 {}
impl SupportedWordSize for i32 {}
impl private::Sealed for u8 {}
impl SupportedWordSize for u8 {}
impl private::Sealed for u16 {}
impl SupportedWordSize for u16 {}
impl private::Sealed for u32 {}
impl SupportedWordSize for u32 {}

mod private {
/// Prevents code outside of the parent module from implementing traits.
pub trait Sealed {}
}