Librería SPI FRAM enfocada inicialmente en productos basados en ESP32, especialmente los desarrollos de JW Control.
JW_FRAM ofrece dos niveles de uso:
- API de bajo nivel para acceso directo a memorias FRAM SPI.
- API de alto nivel con una lógica de uso estilo EEPROM, pensada para guardar variables, textos, estructuras y configuraciones completas de forma cómoda.
- Soporte para memorias FRAM SPI.
- Uso de Adafruit BusIO como dependencia.
- Frecuencia SPI por defecto de 1 MHz.
- Posibilidad de configurar la frecuencia SPI en el constructor por hardware.
- Métodos de bajo nivel:
read,write,read8,write8,writeEnable,getDeviceID,getStatusRegister,setStatusRegister. - Métodos de alto nivel:
get,put,update. - Soporte para:
- tipos numéricos (
int,uint32_t,float,double, etc.) boolString- C strings (
char[]terminados en\0) structtrivially copyable
- tipos numéricos (
- Bloques de configuración validados mediante:
magicversionlengthchecksum
- Validación de rangos de memoria con
isAddressValid(). - Depuración opcional usando cualquier objeto
Stream. - Posibilidad de forzar el tamaño de FRAM al iniciar, útil para modelos no listados en la tabla interna.
Esta librería depende de Adafruit BusIO.
En library.properties ya se declara:
depends=Adafruit BusIO- Instala Adafruit BusIO desde el gestor de librerías de Arduino.
- Copia esta librería en tu carpeta de librerías o instálala como archivo ZIP.
- Incluye la librería en tu sketch:
#include <JW_FRAM.h>#include <JW_FRAM.h>
JW_FRAM fram(5); // Pin CS
void setup() {
Serial.begin(115200);
fram.enableDebug(Serial);
if (!fram.begin(8 * 1024)) {
Serial.println("Fallo al inicializar la FRAM");
while (1) {}
}
uint32_t contador = 1234;
fram.put(0, contador);
uint32_t valorLeido = 0;
fram.get(0, valorLeido);
Serial.print("Contador: ");
Serial.println(valorLeido);
}
void loop() {}La API de bajo nivel está pensada para tener control directo sobre la memoria FRAM.
Métodos disponibles:
writeEnable(bool enable)write8(uint32_t addr, uint8_t value)read8(uint32_t addr)write(uint32_t addr, const uint8_t* values, size_t count)read(uint32_t addr, uint8_t* values, size_t count)getDeviceID(uint8_t* manufacturerID, uint16_t* productID)getStatusRegister()setStatusRegister(uint8_t value)setAddressSize(uint8_t nAddressSize)
En esta capa, la escritura es manual. Eso significa que debes hacer:
fram.writeEnable(true);
fram.write8(0, 0x55);
fram.writeEnable(false);La API de alto nivel maneja automáticamente writeEnable(true/false) cuando corresponde.
fram.get(addr, variable);
fram.put(addr, variable);
fram.update(addr, variable);Lee un valor desde la FRAM y lo copia a una variable.
Escribe un valor completo en la FRAM.
Primero lee el valor actual y solo escribe si detecta cambios.
Estos métodos están pensados para tipos trivially copyable, como por ejemplo:
bool- enteros
floatdouble- arreglos fijos
- estructuras simples
struct PlcConfig {
uint8_t mode;
bool enabled;
float kp;
float ki;
float kd;
};struct BadConfig {
String ssid;
String pass;
};Si necesitas textos dentro de estructuras persistentes, es mejor usar arreglos fijos como char nombre[32];.
Formato almacenado:
[len][data...]
Reglas:
- máximo 127 caracteres
- modo estricto
- si el texto supera 127 caracteres, la función devuelve
false - no se recorta el texto automáticamente
Métodos:
bool writeString(uint32_t addr, const String& value);
bool readString(uint32_t addr, String& value, uint8_t maxLen = 127);Formato almacenado:
[data...]['\0']
Reglas:
- máximo 127 caracteres útiles
- si el texto excede ese límite, la escritura falla
- la lectura se detiene al encontrar
\0
Métodos:
bool writeCString(uint32_t addr, const char* str, uint8_t maxLen = 127);
bool readCString(uint32_t addr, char* buffer, size_t bufferSize, uint8_t maxLen = 127);Los métodos writeBlock() y readBlock() permiten guardar una estructura acompañada de un encabezado de validación.
El encabezado contiene:
magicversionreservedlengthchecksum
Esto sirve para detectar:
- memoria no inicializada
- estructuras incompatibles entre versiones
- corrupción de datos
- tamaños de payload incorrectos
struct SystemConfig {
uint8_t configVersion;
bool firstBootDone;
float kp;
float ki;
float kd;
uint32_t totalStarts;
char machineName[24];
};
SystemConfig cfg = {1, true, 2.0f, 0.5f, 0.1f, 42, "JWPLC"};
fram.writeBlock(128, cfg, 1);
SystemConfig restored;
if (fram.readBlock(128, restored, 1)) {
// configuración válida recuperada
}Puedes habilitar depuración usando cualquier objeto compatible con Stream.
fram.enableDebug(Serial);
fram.disableDebug();Eso evita amarrar la librería exclusivamente a Serial.
Si la librería no reconoce el Device ID, puedes forzar manualmente el tamaño al iniciar:
fram.begin(8 * 1024);Eso permite trabajar con memorias FRAM compatibles aunque no estén todavía incluidas en la tabla interna.
La librería ya fue preparada con archivos compatibles con el ecosistema Arduino:
src/examples/library.propertiesREADME.mdCHANGELOG.mdkeywords.txtLICENCE
Para versiones posteriores podrían añadirse:
- CRC16 en lugar de checksum simple
- funciones
fill()oclear() - más modelos en la tabla de dispositivos
- más ejemplos de uso orientados a productos JWPLC
La base original de Adafruit usa licencia BSD. Si esta librería deriva de ese trabajo, se debe conservar la atribución correspondiente y mantener el texto de licencia apropiado. El repositorio de Adafruit FRAM SPI publica su licencia BSD con cláusula de atribución y limitación de responsabilidad. citeturn948721view0