Bus: send DMA-inaccessible sources (PSRAM / flash on ESP32) through the CPU path - #324
Merged
Merged
Conversation
pushImageDMA() hands the caller's pointer straight to the bus. On ESP32 the SPI DMA cannot read PSRAM or flash, so an image held in PSRAM was sent as garbage (every pixel differed when read back). Sprites were not affected: pushSprite() already checks heap_capable_dma() before asking for DMA. The SPI bus and the ESP32-S2 / ESP32-S3 parallel buses now check heap_capable_dma() on the source and fall back to their CPU (copy) path when it is false: - ESP32: PSRAM and flash sources take the CPU path. - ESP32-S3 and the other GDMA targets: PSRAM keeps using DMA. Flash constants, which were handed to the DMA as external RAM, take the CPU path. - ESP32-S2: PSRAM sources take the CPU path. They used to go to the DMA without writing the data cache back first.
ainyan03
added a commit
to ainyan03/M5GFX
that referenced
this pull request
Oct 2, 2026
pushImageDMA() hands the caller's pointer straight to the bus. On the ESP32 the SPI DMA cannot read PSRAM or flash, so an image held in PSRAM was sent as garbage. The SPI bus now sends such sources by CPU, after the queued DMA has finished. External RAM stays on the DMA path where the SPI DMA can read it (GDMA targets without flash encryption), with the existing alignment handling. The ESP32-S2 / S3 parallel buses copy DMA-inaccessible sources (PSRAM, flash) into their internal DMA buffer instead of passing them to the DMA without writing the data cache back. Backport of m5stack#324.
This was referenced Oct 2, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
pushImageDMA()hands the caller's pointer straight to the bus. On ESP32 the SPI DMA cannot read PSRAM or flash, so an image held in PSRAM is sent as garbage. Sprites are not affected:pushSprite()already checksheap_capable_dma()before asking for DMA.The SPI bus and the ESP32-S2 / ESP32-S3 parallel buses now check
heap_capable_dma()on the source and fall back to their CPU (copy) path when it is false.Internal RAM sources keep using DMA on all targets.
addDMAQueue()drains the queue and waits before the CPU output, as the existing flash-encryption fallback already does, so a queued descriptor never reads a reused flip buffer.Reproduction (ESP32 with 2 MB quad PSRAM, 135x240 ST7789 on SPI, Arduino core 3.x with
-DBOARD_HAS_PSRAM)Reading the full screen back with
readRect()after a full-screen transfer:ESP32-S3 boards (octal and quad PSRAM) still read back identical and keep the PSRAM DMA timing.