Skip to content

Conversation

@AstrickHarren
Copy link

This should partially fix #3285 basically we don't take owner ship of i2s when starting transfer. Not sure if this is a good way to go so I kinda want to make sure. Uses double lifetime so I can convert it back to a draft if you will and in addition to that I can help stabilizing the interface as well but I don't really know if we still want the same structure we used in esp-idf where a message queue (channel) is used to juggle between DMA owned and CPU owned descriptors.

@Dominaezzz
Copy link
Collaborator

Thanks for the PR!

This will probably prevent some people from storing the ongoing transaction in the same struct that they also store the I2s driver (when it's idle).

but I don't really know if we still want the same structure we used in esp-idf where a message queue (channel) is used to juggle between DMA owned and CPU owned descriptors.

Once #2269 is resolved for I2S, users will be able to pick any structure they like (without having to rewrite the driver from scratch).
Until then, any structure that enables the current users to use the driver is good enough.

@AstrickHarren
Copy link
Author

This will probably prevent some people from storing the ongoing transaction in the same struct that they also store the I2s driver (when it's idle).

I could be wrong but I don't think you can do that anyway cuz when you try to create a transfer, you lose the ownership to the original i2s driver anyway. I mean the closest I can think of to store both the transfer and the driver in the same struct would be something like this

pub struct Foo<'d, BUFFER> {
    i2s: I2sRx<'d, Async>,
    transfer: Option<I2sReadDmaTransferAsync<'d, BUFFER>>,
}

impl<'d, BUFFER: WriteBuffer> Foo<'d, BUFFER> {
    fn start(&mut self, buf: BUFFER) -> Result<(), Error> {
        self.transfer = Some(self.i2s.read_dma_circular_async(buf)?); // cannot move out `self.i2s`
        Ok(())
    }
}

So you won't be able to move out i2s anyway. But then if you mean by storing the peripheral I2S struct defined in mod peripheral, it is also impossible to have a such a peripheral and its transfer, which borrows (or moves, which takes us back to the previous problems showed in the snippet) itself stay in the same struct because rust doesn't really allow self referential object. So I'm not sure I understand your point.

@Dominaezzz
Copy link
Collaborator

This is what I meant.

pub struct Foo<'d, BUFFER> {
    i2s: Option<I2sRx<'d, Async>>,
    transfer: Option<I2sReadDmaTransferAsync<'d, BUFFER>>,
}

That would let you move the driver out, start the transfer, then store the transfer.
If this API switches to borrowing, users will run into the self referential struct problem like you said.

Here's an example of an application doing something like it.

@AstrickHarren
Copy link
Author

AstrickHarren commented Jun 8, 2025

Ah, I get it. Then you should be able to do something like this:

pub struct Foo<'a, 'd, BUFFER> {
    i2s: Option<(&'a mut I2sRx<'d, Async>, BUFFER)>,
    transfer: Option<I2sReadDmaTransferAsync<'a, 'd, BUFFER>>,
}

impl<'a, 'd, BUFFER: WriteBuffer> Foo<'a, 'd, BUFFER> {
    fn start(&mut self) {
        match self.i2s.take() {
            Some((i2s, buf)) => {
                let transfer = i2s.read_dma_circular_async(buf).unwrap();
                self.transfer = Some(transfer);
            }
            None => (),
        }
    }
}

The other solution, I think it may be better, could be to write a stop method for the transfer, as it already has the ownership of I2sRx anyway, so we can simply clear the bit on the i2s start register, and another method to restart it, and restarting doesn't need to reconfigure dma again as it is already configured.
What do you think of this? @Dominaezzz.

@Dominaezzz
Copy link
Collaborator

Sending Foo to a different thread won't be possible if it looks like that iirc.

A stop() method sounds very sensible to me.

@bjoernQ
Copy link
Contributor

bjoernQ commented Jun 10, 2025

stop is something we probably want - see #3285

self-borrows is something we had for DMA but for the reasons @Dominaezzz laid out we consider this to be something we don't want

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.

I2S circular transfers, should be stopable.

3 participants