Struct mnemos_d1_core::dmac::Channel
source · pub struct Channel {
idx: u8,
xfer_done: &'static WaitCell,
}
Expand description
A DMA channel.
Channels are used to perform DMA transfers using the Channel::transfer
method. Before performing a transfer, a channel must be configured with the
desired ChannelMode
s using Channel::set_channel_modes
.
The DMA controller owns a shared pool of 16 DMA channels, which may be used
by drivers to initiate DMA transfers. Channels can be acquired from the
shared pool using the Dmac::claim_channel
and
Dmac::try_claim_channel
methods. Dropping a Channel
releases it back
to the shared pool, allowing it to be claimed by other drivers.
Fields§
§idx: u8
§xfer_done: &'static WaitCell
Implementations§
source§impl Channel
impl Channel
sourcepub fn channel_index(&self) -> u8
pub fn channel_index(&self) -> u8
Returns the channel index of this channel, from 0 to 15.
sourcepub async unsafe fn transfer(&mut self, desc: NonNull<Descriptor>)
pub async unsafe fn transfer(&mut self, desc: NonNull<Descriptor>)
Performs a DMA transfer described by the provided Descriptor
on this
channel.
§Safety
The caller must ensure that the descriptor pointed to by desc
, and the
associated memory region used by the transfer, is valid for as long as
the DMA transfer is active. When this function returns, the transfer has
completed, and it is safe to drop the descriptor. If this future is
cancelled, the transfer is cancelled and the descriptor
and its associated buffer may be dropped safely. However, it is super
ultra not okay to core::mem::forget
this future. If you
mem::forget
a DMA transfer future inside your driver, you deserve
whatever happens next.
§Cancel Safety
Dropping this future cancels the DMA transfer. If this future is dropped, the descriptor and its associated memory region may also be dropped safely.
Of course, the transfer may still have completed partially. If we were writing to a device, the device may be unhappy to have only gotten some of the data it wanted. If we were reading from a device, reads may have side effects and incomplete reads may leave the device in a weird state. Cancelling an incomplete transfer may result in, for example, writing out half of a string to the UART, or only part of a structured message over SPI, and so on. But, at least we don’t have abandoned DMA transfers running around in random parts of the heap you probably wanted to use for normal stuff like having strings, or whatever it is that people do on the computer.
sourcepub unsafe fn set_channel_modes(&mut self, src: ChannelMode, dst: ChannelMode)
pub unsafe fn set_channel_modes(&mut self, src: ChannelMode, dst: ChannelMode)
Sets the source and destination ChannelMode
for this channel.
This configures the behavior of the two sides of the channel.
§Safety
This method should only be used when a DMA transfer is not currently in
flight on this channel. This is ensured when using the
Channel::transfer
method, which mutably borrows the channel while
the transfer is in progress, preventing the channel modes from being
changed.
sourceunsafe fn desc_addr_reg(&self) -> &Reg<DMAC_DESC_ADDR_SPEC>
unsafe fn desc_addr_reg(&self) -> &Reg<DMAC_DESC_ADDR_SPEC>
Returns the raw DMAC_DESC_ADDR
register corresponding to this channel.
§Safety
Manipulation of raw MMIO registers is generally unsafe. This method aliases the DMAC MMIO register block, and therefore should only be called within a critical section or while DMAC interrupts are disabled.
Manipulating a channel’s MMIO register block while a transfer is in
progress on that channel is probably a bad idea. Using the
Channel::transfer
method, which mutably borrows the channel while
the transfer is in progress, will prevent this method from being called
until the transfer completes. However, if a transfer is started with
Channel::start_descriptor
, it is possible to manipulate the channel
register block while a transfer is in progress. I don’t know what
happens if you do this, but it’s probably bad.
sourceunsafe fn en_reg(&self) -> &Reg<DMAC_EN_SPEC>
unsafe fn en_reg(&self) -> &Reg<DMAC_EN_SPEC>
Returns the raw DMAC_EN
register corresponding to this channel.
§Safety
Manipulation of raw MMIO registers is generally unsafe. This method aliases the DMAC MMIO register block, and therefore should only be called within a critical section or while DMAC interrupts are disabled.
Manipulating a channel’s MMIO register block while a transfer is in
progress on that channel is probably a bad idea. Using the
Channel::transfer
method, which mutably borrows the channel while
the transfer is in progress, will prevent this method from being called
until the transfer completes. However, if a transfer is started with
Channel::start_descriptor
, it is possible to manipulate the channel
register block while a transfer is in progress. I don’t know what
happens if you do this, but it’s probably bad.
sourceunsafe fn mode_reg(&self) -> &Reg<DMAC_MODE_SPEC>
unsafe fn mode_reg(&self) -> &Reg<DMAC_MODE_SPEC>
Returns the raw DMAC_MODE
register corresponding to this channel.
§Safety
Manipulation of raw MMIO registers is generally unsafe. This method aliases the DMAC MMIO register block, and therefore should only be called within a critical section or while DMAC interrupts are disabled.
Manipulating a channel’s MMIO register block while a transfer is in
progress on that channel is probably a bad idea. Using the
Channel::transfer
method, which mutably borrows the channel while
the transfer is in progress, will prevent this method from being called
until the transfer completes. However, if a transfer is started with
Channel::start_descriptor
, it is possible to manipulate the channel
register block while a transfer is in progress. I don’t know what
happens if you do this, but it’s probably bad.
sourceunsafe fn start_descriptor(&mut self, desc: NonNull<Descriptor>)
unsafe fn start_descriptor(&mut self, desc: NonNull<Descriptor>)
Begins a DMA transfer without waiting for it to complete.
This is a lower-level API, and you should probably use
Channel::transfer
instead.
§Safety
The caller must ensure that the descriptor pointed to by desc
is valid
for as long as the DMA transfer is active.
The caller must not initiate another transfer on this channel until the
transfer started using start_descriptor
completes. I don’t know what
happens if you do this, but I’m sure it’s bad.
sourceunsafe fn stop_dma(&mut self)
unsafe fn stop_dma(&mut self)
Cancel any DMA transfer currently in progress on this channel.
This is a lower-level API, and you should probably use
Channel::transfer
instead, as it stops the transfer automatically
once it has completed or when the future is dropped.
§Safety
This is actually pretty safe. AFAICT, calling stop_dma
on a channel
with no transfer currently in flight seems fine, actually. But, this
does a raw MMIO register write, so.