Skip to content

Commit 2913282

Browse files
Merge pull request #225 from kalkyl/i2s-dma2
Add check for I2S buffer pointer alignment
2 parents af83e6e + fe2e822 commit 2913282

File tree

3 files changed

+60
-16
lines changed

3 files changed

+60
-16
lines changed

examples/i2s-controller-demo/src/main.rs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@ use {
2929
rtt_target::{rprintln, rtt_init_print},
3030
};
3131

32+
#[repr(align(4))]
33+
struct Aligned<T: ?Sized>(T);
34+
3235
#[rtic::app(device = crate::hal::pac, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
3336
const APP: () = {
3437
struct Resources {
35-
signal_buf: &'static [i16],
36-
mute_buf: &'static [i16],
38+
signal_buf: &'static [i16; 32],
39+
mute_buf: &'static [i16; 32],
3740
#[init(None)]
3841
queue: Option<Queue<State, U256>>,
3942
producer: Producer<'static, State, U256>,
@@ -46,19 +49,20 @@ const APP: () = {
4649
btn1: Pin<Input<PullUp>>,
4750
btn2: Pin<Input<PullUp>>,
4851
led: Pin<Output<PushPull>>,
49-
transfer: Option<Transfer<&'static [i16]>>,
52+
transfer: Option<Transfer<&'static [i16; 32]>>,
5053
}
5154

5255
#[init(resources = [queue], spawn = [tick])]
5356
fn init(mut ctx: init::Context) -> init::LateResources {
54-
static mut MUTE_BUF: [i16; 32] = [0i16; 32];
55-
static mut SIGNAL_BUF: [i16; 32] = [0i16; 32];
57+
// The I2S buffer address must be 4 byte aligned.
58+
static mut MUTE_BUF: Aligned<[i16; 32]> = Aligned([0i16; 32]);
59+
static mut SIGNAL_BUF: Aligned<[i16; 32]> = Aligned([0i16; 32]);
5660

5761
// Fill signal buffer with triangle waveform, 2 channels interleaved
58-
let len = SIGNAL_BUF.len() / 2;
62+
let len = SIGNAL_BUF.0.len() / 2;
5963
for x in 0..len {
60-
SIGNAL_BUF[2 * x] = triangle_wave(x as i32, len, 2048, 0, 1) as i16;
61-
SIGNAL_BUF[2 * x + 1] = triangle_wave(x as i32, len, 2048, 0, 1) as i16;
64+
SIGNAL_BUF.0[2 * x] = triangle_wave(x as i32, len, 2048, 0, 1) as i16;
65+
SIGNAL_BUF.0[2 * x + 1] = triangle_wave(x as i32, len, 2048, 0, 1) as i16;
6266
}
6367

6468
let _clocks = hal::clocks::Clocks::new(ctx.device.CLOCK).enable_ext_hfosc();
@@ -72,8 +76,8 @@ const APP: () = {
7276
// Configure I2S controller
7377
let mck_pin = p0.p0_28.into_push_pull_output(Level::Low).degrade();
7478
let sck_pin = p0.p0_29.into_push_pull_output(Level::Low).degrade();
75-
let lrck_pin = p0.p0_31.into_push_pull_output(Level::Low).degrade();
7679
let sdout_pin = p0.p0_30.into_push_pull_output(Level::Low).degrade();
80+
let lrck_pin = p0.p0_31.into_push_pull_output(Level::Low).degrade();
7781

7882
let i2s = I2S::new_controller(
7983
ctx.device.I2S,
@@ -124,9 +128,9 @@ const APP: () = {
124128
led: p0.p0_13.into_push_pull_output(Level::High).degrade(),
125129
uarte,
126130
uarte_timer: Timer::new(ctx.device.TIMER0),
127-
transfer: i2s.tx(&MUTE_BUF[..]).ok(),
128-
signal_buf: &SIGNAL_BUF[..],
129-
mute_buf: &MUTE_BUF[..],
131+
transfer: i2s.tx(&MUTE_BUF.0).ok(),
132+
signal_buf: &SIGNAL_BUF.0,
133+
mute_buf: &MUTE_BUF.0,
130134
}
131135
}
132136

examples/i2s-peripheral-demo/src/main.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ use {
2020
rtt_target::{rprintln, rtt_init_print},
2121
};
2222

23+
#[repr(align(4))]
24+
struct Aligned<T: ?Sized>(T);
25+
2326
const OFF: [u8; 9] = [0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF];
2427
const GREEN: [u8; 9] = [0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x10, 0x00, 0xFF];
2528
const ORANGE: [u8; 9] = [0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x10, 0x10, 0xFF];
@@ -34,7 +37,8 @@ const APP: () = {
3437

3538
#[init]
3639
fn init(ctx: init::Context) -> init::LateResources {
37-
static mut RX_BUF: [i16; 128] = [0; 128];
40+
// The I2S buffer address must be 4 byte aligned.
41+
static mut RX_BUF: Aligned<[i16; 128]> = Aligned([0; 128]);
3842

3943
let _clocks = hal::clocks::Clocks::new(ctx.device.CLOCK).enable_ext_hfosc();
4044
rtt_init_print!();
@@ -78,7 +82,7 @@ const APP: () = {
7882
);
7983
init::LateResources {
8084
rgb,
81-
transfer: i2s.rx(RX_BUF).ok(),
85+
transfer: i2s.rx(&mut RX_BUF.0).ok(),
8286
}
8387
}
8488

@@ -87,7 +91,7 @@ const APP: () = {
8791
let (rx_buf, i2s) = ctx.resources.transfer.take().unwrap().wait();
8892
if i2s.is_event_triggered(I2SEvent::RxPtrUpdated) {
8993
i2s.reset_event(I2SEvent::RxPtrUpdated);
90-
//Calculate mono summed average of received buffer
94+
// Calculate mono summed average of received buffer
9195
let avg = (rx_buf.iter().map(|x| (*x).abs() as u32).sum::<u32>() / rx_buf.len() as u32)
9296
as u16;
9397
let color = match avg {

nrf-hal-common/src/i2s.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,14 +259,20 @@ impl I2S {
259259
_ => Channels::Right,
260260
}
261261
}
262+
262263
/// Receives data into the given `buffer` until it's filled.
264+
/// Buffer address must be 4 byte aligned and located in RAM.
263265
/// Returns a value that represents the in-progress DMA transfer.
264266
#[allow(unused_mut)]
265267
pub fn rx<W, B>(mut self, mut buffer: B) -> Result<Transfer<B>, Error>
266268
where
269+
W: SupportedWordSize,
267270
B: WriteBuffer<Word = W>,
268271
{
269272
let (ptr, len) = unsafe { buffer.write_buffer() };
273+
if ptr as u32 % 4 != 0 {
274+
return Err(Error::BufferMisaligned);
275+
}
270276
let maxcnt = (len / (core::mem::size_of::<u32>() / core::mem::size_of::<W>())) as u32;
271277
if maxcnt > MAX_DMA_MAXCNT {
272278
return Err(Error::BufferTooLong);
@@ -283,7 +289,8 @@ impl I2S {
283289

284290
/// Full duplex DMA transfer.
285291
/// Transmits the given `tx_buffer` while simultaneously receiving data
286-
/// into the given `rx_buffer` until it is filled. The buffers must be of equal size.
292+
/// into the given `rx_buffer` until it is filled.
293+
/// The buffers must be of equal size and their addresses must be 4 byte aligned and located in RAM.
287294
/// Returns a value that represents the in-progress DMA transfer.
288295
#[allow(unused_mut)]
289296
pub fn transfer<W, TxB, RxB>(
@@ -292,11 +299,15 @@ impl I2S {
292299
mut rx_buffer: RxB,
293300
) -> Result<TransferFullDuplex<TxB, RxB>, Error>
294301
where
302+
W: SupportedWordSize,
295303
TxB: ReadBuffer<Word = W>,
296304
RxB: WriteBuffer<Word = W>,
297305
{
298306
let (rx_ptr, rx_len) = unsafe { rx_buffer.write_buffer() };
299307
let (tx_ptr, tx_len) = unsafe { tx_buffer.read_buffer() };
308+
if tx_ptr as u32 % 4 != 0 || rx_ptr as u32 % 4 != 0 {
309+
return Err(Error::BufferMisaligned);
310+
}
300311
let maxcnt = (tx_len / (core::mem::size_of::<u32>() / core::mem::size_of::<W>())) as u32;
301312
if tx_len != rx_len {
302313
return Err(Error::BuffersDontMatch);
@@ -328,13 +339,18 @@ impl I2S {
328339
}
329340

330341
/// Transmits the given `tx_buffer`.
342+
/// Buffer address must be 4 byte aligned and located in RAM.
331343
/// Returns a value that represents the in-progress DMA transfer.
332344
#[allow(unused_mut)]
333345
pub fn tx<W, B>(mut self, buffer: B) -> Result<Transfer<B>, Error>
334346
where
347+
W: SupportedWordSize,
335348
B: ReadBuffer<Word = W>,
336349
{
337350
let (ptr, len) = unsafe { buffer.read_buffer() };
351+
if ptr as u32 % 4 != 0 {
352+
return Err(Error::BufferMisaligned);
353+
}
338354
let maxcnt = (len / (core::mem::size_of::<u32>() / core::mem::size_of::<W>())) as u32;
339355
if maxcnt > MAX_DMA_MAXCNT {
340356
return Err(Error::BufferTooLong);
@@ -468,6 +484,7 @@ pub enum Error {
468484
DMABufferNotInDataMemory,
469485
BufferTooLong,
470486
BuffersDontMatch,
487+
BufferMisaligned,
471488
}
472489

473490
/// I2S Mode
@@ -650,3 +667,22 @@ impl<TxB, RxB> Drop for TransferFullDuplex<TxB, RxB> {
650667
}
651668
}
652669
}
670+
671+
pub trait SupportedWordSize: private::Sealed {}
672+
impl private::Sealed for i8 {}
673+
impl SupportedWordSize for i8 {}
674+
impl private::Sealed for u8 {}
675+
impl SupportedWordSize for u8 {}
676+
impl private::Sealed for i16 {}
677+
impl SupportedWordSize for i16 {}
678+
impl private::Sealed for u16 {}
679+
impl SupportedWordSize for u16 {}
680+
impl private::Sealed for i32 {}
681+
impl SupportedWordSize for i32 {}
682+
impl private::Sealed for u32 {}
683+
impl SupportedWordSize for u32 {}
684+
685+
mod private {
686+
/// Prevents code outside of the parent module from implementing traits.
687+
pub trait Sealed {}
688+
}

0 commit comments

Comments
 (0)