Skip to content

Commit

Permalink
Merge pull request #209 from kalkyl/i2s-dma
Browse files Browse the repository at this point in the history
Use DMA Transfer API in I2S module
  • Loading branch information
jonas-schievink authored Sep 4, 2020
2 parents 78add9d + 3b4cc4b commit c3d01a2
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 123 deletions.
47 changes: 24 additions & 23 deletions examples/i2s-controller-demo/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,8 @@ use {
#[rtic::app(device = crate::hal::pac, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
const APP: () = {
struct Resources {
i2s: hal::i2s::I2S,
#[init([0; 32])]
signal_buf: [i16; 32],
#[init([0; 32])]
mute_buf: [i16; 32],
signal_buf: &'static [i16],
mute_buf: &'static [i16],
#[init(None)]
queue: Option<Queue<State, U256>>,
producer: Producer<'static, State, U256>,
Expand All @@ -49,10 +46,21 @@ const APP: () = {
btn1: Pin<Input<PullUp>>,
btn2: Pin<Input<PullUp>>,
led: Pin<Output<PushPull>>,
transfer: Option<Transfer<&'static [i16]>>,
}

#[init(resources = [queue, signal_buf, mute_buf], spawn = [tick])]
#[init(resources = [queue], spawn = [tick])]
fn init(mut ctx: init::Context) -> init::LateResources {
static mut MUTE_BUF: [i16; 32] = [0i16; 32];
static mut SIGNAL_BUF: [i16; 32] = [0i16; 32];

// Fill signal buffer with triangle waveform, 2 channels interleaved
let len = SIGNAL_BUF.len() / 2;
for x in 0..len {
SIGNAL_BUF[2 * x] = triangle_wave(x as i32, len, 2048, 0, 1) as i16;
SIGNAL_BUF[2 * x + 1] = triangle_wave(x as i32, len, 2048, 0, 1) as i16;
}

let _clocks = hal::clocks::Clocks::new(ctx.device.CLOCK).enable_ext_hfosc();
// Enable the monotonic timer (CYCCNT)
ctx.core.DCB.enable_trace();
Expand All @@ -75,16 +83,7 @@ const APP: () = {
None,
Some(&sdout_pin),
);
i2s.tx_buffer(&ctx.resources.mute_buf[..]).ok();
i2s.enable().start();

// Fill signal buffer with triangle waveform, 2 channels interleaved
let signal_buf = ctx.resources.signal_buf;
let len = signal_buf.len() / 2;
for x in 0..len {
signal_buf[2 * x] = triangle_wave(x as i32, len, 2048, 0, 1) as i16;
signal_buf[2 * x + 1] = triangle_wave(x as i32, len, 2048, 0, 1) as i16;
}
i2s.start();

// Configure buttons
let btn1 = p0.p0_11.into_pullup_input().degrade();
Expand Down Expand Up @@ -117,7 +116,6 @@ const APP: () = {
ctx.spawn.tick().ok();

init::LateResources {
i2s,
producer,
consumer,
gpiote,
Expand All @@ -126,6 +124,9 @@ const APP: () = {
led: p0.p0_13.into_push_pull_output(Level::High).degrade(),
uarte,
uarte_timer: Timer::new(ctx.device.TIMER0),
transfer: i2s.tx(&MUTE_BUF[..]).ok(),
signal_buf: &SIGNAL_BUF[..],
mute_buf: &MUTE_BUF[..],
}
}

Expand All @@ -150,7 +151,7 @@ const APP: () = {
}
}
Err(hal::uarte::Error::Timeout(n)) if n > 0 => {
if let Ok(msg) = core::str::from_utf8(&uarte_rx_buf[0..n]) {
if let Ok(msg) = core::str::from_utf8(&uarte_rx_buf[..n]) {
rprintln!("{}", msg);
for action in encode(msg) {
for _ in 0..action.duration {
Expand All @@ -164,18 +165,18 @@ const APP: () = {
}
}

#[task(resources = [consumer, i2s, signal_buf, mute_buf, led, speed], schedule = [tick])]
#[task(resources = [consumer, transfer, signal_buf, mute_buf, led, speed], schedule = [tick])]
fn tick(ctx: tick::Context) {
let i2s = ctx.resources.i2s;
let (_buf, i2s) = ctx.resources.transfer.take().unwrap().wait();
match ctx.resources.consumer.dequeue() {
Some(State::On) => {
// Move TX pointer to signal buffer (sound ON)
i2s.tx_buffer(&ctx.resources.signal_buf[..]).ok();
*ctx.resources.transfer = i2s.tx(*ctx.resources.signal_buf).ok();
ctx.resources.led.set_low().ok();
}
_ => {
// Move TX pointer to silent buffer (sound OFF)
i2s.tx_buffer(&ctx.resources.mute_buf[..]).ok();
*ctx.resources.transfer = i2s.tx(*ctx.resources.mute_buf).ok();
ctx.resources.led.set_high().ok();
}
}
Expand All @@ -190,7 +191,7 @@ const APP: () = {
ctx.schedule.debounce(ctx.start + 3_000_000.cycles()).ok();
}

#[task(resources = [btn1, btn2, i2s, speed])]
#[task(resources = [btn1, btn2, speed])]
fn debounce(ctx: debounce::Context) {
if ctx.resources.btn1.is_low().unwrap() {
rprintln!("Go slower");
Expand Down
2 changes: 0 additions & 2 deletions examples/i2s-peripheral-demo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ cortex-m = "0.6.2"
cortex-m-rtic = "0.5.3"
rtt-target = {version = "0.2.0", features = ["cortex-m"] }
nrf52840-hal = { features = ["rt"], path = "../../nrf52840-hal" }
small_morse = "0.1.0"
m = "0.1.1"

[dependencies.embedded-hal]
version = "0.2.3"
Expand Down
39 changes: 18 additions & 21 deletions examples/i2s-peripheral-demo/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
#![no_main]

// I2S `peripheral mode` demo
// RMS level indicator using an RGB LED (APA102 on ItsyBitsy nRF52840)
// Signal average level indicator using an RGB LED (APA102 on ItsyBitsy nRF52840)

use embedded_hal::blocking::spi::Write;
use m::Float;
use {
core::{
panic::PanicInfo,
Expand All @@ -29,14 +28,14 @@ const RED: [u8; 9] = [0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x10, 0xFF];
#[rtic::app(device = crate::hal::pac, peripherals = true)]
const APP: () = {
struct Resources {
i2s: I2S,
#[init([0; 128])]
rx_buf: [i16; 128],
rgb: Spim<SPIM0>,
transfer: Option<Transfer<&'static mut [i16; 128]>>,
}

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

let _clocks = hal::clocks::Clocks::new(ctx.device.CLOCK).enable_ext_hfosc();
rtt_init_print!();
rprintln!("Play me some audio...");
Expand All @@ -56,10 +55,7 @@ const APP: () = {
Some(&sdin_pin),
None,
);
i2s.enable_interrupt(I2SEvent::RxPtrUpdated)
.rx_buffer(&mut ctx.resources.rx_buf[..])
.ok();
i2s.enable().start();
i2s.enable_interrupt(I2SEvent::RxPtrUpdated).start();

// Configure APA102 RGB LED control
let p1 = hal::gpio::p1::Parts::new(ctx.device.P1);
Expand All @@ -80,28 +76,29 @@ const APP: () = {
},
0,
);

init::LateResources { i2s, rgb }
init::LateResources {
rgb,
transfer: i2s.rx(RX_BUF).ok(),
}
}

#[task(binds = I2S, resources = [i2s, rx_buf, rgb])]
#[task(binds = I2S, resources = [rgb, transfer])]
fn on_i2s(ctx: on_i2s::Context) {
let on_i2s::Resources { i2s, rx_buf, rgb } = ctx.resources;
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 RMS of received buffer
let rms = Float::sqrt(
(rx_buf.iter().map(|x| *x as i32).map(|x| x * x).sum::<i32>() / rx_buf.len() as i32)
as f32,
) as u16;
let color = match rms {
//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 {
0..=4 => &OFF,
5..=10_337 => &GREEN,
10_338..=16_383 => &ORANGE,
_ => &RED,
};
<Spim<SPIM0> as Write<u8>>::write(rgb, color).ok();
<Spim<SPIM0> as Write<u8>>::write(ctx.resources.rgb, color).ok();
}
*ctx.resources.transfer = i2s.rx(rx_buf).ok();
}
};

Expand Down
1 change: 1 addition & 0 deletions nrf-hal-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ nb = "1.0.0"
fixed = "1.0.0"
rand_core = "0.5.1"
cfg-if = "0.1.10"
embedded-dma = "0.1.1"

[dependencies.void]
default-features = false
Expand Down
Loading

0 comments on commit c3d01a2

Please sign in to comment.