The memory range is up to 0x7FFF (32KB). The 'TestEprom' function writes an increasing value in a memory range and then read the same location printing the result in the monitor. I was expecting to receive a reading error after the fram upper address limit is reached; actually, I get valid results even from addresses over the top.
For sure I'm doing something wrong, but I can not find the error.
I exctracted the relevant part from the original sketch and this is the code I'm testing, with the results I got:
#include <Wire.h>
#include <Adafruit_FRAM_I2C.h>
#define FRAM_ADDRESS 0x51 //A0 set by a solder on board
Adafruit_FRAM_I2C fram = Adafruit_FRAM_I2C();
void setup() {
Wire.begin();
Serial.begin(115200);
fram.begin(FRAM_ADDRESS);
FRAMID();
TestEprom(0x7ff8, 0x10);
}
void loop() {
}
void FRAMID() {
uint16_t manufID, prodID;
fram.getDeviceID(&manufID, &prodID);
Serial.print("Manufacturer ID: 0x");
Serial.println(manufID, HEX);
Serial.print("Product ID: 0x");
Serial.println(prodID, HEX);
}
void TestEprom(uint16_t from, uint16_t num) {
uint8_t cnt, v;
for (uint16_t a = from; a < from + num; a++) {
fram.write(a, cnt);
// the following row is to ensure that what I am reading is not due to
// address wrapping to 0 after the top
fram.write(cnt, 0);
delay(1);
v = fram.read(a);
if (v == cnt) {
Serial.print("0x");
Serial.print(a, HEX);
Serial.print(": ");
Serial.print(v);
Serial.print(", ");
cnt++;
} else {
Serial.println(F("\n EEPROM read failed !"));
return;
}
Serial.println();
}
}
//Serial monitor output
Manufacturer ID: 0xA
Product ID: 0x510
0x7FF8: 0,
0x7FF9: 1,
0x7FFA: 2,
0x7FFB: 3,
0x7FFC: 4,
0x7FFD: 5,
0x7FFE: 6,
0x7FFF: 7,
0x8000: 8,
0x8001: 9,
0x8002: 10,
0x8003: 11,
0x8004: 12,
0x8005: 13,
0x8006: 14,
0x8007: 15,
The code I posted is complete and I use it for testing; it shows what happens.
In the code there is this line:
// the following row is to ensure that what I am reading is not due to
// address wrapping to 0 after the top
fram.write(cnt, 0);
I suspected that the Eprom could fall back to 0 when the address exceed the max range, so with the above line I write a 0 in all the cells starting from address 0.
The next reading should return 0 if there was a fall back, otherwise it returns the 'cnt' value, as it actually happens.
Why are you writing a 0 into address cnt? cnt has no correlation to the memory address that would be overwritten if the unused upper address bits were ignored.
Shouldn't it be something like this:
I use 'cnt' as address since it spans from 0 to num (0x10 in my case), so I'm writing a 0 in these cells (0..16).
Now, If the Fram address is 'truncated' after 0x7fff the next writing will happens to address 0x0000 for 0x8000, 0x0001 for 0x8001...
Reading back the memory if there is a fall back to 0 after 0x7fff and I read address 0x8000 I will actually read address 0x0000, which I set to 0 ); the same for address 0x8001 = address 0x0001...
In other words I should read all 0s after 0x7fff; actually, as stated, I read the current value of cnt, from 8 to 15.
Hope this is clear
Sry, looking through the tiny windo earlier I saw "extracted" and failed to look closer to see that you had already made a minimum sketch for yourself and us.
When address = 0x7FF8, you write 0 to location 0
When address = 0x7FF9, you write 0 to location 1
....
When address = 0x7FFF, you write 0 to location 7
When address = 0x8000, you write 0 to location 8 -- if 0x8000 overwrites location 0, then it will no longer be 0, it will be 8 when you read it back.
Try this, where you are writing to the upper part of FRAM first, then setting the beginning of FRAM to 0 before reading back the data you wrote to the upper part.
void TestEprom(uint16_t from, uint16_t num) {
uint8_t cnt = 0;
uint8_t v;
for (uint16_t a = from; a < from + num; a++) {
fram.write(a, cnt);
delay(1);
cnt++;
}
cnt = 0;
//write 0 to the first num locations of FRAM
for (uint16_t a = from; a < from + num; a++) {
fram.write(cnt, 0);
delay(1);
cnt++;
}
cnt = 0;
for (uint16_t a = from; a < from + num; a++) {
v = fram.read(a);
if (v == cnt) {
Serial.print("0x");
Serial.print(a, HEX);
Serial.print(": ");
Serial.print(v);
Serial.print(", ");
cnt++;
} else {
Serial.println(F("\n EEPROM read failed !"));
return;
}
Serial.println();
}
}
Good point david_2018, this is what I, almost, just did and the results are even more intriguing.
I added a new function (NewTestEprom) and I printed the results for both functions (for 8 cells only to shorten it).
This is the modified sketch:
#include <Wire.h>
#include <Adafruit_FRAM_I2C.h>
#define FRAM_ADDRESS 0x51 //A0 set by a solder on board
Adafruit_FRAM_I2C fram = Adafruit_FRAM_I2C();
void setup() {
Wire.begin();
Serial.begin(115200);
delay(200);
fram.begin(FRAM_ADDRESS);
Serial.println("Original TestEprom");
TestEprom(0x7ffc, 0x08);
Serial.println();
Serial.println("New TestEprom");
NewTestEprom(0x7ffc, 0x08);
}
void loop() {
}
void TestEprom(uint16_t from, uint16_t num) {
uint8_t cnt, vMem, vStart;
uint16_t startAdr = 0;
cnt=0;
for (uint16_t a = from; a < from + num; a++) {
fram.write(a, cnt);
fram.write(startAdr, 100 + cnt); //fills the first 'num' cells with a counter
vMem = fram.read(a);
vStart = fram.read(startAdr);
Serial.print("RealMemAddr: ");
Serial.print(a, HEX);
Serial.print(" = ");
Serial.print(vMem);
Serial.print(" - StartMem: 0x");
Serial.print(startAdr, HEX);
Serial.print(" = ");
Serial.println(vStart);
cnt++;
startAdr++;
}
}
void NewTestEprom(uint16_t from, uint16_t num) {
uint8_t cnt, v;
cnt = 0;
for (uint16_t a = from; a < from + num; a++) {
fram.write(a, cnt);
cnt++;
}
for (uint16_t a = 0; a < num; a++) {
fram.write(a, a + 100); //this to ensure that what I am reading is not due to address wrap to 0 after the top
}
cnt = 0;
for (uint16_t a = from; a < from + num; a++) {
v = fram.read(a);
Serial.print("RealMemAddr: 0x");
Serial.print(a, HEX);
Serial.print(" = ");
Serial.println(v);
cnt++;
}
}
As you see, the TestEprom still gives wrong values while the new NewTestEprom is correct as expected.
Now the point is: where is my stupid bug into the TestEprom function?
The proceeding appears the same to me; the New function has just the 3 operations (write values, clear the low memory, read values) separated in 3 different cycles.
I'm confused.
Why would you expect that? Memory rarely has anything to detect that sort of error, and libraries for accessing memory usually don't add it.
For example, an AVR will happily let you do reads and writes beyond the end of RAM memory, and the only indication you'll get that you've done something wrong is that weird things might happen. (maybe values written disappear and reads result in random values. Maybe the addresses "wrap" and you end up accessing memory at lower addresses.)
Calling the function with a starting address of 0x7FFC, it does the following:
write 0 to 0x7FFC, write 100 to 0x0000, read 0x7FFC ( 0), read 0x0000 (100)
write 1 to 0x7FFD, write 101 to 0x0001, read 0x7FFD (1), read 0x0001 (101)
write 2 to 0x7FFE, write 102 to 0x0002, read 0x7FFE (2), read 0x0002 (102)
write 3 to 0x7FFF, write 103 to 0x0003, read 0x7FFF (3), read 0x0003 (103)
write 4 to 0x8000, write 104 to 0x0004, read 0x8000 (4), read 0x0004 (104)
This is where it goes wrong. The write to 0x8000 is actually writing to location 0x0000, which overwrites the 100 that you wrote to 0x0000 earlier. When you read from 0x8000, it is actually reading from 0x0000, which now contains the 4 that you just wrote to it. The write to 0x0004 is totally irrelevant, and has no effect on address 0x8000 or 0x0000, and anything you wrote to 0x0000 before the write to 0x8000 also has no effect.
The NewTestEprom function works properly because the write to 0x8000, that actually places data into address 0x0000, is later overwritten by the explicit write to 0x0000. This results in the later read of 0x8000 returning the data from the write to 0x0000 instead of the data from the write to 0x8000.
You are totally right. It was a my (stupid) mistake in the flow.
I rewritten on a piece of paper the sequence with all the addresses and I found my error.
Thanks David