0

Fram module i2c vs spi
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Fram module i2c vs spi

by RedIron on Sun Jan 10, 2021 6:54 am

Hi guys hope you are all doing great.

I got my hands on 2 FRAM breakout, one I2C (Adafruit I2C Non-Volatile FRAM Breakout - 256Kbit / 32KByte) and one SPI (MB85RS4MT).
My goal is to test the difference in logging speed between these two, I'm logging struc in order to be able to log different data types. I'm using two standard Arduino Uno (one for each breakout) and the standard Adafruit Fram libraries.

So far I've been able to log data on I2C breakout.
Code: Select all | TOGGLE FULL SIZE
/*
  Based on :
  https://arduino.stackexchange.com/questions/76951/arduino-i2c-external-32kb-fram-data-organization
  https://forum.arduino.cc/index.php?topic=720754.new#new
  https://forum.arduino.cc/index.php?topic=618910.0
*/

#include <Wire.h>
#include "Adafruit_FRAM_I2C.h"

Adafruit_FRAM_I2C fram = Adafruit_FRAM_I2C();
uint16_t framAddr = 0;

unsigned long nbWrites = 0;
unsigned long logTime = 0;
unsigned long logTimer = 0;
unsigned long averageLogTime = 0;
unsigned long maxLogTime = 0;
unsigned long nbLogLess100us = 0;
unsigned long nbLogLess1000us = 0;
unsigned long nbLogMore1000us = 0;
unsigned long nbLogMore10000us = 0;

struct program_data {
  int variable0;
  int variable1;
  int variable2;
  int variable3;
  int variable4;
  int variable5;
  int variable6;
  int variable7;
  int variable8;
  int variable9;
} data;


int address = 0;
int i = 0;


void setup() {
  Serial.begin(115200);
  fram.begin(0x50);
}

void loop() {
  // Start logTimer
  logTimer = micros();

  // Get data
  GetData();

  // Save data
  SaveData(&data);

  // Stop logTimer
  logTime = micros() - logTimer;
  averageLogTime += logTime;

  // Log Time statistics
  LogStats();
  nbWrites++;

  // Print data
  if (nbWrites > 10) {
    address = 0;
    for (int n = 0; n < nbWrites; n++) {
      RestoreData(&data);
    }
    EndStats();
    while (true);
  }
}


void GetData() {
  data.variable0 = nbWrites;
  data.variable1 = 100;
  data.variable2 = 100;
  data.variable3 = 100;
  data.variable4 = 100;
  data.variable5 = 100;
  data.variable6 = 100;
  data.variable7 = 100;
  data.variable8 = 100;
  data.variable9 = 100;
}


void SaveData(struct program_data *data_ptr) {
  byte *ptr = (byte *)data_ptr;

  for (i = 0; i < sizeof(struct program_data); i++) {
    fram.write8(address + i, ptr[i]);
  }
  address = address + i;
}

void RestoreData(struct program_data *data_ptr) {
  byte *ptr = (byte *)data_ptr;

  for (i = 0; i < sizeof(struct program_data); i++) {
    ptr[i] = fram.read8(address + i);
  }

  address = address + i;

  // Print all data
  Serial.print(data.variable0); Serial.print(",");
  Serial.print(data.variable1); Serial.print(",");
  Serial.print(data.variable2); Serial.print(",");
  Serial.print(data.variable3); Serial.print(",");
  Serial.print(data.variable4); Serial.print(",");
  Serial.print(data.variable5); Serial.print(",");
  Serial.print(data.variable6); Serial.print(",");
  Serial.print(data.variable7); Serial.print(",");
  Serial.print(data.variable8); Serial.print(",");
  Serial.print(data.variable9); Serial.print(",");
  Serial.println("");
}

void LogStats() {
  if (logTime > maxLogTime) {
    maxLogTime = logTime;
  }

  if (logTime <= 100) {
    nbLogLess100us++;
  }

  if (logTime > 100 && logTime <= 1000) {
    nbLogLess1000us++;
  }

  if (logTime > 1000 && logTime <= 10000) {
    nbLogMore1000us++;
  }

  if (logTime > 10000) {
    nbLogMore10000us++;
  }
}

void EndStats() {
  Serial.println("");
  Serial.print("Average Log Time"); Serial.print("\t"); Serial.println(averageLogTime / nbWrites);
  Serial.print("Max Log Time"); Serial.print("\t"); Serial.print("\t"); Serial.println(maxLogTime);
  Serial.print("Log Time <100us"); Serial.print("\t"); Serial.print("\t"); Serial.print(nbLogLess100us); Serial.print("\t"); Serial.println(((nbLogLess100us * 100.00) / nbWrites), 1);
  Serial.print("Log Time <1000us"); Serial.print("\t"); Serial.print(nbLogLess1000us); Serial.print("\t"); Serial.println(((nbLogLess1000us * 100.00) / nbWrites), 1);
  Serial.print("Log Time >1000us"); Serial.print("\t"); Serial.print(nbLogMore1000us); Serial.print("\t"); Serial.println(((nbLogMore1000us * 100.00) / nbWrites), 1);
  Serial.print("Log Time >10000us"); Serial.print("\t"); Serial.print(nbLogMore10000us); Serial.print("\t"); Serial.println(((nbLogMore10000us * 100.00) / nbWrites), 1);
}

And I'm get thoses results:
Code: Select all | TOGGLE FULL SIZE
0,100,100,100,100,100,100,100,100,100,
1,100,100,100,100,100,100,100,100,100,
2,100,100,100,100,100,100,100,100,100,
3,100,100,100,100,100,100,100,100,100,
4,100,100,100,100,100,100,100,100,100,
5,100,100,100,100,100,100,100,100,100,
6,100,100,100,100,100,100,100,100,100,
7,100,100,100,100,100,100,100,100,100,
8,100,100,100,100,100,100,100,100,100,
9,100,100,100,100,100,100,100,100,100,
10,100,100,100,100,100,100,100,100,100,

Average Log Time   8490
Max Log Time      8496
Log Time <100us      0   0.0
Log Time <1000us   0   0.0
Log Time >1000us   11   100.0
Log Time >10000us   0   0.0

Code is cleary working.

I then wanted to test the same code (with some minor changes) for the SPI breakout, like so :
Code: Select all | TOGGLE FULL SIZE
#include <SPI.h>
#include "Adafruit_FRAM_SPI.h"

/* Example code for the Adafruit SPI FRAM breakout */
uint8_t FRAM_CS = 10;

Adafruit_FRAM_SPI fram = Adafruit_FRAM_SPI(FRAM_CS);  // use hardware SPI

//uint8_t FRAM_SCK = 13;
//uint8_t FRAM_MISO = 12;
//uint8_t FRAM_MOSI = 11;
//Or use software SPI, any pins!
//Adafruit_FRAM_SPI fram = Adafruit_FRAM_SPI(FRAM_SCK, FRAM_MISO, FRAM_MOSI, FRAM_CS);

uint16_t          addr = 0;

unsigned long nbWrites = 0;
unsigned long logTime = 0;
unsigned long logTimer = 0;
unsigned long averageLogTime = 0;
unsigned long maxLogTime = 0;
unsigned long nbLogLess100us = 0;
unsigned long nbLogLess1000us = 0;
unsigned long nbLogMore1000us = 0;
unsigned long nbLogMore10000us = 0;

struct program_data {
  int variable0;
  int variable1;
  int variable2;
  int variable3;
  int variable4;
  int variable5;
  int variable6;
  int variable7;
  int variable8;
  int variable9;
} data;

int address = 0;
int i = 0;


void setup() {
  Serial.begin(115200);
  if (fram.begin()) {
    Serial.println("Found SPI FRAM");
  } else {
    Serial.println("No SPI FRAM found ... check your connections\r\n");
    while (1);
  }
}

void loop() {
  // Start logTimer
  logTimer = micros();

  // Get data
  GetData();

  // Save data
  SaveData(&data);

  // Stop logTimer
  logTime = micros() - logTimer;
  averageLogTime += logTime;
 
  // Log Time statistics
  LogStats();
  nbWrites++;

  // Print data
  if (nbWrites > 10) {
    address = 0;
    for (int n = 0; n < nbWrites; n++) {
      RestoreData(&data);
    }
    EndStats();
    while (true);
  }
}


void GetData() {
  data.variable0 = nbWrites;
  data.variable1 = 100;
  data.variable2 = 100;
  data.variable3 = 100;
  data.variable4 = 100;
  data.variable5 = 100;
  data.variable6 = 100;
  data.variable7 = 100;
  data.variable8 = 100;
  data.variable9 = 100;
}


void SaveData(struct program_data *data_ptr) {
  byte *ptr = (byte *)data_ptr;
 
  fram.writeEnable(true);
  for (i = 0; i < sizeof(struct program_data); i++) {
    fram.write8(address + i, ptr[i]);
  }
  fram.writeEnable(false);
 
  address = address + i;
}

void RestoreData(struct program_data *data_ptr) {
  byte *ptr = (byte *)data_ptr;

  for (i = 0; i < sizeof(struct program_data); i++) {
    ptr[i] = fram.read8(address + i);
  }

  address = address + i;

  // Print all data
  Serial.print(data.variable0); Serial.print(",");
  Serial.print(data.variable1); Serial.print(",");
  Serial.print(data.variable2); Serial.print(",");
  Serial.print(data.variable3); Serial.print(",");
  Serial.print(data.variable4); Serial.print(",");
  Serial.print(data.variable5); Serial.print(",");
  Serial.print(data.variable6); Serial.print(",");
  Serial.print(data.variable7); Serial.print(",");
  Serial.print(data.variable8); Serial.print(",");
  Serial.print(data.variable9); Serial.print(",");
  Serial.println("");
}

void LogStats() {
  if (logTime > maxLogTime) {
    maxLogTime = logTime;
  }

  if (logTime <= 100) {
    nbLogLess100us++;
  }

  if (logTime > 100 && logTime <= 1000) {
    nbLogLess1000us++;
  }

  if (logTime > 1000 && logTime <= 10000) {
    nbLogMore1000us++;
  }

  if (logTime > 10000) {
    nbLogMore10000us++;
  }
}

void EndStats() {
  Serial.println("");
  Serial.print("Average Log Time"); Serial.print("\t"); Serial.println(averageLogTime / nbWrites);
  Serial.print("Max Log Time"); Serial.print("\t"); Serial.print("\t"); Serial.println(maxLogTime);
  Serial.print("Log Time <100us"); Serial.print("\t"); Serial.print("\t"); Serial.print(nbLogLess100us); Serial.print("\t"); Serial.println(((nbLogLess100us * 100.00) / nbWrites), 1);
  Serial.print("Log Time <1000us"); Serial.print("\t"); Serial.print(nbLogLess1000us); Serial.print("\t"); Serial.println(((nbLogLess1000us * 100.00) / nbWrites), 1);
  Serial.print("Log Time >1000us"); Serial.print("\t"); Serial.print(nbLogMore1000us); Serial.print("\t"); Serial.println(((nbLogMore1000us * 100.00) / nbWrites), 1);
  Serial.print("Log Time >10000us"); Serial.print("\t"); Serial.print(nbLogMore10000us); Serial.print("\t"); Serial.println(((nbLogMore10000us * 100.00) / nbWrites), 1);
}


But I'm getting only 0 !
Code: Select all | TOGGLE FULL SIZE
Found SPI FRAM
127,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,

Average Log Time   1473
Max Log Time      1532
Log Time <100us      0   0.0
Log Time <1000us   0   0.0
Log Time >1000us   11   100.0
Log Time >10000us   0   0.0


I should add that the SPI breakout is working, I've been able to log on it.

Why is the SPI version not working ? Any ideas ?
Any help is greatly appreciated. Thanks

RedIron
 
Posts: 5
Joined: Sun Jan 10, 2021 6:23 am

Re: Fram module i2c vs spi

by mikeysklar on Mon Jan 11, 2021 8:12 pm

@RedIron,

It looks like you are pretty close to getting both going.

Since these devices are different sized FRAM chips (256k and 32k) they probably have different address sizes you need to adjust the code for.

You can run the FRAMinfo.ino on each device and see the output for specifics. I think the default is 2-byte so you might need to change one to be a 3-byte. A change like fram.begin(3) might need to be added.

mikeysklar
 
Posts: 3415
Joined: Mon Aug 01, 2016 8:10 pm

Re: Fram module i2c vs spi

by RedIron on Tue Jan 12, 2021 3:00 pm

Hi mikeysklar,

You are exactly right. It was indeed because I didn't the default 2bytes.
Now with fram.begin(3) it works well.
Code: Select all | TOGGLE FULL SIZE
0,100,100,100,100,100,100,100,100,100,
1,101,101,101,101,101,101,101,101,101,
2,102,102,102,102,102,102,102,102,102,
3,103,103,103,103,103,103,103,103,103,
4,104,104,104,104,104,104,104,104,104,
5,105,105,105,105,105,105,105,105,105,
6,106,106,106,106,106,106,106,106,106,
7,107,107,107,107,107,107,107,107,107,
8,108,108,108,108,108,108,108,108,108,
9,109,109,109,109,109,109,109,109,109,

Running at 50Hz, 10 writes, generated 0 errors, total Time in seconds: 0.20
Average Log Time   1726 us
Max Log Time      1732 us
Log Time <100us      0   0.0
Log Time <1000us   0   0.0
Log Time >1000us   10   100.0
Log Time >10000us   0   0.0



Thanks for your help

RedIron
 
Posts: 5
Joined: Sun Jan 10, 2021 6:23 am

Re: Fram module i2c vs spi

by mikeysklar on Tue Jan 12, 2021 5:31 pm

Cool. That is a tricky one.

mikeysklar
 
Posts: 3415
Joined: Mon Aug 01, 2016 8:10 pm

Re: Fram module i2c vs spi

by RedIron on Thu Jan 14, 2021 4:12 am

Who should I write to if I want to propose some changes/addition to the library ?

RedIron
 
Posts: 5
Joined: Sun Jan 10, 2021 6:23 am

Re: Fram module i2c vs spi

by mikeysklar on Thu Jan 14, 2021 6:44 pm

@RedIron,

You can open up issues or feature requests on the github archive:

https://github.com/adafruit/Adafruit_FRAM_I2C/issues

mikeysklar
 
Posts: 3415
Joined: Mon Aug 01, 2016 8:10 pm

Please be positive and constructive with your questions and comments.


cron