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

Change semantics of DMA futures #1835

Merged
merged 5 commits into from
Jul 24, 2024
Merged

Conversation

Dominaezzz
Copy link
Collaborator

@Dominaezzz Dominaezzz commented Jul 18, 2024

Thank you for your contribution!

We appreciate the time and effort you've put into this pull request.
To help us review it efficiently, please ensure you've gone through the following checklist:

Submission Checklist 📝

  • I have updated existing examples or added new ones (if applicable).
  • I have used cargo xtask fmt-packages command to ensure that all changed code is formatted correctly.
  • My changes were added to the CHANGELOG.md in the proper section.
  • My changes are in accordance to the esp-rs API guidelines

Extra:

Pull Request Details 📖

Description

This PR is part of #1785, a small part that can be reviewed before the big PR comes in.
I've skipped changelog since this is an internal refactor.

The new semantics in this PR is also a proposal for how most (a handful are a little messy) interrupt based futures should work in the hal, so review this PR with that in mind as well.

The existing semantics of the DMA futures are:

  • Set INT_ENA in the constructor.
  • Interrupt fires and unsets INT_ENA, clears INT_CLR and wakes waker.
  • Poll checks for the unset INT_ENA then returns some result.

The new semantics are:

  • Do nothing in constructor. (Rust Futures do nothing unless polled)
  • Poll checks for INT_RAW...
  • If !=0, clear INT_CLR and returns a result based on what was in INT_RAW.
  • Otherwise set INT_ENA and return Poll::Pending.
  • Interrupt fires and unsets INT_ENA and wakes waker.
  • Poll checks for INT_RAW, clear INT_CLR and returns a result based on what was in INT_RAW.
  • Clear INT_ENA in the Drop. (No-op if interrupt fired)

The new semantics are meant to achieve two things.

  • Cancel safety
  • Eliminate any race conditions

Cancel safety is achieved by the fact that that the interrupt bits are not cleared unless poll returns Poll::Ready(...). So if the future is dropped before (or even after) the interrupt fires, the interrupt bits are still there and can be consumed by some other part of the application if needed. The future can also be re-created if the application wants to try waiting again.

Race conditions are eliminated by not using INT_ENA to check that the interrupt has fired but by instead checking INT_RAW. The existing semantics required you to create the future before starting the DMA, which ran the risk of bugs like #1728 . The new semantics in this PR let you create the future at any point, even after the transfer has started or even after it had finished.

Future enhancements include:

  • Marking the futures as !Send. Bad things can happen (before and after this PR) if the interrupt is executed on a different core to where the future is polled.

Testing

I've tested this alongside other changes but not in isolation, I'll need to test this in isolation but it can still be reviewed before that.

@bjoernQ
Copy link
Contributor

bjoernQ commented Jul 19, 2024

I agree, using INT_ENA to signal ready always felt a bit weird. Code looks good so far but I'd like to test things a bit.

No idea what is wrong with CI

@bjoernQ
Copy link
Contributor

bjoernQ commented Jul 19, 2024

This somehow breaks async-I2S-tx in a different way than what was fixed in #1833

@bjoernQ bjoernQ added the skip-changelog No changelog modification needed label Jul 19, 2024
@Dominaezzz
Copy link
Collaborator Author

This somehow breaks async-I2S-tx in a different way than what was fixed in #1833

Oh dear. I tested the async SPI and that worked.

What hardware are you testing the I2S example with?

Also I'm guessing it's the circular transfers that are the problem and not the one shot ones? Since those use different futures from the SPI driver.

@bjoernQ
Copy link
Contributor

bjoernQ commented Jul 19, 2024

What hardware are you testing the I2S example with?

You can just run the example without anything attached and see it freezes while it was continuously pushing data before

liebman added a commit to liebman/esp-hal that referenced this pull request Jul 21, 2024
@bjoernQ
Copy link
Contributor

bjoernQ commented Jul 22, 2024

I2S TX is now working for me, thanks!

I did some more testing and for PARL_IO_RX ( cargo xtask run-example examples esp32c6 embassy_parl_io_rx without anything attached ) it now prints data received in the first iteration but then gets stuck. On main it continuously prints data

esp-hal/src/parl_io.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@bjoernQ bjoernQ left a comment

Choose a reason for hiding this comment

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

LGTM - Thanks

Copy link
Member

@MabezDev MabezDev left a comment

Choose a reason for hiding this comment

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

Apologies for the delay, this looks like a nice change, thanks!

Could you do a quick rebase on main and then we can merge this :)

@MabezDev MabezDev enabled auto-merge July 24, 2024 14:12
@MabezDev MabezDev added this pull request to the merge queue Jul 24, 2024
Merged via the queue into esp-rs:main with commit 4ef91c5 Jul 24, 2024
18 checks passed
@Dominaezzz Dominaezzz deleted the dma_futures branch July 24, 2024 15:24
liebman added a commit to liebman/esp-hal that referenced this pull request Jul 24, 2024
@plaes
Copy link
Contributor

plaes commented Jul 25, 2024

Seems like this completely breaks SPI for me on esp32 (revision v3.0).
I'm using this embassy-based project https://github.com/plaes/rust-lilygo-ttgo-lora32

git bisect bad
4ef91c5941883a5dc589209eb91fe25641570686 is the first bad commit
commit 4ef91c5941883a5dc589209eb91fe25641570686 (HEAD)
Author: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com>
Date:   Wed Jul 24 15:26:39 2024 +0100

    Change semantics of DMA futures (#1835)
...

@bjoernQ
Copy link
Contributor

bjoernQ commented Jul 25, 2024

See #1857

liebman added a commit to liebman/esp-hal that referenced this pull request Jul 25, 2024
liebman added a commit to liebman/esp-hal that referenced this pull request Jul 29, 2024
github-merge-queue bot pushed a commit that referenced this pull request Jul 29, 2024
* implement async for lcd_cam i8080

* lcd_cam: implement InterruptConfigurable for blocking and improve async

* lcd_cam: use new async interrupt semantics from #1835

* lcd_cam: move interrupt handler binding into `new_async()`

* lcd_cam: Instance::is_listening_lcd_done not used

* i8080: no need for seperate `new_async()`

* i8080: don't use DmaTxFuture, just test for dma error after complete

* add HIL tests for LCD_CAM i8080 in blocking and async.

* lcd_cam_i8080: test channels configured for async as well since teh compiler can't prevent it for now

* fmt :-/

* lcd_cam fix comment

* changelog

* lcd_cam async: no need to enable interrupts until polled

* lcd_cam: i8080 update for ReadBuffer changes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
skip-changelog No changelog modification needed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants