Home

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).

FRAMLR
Vcc3V33V3
GndGNDGND
WPncnc
SCLX9Y9
SDAX10Y10
A2ncnc
A1ncnc
A0ncnc

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:

  1. i2c Mandatory. An initialised master mode I2C bus.
  2. 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:

  1. addr Starting byte address
  2. buf A buffer containing the data to write or to hold read data
  3. read If True, perform a read otherwise write. The size of the buffer determines the quantity of data read or written. A FRAMException 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.