fix(nrf): move the panel SPI off SPIM3 onto SPIM2 (anomalies 195/198) - #137
Merged
Merged
Conversation
SPIM3 is the only nRF52840 SPIM instance carrying anomalies 195 and 198, and
both bite this firmware:
- 195: the instance keeps drawing current after disable. The nrfx workaround
pokes 0x4002F004 on every uninit and never undoes it on re-init.
- 198: transmit data may be corrupted when another bus master touches the TX
buffer's RAM block mid-transfer. The Arduino per-byte path makes that buffer
a one-byte STACK local, contended by SoftDevice interrupts on every byte --
and 198's workaround is compiled out here entirely, because
NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED is never defined.
Both nrfx workarounds are gated on `p_spim == NRF_SPIM3`, so moving to SPIM2
makes the anomalies inapplicable rather than worked around.
The Adafruit core binds the global `SPI` object to an instance chosen by
SPI_32MHZ_INTERFACE (framework SPI.cpp): 0 -- its default -- gives SPIM3, 1
gives SPIM2. Only `SPI` matters: bb_epaper drives the panel through that global
and nothing here ever calls SPI1.begin(), so the instance handed to SPI1 is
left uninitialised.
Free at our clock. SPIM2 tops out at 8 MHz and bbepInitIO already asks for
exactly 8000000, which setClockDivider maps to NRF_SPIM_FREQ_8M on either
instance. It forfeits the 16/32 MHz only SPIM3 offers -- deliberately, since
raising the panel clock increases the DMA bus pressure this change exists to
avoid. No pin change; PIN_SPI_* are untouched. No I2C conflict: Wire is TWIM0
and Wire1 is TWIM1, while SPIM2's block is shared only with SPIS2/SPI2.
The macro is consumed by the framework's SPI.cpp, not by our sources, so it
only works while -D reaches the framework build -- verified for this commit:
pio run -e nrf52840custom -v | grep 'SPI_32MHZ_INTERFACE=1.*SPI\.cpp'
Not yet exercised on hardware.
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.
Single-commit nRF52840 change: move the panel SPI off SPIM3 and onto SPIM2. Independent of #135 and #136.
Why
SPIM3 is the only nRF52840 SPIM instance carrying anomalies 195 and 198, and both bite this firmware:
0x4002F004on every uninit and never undoes it on re-init.NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLEDis never defined.Both nrfx workarounds are gated on
p_spim == NRF_SPIM3, so moving to SPIM2 makes the anomalies inapplicable rather than worked around.How
The Adafruit core binds the global
SPIobject to an instance chosen bySPI_32MHZ_INTERFACE(frameworkSPI.cpp): 0 — its default — gives SPIM3, 1 gives SPIM2. OnlySPImatters:bb_epaperdrives the panel through that global, and nothing here ever callsSPI1.begin(), so the instance handed to SPI1 is left uninitialised.The flag is scoped to
[env:nrf52840custom], so it does not reach the ESP32 environments through[env]inheritance.Cost
None at our clock. SPIM2 tops out at 8 MHz and
bbepInitIOalready asks for exactly 8000000, whichsetClockDividermaps toNRF_SPIM_FREQ_8Mon either instance. It forfeits the 16/32 MHz only SPIM3 offers — deliberately, since raising the panel clock increases the DMA bus pressure this change exists to avoid.No pin change (
PIN_SPI_*untouched). No I2C conflict:Wireis TWIM0 andWire1is TWIM1, while SPIM2's block is shared only with SPIS2/SPI2, neither used.Verification
The macro is consumed by the framework's
SPI.cpp, not by our sources, so it only works while-Dreaches the framework build — and if it silently stops doing so we are back on SPIM3 with no error. Confirmed for this commit:The check is recorded in an inline comment so it survives a platform update. Builds clean; not yet exercised on hardware — it wants a panel-refresh soak before merge.