Writing to Internal Flash on Fez Cerb persists only on first write

Hi, I’ve put together some code based on a codeshare class I found which allows writing/reading the Internal Flash of Fez Cerb - [url]https://www.ghielectronics.com/community/codeshare/entry/885[/url], it writes whatever byte I set but only on the first write, all subsequent writes do not persist. Below is a test method I use to demonstrate

var b1 = WriteByte(0x00);  //b1 will equal 0x00
var b2 = WriteByte(0xFF);  //b2 will also equal 0x00

public byte WriteByte(byte b)
            InternalStorage flashStorage = new InternalStorage(11);

            var address = flashStorage.Length - 10000;

            var wBuffer = new byte[1] { b };
            var length = flashStorage.Write(wBuffer, address, 0, 1);
            //Read Bytes from Flash
            var rBuffer = new byte[1];
            flashStorage.Read(rBuffer, address, 0, 1);

            return rBuffer[0];

I think your address might be wrong. Check how big is the sector 11. Also check how the address parameter is used in the Internal flash implementation you are using from the codeshare.

@ Architech - Hi, sector 11 is 131072 bytes, it starts at address 0x80E0000

StorageAddressBase = 0x80C0000;
StorageSize = 0x20000;

The write method calculates the address using the code below

The address I write to is "80FD8F0" or "135256304" which falls within the range for sector 11.

@ Architech - I’ve spotted something, when writing to the same address each time, it seems to do an AND operation on the bits, the address will initially have 0xFF, so whatever is wrote will successfully write since 0xFF is 1111 1111, I’ve tested this with the code below and it seems that this is what in fact it happening

var b1 = k.WriteByte(0xF0); // write 1111 0000, b1 is equal to 0xF0
var b2 = k.WriteByte(0x1F); // write 0001 1111, b2 is equal to 0x10

The code above shows that the bits are being AND’d, why would this happen, the code for the write operation looks ok

I might be a bit rusty in this, but I think I know why. Because that’s how flash memory works! ;). You see, you can only erase whole sectors at a time. And an erased byte is 0xFF. You can only change bits to zero, and once it is a zero, it is stuck as a zero until the sector is erased. Writing flash is not like writing ram where you can write whatever you want. You have to follow a few rules… If my memory is correct.

1 Like

@ Valkyrie-MT - correct

@ Valkyrie-MT - Yes I think you are right, this is how it is behaving, I think it would be a little over the top to erase and entire block every time I want to do a write operation, there is the Register class and its SetBits method, perhaps this could be used to write values to a memory address, I’ll have to check once I get home.

ST has an application note which describes EEPROM Emulation with Flash :
Maybe this can give you some ideas… :whistle:

Hmm, dont we have a driver/builtin-function for this?

@ Lutz1 - Looks interesting, especially the bit about wear leveling, some areas of the flash would need to be written to quite often so I’ll have to account for this.

OK, then an external solution like SRAM with battery or a FRAM
might be better.

@ Lutz - It’s a bit late for that, I already have 100 PCB made, it’s only a few bytes of data that need to be wrote regularly, I’m sure I can come up with a software solution to distribute the writes across the available flash storage.

@ chillydk147 - If you need only few bytes have you tried backup SRAM?


@ Architech - I don’t think SRAM will work for me, I need data to be persisted after power loss.

@ chillydk147 - Good news. You can definitely do what you want to do. I know because I did it myself. For my personal project which was never finished, I implemented some classes that persisted settings and logs to the on-chip flash of the STM32F405 (Cerb family). That part worked great. If you have a fixed number of bytes that just need to be periodically updated, this is the easiest case. Here is what I would do. Let’s say you need 10 bytes. Write the first byte as a flag before your 10 bytes of data. The flag byte is 0xFF (erased) before you write, then when you write your data to flash, overwrite the flag with 0x0F to tell you this is the current value followed by your 10 bytes of data. Then when you have an update to your 10 bytes, write a new 0x0F flag with the new data after the first 11 bytes, then change the first flag already on flash to 0x00 (notice the binary of the flags are always changing from 1 → 0). That is your flag for obsolete data (0x00). Whenever you read, start at the beginning of the sector and jump every 11 bytes to the flag bytes to find 0x0F, then read the data that follows. Once you understand it, you can do this in a day. When the sector is full you can erase the sector and start at the beginning. The only issue with that is for a few milliseconds, you could lose your data to a perfectly timed power loss. I did the math on my application and found that the probability was so low, I would almost never see it even if the product was a wild success. But, if you want to be perfect, you can use 2 sectors and when one is full, use the other and switch back and forth.

Also, if you have frequent updates, think about using a timer to delay the writes to be not too frequent, so you don’t wear your flash.

Also, do the math and try to figure out how many times you will have to erase the sector during the life of the device and keep it under 2000 (although the number depends on your hardware).

P.S. I built my own custom firmware to leave me 3 sectors that are not overwritten when I reflash with a new app update. You don’t have to do that as long as you keep your app small and be sure to write to the last sectors. If you do want to do your own firmware, you can start with this: GitHub - Valkyrie-MT/NETMF4.3_Community: NETMF 4.3 Community features and GCC compatibility

The key is changing the scatterfile and a few other bits. Excerpt from the scatterfile:

39     <Set Name="Config_BaseAddress"  Value="0x08008000"/>  <!-- Start of Config sector --> 
40     <Set Name="Config_Size"         Value="0x00004000"/>  <!-- Note: this leaves the sector (3) in 0x0800C000 to 0x08010000 empty and unused --> 
41     <Set Name="Code_BaseAddress"    Value="0x08010000"/>  <!-- Start of .NET MF Runtime --> 
42     <Set Name="Deploy_BaseAddress"  Value="0x08080000"/>  <!-- Start of Application deployment area --> 
43     <Set Name="Code_Size"           Value="%Deploy_BaseAddress - Code_BaseAddress%" />  
44     <Set Name="Data_Size"           Value="0x00040000" />  <!-- Note: this leaves the last sectors (10 & 11) empty for use in programs --> 
45     <Set Name="Valid"               Value="true"/> 
46   </If> 

1 Like

@ Valkyrie-MT - Thanks this is most helpful, in my case I’d require a fixed length of 200 bytes for regularly updated data, I’ve calculated that a typical 5-10 minutes usage will consume 2KB of data, so assuming I assign the last 128KB sector to this, then I’d only have to do an erase every (128K/200) 640 writes. Also going by your guide of 2000 erase cycles, I would get 1.28 million writes before things can potentially go wrong, the average write interval would be about once every 15 seconds, the max-average usage would be 2 hours per day, so all these calculations add up to a few years of usage.

My only concern is, as the sector begins to fill, will things start to slow up as I need to find the Start Flag at power up, the loop length will be 640, so that’s potentially 640 Reads, I’ll have to test how long this will take when I get home.

@ chillydk147 - so that’s potentially 640 Reads

You may perform a binary search, worst case will be 9 reads.

@ SouthernStars - Does this binary search require me to read the entire 128KB into a byte array buffer beforehand?

Usually a binary search algorithm uses a sorted list; that’s not what you’ve got here.

edit: of course, now I think of it, you do kind of have an ordered list. You’re looking for the last entry that’s actually written. Divide in two, check your entry, and discard the upper or lower chunk depending on the situation (if the mid-value has been written, discard the lower).

Personally, the 600 reads are from on-die flash, I’d live with it. Actually, you should just test how good/not the perf is, but I am expecting it’s probably acceptable.

@ Brett - Thanks, I will test later today