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

DMA support for all chip variants #86

Merged
merged 7 commits into from
Oct 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
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
45 changes: 12 additions & 33 deletions imxrt-hal/src/dma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,19 +153,21 @@
#![allow(non_snake_case)] // Compatibility with RAL

mod buffer;
mod chip;
mod element;
mod memcpy;
pub(crate) mod peripheral;
mod register;

pub use buffer::{Buffer, Circular, CircularError, Drain, Linear, ReadHalf, WriteHalf};
pub use chip::CHANNEL_COUNT;
pub use element::Element;
pub use memcpy::Memcpy;
pub use peripheral::{helpers::*, Peripheral};

use crate::{ccm, ral};
use core::{
fmt::{self, Debug, Display},
fmt::{self, Debug},
mem,
};
pub use register::tcd::BandwidthControl;
Expand All @@ -181,7 +183,7 @@ use register::{DMARegisters, MultiplexerRegisters, Static, DMA, MULTIPLEXER};
/// DMA channels have very little public interface. They're best used when paired with a
/// [`Peripheral`](struct.Peripheral.html) or a [`Memcpy`](struct.Memcpy.html).
pub struct Channel {
/// Our channel number, expected to be between 0 to 31
/// Our channel number, expected to be between 0 and (CHANNEL_COUNT - 1)
index: usize,
/// Reference to the DMA registers
registers: Static<DMARegisters>,
Expand All @@ -205,7 +207,7 @@ impl Channel {

/// Returns the DMA channel number
///
/// Channels are unique and numbered within the half-open range `[0, 32)`.
/// Channels are unique and numbered within the half-open range `[0, CHANNEL_COUNT)`.
pub fn channel(&self) -> usize {
self.index
}
Expand Down Expand Up @@ -457,7 +459,7 @@ pub enum Error<P> {
/// let channel_27 = dma_channels[27].take().unwrap();
/// let channel_0 = dma_channels[0].take().unwrap();
/// ```
pub struct Unclocked([Option<Channel>; 32]);
pub struct Unclocked([Option<Channel>; CHANNEL_COUNT]);
impl Unclocked {
pub(crate) fn new(dma: ral::dma0::Instance, mux: ral::dmamux::Instance) -> Self {
// Explicitly dropping instances
Expand All @@ -467,20 +469,18 @@ impl Unclocked {
drop(dma);
drop(mux);

Unclocked([
None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None,
])
Unclocked(chip::DMA_CHANNEL_INIT)
}
/// Enable the clocks for the DMA peripheral
///
/// The return is 32 channels, each being initialized as `Some(Channel)`. Users may take channels as needed.
/// The index in the array maps to the DMA channel number.
/// The return is an array of 32 channels. However, **only the first [`CHANNEL_COUNT`](constant.CHANNEL_COUNT.html) channels
/// are initialized to `Some(channel)`. The rest are `None`.**
///
/// Users may take channels as needed. The index in the array maps to the DMA channel number.
pub fn clock(mut self, ccm: &mut ccm::Handle) -> [Option<Channel>; 32] {
let (ccm, _) = ccm.raw();
ral::modify_reg!(ral::ccm, ccm, CCGR5, CG3: 0x03);
for (idx, channel) in self.0.iter_mut().enumerate() {
for (idx, channel) in self.0.iter_mut().take(CHANNEL_COUNT).enumerate() {
*channel = Some(Channel::new(idx));
}
self.0
Expand Down Expand Up @@ -512,27 +512,6 @@ impl Debug for ErrorStatus {
}
}

impl Display for ErrorStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f,
"DMA_ES: VLD {vld} ECX {ecx} GPE {gpe} CPE {cpe} ERRCHN {errchn} SAE {sae} SOE {soe} DAE {dae} DOE {doe} NCE {nce} SGE {sge} SBE {sbe} DBE {dbe}",
vld = (self.es >> 31) & 0x1,
ecx = (self.es >> 16) & 0x1,
gpe = (self.es >> 15) & 0x1,
cpe = (self.es >> 14) & 0x1,
errchn = (self.es >> 8) & 0x1F,
sae = (self.es >> 7) & 0x1,
soe = (self.es >> 6) & 0x1,
dae = (self.es >> 5) & 0x1,
doe = (self.es >> 4) & 0x1,
nce = (self.es >> 3) & 0x1,
sge = (self.es >> 2) & 0x1,
sbe = (self.es >> 1) & 0x1,
dbe = self.es & 0x1
)
}
}

/// Describes a DMA transfer
///
/// `Transfer` describes a source or a destination of a DMA transfer. See the member
Expand Down
99 changes: 99 additions & 0 deletions imxrt-hal/src/dma/chip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//! The DMA chip module contains any DMA configurations that are
//! particular for a i.MX RT chip or chip family
//!
//! Things that are known to differ:
//!
//! - DMA channels
//! - Availability of DMA channel grouping, group scheduling, and error indications. As
//! of this writing, DMA channel grouping and group scheduling is not implemented, so
//! we can ignore that for now. We vary the way we display `ErrorStatus` messages.

use super::ErrorStatus;
use core::fmt::{self, Display};

//
// Specify the DMA channel count
//

/// The number of DMA channels
///
/// This varies depending on the i.MX RT processor variant. Consult your
/// reference manual for more information.
#[cfg(feature = "imxrt1011")]
pub const CHANNEL_COUNT: usize = 16;

/// The number of DMA channels
///
/// This varies depending on the i.MX RT processor variant. Consult your
/// reference manual for more information.
#[cfg(not(feature = "imxrt1011"))]
pub const CHANNEL_COUNT: usize = 32;

/// Helper symbol to support DMA channel initialization
///
/// We always provide users with an array of 32 channels. But, only the first `CHANNEL_COUNT`
/// channels are initialized.
pub(crate) const DMA_CHANNEL_INIT: [Option<super::Channel>; 32] = [
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
];

//
// Conditionally display group priority errors (GPE), and handle
// different masks for error channel (ERRCHN)
//

#[cfg(feature = "imxrt1011")]
impl Display for ErrorStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f,
"DMA_ES: VLD {vld} ECX {ecx} CPE {cpe} ERRCHN {errchn} SAE {sae} SOE {soe} DAE {dae} DOE {doe} NCE {nce} SGE {sge} SBE {sbe} DBE {dbe}",
vld = (self.es >> 31) & 0x1,
ecx = (self.es >> 16) & 0x1,
// No GPE
cpe = (self.es >> 14) & 0x1,
errchn = (self.es >> 8) & 0x0F, // Four bits for error channel
sae = (self.es >> 7) & 0x1,
soe = (self.es >> 6) & 0x1,
dae = (self.es >> 5) & 0x1,
doe = (self.es >> 4) & 0x1,
nce = (self.es >> 3) & 0x1,
sge = (self.es >> 2) & 0x1,
sbe = (self.es >> 1) & 0x1,
dbe = self.es & 0x1
)
}
}

#[cfg(not(feature = "imxrt1011"))]
impl Display for ErrorStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f,
"DMA_ES: VLD {vld} ECX {ecx} GPE {gpe} CPE {cpe} ERRCHN {errchn} SAE {sae} SOE {soe} DAE {dae} DOE {doe} NCE {nce} SGE {sge} SBE {sbe} DBE {dbe}",
vld = (self.es >> 31) & 0x1,
ecx = (self.es >> 16) & 0x1,
gpe = (self.es >> 15) & 0x1,
cpe = (self.es >> 14) & 0x1,
errchn = (self.es >> 8) & 0x1F, // Five bits for error channel
sae = (self.es >> 7) & 0x1,
soe = (self.es >> 6) & 0x1,
dae = (self.es >> 5) & 0x1,
doe = (self.es >> 4) & 0x1,
nce = (self.es >> 3) & 0x1,
sge = (self.es >> 2) & 0x1,
sbe = (self.es >> 1) & 0x1,
dbe = self.es & 0x1
)
}
}

//
// These don't vary across chips.
// They're only in this module to
// show that we thought about that.
//

/// Address to the DMA multiplexer registers
pub(crate) const DMA_MULTIPLEXER_ADDRESS: *const u32 = 0x400E_C000 as *const _;
/// Address to the DMA peripheral registers
pub(crate) const DMA_ADDRESS: *const u32 = 0x400E_8000 as *const _;
11 changes: 6 additions & 5 deletions imxrt-hal/src/dma/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ use core::ops::Index;
#[repr(C)]
pub(super) struct MultiplexerRegisters {
/// Multiplexer configuration registers, one per channel
pub chcfg: [RWRegister<u32>; 32],
pub chcfg: [RWRegister<u32>; super::CHANNEL_COUNT],
}

pub(super) const MULTIPLEXER: Static<MultiplexerRegisters> = Static(0x400E_C000 as *const _);
pub(super) const MULTIPLEXER: Static<MultiplexerRegisters> =
Static(super::chip::DMA_MULTIPLEXER_ADDRESS as *const _);

impl MultiplexerRegisters {
pub const ENBL: u32 = 1 << 31;
Expand Down Expand Up @@ -72,10 +73,10 @@ pub(super) struct DMARegisters {
pub DCHPRI: ChannelPriorityRegisters,
_reserved8: [u32; 952],
/// Transfer Control Descriptors
pub TCD: [TransferControlDescriptor; 32],
pub TCD: [TransferControlDescriptor; super::CHANNEL_COUNT],
}

pub(super) const DMA: Static<DMARegisters> = Static(0x400E_8000 as *const _);
pub(super) const DMA: Static<DMARegisters> = Static(super::chip::DMA_ADDRESS as *const _);

/// Wrapper for channel priority registers
///
Expand All @@ -85,7 +86,7 @@ pub(super) const DMA: Static<DMARegisters> = Static(0x400E_8000 as *const _);
/// the channel number to a reference to the priority
/// register.
#[repr(transparent)]
pub(super) struct ChannelPriorityRegisters([RWRegister<u8>; 32]);
pub(super) struct ChannelPriorityRegisters([RWRegister<u8>; super::CHANNEL_COUNT]);

impl Index<usize> for ChannelPriorityRegisters {
type Output = RWRegister<u8>;
Expand Down