Skip to content

Conversation

djdisodo
Copy link
Contributor

@djdisodo djdisodo commented Sep 1, 2025

motivation: need better way to cancel dma mid flight and read remaining transfer count

dma transfer's are built using TransferBuilder

this should support wide range of configuration, repeating read/write, ring read/ring write, etc

configuration errors are caught in compile time

@bschwind
Copy link
Contributor

Tangentially related, but it would be cool to add support for PIO to PIO DMA transfers. I have a proof of concept in a branch but the API is hacky:

tonarino@508d698

It's great for PIO programs that are just converting from one digital format to another. Super fast data transfers and the CPU barely has to get involved.

@djdisodo
Copy link
Contributor Author

@bschwind
i tried to make api possible to read from any &Word address and write to any &mut Word address

if work go as planned pio-to-pio dma will just work too

but i think pio fifo reg would need to be exposed as well

@bschwind
Copy link
Contributor

@djdisodo that's great to hear! And yes, I think the FIFO registers would need to be exposed, though you could maybe set up an API where you don't have to expose them to users.

Something like

sm.rx().dma_to_pio(dma.reborrow(), other_sm.tx(), false).wait().await;

I haven't put too much thought into a nice API yet though.

@djdisodo
Copy link
Contributor Author

@bschwind

i was trying to use pio with this
however pio txf/rxf isn't exposed

i think there are several ways we can expose these

  1. custom type that implements dma::Target for each tx and rx

although it's used mostly for dma

this eliminates chance of it being used for other things(if there's any)

  1. vcell
    since non-volatile access to those regs would cause unpredictable result
    it's better to force volatile access

but vcell crate itself allows mutating with immutable reference which is weird

  1. Reg<u32, R> and Reg<u32, W>
    provides volatile access

but current design doesn't expose pac

main issue is these are clonable

i think i have to go with 1 probably

also splitting TargetRef and TargetMut into Target/TargetRef/TargetMut

to prevent reading from txf or such where reading behavior isn't defined

@bschwind
Copy link
Contributor

i was trying to use pio with this
however pio txf/rxf isn't exposed

Not sure I follow completely, txf/rxf aren't exposed for users of the embassy-rp crate, but I was guessing that all this DMA work would happen within embassy itself, where you have easy access to those registers.

That being said, I haven't devoted much of my time to this to know well the details on what will work and what won't, so I have limited input to give you at the moment, sorry.

@djdisodo
Copy link
Contributor Author

djdisodo commented Oct 6, 2025

decisions

new_with_transfer_count is not unsafe

only reason i'd consider this unsafe is that you can set TreqSel regardless of what target you use

how do you think? should it be unsafe?

you have to set transfer_count

this transfer_count is maximum bound for transfer_count and calculated transfer count will be returned

rp2040's DMA hardware requires transfer_count to be set, so it can't be infinite

by adding const value to Target that tells if it can be infinitely transferred,

we can later support rp234x's ability to do DMA without transfer_count

@djdisodo
Copy link
Contributor Author

djdisodo commented Oct 6, 2025

here's example code that uses this api

fn a() -> u32 {
        let (rx, tx) = self.sm1.rx_tx();
        let buffer = UnsafeCell::from_mut(buffer);
        let read_dma_target = unsafe { buffer.as_ref_unchecked() };
        let write_dma_target = unsafe { buffer.as_mut_unchecked() };
        let (mut rxt, tcount_original) = rx.dma_read_with_transfer_count(rxc, write_dma_target, u32::MAX);
        let mut txt = tx.dma_write_with_transfer_count(txc, read_dma_target, u32::MAX).0;
        select(
            join(
                rxt.wait(),
                txt.wait(),
            ),
            self.irq_cs.wait()
        ).await;
        let tcount = rxt.transfer_count();
        drop((rxt, txt));


        self.sm1.set_enable(false);

        tcount_original - tcount

}

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.

2 participants