Ich habe mir mal die FRAM Speicher auf den Tisch geholt

Antworten
Benutzeravatar
Admin
Administrator
Beiträge: 1282
Registriert: Mo 20. Apr 2020, 09:47
Wohnort: 82441 Ohlstadt
Kontaktdaten:

Ich habe mir mal die FRAM Speicher auf den Tisch geholt

Beitrag von Admin »

Ja diese FRAM haben ja offenbar sehr viele Schreib/Lese Zugriffe. Die gefallen mir seeeehr gut. meine Test FRAM´s sind 32MB brauchen wenig Strom und sind offenbar sehr schnell. Damit kann man wichtige Daten zwischenspeichern, dass man bei Ausfall der Spannung, also bei Neustart der CPU wieder da ansetzen kann, wo man zuletzt war. Also keine Datenausfälle.

Das ist guuuut, das kommt in die Suppe. :(V):

Also die nächten Tage werde ich wohl mal da dran bleiben.
Franz

Das hier habe ich im Google aus KI zum FRAM gefunden:
--------------------------------------------------------------------
FRAM-Speicher (Ferroelectric Random Access Memory) ist extrem langlebig und ermöglicht eine praktisch unbegrenzte Anzahl an Schreib-/Lesezugriffen, oft in der Größenordnung von über
10 Milliarden Zyklen (10^10), was weit über die Lebensdauer von Flash-Speichern hinausgeht und ihn ideal für Anwendungen mit häufigen Schreibvorgängen macht, bei denen Daten nicht verloren gehen dürfen. Im Gegensatz zu herkömmlichem RAM sind die Daten in FRAM auch ohne Stromversorgung nicht flüchtig, sodass sie auch nach einem Stromausfall erhalten bleiben.

Hohe Lebensdauer: Mehr als 10 Milliarden Lese-/Schreibzyklen sind typisch, was die Lebensdauer praktisch unbegrenzt macht.
Nichtflüchtig: Daten bleiben auch bei Stromausfall erhalten, ähnlich wie bei Flash-Speicher, aber mit viel schnelleren Schreibvorgängen.
Schnelle Zugriffe: Sehr schnelle Schreibzeiten ermöglichen zahlreiche Zugriffe in kurzer Zeit, oft im Sekundentakt über Jahrzehnte hinweg.
Geringer Stromverbrauch: Im Vergleich zu traditionellen RAM-Typen benötigt FRAM weniger Strom, insbesondere bei Schreibvorgängen.

Vergleich zu anderen Speichertypen:

RAM: Kann beliebig oft beschrieben werden, verliert aber die Daten ohne Strom.
Flash-ROM: Hat eine begrenzte Anzahl von Schreibzyklen (z.B. 1.000–10.000), die oft schneller erschöpft sind als bei FRAM
------------------------------------------------------------------
Benutzeravatar
Admin
Administrator
Beiträge: 1282
Registriert: Mo 20. Apr 2020, 09:47
Wohnort: 82441 Ohlstadt
Kontaktdaten:

Re: Ich habe mir mal die FRAM Speicher auf den Tisch geholt

Beitrag von Admin »

Das ist ein Bespielcode aus der FRAM - Lib (Adafruit_FRAM_I2C). Ein bischen für mich angepasst. Die Speicher - Adressen gebe ich Dezial aus. und nur die ersten 96 Byte. Mehr gibt es bei dem Test nicht zu sehen. Der läuft schon mal auf einem ESP32 D1 Mini, mit dem 32KB FRAM.

Das Programm macht bis jetzt noch nicht viel. Es liest nach jedem Neustart den Wert auf der erten Speicherstelle aus, addiert ihn +1 und schreibt ihn wieder zurück. Also kann man da wunderbar dafür sorgen, dass die zuletzt von irgendwo bekommenen Werte bei einem Spannungsausfall nicht verloren gehen. Man bekommt die Daten, z.B. von einem Poti, das man eingestellt hat, oder das man über I2C von einer anderen Stelle bekommen hat, speichert sie sofort im FRAM und arbeitet erst dann, mit diesen Daten weiter. Wenn dann ein Spannungsausfall für einen Restart sorgt, holt man sich beim Neustart schon im Setup die zuletzt bekommenen Daten, und kann weiterarbeiten als wenn nichts gewesen wäre. Das gefällt meines Vaters Sohn. :oo:

Code: Alles auswählen

#include "Adafruit_FRAM_I2C.h"

/* Beispielcode für das Adafruit I2C FRAM Breakout-Board */

/* Connect SCL    to analog 5
   Connect SDA    to analog 4
   Connect VDD    to 5.0V DC
   Connect GROUND to common ground */

Adafruit_FRAM_I2C fram = Adafruit_FRAM_I2C();

void setup(void) {
  Serial.begin(115200);

  if (fram.begin()) {  // Sie können die neue I2C-Adresse hier einfügen, z. B. begin(0x51);
    Serial.println("I2C FRAM gefunden");
  } else {
    Serial.println("I2C FRAM nicht identifiziert ... überprüfen Sie Ihre Verbindungen?\r\n");
    Serial.println("Wird fortgesetzt, falls dieser Prozessor wiederholte Operationen nicht unterstützt start\r\n");
    while (1)
      ;
  }

  // Lies das erste Byte
  uint8_t test = fram.read(0x0);
  Serial.print("Neustart Zähler ");
  Serial.println(test);
 
  // Test schreiben ++
  fram.write(0x0, test + 1);

  // Den gesamten 32K-Speicherinhalt auslesen!
  uint8_t value;
  for (uint16_t a = 0; a < 96; a++) { // Bis zu 32768 Byte !! Hier nur 96.
    value = fram.read(a);  // Speicherstelle auslesen
    if ((a % 16) == 0) {   // 16 byte in einer Zeile am Bildschirm darstellen.
      Serial.print("\n ");
      //Serial.print(a, HEX);  // Speicherstellen Zähler in HEX ausgeben
      Serial.print(a);       // Speicherstellen Zähler in Dezimal ausgeben
      Serial.print(": ");
    }
    Serial.print("0x");
    if (value < 0x1)
      Serial.print('0');
    Serial.print(value);  // Den Wert der Speicherstelle ausgeben
    Serial.print(" ");
  }
  Serial.println();
  Serial.println(F("####################################################################################")); // Aus Optischen Gründen.
}

void loop(void)  // Wird nicht genutzt, weil er nur einen Durchgang im Setup macht.
{
}
Benutzeravatar
Admin
Administrator
Beiträge: 1282
Registriert: Mo 20. Apr 2020, 09:47
Wohnort: 82441 Ohlstadt
Kontaktdaten:

Re: Ich habe mir mal die FRAM Speicher auf den Tisch geholt

Beitrag von Admin »

Hier ist mal ein Bild von meinem "Testaufbau", der ja nun wirklich seeeeehr einfach ist. :) Ein ESP32 D1 Mini mit einem 32KB FRAM über die I2C Schnittstelle angeschlossen. Spannung hier einfach über USB vom PC.
ESP32_I2C_FRAM.jpg
ESP32_I2C_FRAM.jpg (301.17 KiB) 792 mal betrachtet
Benutzeravatar
Admin
Administrator
Beiträge: 1282
Registriert: Mo 20. Apr 2020, 09:47
Wohnort: 82441 Ohlstadt
Kontaktdaten:

Re: Ich habe mir mal die FRAM Speicher auf den Tisch geholt

Beitrag von Admin »

Jetzt habe ich mir mal eine kleine Anwendung ausgedacht. Also nur um eine Sinnvollen Testgrundlage zu haben. Das besteht als folgenden Dingen / Funtionen.
Ein DC/DC Wandler für 3,3 Volt, ein ESP32_D1_Mini, ein I2C - FRAM, ein ADS1115 - 4 Kanal - 16Bit Analog/Digital Wandler. Ein I2C - OLED Display, ein 10kOhm Poti, ein 8 Ohm Lautsprecher.

Damit mache ich jetzt aus meinen 5 Volt am Tisch 3,3 Volt für den ESP32 und alles andere, was da so dran hängt. Der ESP32 misst mit Hilfe dess ADS1115 den Wert der am Poti eingestellten Spannung, 0-3,3 Volt. Zeigt dies Spannung mit zwei Stellen hinterm Komma am Display an. Und überträgt die Spannung mit 8 Stellen hinterm Komma zum PC. Wenn sich der Spannungswert vorm Komma, oder bis 2 Stellen hinterm Komma, ändert wird diese geänderte Spannnung am FRAM auf die nächsten 4 freie Bytes geschrieben. Man wird durch einen Piep am Lautsprecher darauf hingewiesen. Die Spannung bleibt gerade sein etwa einer Stunde bis 2 Stellen hinterm Komma stabil, also dass der Piep und das Schreiben auf dem SRAM passiert, muss ich die Spannung am Poti verändern. Ich kann diesen Aufbau über 5 Volt versorgen, da ist hinten dran unsichtbar ein DC/DC Wandler, der aus den 5 Volt dann 3,3 Volt macht. Oder vom PC direkt über das USB Kabel mit 5 Volt versorgt, da werden die 3,3Volt auf der CPU Platiene gemacht.

Ich mache mir immer eine keine Verteilerplatine wo ich X-Fach VCC / GND / und die beiden I2C Anschlüße mehrfach abgreifen kann, deshalb geht bei dem Aufbau alles von diesen Zetralen Verteiler zu den einzelnen Bauteilen, CPU / Display / FRAM / Analog -> Digital Wander.

Code: Alles auswählen

/* Abfrage von analogen Werten am ESP32
   - per GPIO-Pin
   - am ADS1115 mit Weitergabe per I2C
  2021-05-28 Heiko (unsinnsbasis.de)
*/

#include <Adafruit_ADS1X15.h>  // bindet Wire.h für I2C mit ein
Adafruit_ADS1115 ads;
#define ADS_I2C_ADDR 0x48
//-----------------------------FRAM-----------------------------------------------------------
#include "Adafruit_EEPROM_I2C.h"
#include "Adafruit_FRAM_I2C.h"
Adafruit_FRAM_I2C i2ceeprom;
#define EEPROM_ADDR 0x50  // the default address!
// -------------------OLED Display einrichten-------------------------------------------------
#include <U8g2lib.h>  // als U8g2 im Bibliotheksverwalter zu finden
U8G2_SH1106_128X64_NONAME_F_HW_I2C oled(U8G2_R0);

//------------------------ADS1115 16Bit Analog-Digital Sensor---------------------------------
const float multiplier = 0.125F;  // ADS1115-Multiplikator bei einf. Verstärkung
int A_Value;                      // Messwert per GPIO
int adc0;                         // Messwert an Kanal 0 des ADS1115
int adc1;                         // Messwert an Kanal 1 des ADS1115
int adc2;                         // Messwert an Kanal 2 des ADS1115
int adc3;                         // Messwert an Kanal 3 des ADS1115
float A_mv, ads_mv0, ads_mv1;     // Messwert in Millivolt umgerechnet
//--------------------------------------------------------------------------------------------
//----------------------- Spannungsmessungen Speichern ---------------------------------------
int Spannung2neu = 0;
int Spannung2alt = 0;
float f = 0;
uint8_t buffer[4];  // floats are 4 bytes!
int Speicher = 0;
int Zaehler = 0;
byte LSpin = 27;
// ----------------------------------------------------SETUP----------------------------------
void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println("Analog-Test ESP32");

  // ------------------EPROM Ereichbar ??--------------------
  if (i2ceeprom.begin(0x50)) {  // Sie können die neue I2C-Adresse hier einfügen, z. B. begin(0x51);
    Serial.println("I2C EEPROM gefunden");
  } else {
    Serial.println("I2C-EEPROM nicht identifiziert ... überprüfen Sie Ihre Verbindungen.?\r\n");
    while (1) delay(10);
  }
  //-----------------------ADS 1115---------------------------
  ads.begin(ADS_I2C_ADDR, &Wire);
  // Werte 1-fach verstärken (ESP32 liefert  max. 3,3V)
  ads.setGain(GAIN_ONE);
  //----------------------- Oled Display -----------------------
  oled.begin();
  oled.clearBuffer();               // Textspeicher löschen
  oled.setFont(u8g2_font_6x12_tr);  // Kleine Schrift 6x12
  //oled.setFont(u8g2_font_9x15_mf);  // Mittelgroß 9x15
  //oled.setFont(u8g2_font_10x20_mf); // Groß 10x20
  oled.setCursor(12, (1 * 10));
  oled.print(F("Analog-Test ESP32"));
  oled.setCursor(28, (2 * 10));
  oled.print(F("Mit ADS1115"));
  oled.sendBuffer();
}
// ----------------------------------------------------LOOP-----------------------------------
void loop() {
  // Messung per ADS1115
  // - Kanal 0 messen (single-ended)
  adc0 = ads.readADC_SingleEnded(0);
  ads_mv0 = ads.computeVolts(adc0);
  // - Kanal 1 messen (single-ended)
  adc1 = ads.readADC_SingleEnded(1);
  ads_mv1 = ads.computeVolts(adc1);
  // oder
  // - differenzielle Messung an Kanal 0/1
  //adc0 = ads.readADC_Differential_0_1();
  //ads_mv = (adc0 * multiplier);
  //Serial.printf("; I2C: %4.2f mV\n", ads_mv);

  // Messung ausgeben
  oled.setFont(u8g2_font_10x20_mf);
  //ADS Kanal 0 anzeigen
  oled.setCursor(20, (2 * 20));
  oled.print(ads_mv0);
  oled.println(F(" Volt "));
  //ADS Kanal 1 anzeigen
  oled.setCursor(20, (3 * 20));
  // if (ads_mv1 < 0) { ads_mv1 == 0; }
  oled.print(ads_mv1);
  oled.print(F(" Volt "));
  oled.sendBuffer();
  delay(1000);
  //------------------------Ist die Spannung verändert ? Ja, dann speichern !-----------------
  // Hier wird die Messung "float" durch das *100, um zwei Kommas nach hinten geschoben
  // und in einen "int" übergeben. Dadurch sind die Werte hinter dem Komma abgeschnitten.
  // Das heißt, aus den gemessenen z.B. "3,1255768" Volt werden 312,55768
  // und mit int sind die stellen hinterm Komma weg.
  // Für den Vergleich als <-> neu bleibt also nur noch der Wert "312"
  // Die dritte stelle hinterm Komma ändert sich schon rel. oft.
  // -----------------------------------------------------------------------------------------
  Spannung2neu = ads_mv1 * 100;
  if (Spannung2alt == Spannung2neu) {
  } else {
    // Schreiben
    Speicher = Speicher + 4;
    Zaehler = Zaehler + 1;
    float f = ads_mv1;
    tone(LSpin, 1000, 100);           // Piep wenn sich die Spannung ändert.
    Serial.print("Spannung 2 = ");
    Serial.print(ads_mv1, 8);
    Serial.println(" Volt");
    memcpy(buffer, (void *)&f, 4);
    Serial.print(F("Schreiben von Float an Adresse "));
    Serial.println(Speicher);
    i2ceeprom.write(Speicher, buffer, 4);
    Spannung2alt = Spannung2neu;
    // Auslesen
    i2ceeprom.read(Speicher, buffer, 4);
    memcpy((void *)&f, buffer, 4);
    Serial.print("Rücklese Wert: ");
    Serial.print(f, 8);
    Serial.print(" ->  Speicherstelle = ");
    Serial.print(Speicher);
    Serial.print(" ->  Wie viele Werte = ");
    Serial.println(Zaehler);
    Serial.println(F("################################################################################"));
  }

  //################################### ENDE ###################################################
}
Und hier ist noch ein Foto von Aufbau:
.
ESP32_D1_Mini_ADS1115_Oled_FRAM.jpg
ESP32_D1_Mini_ADS1115_Oled_FRAM.jpg (160.32 KiB) 342 mal betrachtet
Benutzeravatar
Admin
Administrator
Beiträge: 1282
Registriert: Mo 20. Apr 2020, 09:47
Wohnort: 82441 Ohlstadt
Kontaktdaten:

Re: Ich habe mir mal die FRAM Speicher auf den Tisch geholt

Beitrag von Admin »

Ich habe mich die Tage immer gewundert, dass die Werteänderung beim drehen am Poti immer so extrem langsam erfolgte. Ich hatte da noch eine Sekunde nach der Display - Ausgabe als Bremse drin, weil die Ausgabe aufs Display in jedem Durchgang erfolgte. Die Bremse habe ich raus. Und die Display - Ausgabe nur noch dann, wenn sich die Spannung, im auf dem Display sichtbaren Wert, verändert. Jetzt reagiert die Anzeige direkt mit dem Drehen am Poti, also direkt mit der Änderung der zu messenden Spannung. :idea: Ein Durchgang des Programmes ist jetzt 17 - 18 Millisekunden. Diese entstehen hauptsächlich beim abfragen der zwei Messwerte vom Analog / Digital Wandler über I2C.

Code: Alles auswählen

/* Abfrage von analogen Werten am ESP32
   - per GPIO-Pin
   - am ADS1115 mit Weitergabe per I2C
  2021-05-28 Heiko (unsinnsbasis.de)
*/

#include <Adafruit_ADS1X15.h>  // bindet Wire.h für I2C mit ein
Adafruit_ADS1115 ads;
#define ADS_I2C_ADDR 0x48
//-----------------------------FRAM-----------------------------------------------------------
#include "Adafruit_EEPROM_I2C.h"
#include "Adafruit_FRAM_I2C.h"
Adafruit_FRAM_I2C i2ceeprom;
#define EEPROM_ADDR 0x50  // the default address!
// -------------------OLED Display einrichten-------------------------------------------------
#include <U8g2lib.h>  // als U8g2 im Bibliotheksverwalter zu finden
U8G2_SH1106_128X64_NONAME_F_HW_I2C oled(U8G2_R0);

//------------------------ADS1115 16Bit Analog-Digital Sensor---------------------------------
const float multiplier = 0.125F;  // ADS1115-Multiplikator bei einf. Verstärkung
int A_Value;                      // Messwert per GPIO
int adc0;                         // Messwert an Kanal 0 des ADS1115
int adc1;                         // Messwert an Kanal 1 des ADS1115
int adc2;                         // Messwert an Kanal 2 des ADS1115
int adc3;                         // Messwert an Kanal 3 des ADS1115
float A_mv, ads_mv0, ads_mv1;     // Messwert in Millivolt umgerechnet
//--------------------------------------------------------------------------------------------
//----------------------- Spannungsmessungen Speichern ---------------------------------------
int Spannung2neu = 0;
int Spannung2alt = 0;
float f = 0;
uint8_t buffer[4];  // floats are 4 bytes!
int Speicher = 0;
int Zaehler = 0;
byte LSpin = 27;
//-------------------------------- Messungen -------------------------------------------------
unsigned long Messungstart = 0;
unsigned long Messungende = 0;
unsigned long Laufzeit = 0;
// ----------------------------------------------------SETUP----------------------------------
void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println("Analog-Test ESP32");

  // ------------------EPROM Ereichbar ??--------------------
  if (i2ceeprom.begin(0x50)) {  // Sie können die neue I2C-Adresse hier einfügen, z. B. begin(0x51);
    Serial.println("I2C EEPROM gefunden");
  } else {
    Serial.println("I2C-EEPROM nicht identifiziert ... überprüfen Sie Ihre Verbindungen.?\r\n");
    while (1) delay(10);
  }
  //-----------------------ADS 1115---------------------------
  ads.begin(ADS_I2C_ADDR, &Wire);
  // Werte 1-fach verstärken (ESP32 liefert  max. 3,3V)
  ads.setGain(GAIN_ONE);
  //----------------------- Oled Display -----------------------
  oled.begin();
  oled.clearBuffer();               // Textspeicher löschen
  oled.setFont(u8g2_font_6x12_tr);  // Kleine Schrift 6x12
  //oled.setFont(u8g2_font_9x15_mf);  // Mittelgroß 9x15
  //oled.setFont(u8g2_font_10x20_mf); // Groß 10x20
  oled.setCursor(12, (1 * 10));
  oled.print(F("Analog-Test ESP32"));
  oled.setCursor(28, (2 * 10));
  oled.print(F("Mit ADS1115"));
  oled.sendBuffer();
}
// ----------------------------------------------------LOOP-----------------------------------
void loop() {
  // Messung per ADS1115
  // - Kanal 0 messen (single-ended)
  adc0 = ads.readADC_SingleEnded(0);
  ads_mv0 = ads.computeVolts(adc0);
  // - Kanal 1 messen (single-ended)
  adc1 = ads.readADC_SingleEnded(1);
  ads_mv1 = ads.computeVolts(adc1);
  // oder
  // - differenzielle Messung an Kanal 0/1
  //adc0 = ads.readADC_Differential_0_1();
  //ads_mv = (adc0 * multiplier);
  //Serial.printf("; I2C: %4.2f mV\n", ads_mv);
//===============================================
  //------------------------Ist die Spannung verändert ? Ja, dann speichern !-----------------
  // Hier wird die Messung "float" durch das *100, um zwei Kommas nach hinten geschoben
  // und in einen "int" übergeben. Dadurch sind die Werte hinter dem Komma abgeschnitten.
  // Das heißt, aus den gemessenen z.B. "3,1255768" Volt werden 312,55768
  // und mit int sind die stellen hinterm Komma weg.
  // Für den Vergleich als <-> neu bleibt also nur noch der Wert "312"
  // Die dritte stelle hinterm Komma ändert sich schon rel. oft.
  // -----------------------------------------------------------------------------------------
  Spannung2neu = ads_mv1 * 100;
  if (Spannung2alt == Spannung2neu) {
  } else {
     // Messung auf das Display ausgeben
  oled.setFont(u8g2_font_10x20_mf);
  //ADS Kanal 0 anzeigen
  oled.setCursor(20, (2 * 20));
  oled.print(ads_mv0);
  oled.println(F(" Volt "));
  //ADS Kanal 1 anzeigen
  oled.setCursor(20, (3 * 20));
  // if (ads_mv1 < 0) { ads_mv1 == 0; }
  oled.print(ads_mv1);
  oled.print(F(" Volt "));
  oled.sendBuffer();
    //--------------------------------------------------------------
    // Schreiben
    Speicher = Speicher + 4;
    Zaehler = Zaehler + 1;
    float f = ads_mv1;
    tone(LSpin, 1000, 100);  // Piep wenn sich die Spannung ändert.
    Serial.print("Spannung 2 = ");
    Serial.print(ads_mv1, 8);
    Serial.println(" Volt");
    memcpy(buffer, (void *)&f, 4);
    Serial.print(F("Schreiben von Float an Adresse "));
    Serial.println(Speicher);
    i2ceeprom.write(Speicher, buffer, 4);
    Spannung2alt = Spannung2neu;
    // Auslesen
    i2ceeprom.read(Speicher, buffer, 4);
    memcpy((void *)&f, buffer, 4);
    Serial.print("Rücklese Wert: ");
    Serial.print(f, 8);
    Serial.print(" ->  Speicherstelle = ");
    Serial.print(Speicher);
    Serial.print(" ->  Wie viele Werte = ");
    Serial.println(Zaehler);
    Serial.println(F("################################################################################"));
  }
  //################################### ENDE ###################################################
}
Benutzeravatar
Admin
Administrator
Beiträge: 1282
Registriert: Mo 20. Apr 2020, 09:47
Wohnort: 82441 Ohlstadt
Kontaktdaten:

Re: Ich habe mir mal die FRAM Speicher auf den Tisch geholt

Beitrag von Admin »

Das ist ein SerialPrint von dem Programm. Das zeigt den Messwert, dann die Speicherstelle unter der das gespeichtert wurde, dann der aus dieser Speicherstelle ausgelesener Wert. Dass man sieht, dass der Wert wirklich im FRAM steht.

.
SerialPrint_FRAM01.jpg
SerialPrint_FRAM01.jpg (591.1 KiB) 135 mal betrachtet
Antworten

Zurück zu „Hardware / Schaltungstechnik“

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste