Any experiences with FeRAM's?

Status
Not open for further replies.

sumotoy

Well-known member
FeRAM are ferroelectric ram that don't loose data when powered off and are much faster than flash, don't need write/erase page and can be readed/writed much more times than flash, also it cost resonabily low.
I found some on the net:
MR48V256ATAZBAAL (256K), MR45V064AMAZBATL (64k), all working with fast SPI (20Mhz) and have SOP packadge so it can still be soldered without problems so there's several reason to try.
Before start, someone here have some experience with those ram's?
 
I worked on a project once that used one. I was not the original designer... my part was merely adding a bunch of code to an already existing project that had one on the board.

It worked well. Write times were as fast as the SPI bus.

As I recall, it was a much lower capacity, I believe only 4 or 8 kbytes. But that project was many years ago.

It's too bad these don't come in megabyte sizes. Or maybe they do now? A megabyte or more would be awesome for audio record + play.
 
I'm working with the Adafruit 32 kB FRAM right now.

Initial testing using the Adafruit_FRAM_I2C library accessing the chip via Wire on a Teensy 3.1 at 72 MHz gives me 340 microseconds for a single byte read, 440 microseconds for a single byte write (less loop overhead). That's faster than an EEPROM, but not hugely fast.

I'll try with the i2c_t3 library next and then see if I can write some block read/write functions to speed things along.
 
Thanks happymotion,
btw I think that FRAM will rock only by using SPI since (in some MCU) can go easily over 20Mhz. I2C it's very speed limited with such devices but trying the i2c_t3 at 1mhz would be interesting!
 
Ok, with i2c_t3 instead of Wire, I've had to drop down to 48 MHz, coz "F_BUS" requires it. Using I2C_RATE_1000, single byte reads take 112 us instead of 340. Writes take 80 us instead of 440 us. (I presume that's 1 mHz, but haven't checked.) Setting I2C_RATE_2000 in the Adafruit_FRAM_I2C library speeds these up to 88 us read, 60 us write.

That's a marked improvement, five times faster. I'll try multiple byte reads next.

(And SPI might well help, but my current project is going to be running out of pins, so I'm keen to keep everything using I2C where possible.)
 
Right then...
*rolls up sleeves*
*writes readBlock() & writeBlock()*

With multiple byte reads, I'm getting 21 us per byte with 8 byte chunks, 13 us with 32 byte chunks, and 11 us with 255 byte chunks.

With multiple byte writes, I'm getting 17 us per byte with 8 byte chunks, 13 us with 32 byte chunks, and 11 us with 255 byte chunks.

Considering single byte reads using Wire took 341 us, the speed has gone up by a factor of 300. I'm reasonably pleased about that.

So is there a good repository for libraries that have been changed from Wire to i2c_t3? Actually, I'll ask that in the main I2c_t3 thread. However, for now, here's my modifications to the library:

Adafruit_FRAM_I2C.h
Code:
/**************************************************************************/
/*! 
    @file     Adafruit_FRAM_I2C.h
    @author   KTOWN (Adafruit Industries)

    @section LICENSE

    Software License Agreement (BSD License)

    Copyright (c) 2013, Adafruit Industries
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
    3. Neither the name of the copyright holders nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/
#ifndef _ADAFRUIT_FRAM_I2C_H_
#define _ADAFRUIT_FRAM_I2C_H_

#if ARDUINO >= 100
 #include <Arduino.h>
#else
 #include <WProgram.h>
#endif

#include "i2c_t3.h" //Can be down loaded from http://forum.pjrc.com/threads/21680-New-I2C-library-for-Teensy3
#include <avr/eeprom.h>

#define MB85RC_DEFAULT_ADDRESS        (0x50) /* 1010 + A2 + A1 + A0 = 0x50 default */
#define MB85RC_SLAVE_ID       (0xF8)

class Adafruit_FRAM_I2C {
 public:
  Adafruit_FRAM_I2C(void);
  
  boolean  begin(uint8_t addr = MB85RC_DEFAULT_ADDRESS);
  void     write8 (uint16_t framAddr, uint8_t value);
  uint8_t  read8  (uint16_t framAddr);
  void readBlock(	uint16_t framAddr, uint8_t value[], size_t numBytes);
  void writeBlock(uint16_t framAddr, uint8_t value[], size_t numBytes);
  void     getDeviceID(uint16_t *manufacturerID, uint16_t *productID);

 private:
  uint8_t i2c_addr;
  boolean _framInitialised;
};

#endif

Adafruit_FRAM_I2C.cpp
Code:
/**************************************************************************/
/*!
    @file     Adafruit_FRAM_I2C.cpp
    @author   KTOWN (Adafruit Industries)
    @license  BSD (see license.txt)

    Driver for the Adafruit I2C FRAM breakout.

    Adafruit invests time and resources providing this open source code,
    please support Adafruit and open-source hardware by purchasing
    products from Adafruit!

    @section  HISTORY

    v1.0 - First release
*/
/**************************************************************************/
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <stdlib.h>
#include <math.h>

#include "Adafruit_FRAM_I2C.h"

/*========================================================================*/
/*                            CONSTRUCTORS                                */
/*========================================================================*/

/**************************************************************************/
/*!
    Constructor
*/
/**************************************************************************/
Adafruit_FRAM_I2C::Adafruit_FRAM_I2C(void) 
{
  _framInitialised = false;
}

/*========================================================================*/
/*                           PUBLIC FUNCTIONS                             */
/*========================================================================*/

/**************************************************************************/
/*!
    Initializes I2C and configures the chip (call this function before
    doing anything else)
*/
/**************************************************************************/
boolean Adafruit_FRAM_I2C::begin(uint8_t addr) 
{
  i2c_addr = addr;
  #if defined(__MK20DX128__) || defined(__MK20DX256__) //Teensy 3.0 or Teensy 3.1
	  Wire.begin(I2C_MASTER, 0, I2C_PINS_18_19, I2C_PULLUP_EXT, I2C_RATE_2000);
	#else
	  Wire.begin();
	#endif
  
  /* Make sure we're actually connected */
  uint16_t manufID, prodID;        
  getDeviceID(&manufID, &prodID);
  if (manufID != 0x00A)
  {
    Serial.print("Unexpected Manufacturer ID: 0x");
    Serial.println(manufID, HEX);
    return false;
  }
  if (prodID != 0x510)
  {
    Serial.print("Unexpected Product ID: 0x");
    Serial.println(prodID, HEX);
    return false;
  }

  /* Everything seems to be properly initialised and connected */
  _framInitialised = true;
  return true;
}

/**************************************************************************/
/*!
    @brief  Writes a byte at the specific FRAM address
    
    @params[in] i2cAddr
                The I2C address of the FRAM memory chip (1010+A2+A1+A0)
    @params[in] framAddr
                The 16-bit address to write to in FRAM memory
    @params[in] i2cAddr
                The 8-bit value to write at framAddr
*/
/**************************************************************************/
void Adafruit_FRAM_I2C::write8 (uint16_t framAddr, uint8_t value)
{
  Wire.beginTransmission(i2c_addr);
  Wire.write(framAddr >> 8);
  Wire.write(framAddr & 0xFF);
  Wire.write(value);
  Wire.endTransmission();
}

/**************************************************************************/
/*!
    @brief  Reads an 8 bit value from the specified FRAM address

    @params[in] i2cAddr
                The I2C address of the FRAM memory chip (1010+A2+A1+A0)
    @params[in] framAddr
                The 16-bit address to read from in FRAM memory

    @returns    The 8-bit value retrieved at framAddr
*/
/**************************************************************************/
uint8_t Adafruit_FRAM_I2C::read8 (uint16_t framAddr)
{
  Wire.beginTransmission(i2c_addr);
  Wire.write(framAddr >> 8);
  Wire.write(framAddr & 0xFF);
  Wire.endTransmission();

  // Changed for i2c_t3, requires cast to size_t:
  Wire.requestFrom(i2c_addr, (size_t)1);
  
  return Wire.read();
}

/**************************************************************************/
/*!
    @brief  Reads a block of values from the specified FRAM address

    @params[in] i2cAddr
                The I2C address of the FRAM memory chip (1010+A2+A1+A0)
    @params[in] framAddr
                The 16-bit address to read from in FRAM memory
    @params[in] value[]
                The destination array of single bytes read from in FRAM memory
    @params[in] numBytes
                The size of the block to read, which should be the no larger than the size of the destination array.
                
    @returns    Nothing.
*/
/**************************************************************************/
void Adafruit_FRAM_I2C::readBlock(	uint16_t framAddr, uint8_t value[], size_t numBytes)
{
  Wire.beginTransmission(i2c_addr);
  Wire.write(framAddr >> 8);
  Wire.write(framAddr & 0xFF);
  Wire.endTransmission();

  // Changed for i2c_t3, requires cast to size_t:
  Wire.requestFrom(i2c_addr, numBytes);
  for( uint8_t a=0; a<numBytes; a++ ) { 
    value[a] = Wire.readByte();
  }
  
  return;
}


/**************************************************************************/
/*!
    @brief  Writes a block of values to the specified FRAM address

    @params[in] i2cAddr
                The I2C address of the FRAM memory chip (1010+A2+A1+A0)
    @params[in] framAddr
                The 16-bit address to write to in FRAM memory
    @params[in] value[]
                The source array of single bytes written to in FRAM memory
    @params[in] numBytes
                The size of the block to write, which should be the no larger than the size of the source array.
                
    @returns    Nothing.
*/
/**************************************************************************/

void Adafruit_FRAM_I2C::writeBlock(	uint16_t framAddr, uint8_t value[], size_t numBytes)
{
  Wire.beginTransmission(i2c_addr);
  Wire.write(framAddr >> 8);
  Wire.write(framAddr & 0xFF);
  Wire.write(value, numBytes);
  Wire.endTransmission();
  
  return;
}




/**************************************************************************/
/*!
    @brief  Reads the Manufacturer ID and the Product ID frm the IC

    @params[out]  manufacturerID
                  The 12-bit manufacturer ID (Fujitsu = 0x00A)
    @params[out]  productID
                  The memory density (bytes 11..8) and proprietary
                  Product ID fields (bytes 7..0). Should be 0x510 for
                  the MB85RC256V.
*/
/**************************************************************************/
void Adafruit_FRAM_I2C::getDeviceID(uint16_t *manufacturerID, uint16_t *productID)
{
  uint8_t a[3] = { 0, 0, 0 };
  uint8_t results;
  
  Wire.beginTransmission(MB85RC_SLAVE_ID >> 1);
  Wire.write(i2c_addr << 1);
  // Changed for i2c_t3, requires cast to I2c_stop:
  results = Wire.endTransmission((i2c_stop)false);

  Wire.requestFrom(MB85RC_SLAVE_ID >> 1, 3);
  a[0] = Wire.read();
  a[1] = Wire.read();
  a[2] = Wire.read();

  /* Shift values to separate manuf and prod IDs */
  /* See p.10 of http://www.fujitsu.com/downloads/MICRO/fsa/pdf/products/memory/fram/MB85RC256V-DS501-00017-3v0-E.pdf */
  *manufacturerID = (a[0] << 4) + (a[1]  >> 4);
  *productID = ((a[1] & 0x0F) << 8) + a[2];
}
 
Very nice. I may adapt this for the Adesto RM24 series of NVRAM. Their NVRAM is available in 32kb, 64kb, and 128kb sizes, support 1MHz I2C, and they are <$1 each.
 
Status
Not open for further replies.
Back
Top