> We want our driver a bit smarter than that; it should first check whether it's possible to write the bytes directly. In other words, we want to ensure that every 1 in our intended write is also a 1 in the target space.
Is this standard practice? Everyone knows that one should write only on previously erased units (sectors/blocks/pages/whatever). Maybe it's just for the sake of the example, but I think it's kind of insane to produce a routine to check for EVERY BIT and see if it's 1 AND if we can fit whatever we want to write. What are the chances one can overwrite (for example) a string TWICE?
I didn't read enough of the post to get the context, but...
You might often want to write less than a full block. In that case, if you always erase, you have to read the full block to ram, make your change, then erase, then write the full block. If you write byte by byte, that's a lot of erase cycles. So you add a check to see if the bytes you want to write are already in the erased state. But it's not much more work to check if the desired state is attainable instead of just if the current state is erased. Isn't it just if Current & New == New?
That's a risk, yes. For our use case, there is very strict error checking/firmware signature verification on every process involving the flash, so the corruption case is always handled gracefully, leading to a full erase anyway.
Hey! Author here :) This is a very good question, and you're right that I should've expanded on my rationale as this is not standard practice at all.
There are some particularities of the data we're writing that make this case more common than usual, and in any case the time spent in the bit masking routine is negligible compared to the flash erase time, so it works out well (keep in mind that the `all()` consumer will short-circuit as soon as two bits differ, so in the general case it's cheap, and in the erased case it isn't too different from verifying every byte is 0xFF). We're also really, really strongly optimizing for flash life above speed, as this code is meant to run very rarely for FOTA upgrades.
For a general purpose storage flash driver, I'd definitely erase every sector.
Still reasonably early days like the rest of the ecosystem, but there is good support for a lot of ATSAMD and ATSAME devices here (https://github.com/atsamd-rs/atsamd).
I'm not very familiar with the ATSAM* series so compatibility-wise this might be wrong, but you could likely add ATSAML support to that repo reasonably easily.
13 comments
[ 3.2 ms ] story [ 26.0 ms ] threadIs this standard practice? Everyone knows that one should write only on previously erased units (sectors/blocks/pages/whatever). Maybe it's just for the sake of the example, but I think it's kind of insane to produce a routine to check for EVERY BIT and see if it's 1 AND if we can fit whatever we want to write. What are the chances one can overwrite (for example) a string TWICE?
You might often want to write less than a full block. In that case, if you always erase, you have to read the full block to ram, make your change, then erase, then write the full block. If you write byte by byte, that's a lot of erase cycles. So you add a check to see if the bytes you want to write are already in the erased state. But it's not much more work to check if the desired state is attainable instead of just if the current state is erased. Isn't it just if Current & New == New?
Those would be partially-charged cells, and should be erased properly before writing, lest you start getting temperamental read errors later.
But repeatedly erasing blocks just to add a byte will wear out the block, as well as take a long time as you point out.
I think the solution to these two constraints is filesystem-like book-keeping of which regions are in which states.
There are some particularities of the data we're writing that make this case more common than usual, and in any case the time spent in the bit masking routine is negligible compared to the flash erase time, so it works out well (keep in mind that the `all()` consumer will short-circuit as soon as two bits differ, so in the general case it's cheap, and in the erased case it isn't too different from verifying every byte is 0xFF). We're also really, really strongly optimizing for flash life above speed, as this code is meant to run very rarely for FOTA upgrades.
For a general purpose storage flash driver, I'd definitely erase every sector.
I'm not very familiar with the ATSAM* series so compatibility-wise this might be wrong, but you could likely add ATSAML support to that repo reasonably easily.