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

Allow splitting the SPI FiFo into two halves (All chips support doing this, and it allows for double buffering without DMA) #2798

Open
Tracked by #2494
bjoernQ opened this issue Dec 13, 2024 · 12 comments
Labels
peripheral:spi SPI peripheral

Comments

@bjoernQ
Copy link
Contributor

bjoernQ commented Dec 13, 2024

No description provided.

@tom-borcin tom-borcin added the investigation Not needed for 1.0, but don't know if we can support without breaking the driver. label Dec 16, 2024
@bjoernQ
Copy link
Contributor Author

bjoernQ commented Jan 15, 2025

This seems to be related #1579

@bugadani
Copy link
Contributor

Oh I have misunderstood this issue, this is about the data buffer of a CPU controlled transfer:

Image

This is an interesting idea: we could start a transfer of arbitrary* length, and feed data into and out of the FIFO. This probably has better characteristics than chunking in a loop and transferring each chunk into the fifo, and firing off a transfer, but it needs more or less constant CPU supervision to stay in sync.

Unfortunately, the TRM just confuses me. The following screenshot is from the HIGHPART=1 case:

Image

I can imagine how each byte is addressed, but the way it's written does not mean what I imagine.

I don't understand why only the last byte position is sent repeatedly from bytes 33 - 256, and why the logic changes after that. If this description is correct (and the TRM is very consistent in repeating this for other configurations), we would need some very complicated logic to fill the buffer.

With that said, I can imagine us adding a new "streaming" transfer mode to the Spi driver. We could add an fn start_stream(&mut self, size) -> Handle<'_> or similar, and implement the logic in that handle.

@bugadani
Copy link
Contributor

I'm not confident enough to call this investigation:done

@Dominaezzz
Copy link
Collaborator

but it needs more or less constant CPU supervision to stay in sync.

What's being kept in sync?
Every 32 bytes (rather than the full 64) would be it's own transfer.

@Dominaezzz
Copy link
Collaborator

This seems to be related #1579

Yeah that was the solution. (I closed it due to endless merge conflicts 😭).

@bugadani
Copy link
Contributor

bugadani commented Jan 17, 2025

What's being kept in sync?

The 32/64th byte is repeated a bunch of times until the state machine resets back to the first byte. We need to know where to write the next byte in the FIFO, or we end up getting incorrect data shifted out of the FIFO 3/4 of the time.

Every 32 bytes (rather than the full 64) would be it's own transfer.

That doesn't seem to align well with what I've read in the TRM, which suggests we can send longer data in a single transfer. Just with one byte repeated over and over again. Indeed we can chunk things up twice as fine and get the behavior you mention by alternating HIGH_PART/LOW_PART, but that's not the only way to hold this hammer.

@Dominaezzz
Copy link
Collaborator

but that's not the only way to hold this hammer.

Ah got it, I understand what you're saying now.
I did briefly look into this idea and gave up when the different TRMs specified different overflow behaviour.

@bugadani
Copy link
Contributor

gave up when the different TRMs specified different overflow behaviour

Yikes.

@MabezDev
Copy link
Member

This is sounding like more complexity than it's worth (at least in the base Spi driver). I was expecting it to split the fifo and bounce between the two halves.

Given that every esp-idf SPI driver starts with the following code:

//use all 64 bytes of the buffer
hw->user.usr_miso_highpart = 0;
hw->user.usr_mosi_highpart = 0;

and never touches it again, I think I'm inclined to not support this in the base Spi driver.

A custom driver can always be created further down the line, but IMO our time is better spent trying stabilize DMA at some point that getting this to work.

Removing the 1.0 blocker label.

@MabezDev MabezDev removed 1.0-blocker investigation Not needed for 1.0, but don't know if we can support without breaking the driver. labels Jan 21, 2025
@Dominaezzz
Copy link
Collaborator

This is sounding like more complexity than it's worth (at least in the base Spi driver). I was expecting it to split the fifo and bounce between the two halves.

Yes your expectations are correct, the streaming thing Daniel is taking about is technically a separate issue.

Please reconsider 😅

@MabezDev
Copy link
Member

Please reconsider 😅

I took another look at the TRMs, and after a few more reads, I finally understand what it's saying.

Even if we do implement this, I'm struggling to see a user can benefit from this (with the current APIs available). Right now a user can send or receive a buffer, but the benefit here is meant to be that they can be preparing the next buffer whilst the other buffer is sending?

This seems like something we can look at after stabilization, but I just want to check with you that I'm not missing anything here?

@Dominaezzz
Copy link
Collaborator

Correct that is the main benefit, double buffering. You're not missing anything.

The secondary benefit is that it makes #2800 a bit easier to implement when you have an object representing the buf/FIFO.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
peripheral:spi SPI peripheral
Projects
Status: Todo
Development

No branches or pull requests

5 participants