stm32/dma,spi: Fix invalid SPI reads due to D-Cache coherency. by projectgus · Pull Request #13717 · micropython/micropython · GitHub
Skip to content

stm32/dma,spi: Fix invalid SPI reads due to D-Cache coherency.#13717

Merged
dpgeorge merged 3 commits intomicropython:masterfrom
projectgus:bugfix/stm32f7_dcache_dma
Mar 8, 2024
Merged

stm32/dma,spi: Fix invalid SPI reads due to D-Cache coherency.#13717
dpgeorge merged 3 commits intomicropython:masterfrom
projectgus:bugfix/stm32f7_dcache_dma

Conversation

@projectgus
Copy link
Copy Markdown
Contributor

@projectgus projectgus commented Feb 21, 2024

Adds a new DMA API to protect against cache coherency issues on chips with D-Cache, when working with arbitrary buffers (i.e. supplied by Python code).

The API is added to SPI, fixes #13471. Future work may be needed to call this API from other STM32 drivers that use DMA with arbitrary buffers.

Explanation:

  1. It's necessary to invalidate D-Cache after a DMA RX operation completes, in case the CPU read (or speculatively accessed) memory in the DMA region during the operation. This seems to have been the root cause of STM32: SPI.read(n) fails if n > 1 (regression) #13471 (and only when src==dest, for that case.)

  2. More generally, it is also necessary to temporarily mark the first and last cache lines of a DMA RX operation as "uncached", in case the DMA buffer shares this cache line with unrelated data. The CPU could otherwise write the other data at any time during the DMA operation (for example from an interrupt handler), creating a dirty cache line that's inconsistent with the DMA result.

Test code

Regression test included in the PR, based on the work done by @peterhinch and @robert-hh in the linked issue.

@projectgus
Copy link
Copy Markdown
Contributor Author

@projectgus projectgus force-pushed the bugfix/stm32f7_dcache_dma branch 2 times, most recently from 1428022 to fe79346 Compare February 21, 2024 03:47
@dpgeorge
Copy link
Copy Markdown
Member

Is there any reasonable place to include those tests in the code base? I saw there is a tests/ports/stm32/spi.py but it doesn't rely on any hardware configuration. These tests require the MISO pin to be connected to GND.

We should definitely include those tests in the repo, and tests/ports/stm32/ is the best location for them.

I suggest making these tests separate file(s) to the existing tests, adding a comment at the top of the file of the require hardware connections, and then possibly trying to auto-detect those hardware connections (eg toggle IO and see if it changes) and SKIP'ing if they are not there.

Alternatives:

  • don't do any auto-detection of the hardware connection and let the test fail if it's not set up properly, then the user is made aware that they must make hardware connections
  • make a new tests/ports/stm32_hardware directory for these kinds of tests, so they can be easily included/excluded from a test run

Note there are already some tests in stm32 that require specific hardware, like a PYBv1 with accelerometer. Also the tests/ports/cc3200 directory has similar hardware-dependent tests.

@robert-hh
Copy link
Copy Markdown
Contributor

robert-hh commented Feb 21, 2024

Very good catch. The PR works here, just reading with a constant pattern supplied. I have an inverter here in my test set-up between MOSI and MISO, so it works with any value pair, including 0x00 and 0xff.

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 4, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.39%. Comparing base (b3c62f3) to head (7fd8a6d).
Report is 3 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #13717   +/-   ##
=======================================
  Coverage   98.39%   98.39%           
=======================================
  Files         161      161           
  Lines       21078    21078           
=======================================
  Hits        20739    20739           
  Misses        339      339           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@projectgus
Copy link
Copy Markdown
Contributor Author

Have added regression test in ports/stm32_hardware. Would have preferred auto-skip idea, but couldn't think of a good way to programmatically find the GPIO for SPI2 MOSI to toggle it for a given SoC.

The inline functions that these are wrappers around already account for
cache line size.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
The existing MPU_CONFIG_DISABLE macro enables the MPU region but disables
all access to it.

The rename is necessary to support an MPU_CONFIG_DISABLE macro that
actually disables the MPU region entirely.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
@dpgeorge
Copy link
Copy Markdown
Member

dpgeorge commented Mar 8, 2024

This new DMA API corrects possible cache coherency issues on chips with
D-Cache, when working with buffers at arbitrary memory locations (i.e.
supplied by Python code).

The API is used by SPI to fix an issue with corrupt data when reading from
SPI using DMA in certain cases.  A regression test is included (it depends
on external hardware connection).

Explanation:

1) It's necessary to invalidate D-Cache after a DMA RX operation completes
   in case the CPU reads (or speculatively reads) from the DMA RX region
   during the operation.  This seems to have been the root cause of issue
   micropython#13471 (only when src==dest for this case).

2) More generally, it is also necessary to temporarily mark the first and
   last cache lines of a DMA RX operation as "uncached", in case the DMA
   buffer shares this cache line with unrelated data.  The CPU could
   otherwise write the other data at any time during the DMA operation (for
   example from an interrupt handler), creating a dirty cache line that's
   inconsistent with the DMA result.

Fixes issue micropython#13471.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
@dpgeorge dpgeorge force-pushed the bugfix/stm32f7_dcache_dma branch from 9070244 to 7fd8a6d Compare March 8, 2024 01:22
@dpgeorge dpgeorge merged commit 7fd8a6d into micropython:master Mar 8, 2024
@projectgus projectgus deleted the bugfix/stm32f7_dcache_dma branch November 1, 2024 05:12
peterzuger added a commit to peterzuger/micropython that referenced this pull request Dec 7, 2025
See micropython issue micropython#13471 and the related PR micropython#13717 for an explanation
of a similar issue in the SPI DMA driver.

Signed-off-by: Peter Züger <zueger.peter@icloud.com>
peterzuger added a commit to peterzuger/micropython that referenced this pull request Dec 8, 2025
See micropython issue micropython#13471 and the related PR micropython#13717 for an explanation
of a similar issue in the SPI DMA driver.

Signed-off-by: Peter Züger <zueger.peter@icloud.com>
oliver-joos pushed a commit to oliver-joos/micropython that referenced this pull request Dec 8, 2025
See micropython issue micropython#13471 and the related PR micropython#13717 for an explanation
of a similar issue in the SPI DMA driver.

Signed-off-by: Peter Züger <zueger.peter@icloud.com>
oliver-joos pushed a commit to oliver-joos/micropython that referenced this pull request Dec 12, 2025
See micropython issue micropython#13471 and the related PR micropython#13717 for an explanation
of a similar issue in the SPI DMA driver.

Signed-off-by: Peter Züger <zueger.peter@icloud.com>
oliver-joos pushed a commit to oliver-joos/micropython that referenced this pull request Jan 22, 2026
See micropython issue micropython#13471 and the related PR micropython#13717 for an explanation
of a similar issue in the SPI DMA driver.

Signed-off-by: Peter Züger <zueger.peter@icloud.com>
oliver-joos pushed a commit to oliver-joos/micropython that referenced this pull request Jan 30, 2026
See micropython issue micropython#13471 and the related PR micropython#13717 for an explanation
of a similar issue in the SPI DMA driver.

Signed-off-by: Peter Züger <zueger.peter@icloud.com>
oliver-joos pushed a commit to oliver-joos/micropython that referenced this pull request Feb 11, 2026
See micropython issue micropython#13471 and the related PR micropython#13717 for an explanation
of a similar issue in the SPI DMA driver.

Signed-off-by: Peter Züger <zueger.peter@icloud.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

STM32: SPI.read(n) fails if n > 1 (regression)

4 participants