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

Fix reading/writing small buffers #1760

Merged
merged 2 commits into from
Jul 15, 2024

Conversation

bjoernQ
Copy link
Contributor

@bjoernQ bjoernQ commented Jul 5, 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

Fixes #1728

Testing

See #1728 for a minimal repro

@Dominaezzz
Copy link
Collaborator

I've been staring at the code for the last 30 minutes and I can't figure out why this PR fixes the linked issue.

On a somewhat unrelated note, I spotted something else that could also contribute to the transfer getting stuck.

This is the existing code before this PR.

        reset_dma_before_load_dma_dscr(reg_block);
        chain.fill_for_tx(false, ptr, len)?;
        unsafe {
            tx.prepare_transfer_without_start(self.dma_peripheral(), chain)
                .and_then(|_| tx.start_transfer())?;
        }
        self.clear_dma_interrupts();
        reset_dma_before_usr_cmd(reg_block);

        if listen {
            tx.listen_eof();
        }
        reg_block.cmd().modify(|_, w| w.usr().set_bit());

There's a race condition in it. tx.start_transfer() is called before self.clear_dma_interrupts().
This means the code could end up clearing interrupts from the started transfer that was just started.

In practice this is rare since most people should be doing DMA transfers with large buffers but if the DMA buffer is small enough, the DMA could end up filling the peripheral's FIFO before the peripheral has even been started.

Having said that, I now realize it's also incorrect to call reset_dma_before_usr_cmd(reg_block) after tx.start_transfer(), since the code would end up discarding data from the peripheral's FIFO that DMA may have just placed there. Though this only applies to GDMA and not PDMA.

(More stuff to exercise in the HIL tests I guess 😄)

@bjoernQ
Copy link
Contributor Author

bjoernQ commented Jul 5, 2024

On ESP32 the interrupt triggered before reg_block.cmd().modify(|_, w| w.usr().set_bit()); and before tx.listen_eof() - so the interrupt cleared INT_ENA, then it gets set again making the future believe the transfer is still ongoing

@bjoernQ
Copy link
Contributor Author

bjoernQ commented Jul 5, 2024

I agree on clearing the interrupts before preparing DMA, but regarding reset_dma_before_usr_cmd the TRM says

image

@bjoernQ bjoernQ force-pushed the fix-spi-read-write-small-buffers branch from f54e029 to 35a2163 Compare July 5, 2024 14:04
@Dominaezzz
Copy link
Collaborator

Ahhh I see, okay those are probably fine then. I wish the TRM had more details about how these buffers worked.

Copy link
Contributor

@JurajSadel JurajSadel 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!

@jessebraham jessebraham added this pull request to the merge queue Jul 8, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jul 8, 2024
@MabezDev
Copy link
Member

MabezDev commented Jul 8, 2024

The failed test test_symmetric_dma_transfer_huge_buffer could be a stack overflow, I've seen that defmt panic before when the global defmt flag gets trashed. Not sure why this has been induced from these changes though 🤔

@SergioGasquez
Copy link
Member

The failed test test_symmetric_dma_transfer_huge_buffer could be a stack overflow.

The test also fails with const DMA_BUFFER_SIZE: usize = 50

@jessebraham
Copy link
Member

Since Bjoern is on vacation this week, I will convert this to a draft for the time being.

@jessebraham jessebraham marked this pull request as draft July 8, 2024 16:39
@bjoernQ bjoernQ force-pushed the fix-spi-read-write-small-buffers branch from 35a2163 to e0de4e0 Compare July 15, 2024 10:45
@bjoernQ
Copy link
Contributor Author

bjoernQ commented Jul 15, 2024

Turned out clearing the interrupts earlier (which seemed to make sense) caused problems for ESP32-S3 .... Very glad we have HIL-TESTs in place

@bjoernQ bjoernQ marked this pull request as ready for review July 15, 2024 10:57
Copy link
Contributor

@JurajSadel JurajSadel 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

@SergioGasquez SergioGasquez left a comment

Choose a reason for hiding this comment

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

LGTM!

@SergioGasquez SergioGasquez added this pull request to the merge queue Jul 15, 2024
Merged via the queue into esp-rs:main with commit 7e981a5 Jul 15, 2024
31 checks passed
@bjoernQ bjoernQ deleted the fix-spi-read-write-small-buffers branch November 26, 2024 08:41
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.

ESP32: Async SPI Master freezes in write
6 participants