From 2f67002e4200e4edee8b85d6043fe444adbbd070 Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sat, 10 Nov 2018 18:02:56 -0600 Subject: [PATCH 1/6] intial SPI --- adafruit_fram.py | 100 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/adafruit_fram.py b/adafruit_fram.py index 45c8341..145c8a4 100644 --- a/adafruit_fram.py +++ b/adafruit_fram.py @@ -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. @@ -257,3 +260,100 @@ def _write(self, start_register, data, wraparound=False): buffer[1] = ((start_register + i) - self._max_size) & 0xFF buffer[2] = data[i] i2c.write(buffer) + +# 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 + #read_buffer = bytearray(1) + 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). + 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 not self._wp_pin is None: + self._wp_pin.value = value From 286fe450bb5ecf55fb01368483e4f4254ddf907e Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sat, 10 Nov 2018 18:18:05 -0600 Subject: [PATCH 2/6] update write_protected.setter --- adafruit_fram.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/adafruit_fram.py b/adafruit_fram.py index 145c8a4..330d3b9 100644 --- a/adafruit_fram.py +++ b/adafruit_fram.py @@ -105,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. @@ -261,6 +255,15 @@ def _write(self, start_register, data, wraparound=False): 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: @@ -346,6 +349,8 @@ 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 From 77f59eec7cffc7123fbcc22e7a317e9e9e784a3f Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sat, 10 Nov 2018 18:41:10 -0600 Subject: [PATCH 3/6] update simpletest; wrong is not simple. --- examples/fram_i2c_simpletest.py | 4 ++-- examples/fram_spi_simpletest.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 examples/fram_spi_simpletest.py diff --git a/examples/fram_i2c_simpletest.py b/examples/fram_i2c_simpletest.py index 72c040f..116d8ee 100644 --- a/examples/fram_i2c_simpletest.py +++ b/examples/fram_i2c_simpletest.py @@ -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]) diff --git a/examples/fram_spi_simpletest.py b/examples/fram_spi_simpletest.py new file mode 100644 index 0000000..2deb5f5 --- /dev/null +++ b/examples/fram_spi_simpletest.py @@ -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]) From 42ab48ad324308e52ac5f9d0df7d93bd28da8b0b Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sat, 10 Nov 2018 18:42:27 -0600 Subject: [PATCH 4/6] update docs --- docs/examples.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/examples.rst b/docs/examples.rst index f54b285..8be8954 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -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: From 205e5b9e6b0c75fa44b046e85d0ff98dc494c6bc Mon Sep 17 00:00:00 2001 From: sommersoft Date: Sat, 10 Nov 2018 18:46:52 -0600 Subject: [PATCH 5/6] sphinx fix --- docs/examples.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/examples.rst b/docs/examples.rst index 8be8954..d109edd 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -7,6 +7,6 @@ Ensure your device works with this simple test. :caption: examples/fram_i2c_simpletest.py :linenos: - .. literalinclude:: ../examples/fram_spi_simpletest.py - :caption: examples/fram_spi_simpletest.py - :linenos: +.. literalinclude:: ../examples/fram_spi_simpletest.py + :caption: examples/fram_spi_simpletest.py + :linenos: From 8fa67980d9b17d2123dcf68eba90f4e523d9f3b4 Mon Sep 17 00:00:00 2001 From: sommersoft Date: Fri, 30 Nov 2018 16:42:06 -0600 Subject: [PATCH 6/6] fix change requests --- adafruit_fram.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/adafruit_fram.py b/adafruit_fram.py index 330d3b9..fc39347 100644 --- a/adafruit_fram.py +++ b/adafruit_fram.py @@ -312,7 +312,6 @@ def _read_register(self, register, read_buffer): write_buffer[0] = _SPI_OPCODE_READ write_buffer[1] = register >> 8 write_buffer[2] = register & 0xFF - #read_buffer = bytearray(1) with self._spi as spi: spi.write(write_buffer) spi.readinto(read_buffer) @@ -360,5 +359,5 @@ def write_protected(self, value): write_buffer[1] = 0x00 # clear WPEN, BP0, and BP1 with self._spi as spi: spi.write(write_buffer) - if not self._wp_pin is None: + if self._wp_pin is not None: self._wp_pin.value = value