Skip to content

Commit 7a2fe12

Browse files
authored
Merge pull request #4 from sommersoft/spi_new
Add SPI Usage
2 parents f4997ee + 8fa6798 commit 7a2fe12

File tree

4 files changed

+145
-8
lines changed

4 files changed

+145
-8
lines changed

adafruit_fram.py

+110-6
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757
_I2C_MANF_ID = const(0x0A)
5858
_I2C_PROD_ID = const(0x510)
5959

60+
_SPI_MANF_ID = const(0x04)
61+
_SPI_PROD_ID = const(0x302)
62+
6063
class FRAM:
6164
"""
6265
Driver base for the FRAM Breakout.
@@ -102,12 +105,6 @@ def write_protected(self):
102105
"""
103106
return self._wp if self._wp_pin is None else self._wp_pin.value
104107

105-
@write_protected.setter
106-
def write_protected(self, value):
107-
self._wp = value
108-
if not self._wp_pin is None:
109-
self._wp_pin.value = value
110-
111108
def __len__(self):
112109
""" The maximum size of the current FRAM chip. This is the highest
113110
register location that can be read or written to.
@@ -257,3 +254,110 @@ def _write(self, start_register, data, wraparound=False):
257254
buffer[1] = ((start_register + i) - self._max_size) & 0xFF
258255
buffer[2] = data[i]
259256
i2c.write(buffer)
257+
258+
# pylint: disable=no-member
259+
@FRAM.write_protected.setter
260+
def write_protected(self, value):
261+
if value not in (True, False):
262+
raise ValueError("Write protected value must be 'True' or 'False'.")
263+
self._wp = value
264+
if not self._wp_pin is None:
265+
self._wp_pin.value = value
266+
267+
# the following pylint disables are related to the '_SPI_OPCODE' consts, the super
268+
# class setter '@FRAM.write_protected.setter', and pylint not being able to see
269+
# 'spi.write()' in SPIDevice. Travis run for reference:
270+
# https://travis-ci.com/sommersoft/Adafruit_CircuitPython_FRAM/builds/87112669
271+
272+
# pylint: disable=no-member,undefined-variable
273+
class FRAM_SPI(FRAM):
274+
""" SPI class for FRAM.
275+
276+
:param: ~busio.SPI spi_bus: The SPI bus the FRAM is connected to.
277+
:param: ~digitalio.DigitalInOut spi_cs: The SPI CS pin.
278+
:param: bool write_protect: Turns on/off initial write protection.
279+
Default is ``False``.
280+
:param: wp_pin: (Optional) Physical pin connected to the ``WP`` breakout pin.
281+
Must be a ``digitalio.DigitalInOut`` object.
282+
:param int baudrate: SPI baudrate to use. Default is ``1000000``.
283+
"""
284+
285+
_SPI_OPCODE_WREN = const(0x6) # Set write enable latch
286+
_SPI_OPCODE_WRDI = const(0x4) # Reset write enable latch
287+
_SPI_OPCODE_RDSR = const(0x5) # Read status register
288+
_SPI_OPCODE_WRSR = const(0x1) # Write status register
289+
_SPI_OPCODE_READ = const(0x3) # Read memory code
290+
_SPI_OPCODE_WRITE = const(0x2) # Write memory code
291+
_SPI_OPCODE_RDID = const(0x9F) # Read device ID
292+
293+
#pylint: disable=too-many-arguments,too-many-locals
294+
def __init__(self, spi_bus, spi_cs, write_protect=False,
295+
wp_pin=None, baudrate=100000):
296+
from adafruit_bus_device.spi_device import SPIDevice as spidev
297+
_spi = spidev(spi_bus, spi_cs, baudrate=baudrate)
298+
299+
read_buffer = bytearray(4)
300+
with _spi as spi:
301+
spi.write(bytearray([_SPI_OPCODE_RDID]))
302+
spi.readinto(read_buffer)
303+
prod_id = (read_buffer[3] << 8) + (read_buffer[2])
304+
if (read_buffer[0] != _SPI_MANF_ID) and (prod_id != _SPI_PROD_ID):
305+
raise OSError("FRAM SPI device not found.")
306+
307+
self._spi = _spi
308+
super().__init__(_MAX_SIZE_SPI, write_protect, wp_pin)
309+
310+
def _read_register(self, register, read_buffer):
311+
write_buffer = bytearray(3)
312+
write_buffer[0] = _SPI_OPCODE_READ
313+
write_buffer[1] = register >> 8
314+
write_buffer[2] = register & 0xFF
315+
with self._spi as spi:
316+
spi.write(write_buffer)
317+
spi.readinto(read_buffer)
318+
return read_buffer
319+
320+
def _write(self, start_register, data, wraparound=False):
321+
buffer = bytearray(3)
322+
if not isinstance(data, int):
323+
data_length = len(data)
324+
else:
325+
data_length = 1
326+
data = [data]
327+
if (start_register + data_length) - 1 > self._max_size:
328+
if wraparound:
329+
pass
330+
else:
331+
raise ValueError("Starting register + data length extends beyond"
332+
" FRAM maximum size. Use 'wraparound=True' to"
333+
" override this warning.")
334+
with self._spi as spi:
335+
spi.write(bytearray([_SPI_OPCODE_WREN]))
336+
with self._spi as spi:
337+
buffer[0] = _SPI_OPCODE_WRITE
338+
buffer[1] = start_register >> 8
339+
buffer[2] = start_register & 0xFF
340+
spi.write(buffer)
341+
for i in range(0, data_length):
342+
spi.write(bytearray([data[i]]))
343+
with self._spi as spi:
344+
spi.write(bytearray([_SPI_OPCODE_WRDI]))
345+
346+
@FRAM.write_protected.setter
347+
def write_protected(self, value):
348+
# While it is possible to protect block ranges on the SPI chip,
349+
# it seems superfluous to do so. So, block protection always protects
350+
# the entire memory (BP0 and BP1).
351+
if value not in (True, False):
352+
raise ValueError("Write protected value must be 'True' or 'False'.")
353+
self._wp = value
354+
write_buffer = bytearray(2)
355+
write_buffer[0] = _SPI_OPCODE_WRSR
356+
if value:
357+
write_buffer[1] = 0x8C # set WPEN, BP0, and BP1
358+
else:
359+
write_buffer[1] = 0x00 # clear WPEN, BP0, and BP1
360+
with self._spi as spi:
361+
spi.write(write_buffer)
362+
if self._wp_pin is not None:
363+
self._wp_pin.value = value

docs/examples.rst

+4
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,7 @@ Ensure your device works with this simple test.
66
.. literalinclude:: ../examples/fram_i2c_simpletest.py
77
:caption: examples/fram_i2c_simpletest.py
88
:linenos:
9+
10+
.. literalinclude:: ../examples/fram_spi_simpletest.py
11+
:caption: examples/fram_spi_simpletest.py
12+
:linenos:

examples/fram_i2c_simpletest.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,5 @@
3434
## problems on memory-constrained platforms.
3535

3636
#values = list(range(100)) # or bytearray or tuple
37-
#fram[0:100] = values
38-
#print(fram[0:100])
37+
#fram[0] = values
38+
#print(fram[0:99])

examples/fram_spi_simpletest.py

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
## Simple Example For CircuitPython/Python SPI FRAM Library
2+
3+
import board
4+
import busio
5+
import digitalio
6+
import adafruit_fram
7+
8+
## Create a FRAM object.
9+
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
10+
cs = digitalio.DigitalInOut(board.D5)
11+
fram = adafruit_fram.FRAM_SPI(spi, cs)
12+
13+
## Write a single-byte value to register address '0'
14+
15+
fram[0] = 1
16+
17+
## Read that byte to ensure a proper write.
18+
## Note: 'read()' returns a bytearray
19+
20+
print(fram[0])
21+
22+
## Or write a sequential value, then read the values back.
23+
## Note: 'read()' returns a bytearray. It also allocates
24+
## a buffer the size of 'length', which may cause
25+
## problems on memory-constrained platforms.
26+
27+
#values = list(range(100)) # or bytearray or tuple
28+
#fram[0] = values
29+
#print(fram[0:99])

0 commit comments

Comments
 (0)