FRAM-Speicher MB85RC256V

FRAM (Ferroelectric Random Access Memory) ist ein nichtflüchtiger, elektronischer Speichertyp, den man als kleines Modul zur leichten Speicherweiterung für seinen Mikrocontroller (hier: Arduino Uno) verwenden kann.

FRAM-Modul MB85RC256V
Abb.: FRAM-Modul MB85RC256V mit I²C-Schnittstelle

Gegenüber eines EEPROMs gibt es einige Vorteile zu bedenken: Das FRAM ermöglich deutlich mehr Schreibzyklen, haben eine höhere Schreibgeschwindigkeit, einem Bruchteil des Stromverbrauches und eine höhere Resistenz gegenüber Strahlung. Außerdem soll der Speicher recht lange halten, d.h. bei Raumtemperatur bis zu 100 Jahre und bei 85°C wohl bis zu 10 Jahre.

Verwendete Bauteile

Anschlüsse

MB85RC256V Arduino Uno
VCC 5V
GND GND
WP -
SCL A5
SDA A4
A2 GND (alt.: VCC)
A1 GND (alt.: VCC)
A0 GND (alt.: VCC)

WP (Write Protect) ist standardmäßig auf einen internen Pulldown-Widerstand gesetzt. Gibt man diesem Pin ein HIGH-Signal, wird der Schreibschutz des FRAM-Speichers aktiviert.
Die I²C-Adresse des FRAM-Moduls kann durch die Eingänge A2, A1 und A0 geändert werden, indem sie entweder auf GND (Adresse: 0x50) oder VCC (Adresse: 0x57) geschaltet werden.

Aufbau der Schaltung

Schaltplan für Arduino und FRAM-Speicher MB85RC256V

Um leichter Zugriff auf das FRAM-Modul zu bekommen, bietet sich eine Library an. Davon werden hier im Folgenden einige getestet. Der Versuchsaufbau ist immer derselbe. 5 LEDs können über zwei Mikrotaster an- oder ausgeschaltet werden. Durch den nicht-flüchtigen FRAM soll der Status der LEDs gespeichert werden und dann auch nach dem Ausschalten bzw. Reset des Arduino wieder abrufbar sein.

Library "sosandroid/FRAM_MB85RC_I2C"

Mit der Library sosandroid/FRAM_MB85RC_I2C sieht der Sketch folgendermaßen aus:

#include <Wire.h>
#include <FRAM_MB85RC_I2C.h>

#define PIN_BUTTON_TOGGLE 7
#define PIN_BUTTON_MODE   6

// Pins of the connected LEDs
#define LED_AMOUNT 5
const byte leds[LED_AMOUNT] = {8, 9, 10, 11, 12};

#define PRESS_OFFSET 500 // in milliseconds
#define lmillis() ((long)millis())

uint16_t addresses[LED_AMOUNT];
uint8_t framVal, ledStatus[LED_AMOUNT];
long lastButtonPress;
byte ledIndex;
FRAM_MB85RC_I2C fram;

void setup()
{
    Wire.begin();
    fram.begin();

    pinMode(PIN_BUTTON_MODE, INPUT_PULLUP);
    pinMode(PIN_BUTTON_TOGGLE, INPUT_PULLUP);
    for (byte i = 0; i < LED_AMOUNT; i++) {
        pinMode(leds[i], OUTPUT);

        addresses[i] = 0x025 + i;
        fram.readByte(addresses[i], &ledStatus[i]);
        if (ledStatus[i] < 0 || ledStatus[i] > 1) {
            ledStatus[i] = 0;
            fram.writeByte(addresses[i], ledStatus[i]);
        }
        digitalWrite(leds[i], ledStatus[i]);
    }
    lastButtonPress = lmillis() + PRESS_OFFSET;
    ledIndex = 0;
}

void loop()
{
    if (lmillis() - lastButtonPress >= 0) {
        if (digitalRead(PIN_BUTTON_MODE) == LOW) {
            lastButtonPress = lmillis() + PRESS_OFFSET;
            ledIndex = ++ledIndex % LED_AMOUNT;
        } else if (digitalRead(PIN_BUTTON_TOGGLE) == LOW) {
            lastButtonPress = lmillis() + PRESS_OFFSET;
            ledStatus[ledIndex] = ++ledStatus[ledIndex] % 2;
            fram.writeByte(addresses[ledIndex], ledStatus[ledIndex]);
            digitalWrite(leds[ledIndex], ledStatus[ledIndex]);
        }
    }
}

Speicherverbrauch

Library "adafruit/Adafruit_FRAM_I2C"

Der Unterschied von der vorherigen Library zur adafruit/Adafruit_FRAM_I2C ist marginal:

#include <Adafruit_EEPROM_I2C.h>

#define PIN_BUTTON_TOGGLE 7
#define PIN_BUTTON_MODE   6

// Pins of the connected LEDs
#define LED_AMOUNT 5
const byte leds[LED_AMOUNT] = {8, 9, 10, 11, 12};

#define FRAM_ADDR 0x50  // default address

#define PRESS_OFFSET 500 // in milliseconds
#define lmillis() ((long)millis())

uint16_t addresses[LED_AMOUNT];
uint8_t framVal, ledStatus[LED_AMOUNT];
long lastButtonPress;
byte ledIndex;
Adafruit_EEPROM_I2C fram;

void setup()
{
    fram.begin(FRAM_ADDR);

    pinMode(PIN_BUTTON_MODE, INPUT_PULLUP);
    pinMode(PIN_BUTTON_TOGGLE, INPUT_PULLUP);
    for (byte i = 0; i < LED_AMOUNT; i++) {
        pinMode(leds[i], OUTPUT);

        addresses[i] = 0x025 + i;
        ledStatus[i] = fram.read(addresses[i]);
        if (ledStatus[i] < 0 || ledStatus[i] > 1) {
            ledStatus[i] = 0;
            fram.write(addresses[i], ledStatus[i]);
        }
        digitalWrite(leds[i], ledStatus[i]);
    }
    lastButtonPress = lmillis() + PRESS_OFFSET;
    ledIndex = 0;
}

void loop()
{
    if (lmillis() - lastButtonPress >= 0) {
        if (digitalRead(PIN_BUTTON_MODE) == LOW) {
            lastButtonPress = lmillis() + PRESS_OFFSET;
            ledIndex = ++ledIndex % LED_AMOUNT;
        } else if (digitalRead(PIN_BUTTON_TOGGLE) == LOW) {
            lastButtonPress = lmillis() + PRESS_OFFSET;
            ledStatus[ledIndex] = ++ledStatus[ledIndex] % 2;
            fram.write(addresses[ledIndex], ledStatus[ledIndex]);
            digitalWrite(leds[ledIndex], ledStatus[ledIndex]);
        }
    }
}

Speicherverbrauch

Library "MyFRAM_I2C"

Die dritte Library, die ich hier ausprobiere, ist MyFRAM_I2C. Auch hier ist die Verwendung ähnlich zu den oberen beiden Libraries, jedoch wird deutlich weniger Flash- und SRAM-Speicher verwendet (s.u.)

#include "MyFRAM_I2C.h"

#define PIN_BUTTON_TOGGLE 7
#define PIN_BUTTON_MODE   6

// Pins of the connected LEDs
#define LED_AMOUNT 5
const byte leds[LED_AMOUNT] = {8, 9, 10, 11, 12};

#define FRAM_ADDR 0x50  // default address

#define PRESS_OFFSET 500 // in milliseconds
#define lmillis() ((long)millis())

uint16_t addresses[LED_AMOUNT];
long lastButtonPress;
byte ledIndex, ledStatus[LED_AMOUNT];
MyFRAM_I2C fram;

void setup()
{
    fram.setSize(32); // FRAM size: 32 kBit
    fram.init(FRAM_ADDR);

    pinMode(PIN_BUTTON_MODE, INPUT_PULLUP);
    pinMode(PIN_BUTTON_TOGGLE, INPUT_PULLUP);
    for (byte i = 0; i < LED_AMOUNT; i++) {
        pinMode(leds[i], OUTPUT);

        addresses[i] = 0x025 + i;
        ledStatus[i] = fram.readByte(addresses[i]);
        if (ledStatus[i] < 0 || ledStatus[i] > 1) {
            ledStatus[i] = 0;
            fram.writeByte(addresses[i], ledStatus[i]);
        }
        digitalWrite(leds[i], ledStatus[i]);
    }
    lastButtonPress = lmillis() + PRESS_OFFSET;
    ledIndex = 0;
}

void loop()
{
    if (lmillis() - lastButtonPress >= 0) {
        if (digitalRead(PIN_BUTTON_MODE) == LOW) {
            lastButtonPress = lmillis() + PRESS_OFFSET;
            ledIndex = ++ledIndex % LED_AMOUNT;
        } else if (digitalRead(PIN_BUTTON_TOGGLE) == LOW) {
            lastButtonPress = lmillis() + PRESS_OFFSET;
            ledStatus[ledIndex] = ++ledStatus[ledIndex] % 2;
            fram.writeByte(addresses[ledIndex], ledStatus[ledIndex]);
            digitalWrite(leds[ledIndex], ledStatus[ledIndex]);
        }
    }
}

Speicherverbrauch

zurück