Summary of this thread as of 2018-04-02
Current status of the DMA API design:
I think we have a clear idea of what the API should provide:
It MUST
- be memory safe, obviously
- expose a device agnostic API, so we can use it to build DMA based HAL traits
- support one-shot and circular transfers
- support mem to peripheral and peripheral to mem transfers
- not require dynamic memory allocation, i.e. allocator support should be optional
It SHOULD support these features:
- Canceling an ongoing transfer
- Memory to memory transfers
- Peeking into the part of the buffer that the DMA has already written to
- Data widths other than 8-bit
- Using a part / range of the buffer; the API still needs to take ownership of the whole buffer in this scenario
This is out of scope:
- Configuration stuff like enabling burst mode or constraining usage of a channel to certain
peripherals. The API for this functionality is up to the HAL implementer to provide / design.
What we know so far from existing implementations:
- Ownership and stable addresses are a must for memory safety
- (remember that
mem::forget is safe in Rust)
- The ongoing transfer value must take ownership of the buffer and the DMA channel
- storing
[T; N] in the Transfer struct doesn't work because the address is not stable -- it
changes when the Transfer struct is moved
&'static mut fulfills these two requirements but so do Box, Vec and other heap allocated
collections. See owning_ref::StableAddress for a more complete list.
- These concepts need to be abstracted over (using traits or structs):
- An ongoing DMA transfer
- A DMA channel, singletons make sense here
- Buffers compatible with DMA transfers. cf.
StableAddress. Also the element type must be
restricted -- e.g. a transfer on &'static mut [Socket] doesn't make sense.
Unresolved questions:
- Alignment requirements. Does a transfer on a
[u16] buffer require the buffer to be 16-bit
aligned? The answer probably depends on the target device.
Attempts at the problem:
-
Memory safe DMA transfers, a blog post that explores using
&'static mut references to achieve memory safe DMA transfers
-
stm32f103xx-hal, PoC implementations of the idea present in the blog post. It contains
implementations of one-shot and circular DMA transfers
What the title says. This blog post describes the approach to building such APIs. The last part of
the post covers platform agnostic traits that could be suitable for inclusion in embedded-hal.
This issue is for collecting feedback on the proposed approach and deciding on what should land in
embedded-hal.
Summary of this thread as of 2018-04-02
Current status of the DMA API design:
I think we have a clear idea of what the API should provide:
It MUST
It SHOULD support these features:
This is out of scope:
peripherals. The API for this functionality is up to the HAL implementer to provide / design.
What we know so far from existing implementations:
mem::forgetis safe in Rust)[T; N]in theTransferstruct doesn't work because the address is not stable -- itchanges when the
Transferstruct is moved&'static mutfulfills these two requirements but so doBox,Vecand other heap allocatedcollections. See
owning_ref::StableAddressfor a more complete list.StableAddress. Also the element type must berestricted -- e.g. a transfer on
&'static mut [Socket]doesn't make sense.Unresolved questions:
[u16]buffer require the buffer to be 16-bitaligned? The answer probably depends on the target device.
Attempts at the problem:
Memory safe DMA transfers, a blog post that explores using
&'static mutreferences to achieve memory safe DMA transfersstm32f103xx-hal, PoC implementations of the idea present in the blog post. It containsimplementations of one-shot and circular DMA transfers
allocated collections like
BoxandVec.What the title says. This blog post describes the approach to building such APIs. The last part of
the post covers platform agnostic traits that could be suitable for inclusion in
embedded-hal.This issue is for collecting feedback on the proposed approach and deciding on what should land in
embedded-hal.