Skip to content

Add SPI Usage #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Dec 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 110 additions & 6 deletions adafruit_fram.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@
_I2C_MANF_ID = const(0x0A)
_I2C_PROD_ID = const(0x510)

_SPI_MANF_ID = const(0x04)
_SPI_PROD_ID = const(0x302)

class FRAM:
"""
Driver base for the FRAM Breakout.
Expand Down Expand Up @@ -102,12 +105,6 @@ def write_protected(self):
"""
return self._wp if self._wp_pin is None else self._wp_pin.value

@write_protected.setter
def write_protected(self, value):
self._wp = value
if not self._wp_pin is None:
self._wp_pin.value = value

def __len__(self):
""" The maximum size of the current FRAM chip. This is the highest
register location that can be read or written to.
Expand Down Expand Up @@ -257,3 +254,110 @@ def _write(self, start_register, data, wraparound=False):
buffer[1] = ((start_register + i) - self._max_size) & 0xFF
buffer[2] = data[i]
i2c.write(buffer)

# pylint: disable=no-member
@FRAM.write_protected.setter
def write_protected(self, value):
if value not in (True, False):
raise ValueError("Write protected value must be 'True' or 'False'.")
self._wp = value
if not self._wp_pin is None:
self._wp_pin.value = value

# the following pylint disables are related to the '_SPI_OPCODE' consts, the super
# class setter '@FRAM.write_protected.setter', and pylint not being able to see
# 'spi.write()' in SPIDevice. Travis run for reference:
# https://travis-ci.com/sommersoft/Adafruit_CircuitPython_FRAM/builds/87112669

# pylint: disable=no-member,undefined-variable
class FRAM_SPI(FRAM):
""" SPI class for FRAM.

:param: ~busio.SPI spi_bus: The SPI bus the FRAM is connected to.
:param: ~digitalio.DigitalInOut spi_cs: The SPI CS pin.
:param: bool write_protect: Turns on/off initial write protection.
Default is ``False``.
:param: wp_pin: (Optional) Physical pin connected to the ``WP`` breakout pin.
Must be a ``digitalio.DigitalInOut`` object.
:param int baudrate: SPI baudrate to use. Default is ``1000000``.
"""

_SPI_OPCODE_WREN = const(0x6) # Set write enable latch
_SPI_OPCODE_WRDI = const(0x4) # Reset write enable latch
_SPI_OPCODE_RDSR = const(0x5) # Read status register
_SPI_OPCODE_WRSR = const(0x1) # Write status register
_SPI_OPCODE_READ = const(0x3) # Read memory code
_SPI_OPCODE_WRITE = const(0x2) # Write memory code
_SPI_OPCODE_RDID = const(0x9F) # Read device ID

#pylint: disable=too-many-arguments,too-many-locals
def __init__(self, spi_bus, spi_cs, write_protect=False,
wp_pin=None, baudrate=100000):
from adafruit_bus_device.spi_device import SPIDevice as spidev
_spi = spidev(spi_bus, spi_cs, baudrate=baudrate)

read_buffer = bytearray(4)
with _spi as spi:
spi.write(bytearray([_SPI_OPCODE_RDID]))
spi.readinto(read_buffer)
prod_id = (read_buffer[3] << 8) + (read_buffer[2])
if (read_buffer[0] != _SPI_MANF_ID) and (prod_id != _SPI_PROD_ID):
raise OSError("FRAM SPI device not found.")

self._spi = _spi
super().__init__(_MAX_SIZE_SPI, write_protect, wp_pin)

def _read_register(self, register, read_buffer):
write_buffer = bytearray(3)
write_buffer[0] = _SPI_OPCODE_READ
write_buffer[1] = register >> 8
write_buffer[2] = register & 0xFF
with self._spi as spi:
spi.write(write_buffer)
spi.readinto(read_buffer)
return read_buffer

def _write(self, start_register, data, wraparound=False):
buffer = bytearray(3)
if not isinstance(data, int):
data_length = len(data)
else:
data_length = 1
data = [data]
if (start_register + data_length) - 1 > self._max_size:
if wraparound:
pass
else:
raise ValueError("Starting register + data length extends beyond"
" FRAM maximum size. Use 'wraparound=True' to"
" override this warning.")
with self._spi as spi:
spi.write(bytearray([_SPI_OPCODE_WREN]))
with self._spi as spi:
buffer[0] = _SPI_OPCODE_WRITE
buffer[1] = start_register >> 8
buffer[2] = start_register & 0xFF
spi.write(buffer)
for i in range(0, data_length):
spi.write(bytearray([data[i]]))
with self._spi as spi:
spi.write(bytearray([_SPI_OPCODE_WRDI]))

@FRAM.write_protected.setter
def write_protected(self, value):
# While it is possible to protect block ranges on the SPI chip,
# it seems superfluous to do so. So, block protection always protects
# the entire memory (BP0 and BP1).
if value not in (True, False):
raise ValueError("Write protected value must be 'True' or 'False'.")
self._wp = value
write_buffer = bytearray(2)
write_buffer[0] = _SPI_OPCODE_WRSR
if value:
write_buffer[1] = 0x8C # set WPEN, BP0, and BP1
else:
write_buffer[1] = 0x00 # clear WPEN, BP0, and BP1
with self._spi as spi:
spi.write(write_buffer)
if self._wp_pin is not None:
self._wp_pin.value = value
4 changes: 4 additions & 0 deletions docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ Ensure your device works with this simple test.
.. literalinclude:: ../examples/fram_i2c_simpletest.py
:caption: examples/fram_i2c_simpletest.py
:linenos:

.. literalinclude:: ../examples/fram_spi_simpletest.py
:caption: examples/fram_spi_simpletest.py
:linenos:
4 changes: 2 additions & 2 deletions examples/fram_i2c_simpletest.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@
## problems on memory-constrained platforms.

#values = list(range(100)) # or bytearray or tuple
#fram[0:100] = values
#print(fram[0:100])
#fram[0] = values
#print(fram[0:99])
29 changes: 29 additions & 0 deletions examples/fram_spi_simpletest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
## Simple Example For CircuitPython/Python SPI FRAM Library

import board
import busio
import digitalio
import adafruit_fram

## Create a FRAM object.
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
cs = digitalio.DigitalInOut(board.D5)
fram = adafruit_fram.FRAM_SPI(spi, cs)

## Write a single-byte value to register address '0'

fram[0] = 1

## Read that byte to ensure a proper write.
## Note: 'read()' returns a bytearray

print(fram[0])

## Or write a sequential value, then read the values back.
## Note: 'read()' returns a bytearray. It also allocates
## a buffer the size of 'length', which may cause
## problems on memory-constrained platforms.

#values = list(range(100)) # or bytearray or tuple
#fram[0] = values
#print(fram[0:99])