QSPI: read the status register before rewriting it - #718
Open
lylepmills wants to merge 1 commit into
Open
lylepmills wants to merge 1 commit into
lylepmills wants to merge 1 commit into
Conversation
QuadEnable() runs on every Init (every switch between indirect and memory-mapped mode) and DefaultStatusRegister() on every boot. Both wrote the non-volatile status register unconditionally. Read it first and skip the write when it already holds the target state; any other value, or a failed read, still takes the existing write path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Proposal
QuadEnable()andDefaultStatusRegister()write the flash's status register unconditionally. That register is non-volatile, and these writes happen often:DefaultStatusRegister()runs on every boot.QuadEnable()runs on everyInit, so on every switch between indirect and memory-mapped mode. AWriteorErasefrom a running program does two of these, and so does every block the bootloader programs.This PR reads the status register first and skips the write when it already holds the value the write would produce. I'm proposing this rather than asserting it's safe. If there is a reason these writes need to be unconditional that I've missed, I'd like to hear it.
What changes
Impl::ReadStatusRegister(): a one-line RDSR (0x05), the same readAutopollingMemReadyalready uses. Returns false if the read fails.QuadEnable(): skips WREN + WRSR when QE is set and WIP and WEL are both clear. That's the state the existing code polls for after its own write.DefaultStatusRegister(): skips WREN + WRSR when the register reads exactly0x40. The read happens before WREN, so it can't split the write command from its data byte.Everything else still takes the existing write path:
0xC0and is still rewritten;No public API changes. 46 added lines in
src/per/qspi.cpp; it builds with no warnings, and clang-format 10 reports no changes.Why
On our unit, each of these writes had become slow. #691 describes a similar symptom: I/O slowing after many reprogramming cycles until the bootloader timed out. I can't show that the status register is the part that wore there, but in our case skipping these writes removed almost all of the time.
Testing
Simulation. I extracted the real
DefaultStatusRegister,QuadEnableandReadStatusRegisterbodies and ran them against a simulated IS25LP status register. The simulation counts non-volatile writes and rejects a WRSR without WEL, or a command issued before the previous command's data phase.In every case the register ends at 0x40 with WEL clear. I'm happy to add this as a unit test if you'd like it; I left it out because it doesn't fit the existing test layout directly.
Hardware. One Daisy Seed3 on our development bench, heavily reflashed. Our firmware and our bootloader build are based on libDaisy e1f740a; its
qspi.cppis identical to currentmaster.Not tested:
Questions
Init, so the unconditional write is doing something the read can't?🤖 Generated with Claude Code