Awesome
micropython-fram
A driver to enable the Pyboard to access the Ferroelectric RAM (FRAM) board from Adafruit. FRAM is a technology offering nonvolatile memory with extremely long endurance and fast access, avoiding the limitations of Flash memory. Its endurance is specified as 10^13 writes, contrasted with 10,000 which is the quoted endurance of the Pyboard's onboard Flash memory. In data logging applications the latter can be exceeded relatively rapidly. Flash writes can be slow because of the need for a sector erase: this is not a fast process. FRAM is byte addressable and is not subject to this limitation. The downside is limited capacity. Compared to a Micro SD card fitted to the Pyboard it offers lower power consumption and longer endurance.
From one to eight boards may be used to construct a nonvolatile memory module with size ranging from 32KB to 256KB. The driver allows the memory either to be mounted in the Pyboard filesystem as a disk device or to be addressed as an array of bytes.
Now accepts an I2C bus as argument to facilitate the use of multiple devices on the bus. Also adapted to work on the ESP8266.
Connections
To wire up a single FRAM module, connect to the Pyboard as below (nc indicates no connection).
FRAM | L | R |
---|---|---|
Vcc | 3V3 | 3V3 |
Gnd | GND | GND |
WP | nc | nc |
SCL | X9 | Y9 |
SDA | X10 | Y10 |
A2 | nc | nc |
A1 | nc | nc |
A0 | nc | nc |
For multiple modules the address lines A0, A1 and A2 of each module need to be wired to 3V3 in such a way as to give each device a unique address. These must start at zero and be contiguous. Thus with three modules, the first would have address lines unconnected (address 0), the second would have A0 connected to 3V3 (address 1) and the third would have A1 connected to 3V3 (address 2).
Multiple modules should have 3V3, Gnd, SCL and SDA lines wired in parallel.
Driver
The driver supports mounting the FRAM modules as a filesystem. Initially the device will be unformatted so it is necessary to issue code along these lines to format the device.
import pyb
from fram import FRAM
i2c = pyb.I2C(2, pyb.I2C.MASTER)
f = FRAM(i2c)
pyb.mount(f, '/fram', mkfs = True)
pyb.mount(None, '/fram')
At the time of writing the pyb
module provides no way to reformat a drive
which already has a filesystem. As a workround the following will perform this:
import pyb
from fram import FRAM
i2c = pyb.I2C(2, pyb.I2C.MASTER)
f = FRAM(i2c)
f.low_level_format()
pyb.mount(f, '/fram', mkfs = True)
pyb.mount(None, '/fram')
Note that, at the outset, you need to decide whether to use the array as a
mounted filesystem or as a byte array. As a filesystem the limited size is an
issue, but a potential use case is for pickling Python objects for example to
achieve persistence when issuing pyb.standby()
. Also for holding a small
frequently updated persistent btree database.
Constructor
FRAM()
Takes two arguments:
i2c
Mandatory. An initialised master mode I2C bus.verbose
(default False). If True, the constructor issues information on the FRAM devices it has detected.
A FRAMException
will be raised if a device is not detected or if device
address lines are not wired as described in Connections above.
Methods providing the block protocol
For the protocol definition see the pyb documentation
readblocks()
writeblocks()
count()
ioctl()
Methods providing byte level access
The following methods are available for general use.
readwrite()
Provides byte level access to the memory array. Arguments:
addr
Starting byte addressbuf
A buffer containing the data to write or to hold read dataread
If True, perform a read otherwise write. The size of the buffer determines the quantity of data read or written. AFRAMException
will be thrown if the read or write extends beyond the end of the array.
low_level_format()
Erases the filesystem! Currently (this may change) the
pyb module doesn't provide a means of forcing a drive format. Issuing a
low_level_format()
followed by pyb.mount()
with mkfs-True
will
format the drive deleting all files.
available()
Returns True if the device is detected and is supported.
Other than for debugging there is no need to call available()
: the
constructor will throw a FRAMException
if it fails to communicate with and
correctly identify the chip.
File copy
This is really a piece of history now superseded. upysh in micropython-lib is a much more capable solution.
A rudimentary cp(source, dest)
function is provided as a generic file copy
routine for setup and debugging purposes at the REPL. The first argument is the
full pathname to the source file. The second may be a full path to the
destination file or a directory specifier which must have a trailing '/'. If an
OSError is thrown (e.g. by the source file not existing or the FRAM becoming
full) it is up to the caller to handle it. For example (assuming the FRAM is
mounted on /fram):
cp('/flash/main.py','/fram/')
ESP8266
The driver now supports this module. The file framtest_esp8266.py
demonstrates
its use. Note that currently the ESP8266 does not support concurrent mounting
of multiple filesystems. Consequently the onboard flash must be unmounted (with
uos.umount()
) before the FRAM can be mounted.