References/links:
Unfortunately the TL866II Plus programmer can read but cannot write to the FM24C04B FRAM. For more details see this thread on the EEVBLOG forum. An HP 34970A I bought some time ago had the classic 74x calibration errors caused by the FRAMs.

So I though the fastest way to program the FRAMs would be to write some arduino code for my I2C Memory Programmer. The program needs a table called pages which hold all the data from the FRAM. It can then program the FRAM with the contents of the table or verify them against it. If you need to create a pages table you can read the contents and copy the output to the code. You will have to reload the program to the arduino.
// ****************************************************************************** | |
// Cypress FM24C04B FRAM reading/writing with Arduino | |
// Used to read/write FRAMs from an HP 34970A | |
// 2021 Grease monkey - No rights reserved | |
// !!! Don't laugh at the code. I change engine oils for a living !!! | |
// FRAM library: https://github.com/battosai30/FRAM | |
// ****************************************************************************** | |
#include <FRAM.h> | |
#include <Wire.h> | |
FRAM fram(0b00); // i2c address is determined by state of pins A2 and A1 | |
// for example, if A2 = VCC and A1 = GND write : FRAM fram(0b10); | |
// Mainboard Unit 2 FRAM Contents | |
byte pages[2][256]= | |
{ | |
{ | |
0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x0, 0x9, 0x0, 0x0, 0x0, 0x10, 0x87, 0xAB, 0x20, 0x9, | |
0x0, 0x14, 0x0, 0x0, 0xA7, 0xD4, 0x0, 0x64, 0x28, 0x48, 0x46, 0x6C, 0xDD, 0xCB, 0x0, 0x60, | |
0x0, 0x0, 0x30, 0x0, 0x87, 0x6, 0xA7, 0xD4, 0xB, 0x34, 0x6, 0x1A, 0x3A, 0x99, 0x8C, 0x90, | |
0x32, 0x6, 0x85, 0x16, 0x19, 0x20, 0x6, 0xC, 0xC9, 0x3, 0xAE, 0x6A, 0x10, 0xDC, 0x0, 0x0, | |
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xE3, 0x49, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 | |
}, | |
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} | |
}; | |
void setup() { | |
// Setup serial coms | |
Serial.begin(115200); | |
} | |
void loop() { | |
// Main menu loop | |
byte incomingByte = 0; | |
Serial.println("\n\nFM24C04B Memory read/write/verify:"); | |
Serial.println("\n\nSelect option:"); | |
Serial.println(" 1. Read memory contents"); | |
Serial.println(" 2. Write memory contents"); | |
Serial.println(" 3. Compare against table"); | |
// Read incoming character | |
while (1){ | |
if (Serial.available() > 0) { | |
incomingByte = Serial.read(); | |
if (incomingByte >= 49 && incomingByte <= 51) | |
break; | |
} | |
} | |
// Take action | |
switch(incomingByte){ | |
case 49: | |
Serial.println("\n\nReading memory:"); | |
readMemory(); | |
create_table(); | |
break; | |
case 50: | |
Serial.println("\n\nWriting to memory:"); | |
writepage(0); | |
writepage(1); | |
break; | |
case 51: | |
Serial.println("\n\nComparing memory:"); | |
CompareMemory(); | |
break; | |
default: | |
break; | |
} | |
} | |
// Reads the whole FRAM memory and prints a table of the contents | |
void readMemory() | |
{ | |
int a = 0; | |
int b = 0; | |
int page = 0; | |
for (page=0; page<2; page++) | |
{ | |
Serial.print("\n\nPage "); | |
Serial.print(page); | |
Serial.print(":\n\t00\t01\t02\t03\t04\t05\t06\t07\t08\t09\t0A\t0B\t0C\t0D\t0E\t0F\n\n"); | |
for (a=0; a<16; a++) | |
{ | |
Serial.print(a,HEX); | |
Serial.print("0h\t"); | |
for (b=0; b<16; b++) | |
{ | |
Serial.print(fram.ReadByte(page,a*16+b),HEX); | |
Serial.print("\t"); | |
} | |
Serial.print("\n"); | |
} | |
} | |
} | |
// Reads the whole FRAM memory, compares it to pages[] table and prints the number of mismatched bytes | |
void CompareMemory() | |
{ | |
int a = 0; | |
int b = 0; | |
int page = 0; | |
int errorCounter = 0; | |
for (page=0; page<2; page++) | |
{ | |
for (a=0; a<16; a++) | |
{ | |
for (b=0; b<16; b++) | |
{ | |
if(fram.ReadByte(page,a*16+b) != pages[page][a*16+b]) | |
{ | |
Serial.print("Page "); | |
Serial.print(page); | |
Serial.print(" , "); | |
Serial.print(a*16+b, HEX); | |
Serial.print(" Fram: 0x"); | |
Serial.print(fram.ReadByte(page,a*16+b),HEX); | |
Serial.print(" Table: 0x"); | |
Serial.println(pages[page][a*16+b],HEX); | |
errorCounter++; | |
} | |
} | |
} | |
} | |
Serial.print(errorCounter); | |
Serial.println(" errors"); | |
} | |
/* Reads the whole FRAM memory and prints a pages[] table eg: | |
byte pages[2][256]= | |
{ | |
{data...}, | |
{data...} | |
}; */ | |
void create_table() | |
{ | |
int a = 0; | |
int b = 0; | |
int p = 0; | |
byte tmp = 0; | |
Serial.print("\n\nbyte pages[2][256]=\n{\n"); | |
for (p=0; p<2; p++) | |
{ | |
Serial.print(" {\n "); | |
for (a=0; a<16; a++) | |
{ | |
for (b=0; b<16; b++) | |
{ | |
Serial.print("0x"); | |
tmp = fram.ReadByte(p,a*16+b); | |
if (tmp <= 0x0F) | |
Serial.print("0"); | |
Serial.print(tmp,HEX); | |
if (a!=15 || b!=15) | |
Serial.print(", "); | |
} | |
if (a!=15) | |
Serial.print("\n "); | |
} | |
if (p==0) | |
Serial.print("\n },\n"); | |
else | |
Serial.print("\n }\n};\n"); | |
} | |
} | |
// Writes all the contents of the pages[] table to the FRAM memory | |
void writepage(int page) | |
{ | |
int a = 0; | |
int b = 0; | |
for (a=0; a<16; a++) | |
{ | |
for (b=0; b<16; b++) | |
{ | |
fram.WriteByte(page,a*16+b,pages[page][a*16+b]); | |
} | |
} | |
} |