alif: Run the CYW43 SPI bus at 32MHz. - #19628
Open
kwagyeman wants to merge 3 commits into
Open
Conversation
The WL_IRQ line from the CYW43 is configured falling-edge triggered, but the chip holds the line asserted (low) for as long as it has pending frames. Under sustained receive the line never returns high between frames, so no new falling edge is generated after a poll that does not fully drain the chip, and the wakeup is lost. Configure the pin level-low sensitive instead. A level trigger would re-fire continuously until PendSV gets to run the poll, so the handler masks the GPIO interrupt after scheduling, and a new post-poll hook (CYW43_POST_POLL_HOOK, already provided by cyw43-driver and used the same way by the rp2 port) clears and unmasks it after every poll: if the line is still low the interrupt immediately re-raises, so wakeups cannot be lost regardless of how many frames are pending. Tested on an OpenMV AE3 (CYW43439 on SPI): WLAN scan/connect/traffic all behave as before, verified with the driver's stats counters that the interrupt path services every received frame. Signed-off-by: Kwabena W. Agyeman <[email protected]>
The CYW43 gSPI interface is specified up to 50MHz but the bus was run at
16MHz. Simply raising the clock fails: at 24MHz and above the chip's
firmware download breaks ("Failed to start CYW43"), because the MISO
round-trip delay exceeds the controller's default sample point. Set the
SPI RX sample delay to 2 spi_clk cycles to move the sample point, which
makes 32MHz operation reliable (verified across repeated WLAN bring-up
and traffic cycles on an OpenMV AE3).
Signed-off-by: Kwabena W. Agyeman <[email protected]>
The 8*MSS TCP window and send buffer limit TCP throughput to window/RTT, which on WiFi round-trip times is below what the link and the CYW43 can carry. Double both to 16*MSS and raise MEM_SIZE to 48K so the heap comfortably covers the send buffer (lwIP's ERR_MEM retry path otherwise dominates). The Ensemble parts have ample SRAM for this. Measured on an OpenMV AE3 (CYW43439): TCP receive from a Python socket benchmark improves ~15-20%, transmit similarly; UDP is unaffected. Signed-off-by: Kwabena W. Agyeman <[email protected]>
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.
Summary
Three improvements to CYW43 WiFi on the alif port, found while
benchmarking an OpenMV AE3 (CYW43439 on SPI):
for as long as it has pending frames, so a falling-edge trigger stops
firing whenever a poll doesn't fully drain the chip — the wakeup is
lost. The pin is now level-low sensitive, masked in the handler, and
unmasked after every poll via
CYW43_POST_POLL_HOOK(the same patternthe rp2 port uses): a still-asserted line immediately re-raises the
IRQ, so no wakeup can be lost.
50MHz). Raising the clock alone fails — the chip's firmware download
breaks at 24MHz and above — because the MISO round-trip exceeds the
controller's default sample point. Setting the SPI RX sample delay to
2 cycles makes 32MHz reliable.
heap): TCP was window/RTT-limited below what the link carries, and the
heap now comfortably covers the send buffer so lwIP's ERR_MEM retry
path stays cold. The Ensemble parts have ample SRAM.
Measured on an OpenMV AE3 (2.4GHz, same board/AP/position, Python socket
benchmarks, 3+ runs per configuration):
The TCP gains come almost entirely from the lwIP buffer commit
(window/RTT-limited before). The 32MHz commit contributes the UDP TX bump —
small, because per-frame CPU cost rather than wire time dominates this SPI
path. The IRQ commit is throughput-neutral in these tests but closes a
real lost-wakeup class.
Testing
Tested on an OpenMV AE3 (CYW43439, SPI): repeated WLAN bring-up cycles and
Python socket TCP/UDP benchmarks in both directions (numbers above).
Interrupt servicing of every received frame was verified with the driver's
stats counters; 32MHz bring-up is stable across repeated
boot/scan/connect/traffic cycles, and reproducibly fails without the
sample-delay change (which is why both are in one commit).
Known pre-existing issue, unchanged by this PR: sustained UDP receive
above ~15Mbit/s collapses to 100% loss on this board. Instrumentation
shows the chip itself stops asserting the IRQ and holds an empty queue
during such floods — a chip-side power-save interaction (with power save
disabled via
cyw43_wifi_pm()it degrades gracefully instead). Addressingit properly needs DMA/service-rate work on the SPI path and is left for a
future change.
Build-tested: OPENMV_AE3.
Trade-offs and Alternatives
The lwIP heap increase costs 32K of SRAM on a part with megabytes of it.
The IRQ change adds a mask/unmask per poll cycle, which is noise compared
to the SPI transfers it brackets.
Generative AI
I used generative AI tools when creating this PR, but a human has checked
the code and is responsible for the code and the description above.