Skip to content

Commit 21c280a

Browse files
committed
Check buffer pointer alignment, disallow using i64/u64 words in buffers
1 parent af83e6e commit 21c280a

File tree

5 files changed

+49
-7
lines changed

5 files changed

+49
-7
lines changed

examples/i2s-controller-demo/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ cortex-m = "0.6.2"
1212
cortex-m-rtic = "0.5.3"
1313
rtt-target = {version = "0.2.0", features = ["cortex-m"] }
1414
nrf52840-hal = { features = ["rt"], path = "../../nrf52840-hal" }
15+
aligned = "0.3.4"
1516
heapless = "0.5.5"
1617
small_morse = "0.1.0"
1718

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// Generates Morse code audio signals for text from UART, playing back over I2S
66
// Tested with nRF52840-DK and a UDA1334a DAC
77

8+
use aligned::{Aligned, A4};
89
use embedded_hal::digital::v2::{InputPin, OutputPin};
910
use heapless::{
1011
consts::*,
@@ -51,8 +52,9 @@ const APP: () = {
5152

5253
#[init(resources = [queue], spawn = [tick])]
5354
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];
55+
// The I2S buffer address must be 4 byte aligned.
56+
static mut MUTE_BUF: Aligned<A4, [i16; 32]> = Aligned([0i16; 32]);
57+
static mut SIGNAL_BUF: Aligned<A4, [i16; 32]> = Aligned([0i16; 32]);
5658

5759
// Fill signal buffer with triangle waveform, 2 channels interleaved
5860
let len = SIGNAL_BUF.len() / 2;

examples/i2s-peripheral-demo/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ cortex-m = "0.6.2"
1212
cortex-m-rtic = "0.5.3"
1313
rtt-target = {version = "0.2.0", features = ["cortex-m"] }
1414
nrf52840-hal = { features = ["rt"], path = "../../nrf52840-hal" }
15+
aligned = "0.3.4"
1516

1617
[dependencies.embedded-hal]
1718
version = "0.2.3"

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// I2S `peripheral mode` demo
55
// Signal average level indicator using an RGB LED (APA102 on ItsyBitsy nRF52840)
66

7+
use aligned::{Aligned, A4};
78
use embedded_hal::blocking::spi::Write;
89
use {
910
core::{
@@ -29,12 +30,13 @@ const RED: [u8; 9] = [0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x10, 0xFF];
2930
const APP: () = {
3031
struct Resources {
3132
rgb: Spim<SPIM0>,
32-
transfer: Option<Transfer<&'static mut [i16; 128]>>,
33+
transfer: Option<Transfer<&'static mut [i16]>>,
3334
}
3435

3536
#[init]
3637
fn init(ctx: init::Context) -> init::LateResources {
37-
static mut RX_BUF: [i16; 128] = [0; 128];
38+
// The I2S buffer address must be 4 byte aligned.
39+
static mut RX_BUF: Aligned<A4, [i16; 128]> = Aligned([0; 128]);
3840

3941
let _clocks = hal::clocks::Clocks::new(ctx.device.CLOCK).enable_ext_hfosc();
4042
rtt_init_print!();
@@ -78,7 +80,7 @@ const APP: () = {
7880
);
7981
init::LateResources {
8082
rgb,
81-
transfer: i2s.rx(RX_BUF).ok(),
83+
transfer: i2s.rx(&mut RX_BUF[..]).ok(),
8284
}
8385
}
8486

@@ -87,7 +89,7 @@ const APP: () = {
8789
let (rx_buf, i2s) = ctx.resources.transfer.take().unwrap().wait();
8890
if i2s.is_event_triggered(I2SEvent::RxPtrUpdated) {
8991
i2s.reset_event(I2SEvent::RxPtrUpdated);
90-
//Calculate mono summed average of received buffer
92+
// Calculate mono summed average of received buffer
9193
let avg = (rx_buf.iter().map(|x| (*x).abs() as u32).sum::<u32>() / rx_buf.len() as u32)
9294
as u16;
9395
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)