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

Initial DMA support #86

Merged
merged 17 commits into from
Jul 18, 2020
Merged

Initial DMA support #86

merged 17 commits into from
Jul 18, 2020

Conversation

teskje
Copy link
Collaborator

@teskje teskje commented Apr 5, 2020

This PR is the first part of an effort to add DMA support to this crate (see issue #66). It adds initial support for DMA, including:

  • A DmaExt extension trait that splits a DMA peripheral into individual channels
  • A Transfer abstraction that provides memory-safe one-shot DMA transfers
  • New methods on serial receivers and transmitters to read/write data via DMA

This works only on STM32F303 devices for now.

src/serial.rs Outdated Show resolved Hide resolved
Copy link
Collaborator Author

@teskje teskje left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was some discussion in the rust-embedded Matrix channel about DMA and Pin. Based on that I think Pin might actually not be enough to guarantee the safety of Transfer and we might need StableDeref instead.

src/serial.rs Outdated Show resolved Hide resolved
@Sh3Rm4n
Copy link
Member

Sh3Rm4n commented Apr 6, 2020

Thank you very much for this PR and providing so much extra information in #66. Now I have enough information to read into. I'll try to review this in the next days :)

@teskje teskje closed this Apr 6, 2020
@teskje teskje reopened this Apr 6, 2020
@teskje
Copy link
Collaborator Author

teskje commented Apr 6, 2020

Thanks!

Btw. I opened an issue about the use of Pin with DMA APIs: rust-embedded/embedonomicon#64
This is definitely something I need to fix before we can merge.

Edit: Switched from Pin to the StableDeref trait now.

@Sh3Rm4n
Copy link
Member

Sh3Rm4n commented May 6, 2020

Am I right, that this is on hold as long as this is still in progress? :)

@teskje
Copy link
Collaborator Author

teskje commented May 6, 2020

Not necessarily. The final goal of this project is to update the Embedonomicon, we don't need to wait for that. I think the discussion around the buffer type is most relevant for this PR and so far as I'm aware, the current proposal is sound. At least nobody has raised any issues with it yet.

So I would suggest I update this PR to make use of the suggested traits and then we try to get it merged. That way we can also get some practical experience with these traits, which we should before we recommend them for everyone.

@teskje
Copy link
Collaborator Author

teskje commented May 9, 2020

I'd say it's ready for review now.

@teskje
Copy link
Collaborator Author

teskje commented Jul 3, 2020

Hey @Sh3Rm4n, I don't want to be a bother but that has been waiting for a while. Anything I can do to help move it forward?

This only includes support for one-shot DMA transfers on STM32f303 MCUs
for now.
This better reflects what that function is doing, namely reading as many
bytes as there is space in the given buffer.
Using Pin for DMA buffers does not provide the necessary safety.
See rust-embedded/embedonomicon#64
This commit migrates the current DMA implementation to the safe DMA
buffer traits proposed by the "DMA API Documentation" focus project.

See: https://github.com/ra-kete/dma-poc/blob/master/README.md
Copy link
Member

@thalesfragoso thalesfragoso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you and sorry for taking this long to review it.
PS: I didn't double check the pins on the datasheet, sorry. Also, I don't have a F3 board .-.

src/dma.rs Outdated Show resolved Hide resolved
src/dma.rs Outdated Show resolved Hide resolved
src/dma.rs Outdated Show resolved Hide resolved
src/dma.rs Show resolved Hide resolved
src/dma.rs Outdated Show resolved Hide resolved
src/dma.rs Show resolved Hide resolved
src/dma.rs Outdated Show resolved Hide resolved
src/dma.rs Outdated Show resolved Hide resolved
src/serial.rs Outdated Show resolved Hide resolved
@thalesfragoso
Copy link
Member

Oh, I forgot something, maybe we should have a method on the Target trait to get the peripheral address, that way we can set the address on the DMA code, what do you think ? Seems less error prone.

@teskje
Copy link
Collaborator Author

teskje commented Jul 17, 2020

Oh, I forgot something, maybe we should have a method on the Target trait to get the peripheral address, that way we can set the address on the DMA code, what do you think ? Seems less error prone.

I looked into that, but it's not easy to implement nicely. The naive transformation would yield something like:

/// Trait for defining DMA targets and their channels
pub unsafe trait Target<C: Channel> {
    fn peripheral_address() -> u32;
}

macro_rules! targets {
    (
        $dma:ident,
        $( $target:ty => ($C:ident, $reg:expr), )+
    ) => {
        $(
            unsafe impl Target<$dma::$C> for $target {
                fn peripheral_address() -> u32 {
                    unsafe { &$reg as *const _ as u32 }
                }
            }
        )+
    };
}

#[cfg(feature = "stm32f303")]
targets!(dma1,
    serial::Rx<stm32::USART1> => (C5, (*stm32::USART1::ptr()).rdr),
    serial::Tx<stm32::USART1> => (C4, (*stm32::USART1::ptr()).tdr),
    serial::Rx<stm32::USART2> => (C6, (*stm32::USART2::ptr()).rdr),
    serial::Tx<stm32::USART2> => (C7, (*stm32::USART2::ptr()).tdr),
    serial::Rx<stm32::USART3> => (C3, (*stm32::USART3::ptr()).rdr),
    serial::Tx<stm32::USART3> => (C2, (*stm32::USART3::ptr()).tdr),
);

Which I don't like much, since (aside from being ugly) I don't think the DMA module should concern itself with the details of specific USART registers. Such low-level knowledge is better kept in the serial module IMO is. Now, this could be resolved with an additional PeripheralAddress trait that's impl'd on Rx and Tx inside the serial module. However, I'm not sure the additional complexity is worth it, at least for the MVP.

I think at some point, when DMA is supported for more than just serial, we'll want to move more setup logic into the Transfer::start_* methods, to remove code duplication. But I'd like to wait until then to see what the actual common usage patterns are. Trying to predict that now feels like over-engineering.

@thalesfragoso
Copy link
Member

I think at some point, when DMA is supported for more than just serial, we'll want to move more setup logic into the Transfer::start_* methods, to remove code duplication. But I'd like to wait until then to see what the actual common usage patterns are. Trying to predict that now feels like over-engineering.

Agreed.

The ordering previously used here (Acquire) was not strong enough, since
it only prevents memory reads after the fence to be moved before the
last read before the fence. We want to prevent moving before the last
*write* before the fence (the one that disables DMA). The SeqCst
ordering does that for us.
Instead of always enabling DMA on the USART peripherals, we want to
enable it only when we actually do a transfer. To this end, this commit
renames the `Target` trait mapping DMA targets to their channels to
`OnChannel`. The new `Target` trait now provides methods to start and
stop DMA on the implementing target, which are called when a `Transfer`
starts or stops DMA.
Copy link
Member

@thalesfragoso thalesfragoso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good, sorry for the nitpicks .-.

src/dma.rs Outdated Show resolved Hide resolved
src/dma.rs Outdated Show resolved Hide resolved
src/dma.rs Outdated Show resolved Hide resolved
src/dma.rs Outdated Show resolved Hide resolved
@teskje teskje merged commit b0aaa37 into stm32-rs:master Jul 18, 2020
@teskje teskje deleted the dma branch July 18, 2020 10:49
@teskje teskje mentioned this pull request Jul 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants