I'm trying to write data to the flash memory on my Moteino and have a basic question.
I am assuming that I can erase one specific byte by writing 0xff to the address. However, I am not able to write in certain situations.
First, I execute this line: flash.writeByte(output,0xbb); It works fine.
Then, I execute the snippet in the SPIFlash_ReadWrite to write one byte to a specific address -- same one I wrote to above. That also works.
Next, no matter how many times I execute this line: flash.writeByte(output,0xbb); it does not change the value in the flash memory.
I don't understand why I can write data to a specific address once but not after that. However, the SPIFlash_ReadWrite script appears to be able to overwrite a data location over and over.
(output is a char with a numeric value in it).
Any ideas?
Ken
You can only write 0s to the flash so, if you successfully wrote 0xbb (0b10111011), you will only be able to change the 1s to zeros, for example write 0xaa (0b10101010) will work, but 0x55 will not (result is probably 0b00010001). You will not make it go back to 0xbb until the block is erased.
Tom
OK. That is what I understood. However, I thought erasing a byte meant writing 0xff to it. That was not working. So, a byte can be erased by writing 0x00 to it?
If not, what value do I write to one byte to erase it?
Thanks for the quick reply.
Ken
Quote from: Prodigal on March 14, 2015, 11:00:12 AM
OK. That is what I understood. However, I thought erasing a byte meant writing 0xff to it. That was not working. So, a byte can be erased by writing 0x00 to it?
If not, what value do I write to one byte to erase it?
Thanks for the quick reply.
Ken
No, you can't erase it by writing to it. You need to do a block erase, which, for this flash might be a 4K byte block minimum. Use flash.blockErase4K(long address) to erase it.
You can't really use flash like RAM. If you want more flexible non-volatile memory, use EEPROM, using the EEPROM library.
Tom
OK, but can I write something to a byte more than once? In other words, can I write 0xbb to a byte, then write 0xcc to the same byte, then 0xdd to the same byte? Assume I am not doing a block erase between writes.
Ken
Quote from: Prodigal on March 14, 2015, 12:39:23 PM
OK, but can I write something to a byte more than once? In other words, can I write 0xbb to a byte, then write 0xcc to the same byte, then 0xdd to the same byte? Assume I am not doing a block erase between writes.
Ken
I'm not explaining myself very well. In an 'erased' state, a single byte memory location reads as all ones (0xff or 0b11111111). That single byte location has 8 bits. You can only 'write' a zero to any bit, you can NOT 'write' a one to any bit. If a bit is a one already, 'writing' a 1 to that bit will not change its value AND if it is already a 0 writing anything to it will not change its value.
So, given this, yes you
can do multiple writes, but the value of the byte will only change to a progressively fewer number of 1 bits. For an example:
Location A has been erased. It contains 0b11111111.
You write 0xbb to it, it now contains 0b10111011.
You write 0xaa to it, it now contains 0b10101010. This is ok, because you're only changing bits to zero.
You TRY to write 0x55 to it, it now contains 0b00000000 because all bits have been written to zero. The only way to change it from this point is to erase the block it is contained in (which, of course will also erase the other 4K-1 bytes in that block).
If you want to have a non-volatile storage where you can change single bytes, use EEPROM on the ATmega processor.
Tom
Tom,
Thanks. This makes sense.
What I want to do is record readings from my sensor in case the host is unreachable and then send them when the host is back up. Ideally, I will delete each reading after the host acknowledges receipt.
I suppose I can only write one reading in each block. Then, I can erase the entire block after the host acknowledges. This limits me to 1,000 data points but it should be pretty straightforward.
Another way to do this would be to use some kind of beginning and ending record delimiter. When writing a new record, I would have to start at the beginning of a block and look for the first 0xff. That is where I can write the new record.
After a reading is successfully sent to the host, I could write all 0x55s where that record is. If a block has all 0s or 1s, it is safe to erase, otherwise there is data that needs to be sent to the host.
I'll have to write a script to test these options.
Quote from: Prodigal on March 14, 2015, 09:22:12 PM
Tom,
Thanks. This makes sense.
What I want to do is record readings from my sensor in case the host is unreachable and then send them when the host is back up. Ideally, I will delete each reading after the host acknowledges receipt.
I suppose I can only write one reading in each block. Then, I can erase the entire block after the host acknowledges. This limits me to 1,000 data points but it should be pretty straightforward.
Another way to do this would be to use some kind of beginning and ending record delimiter. When writing a new record, I would have to start at the beginning of a block and look for the first 0xff. That is where I can write the new record.
After a reading is successfully sent to the host, I could write all 0x55s where that record is. If a block has all 0s or 1s, it is safe to erase, otherwise there is data that needs to be sent to the host.
I'll have to write a script to test these options.
If you're using the flash for queuing purposes (when the host is unreachable), it's simple enough to use a ping-pong block approach and a round robin buffer.
You sequentially write to one block until you've written all 4K locations, then move to the next block.
You read from the current 'dirty' block (when you send the queue to the host) and, when that entire block has been sent to the host, you can erase it, freeing it for use when the other block is completely written.
Tom