RE: FRAM am Arduino
Ich habe die TWBR-Zeilen für die AVR mit bedingter Kompilierung doch wieder rein genommen, da sie den Zugriff auf den FRAM dort beschleunigen (Standard war 100 kHz).
fRam.h
Code:
// Mit Anleihen bei rkuehle (Template), Rob Tillaart (I2C_EEPROM library), Ardu_Arne (FRAM), Tommy56 (fRam.h) und Arduino core (HEX)
// Handling für FRAM Bausteine 16 KBit (1 Adressbyte) und 64KBit (2 Adressbytes)
#include <Arduino.h>
#include <Wire.h>
// 1 für 16 k, 2 für 64 k
#define ADRESS_BYTES 2
#undef ESP
#if defined(ESP8266) || defined (ESP32)
#define BUFFER_LENGTH I2C_BUFFER_LENGTH
#define ESP
#endif
#define TWI_LENGTH BUFFER_LENGTH - ADRESS_BYTES
// I2C-(Basis)Adresse (Das wird dann die 0xC, die im Datenblatt steht)
#define F_RAM 0x57 // auf DS3231 mit 7 gebrückt oder 0x50
// FRAM schreiben - Variable, anzahl Bytes, Adresse im FRAM
void F_RAM_write (byte* wert, int numbytes, uint16_t framAddr) {
int devAdr, rc;
#ifndef ESP
TWBR = 12; // 400 kHz (maximum)
#endif
// Adressierungsart 1 -> 3 Bit in Adresse
if (ADRESS_BYTES == 1) {
// 16 K
devAdr = F_RAM | framAddr >> 8;
Wire.beginTransmission(devAdr);
Wire.write(framAddr & 0xFF);
for (byte i = 0; i < numbytes; i++) Wire.write(wert[i]);
rc = Wire.endTransmission();
//Serial.print("rc: ");Serial.println(rc);
}
else {
// 64 K
Wire.beginTransmission(F_RAM);
Wire.write(framAddr >> 8); Wire.write(framAddr & 0xFF);
for (byte i = 0; i < numbytes; i++) Wire.write(wert[i]);
rc = Wire.endTransmission();
}
#ifndef ESP
TWBR = 72; // 100 kHz (default)
#endif
// TWBR = 72; // 100 kHz (default)
}
// FRAM lesen - Variable, anzahl Bytes, Adresse im FRAM
void F_RAM_read (byte* wert, int numbytes, uint16_t framAddr) {
int devAdr, rc;
#ifndef ESP
TWBR = 12; // 400 kHz (maximum)
#endif
// Adressierungsart 1 -> 3 Bit in Adresse
if (ADRESS_BYTES == 1) {
// 16 K
devAdr = F_RAM | framAddr >> 8;
Wire.beginTransmission(devAdr);
Wire.write(framAddr & 0xFF);
rc = Wire.endTransmission();
Wire.requestFrom(devAdr, numbytes);
for (byte i = 0; i < numbytes; i++) wert[i] = Wire.read();
}
else {
// 64 K
Wire.beginTransmission(F_RAM);
Wire.write(framAddr >> 8); Wire.write(framAddr & 0xFF);
rc = Wire.endTransmission();
Wire.requestFrom(F_RAM, numbytes);
for (byte i = 0; i < numbytes; i++) wert[i] = Wire.read();
}
#ifndef ESP
TWBR = 72; // 100 kHz (default)
#endif
}
// Schreibt beliebige Werte (auch Arrays beliebiger Typen) in den FRAM
template <class T> int fRamWrite(uint16_t framAddr, const T& wert) {
byte* p = (byte*)(void*)&wert;
int16_t len, cnt, orig;
len = sizeof(wert);
orig = len;
// Solange Bytes zu senden sind
while (len > 0) {
cnt = len;
// Wenn länger als TWI-Buffer - Adresslänge, dann begrenzen
if (cnt > TWI_LENGTH) cnt = TWI_LENGTH;
// Schreiben
F_RAM_write (p, cnt, framAddr);
// Restbytes berechnen
len -= cnt;
// neue FRAM-Adresse
framAddr += cnt;
// neue Quelladresse
p += cnt;
}
return orig;
}
// liest beliebige Werte aus dem FRAM . Die Länge wird von der Zielvariablen bestimmt
// optionaler Parameter laenge wird nur berücksichtigt, wenn er kleiner, als die Länge der Variablen ist
template <class T> int fRamRead(uint16_t framAddr, const T& wert, int laenge = 0) {
byte* p = (byte*)(void*)&wert;
int16_t len, cnt, orig;
len = sizeof(wert);
// Wunschlänge gesetzt und passt in Variable rein
if ((laenge > 0) && (laenge < len)) len = laenge;
orig = len;
// Solange Bytes zu holen sind
while (len > 0) {
cnt = len;
// Wenn länger als TWI-Buffer - Adresslänge, dann begrenzen
if (cnt > TWI_LENGTH) cnt = TWI_LENGTH;
// Schreiben
F_RAM_read (p, cnt, framAddr);
// Restbytes berechnen
len -= cnt;
// neue FRAM-Adresse
framAddr += cnt;
// neue Quelladresse
p += cnt;
}
return orig;
}
// Hilfsfunktion für Hexdarstellung
// Puffer, Wert, Stellenzahl (2 oder 4), Ein Blank wird voran gestellt
char *fillHex(char *buf, uint16_t val, uint8_t len) {
uint16_t m;
byte str, t;
if (len == 4) {
//Adresse
str = 5;
buf[0] = ' ';
for (byte i = 1; i < 5; i++) buf[i] = '0';
}
else {
// Byte
str = 3;
buf[0] = ' ';
buf[1] = '0';
}
buf[str] = '\0';
do {
m = val;
val /= 16;
char c = m - 16 * val;
buf[--str] = c < 10 ? c + '0' : c + 'A' - 10;
} while (val);
return buf;
}
// Anzeige des Fram im angegebenen Bereich Hex und als (druckbares) Zeichen
void dumpFram(uint16_t von, uint16_t bis) {
// Hexformatierer
char buf[6];
//Lesepuffer
byte readBuffer[16];
// Zeichenpuffer
char zbuffer[17];
uint16_t start;
uint8_t len = 16;
start = von;
Serial.print("FRAM Dump von "); Serial.print(fillHex(buf, von, 4));
Serial.print(" bis "); Serial.println(fillHex(buf, bis, 4));
while (start <= bis) {
memset(zbuffer, 0, 17); // leeren
if ((bis - start) < 16) len = bis - start + 1;
fRamRead(start, readBuffer, len);
Serial.print(fillHex(buf, start, 4)); // Adresse
for (byte i = 0; i < len; i++) {
Serial.print(fillHex(buf, readBuffer[i], 2));
if ((readBuffer[i] < 32) || (readBuffer[i] > 126)) zbuffer[i] = '.';
else zbuffer[i] = readBuffer[i]; // druckbare Zeichen
}
// Wenn letzte Zeile < 16, dann auffüllen
if (len < 16) {
for (byte i = 0; i < (16 - len); i++) Serial.print(" ");
}
Serial.print(" "); Serial.println(zbuffer);
start += 16;
}
}
//Füllen des Fram mit einem bestimmten Zeichen in einem Bereich
void fillFram(uint16_t von, uint16_t bis, uint8_t val) {
// Hexformatierer
char buf[6];
byte writeBuffer[16];
uint16_t start;
uint8_t len = 16;
start = von;
memset(writeBuffer, val, 16);
Serial.print("FRAM schreiben von "); Serial.print(fillHex(buf, von, 4));
Serial.print(" bis "); Serial.print(fillHex(buf, bis, 4));
Serial.print(" mit "); Serial.println(fillHex(buf, val, 2));
len = 0;
while (start <= bis) {
if ((bis - start) < 16) {
len = bis - start + 1;
F_RAM_write (writeBuffer, len, start);
}
else fRamWrite(start, writeBuffer);
start += 16;
}
}
fRam2.h
Code:
// Mit Anleihen bei rkuehle (Template), Rob Tillaart (I2C_EEPROM library), Ardu_Arne (FRAM), Tommy56 (fRam.h) und Arduino core (HEX)
// Handling für FRAM Bausteine 16 KBit (1 Adressbyte) und 64KBit (2 Adressbytes)
// für mehrere FRAM IC
#include <Arduino.h>
#include <Wire.h>
#undef ESP
#if defined(ESP8266) || defined (ESP32)
#define BUFFER_LENGTH I2C_BUFFER_LENGTH
#define ESP
#endif
// I2C-(Basis)Adresse (Aus 0x5 wird dann die 0xC, die im Datenblatt steht)
//#define F_RAM 0x57 // auf DS3231 mit 7 gebrückt oder 0x50
// FRAM schreiben - I2C-Adresse, Anzahl Adressbytes (1=16kB oder 2), Variable, anzahl Bytes, Adresse im FRAM
void F_RAM_write (byte i2c_adresse, byte num_adressbytes, byte* wert, int numbytes, uint16_t framAddr) {
int devAdr, rc;
#ifndef ESP
TWBR = 12; // 400 kHz (maximum)
#endif
// Adressierungsart 1 -> 3 Bit in Adresse
if (num_adressbytes == 1) {
// 16 K
devAdr = i2c_adresse | framAddr >> 8;
Wire.beginTransmission(devAdr);
Wire.write(framAddr & 0xFF);
for (byte i = 0; i < numbytes; i++) Wire.write(wert[i]);
rc = Wire.endTransmission();
//Serial.print("rc: ");Serial.println(rc);
}
else {
// 64 K
Wire.beginTransmission(i2c_adresse);
Wire.write(framAddr >> 8); Wire.write(framAddr & 0xFF);
for (byte i = 0; i < numbytes; i++) Wire.write(wert[i]);
rc = Wire.endTransmission();
}
#ifndef ESP
TWBR = 72; // 100 kHz (default)
#endif
}
// FRAM lesen - I2C-Adresse, Anzahl Adressbytes (1=16kB oder 2), Variable, anzahl Bytes, Adresse im FRAM
void F_RAM_read (byte i2c_adresse, byte num_adressbytes, byte* wert, int numbytes, uint16_t framAddr) {
int devAdr, rc;
#ifndef ESP
TWBR = 12; // 400 kHz (maximum)
#endif
// Adressierungsart 1 -> 3 Bit in Adresse
if (num_adressbytes == 1) {
// 16 K
devAdr = i2c_adresse | framAddr >> 8;
Wire.beginTransmission(devAdr);
Wire.write(framAddr & 0xFF);
rc = Wire.endTransmission();
Wire.requestFrom(devAdr, numbytes);
for (byte i = 0; i < numbytes; i++) wert[i] = Wire.read();
}
else {
// 64 K
Wire.beginTransmission(i2c_adresse);
Wire.write(framAddr >> 8); Wire.write(framAddr & 0xFF);
rc = Wire.endTransmission();
// cast to int for Wirelib
Wire.requestFrom((int)i2c_adresse, numbytes);
for (byte i = 0; i < numbytes; i++) wert[i] = Wire.read();
}
#ifndef ESP
TWBR = 72; // 100 kHz (default)
#endif
}
// Schreibt beliebige Werte (auch Arrays beliebiger Typen) in den FRAM
template <class T> int fRamWrite(byte i2c_adresse, byte num_adressbytes, uint16_t framAddr, const T& wert) {
byte* p = (byte*)(void*)&wert;
int16_t len, cnt, orig;
len = sizeof(wert);
byte twi_length = BUFFER_LENGTH - num_adressbytes;
orig = len;
// Solange Bytes zu senden sind
while (len > 0) {
cnt = len;
// Wenn länger als TWI-Buffer - Adresslänge, dann begrenzen
if (cnt > twi_length) cnt = twi_length;
// Schreiben
F_RAM_write (i2c_adresse, num_adressbytes, p, cnt, framAddr);
// Restbytes berechnen
len -= cnt;
// neue FRAM-Adresse
framAddr += cnt;
// neue Quelladresse
p += cnt;
}
return orig;
}
// liest beliebige Werte aus dem FRAM . Die Länge wird von der Zielvariablen bestimmt
// optionaler Parameter laenge wird nur berücksichtigt, wenn er kleiner, als die Länge der Variablen ist
template <class T> int fRamRead(byte i2c_adresse, byte num_adressbytes, uint16_t framAddr, const T& wert, int laenge = 0) {
byte* p = (byte*)(void*)&wert;
int16_t len, cnt, orig;
len = sizeof(wert);
byte twi_length = BUFFER_LENGTH - num_adressbytes;
// Wunschlänge gesetzt und passt in Variable rein
if ((laenge > 0) && (laenge < len)) len = laenge;
orig = len;
// Solange Bytes zu holen sind
while (len > 0) {
cnt = len;
// Wenn länger als TWI-Buffer - Adresslänge, dann begrenzen
if (cnt > twi_length) cnt = twi_length;
// Schreiben
F_RAM_read (i2c_adresse, num_adressbytes, p, cnt, framAddr);
// Restbytes berechnen
len -= cnt;
// neue FRAM-Adresse
framAddr += cnt;
// neue Quelladresse
p += cnt;
}
return orig;
}
// Hilfsfunktion für Hexdarstellung
// Puffer, Wert, Stellenzahl (2 oder 4), Ein Blank wird voran gestellt
char *fillHex(char *buf, uint16_t val, uint8_t len, boolean withBlank = true) {
uint16_t m;
byte str, t;
if (len == 4) {
//Adresse
str = 5;
buf[0] = ' ';
for (byte i = 1; i < 5; i++) buf[i] = '0';
}
else {
// Byte
str = 3;
buf[0] = ' ';
buf[1] = '0';
}
buf[str] = '\0';
do {
m = val;
val /= 16;
char c = m - 16 * val;
buf[--str] = c < 10 ? c + '0' : c + 'A' - 10;
} while (val);
if (!withBlank) return buf+1;
return buf;
}
// Anzeige des Fram im angegebenen Bereich Hex und als (druckbares) Zeichen
void dumpFram(byte i2c_adresse, byte num_adressbytes, uint16_t von, uint16_t bis) {
// Hexformatierer
char buf[6];
//Lesepuffer
byte readBuffer[16];
// Zeichenpuffer
char zbuffer[17];
uint16_t start;
uint8_t len = 16;
start = von;
Serial.print("FRAM Dump I2C-Adresse: 0x"); Serial.print(fillHex(buf,i2c_adresse,2, false)); Serial.print(" von 0x"); Serial.print(fillHex(buf, von, 4, false));
Serial.print(" bis 0x"); Serial.println(fillHex(buf, bis, 4, false));
while (start <= bis) {
memset(zbuffer, 0, 17); // leeren
if ((bis - start) < 16) len = bis - start + 1;
fRamRead(i2c_adresse, num_adressbytes, start, readBuffer, len);
Serial.print(fillHex(buf, start, 4)); // Adresse
for (byte i = 0; i < len; i++) {
Serial.print(fillHex(buf, readBuffer[i], 2));
if ((readBuffer[i] < 32) || (readBuffer[i] > 126)) zbuffer[i] = '.';
else zbuffer[i] = readBuffer[i]; // druckbare Zeichen
}
// Wenn letzte Zeile < 16, dann auffüllen
if (len < 16) {
for (byte i = 0; i < (16 - len); i++) Serial.print(" ");
}
Serial.print(" "); Serial.println(zbuffer);
start += 16;
}
}
//Füllen des Fram mit einem bestimmten Zeichen in einem Bereich
void fillFram(byte i2c_adresse, byte num_adressbytes, uint16_t von, uint16_t bis, uint8_t val) {
// Hexformatierer
char buf[6];
byte writeBuffer[16];
uint16_t start;
uint8_t len = 16;
start = von;
memset(writeBuffer, val, 16);
Serial.print("FRAM schreiben I2C-Adresse: 0x"); Serial.print(fillHex(buf,i2c_adresse,2, false)); Serial.print(" von 0x"); Serial.print(fillHex(buf, von, 4, false));
Serial.print(" bis 0x"); Serial.print(fillHex(buf, bis, 4, false));
Serial.print(" mit 0x"); Serial.println(fillHex(buf, val, 2, false));
len = 0;
while (start <= bis) {
if ((bis - start) < 16) {
len = bis - start + 1;
F_RAM_write (i2c_adresse, num_adressbytes, writeBuffer, len, start);
}
else fRamWrite(i2c_adresse, num_adressbytes, start, writeBuffer);
start += 16;
}
}
Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)
Alle von mir veröffentlichten Codes unterliegen der GPL Version 3
|