Repository navigation
✨ (minor) Add for_each_run() to walk two scatter spans together - #19
Merged
Merged
Conversation
for_each_run() calls a function with the longest pair of runs, one from each scatter span, that is contiguous in both. Each run ends at whichever chunk boundary comes first, and once one scatter span runs out its side of the run is empty. Full duplex drivers, such as an SPI moving its transmit and receive buffers by DMA, need exactly this walk and would otherwise each carry their own cursor type.
kammce
added a commit
to libhal/libhal-arm-mcu
that referenced
this pull request
Oct 26, 2026
Both transfer paths walk the outgoing and incoming data together with for_each_run(), one run that is contiguous on both sides at a time. The polled path loops over each run's bytes and the DMA path splits each run into transfers of at most 65,535 bytes. for_each_run() is a private copy of the one proposed in libhal/scatter_span#19, until libhal requires a scatter_span release that has it. scatter_cursor is removed.
kammce
commented
Oct 26, 2026
kammce
left a comment
Member
Author
There was a problem hiding this comment.
Lgtm except for the places where () should wrap up arithmetic
kammce
added a commit
to libhal/libhal-arm-mcu
that referenced
this pull request
Oct 26, 2026
* ✨ v2 Move STM32F1 SPI data by DMA SPI transfers on the STM32F1 now move their bytes by DMA when they can claim both of the peripheral's channels, and the calling context sleeps on its waiter while the bytes move. The channels are claimed for each transfer, so drivers whose requests share a channel take turns. If another driver holds one, such as a USART receiving on it, the transfer polls as before. The generic SPI driver accepts any channel that satisfies the new stm32_generic::byte_dma_channel concept, keeping the F1's DMA controller out of the generic code. scatter_cursor moves into its own partition and gains contiguous() and advance(n), so a whole chunk can go to DMA. * ♻️ v2 Walk SPI buffers in runs instead of scatter_cursor Both transfer paths walk the outgoing and incoming data together with for_each_run(), one run that is contiguous on both sides at a time. The polled path loops over each run's bytes and the DMA path splits each run into transfers of at most 65,535 bytes. for_each_run() is a private copy of the one proposed in libhal/scatter_span#19, until libhal requires a scatter_span release that has it. scatter_cursor is removed. * 🎨 v2 Write logical operators as words, make precedence explicit Covers the SPI driver and the STM32F1 DMA channel driver. * ⚡ v2 Shrink the SPI DMA transfer The DMA transfer() takes its channels as pointers and polls each run when either is missing, so one chunk walk serves both paths and the compiler emits stop_transfer once. dma_channel keeps a pointer to its channel's registers, so stop(), remaining(), failed() and start() don't work out the controller and channel from the index each time. spi demo: 31,849 B -> 31,321 B of text. dma demo: 28,613 B -> 28,453 B. * ♻️ v2 Use mem::for_each_run() from scatter_span 0.1.0 libhal 5.0.0-alpha.13 requires scatter_span 0.1.0, which has it, so the private copy in the SPI driver goes. Also groups the arithmetic in interrupt_for().
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.
Adds
mem::for_each_run(), which walks two scatter spans side by side, one contiguous run at a time.Behavior
scatter_span<byte const>for data going out andscatter_span<byte>for data coming in.sub_scatter_span()would walk the chunks from the start on every call.Why
A full duplex bus moves two caller-supplied buffers in lockstep, and their chunk boundaries rarely line up. The STM32 SPI driver in libhal-arm-mcu needs this to hand each run to DMA, and a
hal::spion any other platform would need the same walk. A single buffer is already covered by a range-for over its chunks.Testing
Five new unit tests cover:
The build and all tests pass with LLVM 23, and
pre-commitpasses.