Repository navigation
fix: write per 64KB block so a dropped probe costs one block, not the chip - #14
Merged
Merged
Conversation
… chip write_chip erased EVERY block, then programmed, then verified. That leaves the whole chip at 0xFF for the entire programming pass: lose contact there and the board has no BIOS and cannot boot to fix itself. On a hand-held probe against a WSON8 part that window is minutes long, and losing contact mid-read is already a thing that happens in practice. Now each 64KB block is erased, programmed and read back as one unit before the next block is touched. The erased window is one block for the ~2s it takes to refill it; everything outside it is either already-correct new data or intact old data. The same restructure makes a write resumable. Blocks that already hold the target bytes are skipped entirely, so re-running an interrupted write continues from where it stopped rather than starting over, and running the same write twice is harmless. The chip itself is the progress record - no sidecar state to go stale or lie. A failed block retries WRITE_BLOCK_ATTEMPTS times, re-erasing first so a half-programmed block cannot AND stale zero bits into the result. The skip baseline is the mandatory backup read, which was already happening, so the check costs no extra probe time. With skip_backup there is no baseline and no skip: the caller opted out of a whole-chip read, so this does not go read the chip anyway to synthesise one. Losing resume is the cost of that flag. The whole-chip verify pass is gone. Every block is now read back after programming, or shown by the liveness-checked baseline to already match, so a final pass would re-read 32MB the loop just read and double the time the probe must stay put for no new information. Also fixes the test fake: LoopbackFlash modelled sector erase but ignored BLOCK_ERASE (0xD8/0xDC), which is write_chip's PRIMARY erase opcode. Any end-to-end write test against it was passing on stale data that the program step happened to AND correctly. It now models block erase and logs (opcode, address) so tests can assert the erase/program SEQUENCE, not just the final bytes - both orderings end with identical chip contents, so bytes alone cannot catch a regression in the blank window. Both new tests were mutation-checked: defeating the skip fails the resume test (all 16 blocks erased instead of 13), and erasing one block ahead fails the blank-window test. 520 tests pass; clippy and fmt clean. Goal: 020-soic-debug-identify-fix-ship
Goal: 020-soic-debug-identify-fix-ship
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.
The bug
write_chiperased every block, then programmed, then verified:The whole chip sits at
0xFFfor the entire programming pass. Lose contact there and the board has no BIOS and cannot boot to fix itself. On a hand-held probe against a WSON8 part that window is minutes long, and losing contact mid-operation is not hypothetical: it already produced a backup that was 67% dropout zeros.The fix
Each 64KB block is erased, programmed and read back as one unit before the next block is touched.
Resume falls out of it
Blocks already holding the target bytes are skipped, so re-running an interrupted write continues where it stopped. Running the same write twice is harmless, and it self-heals a half-written chip.
The chip itself is the progress record - no sidecar file to go stale or lie about what was done.
A failed block retries
WRITE_BLOCK_ATTEMPTStimes, re-erasing first so a half-programmed block cannot AND stale zero bits into the result.Costs nothing
skip_backupthere is no baseline and no skip. It does not go read the chip anyway to synthesise one: the caller opted out of a whole-chip read. Losing resume is the cost of that flag.The test fake was lying
LoopbackFlashmodelled sector erase but ignoredBLOCK_ERASE(0xD8/0xDC) -write_chip's primary erase opcode. Any end-to-end write test against it was passing on stale data the program step happened to AND correctly.It now models block erase, and logs
(opcode, address)so tests can assert the sequence, not just the final bytes. Both orderings end with identical chip contents, so bytes alone cannot catch a regression in the blank window.Tests
520 pass, 0 fail. Clippy and fmt clean.
Both new tests were mutation-checked rather than trusted:
write_chip_skips_blocks_that_already_hold_the_target_image- defeating the skip makes it fail (all 16 blocks erased instead of 13)write_chip_erases_only_the_block_it_is_about_to_program- erasing one block ahead makes it fail