Skip to content

Commit

Permalink
Dmac (#391)
Browse files Browse the repository at this point in the history
* Initial commit

* Fixed silly warning

* Big documentation improvements, add a few helper
functions to DmaController and Channel

* Add support for SAMD51/SAMEx. Add unsafe API. Documentation improvements. Untested on SAMD11 and Cortex-M4 chips.

* Enable unsafe support for *mut T buffers; rustfmt run

* Add Round-Robin Arbitration support

* Rustfmt

* Merge cfg features in common/mod.rs

Merge #[cfg(feature = "unproven")] and #[cfg(feature = "dma")] in common/mod.rs

* Change atomic::compiler_fence to atomic::fence

* Minor refactors based on @bradleyharden's review. The bigger changes will come in separate commits.

* Change the way `DmaTransfer`s are created

* Removed "Dma" prefix on types

* Add incrementing-to-incrementing TransferConfiguration impl for slices

* Update feather_m0 and feather_m4 examples

* Remove pointer math

* Made Beat an associated type of Buffer

* Big refactor. Replaced TransferConfiguration with AnyBufferPair trait. modular_bitfields and various macros

* Bugfix and added Transfer::new_from_arrays

* Implemented AnyChannel. Made holding a payload by the transfer optional.

* Use standalone typenum crate in anticipation of removal of generic-array

* Removed typenum dependency entirely

* Add #[repr(uXX)] to bitfield definitions

* Implemented @bradleyharden's suggestions.

- Minor doc corrections
- Switched type-level enums from structs to ennums
- Changed DmaController::dmac_mut to DmaController::dmac
- Removed redundant DmaController::split method
  • Loading branch information
jbeaurivage authored Mar 24, 2021
1 parent cfe7152 commit d24c3c5
Show file tree
Hide file tree
Showing 10 changed files with 1,674 additions and 0 deletions.
6 changes: 6 additions & 0 deletions boards/feather_m0/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ panic_semihosting = ["panic-semihosting"]
rfm = []
# Enable pins for the flash and neopixel on the Feather M0 Express
express = []
dma = ["atsamd-hal/dma"]
max-channels = ["dma", "atsamd-hal/max-channels"]

[profile.dev]
incremental = false
Expand Down Expand Up @@ -124,6 +126,10 @@ name = "sleeping_timer"
[[example]]
name = "sleeping_timer_rtc"

[[example]]
name = "dmac"
required-features = ["dma"]

[[example]]
name = "clock"
required-features = ["usb"]
102 changes: 102 additions & 0 deletions boards/feather_m0/examples/dmac.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//! This example shows a safe API to
//! execute a memory-to-memory DMA transfer
#![no_std]
#![no_main]

use cortex_m::asm;
use feather_m0 as hal;
use panic_halt as _;

use hal::{
clock::GenericClockController,
entry,
pac::{CorePeripherals, Peripherals},
};

use hal::dmac::{DmaController, PriorityLevel, Transfer, TriggerAction, TriggerSource};

#[entry]
fn main() -> ! {
let mut peripherals = Peripherals::take().unwrap();
let core = CorePeripherals::take().unwrap();
let _clocks = GenericClockController::with_internal_32kosc(
peripherals.GCLK,
&mut peripherals.PM,
&mut peripherals.SYSCTRL,
&mut peripherals.NVMCTRL,
);

let mut pm = peripherals.PM;
let dmac = peripherals.DMAC;
let _nvic = core.NVIC;

// Initialize buffers
const LENGTH: usize = 50;
let buf_src: &'static mut [u8; LENGTH] =
cortex_m::singleton!(: [u8; LENGTH] = [0xff; LENGTH]).unwrap();
let buf_dest: &'static mut [u8; LENGTH] =
cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap();

// Initialize DMA Controller
let mut dmac = DmaController::init(dmac, &mut pm);
// Get individual handles to DMA channels
let channels = dmac.split();

// Initialize DMA Channel 0
let chan0 = channels.0.init(&mut dmac, PriorityLevel::LVL0, false);

// Setup a DMA transfer (memory-to-memory -> incrementing source, incrementing
// destination) with a 8-bit beat size
let xfer = Transfer::new_from_arrays(chan0, buf_src, buf_dest, false).begin(
&mut dmac,
TriggerSource::DISABLE,
TriggerAction::BLOCK,
);

// Wait for transfer to complete and grab resulting buffers
let (chan0, buf_src, buf_dest, _) = xfer.wait(&mut dmac);

// Read the returned buffers
let _a = buf_src[LENGTH - 1];
let _b = buf_dest[LENGTH - 1];

let const_16: &'static mut u16 = cortex_m::singleton!(: u16 = 0xADDE).unwrap();
let buf_16: &'static mut [u16; LENGTH] =
cortex_m::singleton!(:[u16; LENGTH] = [0x0000; LENGTH]).unwrap();

// Setup a DMA transfer (memory-to-memory -> fixed source, incrementing
// destination) with a 16-bit beat size. Demonstrate payload management.
let xfer = Transfer::new(chan0, const_16, buf_16, false)
.with_payload(pm)
.begin(&mut dmac, TriggerSource::DISABLE, TriggerAction::BLOCK);

let (chan0, const_16, buf_16, _pm) = xfer.wait(&mut dmac);

// Read the returned buffers
let _a = *const_16;
let _b = buf_16[LENGTH - 1];

// Manipulate the returned buffer for fun
for i in 0..LENGTH {
buf_16[i] = i as u16;
}

// Setup a DMA transfer (memory-to-memory -> incrementing source, fixed
// destination) with a 16-bit beat size
let xfer = Transfer::new(chan0, buf_16, const_16, false).begin(
&mut dmac,
TriggerSource::DISABLE,
TriggerAction::BLOCK,
);

let (_chan0, buf_16, const_16, _) = xfer.wait(&mut dmac);

// Read the returned buffers
let _a = *const_16; // We expect the value "LENGTH - 1" to end up here
let _b = buf_16[LENGTH - 1];

loop {
asm::nop();
}
}
7 changes: 7 additions & 0 deletions boards/feather_m4/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ default = ["rt", "atsamd-hal/samd51j", "atsamd-hal/samd51"]
rt = ["cortex-m-rt", "atsamd-hal/samd51j-rt"]
unproven = ["atsamd-hal/unproven"]
usb = ["atsamd-hal/usb", "usb-device", "usbd-serial"]
dma = ["atsamd-hal/dma", "unproven"]
max-channels = ["dma", "atsamd-hal/dma"]


[profile.dev]
incremental = false
Expand All @@ -67,3 +70,7 @@ required-features = ["usb"]

[[example]]
name = "sleeping_timer_rtc"

[[example]]
name = "dmac"
required-features = ["dma"]
106 changes: 106 additions & 0 deletions boards/feather_m4/examples/dmac.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//! This example shows a safe API to
//! execute a memory-to-memory DMA transfer
#![no_std]
#![no_main]

use cortex_m::asm;
use feather_m4 as hal;
use panic_halt as _;

use hal::{
clock::GenericClockController,
entry,
pac::{CorePeripherals, Peripherals},
};

use hal::dmac::{
BurstLength, DmaController, FifoThreshold, PriorityLevel, Transfer, TriggerAction,
TriggerSource,
};

#[entry]
fn main() -> ! {
let mut peripherals = Peripherals::take().unwrap();
let core = CorePeripherals::take().unwrap();
let _clocks = GenericClockController::with_external_32kosc(
peripherals.GCLK,
&mut peripherals.MCLK,
&mut peripherals.OSC32KCTRL,
&mut peripherals.OSCCTRL,
&mut peripherals.NVMCTRL,
);

let mut pm = peripherals.PM;
let dmac = peripherals.DMAC;
let _nvic = core.NVIC;

// Initialize buffers
const LENGTH: usize = 50;
let buf_src: &'static mut [u8; LENGTH] =
cortex_m::singleton!(: [u8; LENGTH] = [0xff; LENGTH]).unwrap();
let buf_dest: &'static mut [u8; LENGTH] =
cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap();

// Initialize DMA Controller
let mut dmac = DmaController::init(dmac, &mut pm);
// Get individual handles to DMA channels
let channels = dmac.split();

// Initialize DMA Channel 0
let chan0 = channels.0.init(&mut dmac, PriorityLevel::LVL0, false);

// Setup a DMA transfer (memory-to-memory -> incrementing source, incrementing
// destination) with a 8-bit beat size
let xfer = Transfer::new_from_arrays(chan0, buf_src, buf_dest, false).begin(
&mut dmac,
TriggerSource::DISABLE,
TriggerAction::BLOCK,
);

// Wait for transfer to complete and grab resulting buffers
let (chan0, buf_src, buf_dest, _) = xfer.wait(&mut dmac);

// Read the returned buffers
let _a = buf_src[LENGTH - 1];
let _b = buf_dest[LENGTH - 1];

let const_16: &'static mut u16 = cortex_m::singleton!(: u16 = 0xADDE).unwrap();
let buf_16: &'static mut [u16; LENGTH] =
cortex_m::singleton!(:[u16; LENGTH] = [0x0000; LENGTH]).unwrap();

// Setup a DMA transfer (memory-to-memory -> fixed source, incrementing
// destination) with a 16-bit beat size. Demonstrate payload management.
let xfer = Transfer::new(chan0, const_16, buf_16, false)
.with_payload(pm)
.begin(&mut dmac, TriggerSource::DISABLE, TriggerAction::BLOCK);

let (chan0, const_16, buf_16, _pm) = xfer.wait(&mut dmac);

// Read the returned buffers
let _a = *const_16;
let _b = buf_16[LENGTH - 1];

// Manipulate the returned buffer for fun
for i in 0..LENGTH {
buf_16[i] = i as u16;
}

// Setup a DMA transfer (memory-to-memory -> incrementing source, fixed
// destination) with a 16-bit beat size
let xfer = Transfer::new(chan0, buf_16, const_16, false).begin(
&mut dmac,
TriggerSource::DISABLE,
TriggerAction::BLOCK,
);

let (_chan0, buf_16, const_16, _) = xfer.wait(&mut dmac);

// Read the returned buffers
let _a = *const_16; // We expect the value "LENGTH - 1" to end up here
let _b = buf_16[LENGTH - 1];

loop {
asm::nop();
}
}
3 changes: 3 additions & 0 deletions hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ bitfield = "0.13"
bitflags = "1.2.1"
cortex-m = "0.6"
embedded-hal = "0.2"
modular-bitfield = "0.11"
nb = "0.1"
paste = "1.0"
rand_core = "0.5"
Expand Down Expand Up @@ -178,3 +179,5 @@ min-samd51p = ["min-samd51n"]
unproven = ["embedded-hal/unproven"]
use_rtt = ["jlink_rtt"]
usb = ["usb-device"]
dma = ["unproven"]
max-channels = ["dma"]
Loading

0 comments on commit d24c3c5

Please sign in to comment.