mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
0.4.2 FRAM_I2C
This commit is contained in:
parent
09b05e5efe
commit
89bf078d48
@ -1,3 +1,18 @@
|
||||
platforms:
|
||||
rpipico:
|
||||
board: rp2040:rp2040:rpipico
|
||||
package: rp2040:rp2040
|
||||
gcc:
|
||||
features:
|
||||
defines:
|
||||
- ARDUINO_ARCH_RP2040
|
||||
warnings:
|
||||
flags:
|
||||
|
||||
packages:
|
||||
rp2040:rp2040:
|
||||
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
|
||||
|
||||
compile:
|
||||
# Choosing to run compilation tests on 2 different Arduino platforms
|
||||
platforms:
|
||||
@ -9,3 +24,5 @@ compile:
|
||||
- esp32
|
||||
- esp8266
|
||||
# - mega2560
|
||||
- rpipico
|
||||
|
||||
|
@ -5,6 +5,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
|
||||
## [0.4.2] - 2022-10-03
|
||||
|
||||
### Added
|
||||
- FRAM_RINGBUFFER class - see FRAM_RINGBUFFER.md
|
||||
- build-ci support for RP2040 pico
|
||||
|
||||
### Changed
|
||||
- updated documentation
|
||||
- moved code from FRAM.h to FRAM.cpp
|
||||
|
||||
|
||||
## [0.4.1] - 2022-09-24
|
||||
|
||||
### Added
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// FILE: FRAM.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.4.1
|
||||
// VERSION: 0.4.2
|
||||
// DATE: 2018-01-24
|
||||
// PURPOSE: Arduino library for I2C FRAM
|
||||
// URL: https://github.com/RobTillaart/FRAM_I2C
|
||||
@ -212,6 +212,12 @@ uint16_t FRAM::getSize()
|
||||
}
|
||||
|
||||
|
||||
uint32_t FRAM::getSizeBytes()
|
||||
{
|
||||
return _sizeBytes;
|
||||
};
|
||||
|
||||
|
||||
// override to be used when getSize() fails == 0
|
||||
void FRAM::setSizeBytes(uint32_t value)
|
||||
{
|
||||
@ -419,6 +425,20 @@ void FRAM32::read(uint32_t memaddr, uint8_t * obj, uint16_t size)
|
||||
}
|
||||
|
||||
|
||||
template <class T> uint32_t FRAM32::writeObject(uint32_t memaddr, T &obj)
|
||||
{
|
||||
write(memaddr, (uint8_t *) &obj, sizeof(obj));
|
||||
return memaddr + sizeof(obj);
|
||||
};
|
||||
|
||||
|
||||
template <class T> uint32_t FRAM32::readObject(uint32_t memaddr, T &obj)
|
||||
{
|
||||
read(memaddr, (uint8_t *) &obj, sizeof(obj));
|
||||
return memaddr + sizeof(obj);
|
||||
}
|
||||
|
||||
|
||||
uint32_t FRAM32::clear(uint8_t value)
|
||||
{
|
||||
uint8_t buf[16];
|
||||
|
@ -2,7 +2,7 @@
|
||||
//
|
||||
// FILE: FRAM.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.4.1
|
||||
// VERSION: 0.4.2
|
||||
// DATE: 2018-01-24
|
||||
// PURPOSE: Arduino library for I2C FRAM
|
||||
// URL: https://github.com/RobTillaart/FRAM_I2C
|
||||
@ -13,7 +13,7 @@
|
||||
#include "Wire.h"
|
||||
|
||||
|
||||
#define FRAM_LIB_VERSION (F("0.4.1"))
|
||||
#define FRAM_LIB_VERSION (F("0.4.2"))
|
||||
|
||||
|
||||
#define FRAM_OK 0
|
||||
@ -75,7 +75,7 @@ public:
|
||||
uint16_t getManufacturerID(); // Fujitsu = 0x000A
|
||||
uint16_t getProductID(); // Proprietary
|
||||
uint16_t getSize(); // Returns size in KILO-BYTE (or 0)
|
||||
uint32_t getSizeBytes() { return _sizeBytes; }; // Returns size in BYTE
|
||||
uint32_t getSizeBytes(); // Returns size in BYTE
|
||||
void setSizeBytes(uint32_t value); // override when getSize() fails == 0
|
||||
|
||||
uint32_t clear(uint8_t value = 0); // fills FRAM with value
|
||||
@ -95,7 +95,6 @@ protected:
|
||||
uint16_t _getMetaData(uint8_t id);
|
||||
void _writeBlock(uint16_t memaddr, uint8_t * obj, uint8_t size);
|
||||
void _readBlock(uint16_t memaddr, uint8_t * obj, uint8_t size);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -120,16 +119,8 @@ public:
|
||||
uint32_t read32(uint32_t memaddr);
|
||||
void read(uint32_t memaddr, uint8_t * obj, uint16_t size);
|
||||
|
||||
template <class T> uint32_t writeObject(uint32_t memaddr, T &obj)
|
||||
{
|
||||
write(memaddr, (uint8_t *) &obj, sizeof(obj));
|
||||
return memaddr + sizeof(obj);
|
||||
};
|
||||
template <class T> uint32_t readObject(uint32_t memaddr, T &obj)
|
||||
{
|
||||
read(memaddr, (uint8_t *) &obj, sizeof(obj));
|
||||
return memaddr + sizeof(obj);
|
||||
}
|
||||
template <class T> uint32_t writeObject(uint32_t memaddr, T &obj);
|
||||
template <class T> uint32_t readObject(uint32_t memaddr, T &obj);
|
||||
|
||||
uint32_t clear(uint8_t value = 0); // fills FRAM with value
|
||||
|
||||
|
186
libraries/FRAM_I2C/FRAM_RINGBUFFER.cpp
Normal file
186
libraries/FRAM_I2C/FRAM_RINGBUFFER.cpp
Normal file
@ -0,0 +1,186 @@
|
||||
//
|
||||
// FILE: FRAM_RINGBUFFER.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// DATE: 2022-10-03
|
||||
// PURPOSE: Arduino library for I2C FRAM based RING BUFFER
|
||||
// URL: https://github.com/RobTillaart/FRAM_I2C
|
||||
//
|
||||
|
||||
|
||||
#include "FRAM_RINGBUFFER.h"
|
||||
|
||||
|
||||
FRAM_RINGBUFFER::FRAM_RINGBUFFER()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
uint32_t FRAM_RINGBUFFER::begin(FRAM *fram, uint32_t size, uint32_t start)
|
||||
{
|
||||
_fram = fram;
|
||||
_size = size;
|
||||
_start = start + 20; // allocate 5 uint32_t for storage.
|
||||
flush();
|
||||
_saved = false;
|
||||
return _start + _size; // first free FRAM location.
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ADMINISTRATIVE
|
||||
//
|
||||
void FRAM_RINGBUFFER::flush()
|
||||
{
|
||||
_front = _tail = _start;
|
||||
_count = 0;
|
||||
_saved = false;
|
||||
}
|
||||
|
||||
|
||||
uint32_t FRAM_RINGBUFFER::size()
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
|
||||
uint32_t FRAM_RINGBUFFER::count()
|
||||
{
|
||||
return _count;
|
||||
}
|
||||
|
||||
|
||||
bool FRAM_RINGBUFFER::full()
|
||||
{
|
||||
return _count == _size;
|
||||
}
|
||||
|
||||
|
||||
bool FRAM_RINGBUFFER::empty()
|
||||
{
|
||||
return _count == 0;
|
||||
}
|
||||
|
||||
|
||||
uint32_t FRAM_RINGBUFFER::free()
|
||||
{
|
||||
return _size - _count;
|
||||
}
|
||||
|
||||
|
||||
float FRAM_RINGBUFFER::freePercent()
|
||||
{
|
||||
return (100.0 * _count) / _size;
|
||||
}
|
||||
|
||||
// DEBUG
|
||||
// uint32_t FRAM_RINGBUFFER::tail() { return _tail; };
|
||||
// uint32_t FRAM_RINGBUFFER::front() { return _front; };
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// BYTE INTERFACE
|
||||
//
|
||||
int FRAM_RINGBUFFER::write(uint8_t value)
|
||||
{
|
||||
if (full()) return FRAM_RB_ERR_BUF_FULL;
|
||||
_fram->write8(_front, value);
|
||||
_saved = false;
|
||||
_front++;
|
||||
_count++;
|
||||
if (_front >= _start + _size) _front = _start;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int FRAM_RINGBUFFER::read()
|
||||
{
|
||||
if (empty()) return FRAM_RB_ERR_BUF_EMPTY;
|
||||
int value = _fram->read8(_tail);
|
||||
_saved = false;
|
||||
_tail++;
|
||||
_count--;
|
||||
if (_tail >= _start + _size) _tail = _start;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
int FRAM_RINGBUFFER::peek()
|
||||
{
|
||||
if (empty()) return FRAM_RB_ERR_BUF_EMPTY;
|
||||
int value = _fram->read8(_tail);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
//
|
||||
// MAKE RINGBUFFER PERSISTENT OVER REBOOTS
|
||||
//
|
||||
bool FRAM_RINGBUFFER::isSaved()
|
||||
{
|
||||
return _saved;
|
||||
}
|
||||
|
||||
|
||||
void FRAM_RINGBUFFER::save()
|
||||
{
|
||||
uint32_t pos = _start - 20;
|
||||
if (not _saved)
|
||||
{
|
||||
uint32_t checksum = _size + _front + _tail + _count;
|
||||
_fram->write32(pos + 0, _size );
|
||||
_fram->write32(pos + 4, _front);
|
||||
_fram->write32(pos + 8, _tail );
|
||||
_fram->write32(pos + 12, _count);
|
||||
_fram->write32(pos + 16, checksum);
|
||||
_saved = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool FRAM_RINGBUFFER::load()
|
||||
{
|
||||
uint32_t pos = _start - 20;
|
||||
uint32_t size = _fram->read32(pos + 0);
|
||||
uint32_t front = _fram->read32(pos + 4);
|
||||
uint32_t tail = _fram->read32(pos + 8);
|
||||
uint32_t count = _fram->read32(pos + 12);
|
||||
uint32_t checksum = _fram->read32(pos + 16);
|
||||
// checksum test should be enough.
|
||||
// optional these are possible
|
||||
// (_start <= _front) && (_front < _start + _size);
|
||||
// (_start <= _tail) && (_tail < _start + _size);
|
||||
_saved = (checksum == size + front + tail + count);
|
||||
if (_saved)
|
||||
{
|
||||
_size = size;
|
||||
_front = front;
|
||||
_tail = tail;
|
||||
_count = count;
|
||||
}
|
||||
return _saved;
|
||||
}
|
||||
|
||||
|
||||
void FRAM_RINGBUFFER::wipe()
|
||||
{
|
||||
uint32_t pos = _start - 20; // also overwrite metadata
|
||||
while (pos < _start + _size - 4) // prevent writing adjacent FRAM
|
||||
{
|
||||
_fram->write32(pos, 0xFFFFFFFF);
|
||||
pos += 4;
|
||||
}
|
||||
while (pos < _start + _size) // if _size not a multiple of 4.
|
||||
{
|
||||
_fram->write8(pos, 0xFF);
|
||||
pos++;
|
||||
}
|
||||
flush(); // reset internal variables too.
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
154
libraries/FRAM_I2C/FRAM_RINGBUFFER.h
Normal file
154
libraries/FRAM_I2C/FRAM_RINGBUFFER.h
Normal file
@ -0,0 +1,154 @@
|
||||
#pragma once
|
||||
//
|
||||
// FILE: FRAM_RINGBUFFER.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// DATE: 2022-10-03
|
||||
// PURPOSE: Arduino library for I2C FRAM based ring buffer
|
||||
// URL: https://github.com/RobTillaart/FRAM_I2C
|
||||
//
|
||||
|
||||
|
||||
#include "FRAM.h" // https://github.com/RobTillaart/FRAM_I2C
|
||||
|
||||
|
||||
// ERROR CODES
|
||||
#define FRAM_RB_OK 0
|
||||
#define FRAM_RB_ERR_BUF_FULL -1
|
||||
#define FRAM_RB_ERR_BUF_EMPTY -2
|
||||
#define FRAM_RB_ERR_BUF_NO_ROOM -21 // (almost) full
|
||||
#define FRAM_RB_ERR_BUF_NO_DATA -22 // (almost) empty
|
||||
|
||||
|
||||
class FRAM_RINGBUFFER
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CONSTRUCTOR + BEGIN
|
||||
//
|
||||
FRAM_RINGBUFFER();
|
||||
|
||||
// fram = pointer to FRAM object
|
||||
// size in bytes
|
||||
// memAddr in bytes where ring buffer starts
|
||||
// returns uint32_t == first free (next) FRAM location.
|
||||
uint32_t begin(FRAM *fram, uint32_t size, uint32_t memAddr);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ADMINISTRATIVE
|
||||
//
|
||||
void flush();
|
||||
uint32_t size();
|
||||
uint32_t count();
|
||||
uint32_t free();
|
||||
float freePercent();
|
||||
|
||||
bool full();
|
||||
bool empty();
|
||||
|
||||
// DEBUG
|
||||
// uint32_t tail() { return _tail; };
|
||||
// uint32_t front() { return _front; };
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// BYTE INTERFACE
|
||||
//
|
||||
// returns bytes written.
|
||||
// - FRAM_RB_ERR_BUF_FULL indicates full buffer.
|
||||
int write(uint8_t value);
|
||||
// returns value read
|
||||
// - FRAM_RB_ERR_BUF_EMPTY indicates empty buffer.
|
||||
int read();
|
||||
// returns value read
|
||||
// - FRAM_RB_ERR_BUF_EMPTY indicates empty buffer.
|
||||
int peek();
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// OBJECT INTERFACE
|
||||
//
|
||||
// returns bytes written.
|
||||
// - FRAM_RB_ERR_BUF_NO_ROOM indicates (almost) full buffer
|
||||
// ==> object does not fit.
|
||||
template <class T> int write(T &obj)
|
||||
{
|
||||
uint8_t objectSize = sizeof(obj);
|
||||
if ((_size - _count) < objectSize) return FRAM_RB_ERR_BUF_NO_ROOM;
|
||||
uint8_t * p = (uint8_t *)&obj;
|
||||
for (uint8_t i = 0; i < objectSize; i++)
|
||||
{
|
||||
write(*p++);
|
||||
}
|
||||
_saved = false;
|
||||
return objectSize;
|
||||
};
|
||||
|
||||
// returns bytes read.
|
||||
// - FRAM_RB_ERR_BUF_NO_DATA indicates (almost) empty buffer
|
||||
// ==> Too few bytes to read object.
|
||||
template <class T> int read(T &obj)
|
||||
{
|
||||
uint8_t objectSize = sizeof(obj);
|
||||
if (_count < objectSize) return FRAM_RB_ERR_BUF_NO_DATA;
|
||||
uint8_t * p = (uint8_t *)&obj;
|
||||
for (uint8_t i = 0; i < objectSize; i++)
|
||||
{
|
||||
*p++ = read();
|
||||
}
|
||||
_saved = false;
|
||||
return objectSize;
|
||||
};
|
||||
|
||||
// returns bytes read.
|
||||
// - FRAM_RB_ERR_BUF_NO_DATA indicates (almost) empty buffer
|
||||
// ==> Too few bytes to read object.
|
||||
template <class T> int peek(T &obj)
|
||||
{
|
||||
uint8_t objectSize = sizeof(obj);
|
||||
if (_count < objectSize) return FRAM_RB_ERR_BUF_NO_DATA;
|
||||
bool prevSaved = _saved; // remember saved state
|
||||
uint32_t previousTail = _tail; // remember _tail 'pointer'
|
||||
int n = read(obj);
|
||||
_tail = previousTail; // restore _tail 'pointer'
|
||||
_saved = prevSaved; // restore _saved
|
||||
_count += n;
|
||||
return n;
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
//
|
||||
// MAKE RINGBUFFER PERSISTENT OVER REBOOTS
|
||||
//
|
||||
bool isSaved();
|
||||
// stores the internal variables + checksum.
|
||||
// if you need constant persistency,
|
||||
// call save() after every read() write() flush()
|
||||
void save();
|
||||
// retrieves the internal variables + verify checksum.
|
||||
// returns false if checksum fails ==> data inconsistent (no load)
|
||||
bool load();
|
||||
// removes all data from ring buffer by overwriting the FRAM.
|
||||
void wipe();
|
||||
|
||||
|
||||
private:
|
||||
uint32_t _count = 0; // optimization == front - tail (+ size)
|
||||
uint32_t _size = 0;
|
||||
uint32_t _start = 0;
|
||||
uint32_t _front = _start;
|
||||
uint32_t _tail = _start;
|
||||
FRAM * _fram;
|
||||
bool _saved = false;
|
||||
};
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
144
libraries/FRAM_I2C/FRAM_RINGBUFFER.md
Normal file
144
libraries/FRAM_I2C/FRAM_RINGBUFFER.md
Normal file
@ -0,0 +1,144 @@
|
||||
|
||||
[![Arduino CI](https://github.com/RobTillaart/FRAM_I2C/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
|
||||
[![Arduino-lint](https://github.com/RobTillaart/FRAM_I2C/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/FRAM_I2C/actions/workflows/arduino-lint.yml)
|
||||
[![JSON check](https://github.com/RobTillaart/FRAM_I2C/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/FRAM_I2C/actions/workflows/jsoncheck.yml)
|
||||
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/FRAM_I2C/blob/master/LICENSE)
|
||||
[![GitHub release](https://img.shields.io/github/release/RobTillaart/FRAM_I2C.svg?maxAge=3600)](https://github.com/RobTillaart/FRAM_I2C/releases)
|
||||
|
||||
|
||||
# FRAM_RINGBUFFER
|
||||
|
||||
Library for FRAM_RINGBUFFER to be used with the FRAM_I2C library.
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
FRAM_RINGBUFFER is a class that uses an FRAM object to implement
|
||||
a ring buffer that can be made persistent over reboots.
|
||||
The ring buffer can hold any size objects, but the user is responsible
|
||||
to manage the contents.
|
||||
This means it can hold objects of different sizes, but the user should
|
||||
add this size and/or type info into the object, or preceding every object.
|
||||
|
||||
The FRAM_RINGBUFFER is build upon the FRAM_I2C library so it is not
|
||||
expected to work with other FRAM libraries.
|
||||
|
||||
Types of FRAM that should work with this library:
|
||||
|
||||
| TYPE | SIZE | TESTED |
|
||||
|:----------:|-------:|:------:|
|
||||
| MB85RC04 | 512 | |
|
||||
| MB85RC16 | 2 KB | |
|
||||
| MB85RC64T | 8 KB | |
|
||||
| MB85RC128A | 16 KB | |
|
||||
| MB85RC256V | 32 KB | Y |
|
||||
| MB85RC512T | 64 KB | |
|
||||
| MB85RC1MT | 128 KB | |
|
||||
|
||||
Please let me know if you have verified one that is not in the list.
|
||||
|
||||
|
||||
#### Version
|
||||
|
||||
As the FRAM_RINGBUFFER is strongly connected to FRAM_I2C
|
||||
it has no separate version number.
|
||||
|
||||
|
||||
## Interface
|
||||
|
||||
|
||||
### Admin
|
||||
|
||||
- **FRAM_RINGBUFFER()** Constructor.
|
||||
- **uint32_t begin(FRAM \*fram, uint32_t size, uint32_t memAddr)** initializes
|
||||
the ring buffer.
|
||||
- size is in bytes.
|
||||
- memAddr is start memory address where ring buffer starts.
|
||||
- returns uint32_t == first free (next) FRAM location.
|
||||
- **void flush()** resets the internal administration.
|
||||
- Note: flush() does not wipe the content from FRAM.
|
||||
- **uint32_t size()** returns size.
|
||||
- **uint32_t count()** returns count == bytes used.
|
||||
- **uint32_t free()** returns the number of bytes free.
|
||||
- **float freePercent()** returns the number of bytes free as percentage.
|
||||
- **bool full()** returns true if the ring buffer has no free bytes left.
|
||||
- **bool empty()** returns true if the ring buffer has no data in it.
|
||||
|
||||
|
||||
### read / write (bytes)
|
||||
|
||||
- **int write(uint8_t value)** writes a byte to the ring buffer.
|
||||
- returns the number of bytes written (1) or **FRAM_RB_ERR_BUF_FULL**
|
||||
- **int read()** returns a byte from the ring buffer.
|
||||
- returns **FRAM_RB_ERR_BUF_EMPTY** in case of an empty buffer.
|
||||
- **int peek()** returns the next byte that would be read().
|
||||
- returns **FRAM_RB_ERR_BUF_EMPTY** in case of an empty buffer.
|
||||
|
||||
|
||||
### read / write (objects)
|
||||
|
||||
- **template <class T> int write(T &obj)** writes an object to the ring buffer.
|
||||
- returns the number of bytes written or **FRAM_RB_ERR_BUF_NO_ROOM**
|
||||
- see example how to use.
|
||||
- **template <class T> int read(T &obj)** returns an object from the ring buffer.
|
||||
- returns bytes read or **FRAM_RB_ERR_BUF_NO_DATA** if the buffer has less
|
||||
bytes than the object requested.
|
||||
- **template <class T> int peek(T &obj)** returns the next object in the ring buffer.
|
||||
- returns bytes read or **FRAM_RB_ERR_BUF_NO_DATA** if the buffer has less
|
||||
bytes than the object requested.
|
||||
|
||||
|
||||
### persistency
|
||||
|
||||
- **bool isSaved()** returns true if the administration of the ring buffer
|
||||
is written to FRAM.
|
||||
- **void save()** stores the internal administration + checksum to FRAM.
|
||||
- **bool load()** retrieves the internal administration + checksum from FRAM.
|
||||
- returns true if checksum matches the stored variables. Only then the
|
||||
variables of the ring buffer will be updated.
|
||||
- **void wipe()** removes all data from ring buffer by overwriting the FRAM.
|
||||
|
||||
|
||||
|
||||
### Error codes
|
||||
|
||||
| value | description | Notes |
|
||||
|:-------:|:-------------------------|:--------|
|
||||
| 0 | FRAM_RB_OK |
|
||||
| -1 | FRAM_RB_ERR_BUF_FULL |
|
||||
| -2 | FRAM_RB_ERR_BUF_EMPTY |
|
||||
| -21 | FRAM_RB_ERR_BUF_NO_ROOM | (almost) full
|
||||
| -22 | FRAM_RB_ERR_BUF_NO_DATA | (almost) empty
|
||||
|
||||
|
||||
## Operational
|
||||
|
||||
See examples.
|
||||
|
||||
## Future
|
||||
|
||||
|
||||
### high
|
||||
|
||||
- elaborate FRAM_RINGBUFFER documentation
|
||||
- add bool flag to **load(bool overrule = false)** to overrule the checksum verification.
|
||||
- default false.
|
||||
- add bool flag to **wipe(bool all = true)** to overwrite all or the
|
||||
administration part only.
|
||||
|
||||
|
||||
### medium
|
||||
|
||||
- example for a ring-buffer with different size objects
|
||||
- struct with size and type info.
|
||||
- preceding every object with type + size - 1..4 bytes
|
||||
- add debugging tooling
|
||||
- add object count?
|
||||
|
||||
### low
|
||||
|
||||
- create a RING_BUFFER class that can work with any type of storage.
|
||||
- SD card, EEPROM etc.
|
||||
|
||||
### wont
|
||||
|
@ -54,7 +54,8 @@ This latter will not be shown on an I2C scanner (to be tested).
|
||||
### Constructor
|
||||
|
||||
- **FRAM(TwoWire \*wire = &Wire)** Constructor with optional Wire interface.
|
||||
- **FRAM32(TwoWire \*wire = &Wire)** Constructor with optional Wire interface, specific for **MB85RC1MT** type of device.
|
||||
- **FRAM32(TwoWire \*wire = &Wire)** Constructor with optional Wire interface,
|
||||
specific for **MB85RC1MT** type of device.
|
||||
- **int begin(uint8_t address = 0x50, int8_t writeProtectPin = -1)** address and writeProtectPin is optional.
|
||||
Note the **MB85RC1MT** only uses even addresses.
|
||||
- **int begin(int sda, int scl, uint8_t address = 0x50, int8_t writeProtectPin = -1)** idem for ESP32 a.o.
|
||||
@ -63,7 +64,8 @@ Note the **MB85RC1MT** only uses even addresses.
|
||||
|
||||
### Write & read
|
||||
|
||||
Support for basic types and 2 calls for generic object, use casting if needed. In the **FRAM32** class these functions have an **uin32_t memaddr**.
|
||||
Support for basic types and 2 calls for generic object, use casting if needed.
|
||||
In the **FRAM32** class these functions have an **uin32_t memaddr**.
|
||||
|
||||
- **void write8(uint16_t memaddr, uint8_t value)** uint8_t
|
||||
- **void write16(uint16_t memaddr, uint16_t value)** uint16_t
|
||||
@ -83,7 +85,7 @@ Returns memaddr + sizeof(obj) to get the next address to read from.
|
||||
|
||||
(0.3.5 added)
|
||||
- **uint32_t clear(uint8_t value = 0)** clears the whole FRAM by writing value to all addresses - default zero's.
|
||||
Returns the number of bytes written..
|
||||
Returns the number of bytes written.
|
||||
|
||||
|
||||
### Miscellaneous
|
||||
@ -109,7 +111,7 @@ See also remark in Future section below.
|
||||
|
||||
(0.3.6 added - experimental)
|
||||
- **void sleep()** puts the FRAM in sleep mode so it uses less power.
|
||||
Still needs a power test for 2 types of FRAM.
|
||||
Still needs a power test for several types of FRAM.
|
||||
- **bool wakeup(uint32_t trec = 400)** tries to wake up the device with a default recovery time of 400 microseconds.
|
||||
Returns true if connected after the call.
|
||||
|
||||
@ -152,6 +154,13 @@ _TODO: fill the table_
|
||||
See examples
|
||||
|
||||
|
||||
## FRAM_RINGBUFFER
|
||||
|
||||
Since version 0.4.2 a separate class **FRAM_RINGBUFFER** is added.= to this repo.
|
||||
Its interface is pretty straightforward and described in FRAM_RINGBUFFER.md.
|
||||
The FRAM_ringbuffer.ino examples shows how the class can be used.
|
||||
|
||||
|
||||
## Future
|
||||
|
||||
### high
|
||||
@ -161,7 +170,6 @@ _TODO: fill the table_
|
||||
- now it is responsibility user.
|
||||
- do we want/need this?
|
||||
|
||||
|
||||
### medium
|
||||
|
||||
- **write()** and **writeBlock()** might write beyond the end of FRAM
|
||||
@ -170,8 +178,6 @@ _TODO: fill the table_
|
||||
- error flag ?
|
||||
- extend examples
|
||||
- FRAM for multi language string storage
|
||||
- FRAM as linear buffer for a slow stream?
|
||||
- FRAM as ring buffer
|
||||
- FRAM logging, unequal length strings.
|
||||
- FRAM (8x) concatenated as one continuous memory.
|
||||
|
||||
|
128
libraries/FRAM_I2C/examples/FRAM_ringbuffer/FRAM_ringbuffer.ino
Normal file
128
libraries/FRAM_I2C/examples/FRAM_ringbuffer/FRAM_ringbuffer.ino
Normal file
@ -0,0 +1,128 @@
|
||||
//
|
||||
// FILE: FRAM_ringbuffer.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo FRAM_RINGBUFFER class.
|
||||
// URL: https://github.com/RobTillaart/FRAM_I2C
|
||||
|
||||
// experimental code
|
||||
|
||||
|
||||
#include "FRAM.h"
|
||||
#include "FRAM_RINGBUFFER.h"
|
||||
|
||||
|
||||
FRAM fram;
|
||||
uint32_t sizeInBytes = 0;
|
||||
|
||||
|
||||
FRAM_RINGBUFFER fb;
|
||||
|
||||
// demo struct
|
||||
struct GPSBuffer {
|
||||
float lat;
|
||||
float lon;
|
||||
float speed;
|
||||
float alt;
|
||||
} gps_data;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("FRAM_LIB_VERSION: ");
|
||||
Serial.println(FRAM_LIB_VERSION);
|
||||
|
||||
Wire.begin();
|
||||
|
||||
int rv = fram.begin(0x50);
|
||||
if (rv != 0)
|
||||
{
|
||||
Serial.print("INIT ERROR: ");
|
||||
Serial.println(rv);
|
||||
}
|
||||
|
||||
// get size in bytes
|
||||
sizeInBytes = fram.getSize() * 1024;
|
||||
// clear FRAM
|
||||
for (uint32_t addr = 0; addr < sizeInBytes; addr++)
|
||||
{
|
||||
fram.write8(addr, 0x00);
|
||||
}
|
||||
|
||||
// initialize the ring buffer.
|
||||
fb.begin(&fram, 1600, 0);
|
||||
// clear the ring buffer.
|
||||
fb.flush();
|
||||
if (fb.load() == false)
|
||||
{
|
||||
Serial.println("FB.LOAD() ERROR: ");
|
||||
}
|
||||
|
||||
// dump initial state.
|
||||
dump();
|
||||
|
||||
// add some bytes.
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
fb.write('A' + i); // write ABCDEFGHIJ
|
||||
}
|
||||
Serial.print("PEEK:\t");
|
||||
Serial.println(fb.peek());
|
||||
dump();
|
||||
|
||||
// read some bytes.
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
fb.read();
|
||||
}
|
||||
Serial.print("PEEK:\t");
|
||||
Serial.println(fb.peek());
|
||||
dump();
|
||||
|
||||
fb.flush();
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
fb.write(gps_data);
|
||||
}
|
||||
dump();
|
||||
|
||||
fb.flush();
|
||||
|
||||
float f = 3.14159265;
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
fb.write(f);
|
||||
}
|
||||
dump();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void dump()
|
||||
{
|
||||
Serial.print("\n");
|
||||
Serial.print("SIZE:\t");
|
||||
Serial.println(fb.size());
|
||||
Serial.print("COUNT:\t");
|
||||
Serial.println(fb.count());
|
||||
Serial.print("FULL:\t");
|
||||
Serial.println(fb.full());
|
||||
Serial.print("EMPTY:\t");
|
||||
Serial.println(fb.empty());
|
||||
Serial.print("FREE:\t");
|
||||
Serial.println(fb.free());
|
||||
Serial.print("percent:\t");
|
||||
Serial.println(fb.freePercent(), 1);
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,162 @@
|
||||
//
|
||||
// FILE: FRAM_ringbuffer_II.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: demo FRAM_RINGBUFFER class.
|
||||
// URL: https://github.com/RobTillaart/FRAM_I2C
|
||||
|
||||
// experimental code / playground with 2 ringbuffers
|
||||
|
||||
|
||||
#include "FRAM.h"
|
||||
#include "FRAM_RINGBUFFER.h"
|
||||
|
||||
|
||||
FRAM fram;
|
||||
uint32_t sizeInBytes = 0;
|
||||
|
||||
|
||||
FRAM_RINGBUFFER fb;
|
||||
FRAM_RINGBUFFER fb2;
|
||||
|
||||
// demo struct
|
||||
struct record
|
||||
{
|
||||
uint32_t time;
|
||||
float value;
|
||||
} data;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("FRAM_LIB_VERSION: ");
|
||||
Serial.println(FRAM_LIB_VERSION);
|
||||
|
||||
Wire.begin();
|
||||
Wire.setClock(400000);
|
||||
|
||||
int rv = fram.begin(0x50);
|
||||
if (rv != 0)
|
||||
{
|
||||
Serial.print("INIT ERROR: ");
|
||||
Serial.println(rv);
|
||||
}
|
||||
|
||||
// get size in bytes
|
||||
sizeInBytes = fram.getSize() * 1024;
|
||||
Serial.print("FRAMSIZE:\t");
|
||||
Serial.println(sizeInBytes);
|
||||
|
||||
// clear FRAM optional
|
||||
// for (uint32_t addr = 0; addr < sizeInBytes; addr += 4)
|
||||
// {
|
||||
// fram.write32(addr, 0);
|
||||
// }
|
||||
|
||||
// initialize the two ring buffers.
|
||||
uint32_t nextAddr = fb.begin(&fram, 80, 0);
|
||||
nextAddr = fb2.begin(&fram, 80, nextAddr);
|
||||
Serial.print("NEXTADDR:\t");
|
||||
Serial.println(nextAddr);
|
||||
|
||||
// if you want to start VERY clean...
|
||||
// fb.wipe();
|
||||
// fb2.wipe();
|
||||
|
||||
|
||||
if (fb.load() == false)
|
||||
{
|
||||
Serial.println("FB.LOAD() FAILED.");
|
||||
// clear the ring buffer when it could not be loaded from FRAM.
|
||||
fb.flush();
|
||||
|
||||
// only the first 10 will fit.
|
||||
for (int i = 0; i < 15; i++)
|
||||
{
|
||||
data.time = millis();
|
||||
data.value = sin(data.time / 1024.0);
|
||||
int rv = fb.write(data);
|
||||
|
||||
Serial.print(data.time);
|
||||
Serial.print("\t");
|
||||
Serial.print(data.value, 4);
|
||||
Serial.print("\t");
|
||||
Serial.println(rv);
|
||||
|
||||
delay(100);
|
||||
}
|
||||
// make it persistent.
|
||||
fb.save();
|
||||
}
|
||||
|
||||
while (!fb.empty())
|
||||
{
|
||||
fb.read(data);
|
||||
Serial.print("buf 1");
|
||||
Serial.print("\t");
|
||||
Serial.print(data.time);
|
||||
Serial.print("\t");
|
||||
Serial.println(data.value, 4);
|
||||
|
||||
data.value *= 2;
|
||||
fb2.write(data);
|
||||
}
|
||||
|
||||
while (!fb2.empty())
|
||||
{
|
||||
fb2.read(data);
|
||||
Serial.print("buf 2");
|
||||
Serial.print("\t");
|
||||
Serial.print(data.time);
|
||||
Serial.print("\t");
|
||||
Serial.println(data.value, 4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
void dump()
|
||||
{
|
||||
Serial.print("\n");
|
||||
Serial.print("SIZE:\t");
|
||||
Serial.println(fb.size());
|
||||
Serial.print("COUNT:\t");
|
||||
Serial.println(fb.count());
|
||||
Serial.print("FULL:\t");
|
||||
Serial.println(fb.full());
|
||||
Serial.print("EMPTY:\t");
|
||||
Serial.println(fb.empty());
|
||||
Serial.print("FREE:\t");
|
||||
Serial.println(fb.free());
|
||||
Serial.print("percent:\t");
|
||||
Serial.println(fb.freePercent(), 1);
|
||||
}
|
||||
|
||||
void dump2()
|
||||
{
|
||||
Serial.print("\n");
|
||||
Serial.print("SIZE:\t");
|
||||
Serial.println(fb2.size());
|
||||
Serial.print("COUNT:\t");
|
||||
Serial.println(fb2.count());
|
||||
Serial.print("FULL:\t");
|
||||
Serial.println(fb2.full());
|
||||
Serial.print("EMPTY:\t");
|
||||
Serial.println(fb2.empty());
|
||||
Serial.print("FREE:\t");
|
||||
Serial.println(fb2.free());
|
||||
Serial.print("percent:\t");
|
||||
Serial.println(fb2.freePercent(), 1);
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
@ -3,6 +3,7 @@
|
||||
# Data types (KEYWORD1)
|
||||
FRAM KEYWORD1
|
||||
FRAM32 KEYWORD1
|
||||
FRAM_RINGBUFFER KEYWORD1
|
||||
|
||||
|
||||
# Methods and Functions (KEYWORD2)
|
||||
@ -36,6 +37,27 @@ sleep KEYWORD2
|
||||
wakeup KEYWORD2
|
||||
|
||||
|
||||
# Methods and Functions FRAM_RINGBUFFER
|
||||
begin KEYWORD2
|
||||
flush KEYWORD2
|
||||
size KEYWORD2
|
||||
|
||||
count KEYWORD2
|
||||
free KEYWORD2
|
||||
freePercent KEYWORD2
|
||||
full KEYWORD2
|
||||
empty KEYWORD2
|
||||
|
||||
write KEYWORD2
|
||||
read KEYWORD2
|
||||
peek KEYWORD2
|
||||
|
||||
isSaved KEYWORD2
|
||||
save KEYWORD2
|
||||
load KEYWORD2
|
||||
wipe KEYWORD2
|
||||
|
||||
|
||||
# Constants (LITERAL1)
|
||||
FRAM_LIB_VERSION LITERAL1
|
||||
FRAM_OK LITERAL1
|
||||
@ -51,3 +73,12 @@ FRAM_MB85RC256V LITERAL1
|
||||
FRAM_MB85RC512T LITERAL1
|
||||
FRAM_MB85RC1MT LITERAL1
|
||||
|
||||
|
||||
# constants FRAM_RINGBUFFER
|
||||
FRAM_RB_OK LITERAL1
|
||||
FRAM_RB_ERR_BUF_FULL LITERAL1
|
||||
FRAM_RB_ERR_BUF_EMPTY LITERAL1
|
||||
FRAM_RB_ERR_BUF_NO_ROOM LITERAL1
|
||||
FRAM_RB_ERR_BUF_NO_DATA LITERAL1
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "FRAM_I2C",
|
||||
"keywords": "FRAM, storage",
|
||||
"description": "Library for FRAM for Arduino.",
|
||||
"description": "Library for FRAM for Arduino. Includes an experimental FRAM_RINGBUFFER class (since 0.4.2)",
|
||||
"authors":
|
||||
[
|
||||
{
|
||||
@ -15,7 +15,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/FRAM_I2C.git"
|
||||
},
|
||||
"version": "0.4.1",
|
||||
"version": "0.4.2",
|
||||
"license": "MIT",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "*",
|
||||
|
@ -1,9 +1,9 @@
|
||||
name=FRAM_I2C
|
||||
version=0.4.1
|
||||
version=0.4.2
|
||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
sentence=Arduino library for I2C FRAM.
|
||||
paragraph=
|
||||
paragraph=Includes an experimental FRAM_RINGBUFFER class.
|
||||
category=Data Storage
|
||||
url=https://github.com/RobTillaart/FRAM_I2C.git
|
||||
architectures=*
|
||||
|
Loading…
Reference in New Issue
Block a user