Created
December 20, 2021 00:55
-
-
Save dglaude/6e1fbe1e2c2d1222f99872a506a48a2b to your computer and use it in GitHub Desktop.
Writing URI into st25dv16 from CircuitPython
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# SPDX-FileCopyrightText: Copyright (c) 2021 Tim Cocks for Adafruit Industries | |
# | |
# SPDX-License-Identifier: MIT | |
""" | |
`adafruit_st25dv16` | |
================================================================================ | |
CircuitPython driver for the I2C EEPROM of the Adafruit ST25DV16 Breakout | |
* Author(s): Tim Cocks | |
Implementation Notes | |
-------------------- | |
**Hardware:** | |
* `Adafruit ST25DV16K I2C RFID EEPROM Breakout - STEMMA QT / Qwiic <https://www.adafruit.com/product/4701>`_ | |
**Software and Dependencies:** | |
* Adafruit CircuitPython firmware for the supported boards: | |
https://github.com/adafruit/circuitpython/releases | |
# * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice | |
# * Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register | |
""" | |
# imports | |
import time | |
from micropython import const | |
__version__ = "0.0.0-auto.0" | |
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_24LC32.git" ### fix me | |
_MAX_SIZE_I2C = const(0x800) # 16kbits | |
class EEPROM: | |
""" | |
Driver base for the EEPROM Breakout. | |
""" | |
def __init__(self, max_size, write_protect=False, wp_pin=None): | |
self._max_size = max_size | |
self._wp = write_protect | |
self._wraparound = False | |
if not wp_pin is None: | |
self._wp_pin = wp_pin | |
# Make sure write_prot is set to output | |
self._wp_pin.switch_to_output() | |
self._wp_pin.value = self._wp | |
else: | |
self._wp_pin = wp_pin | |
@property | |
def write_wraparound(self): | |
"""Determines if sequential writes will wrapaound highest memory address | |
(``len(EEPROM) - 1``) address. If ``False``, and a requested write will | |
extend beyond the maximum size, an exception is raised. | |
""" | |
return self._wraparound | |
@write_wraparound.setter | |
def write_wraparound(self, value): | |
if not value in (True, False): | |
raise ValueError("Write wraparound must be 'True' or 'False'.") | |
self._wraparound = value | |
@property | |
def write_protected(self): | |
"""The status of write protection. Default value on initialization is | |
``False``. | |
When a ``WP`` pin is supplied during initialization, or using | |
``write_protect_pin``, the status is tied to that pin and enables | |
hardware-level protection. | |
When no ``WP`` pin is supplied, protection is only at the software | |
level in this library. | |
""" | |
return self._wp if self._wp_pin is None else self._wp_pin.value | |
def __len__(self): | |
"""The size of the current EEPROM chip. This is one more than the highest | |
address location that can be read or written to. | |
.. code-block:: python | |
fram = adafruit_fram.FRAM_xxx() # xxx = 'I2C' or 'SPI' | |
# size returned by len() | |
len(fram) | |
# can be used with range | |
for i in range(0, len(fram)) | |
""" | |
return self._max_size | |
def __getitem__(self, address): | |
"""Read the value at the given index, or values in a slice. | |
.. code-block:: python | |
# read single index | |
fram[0] | |
# read values 0 thru 9 with a slice | |
fram[0:9] | |
""" | |
if isinstance(address, int): | |
if not 0 <= address < self._max_size: | |
raise ValueError( | |
"Address '{0}' out of range. It must be 0 <= address < {1}.".format( | |
address, self._max_size | |
) | |
) | |
buffer = bytearray(1) | |
read_buffer = self._read_address(address, buffer) | |
elif isinstance(address, slice): | |
if address.step is not None: | |
raise ValueError("Slice stepping is not currently available.") | |
regs = list( | |
range( | |
address.start if address.start is not None else 0, | |
address.stop + 1 if address.stop is not None else self._max_size, | |
) | |
) | |
if regs[0] < 0 or (regs[0] + len(regs)) > self._max_size: | |
raise ValueError( | |
"Address slice out of range. It must be 0 <= [starting address" | |
":stopping address] < {0}.".format(self._max_size) | |
) | |
buffer = bytearray(len(regs)) | |
read_buffer = self._read_address(regs[0], buffer) | |
return read_buffer | |
def __setitem__(self, address, value): | |
"""Write the value at the given starting index. | |
.. code-block:: python | |
# write single index | |
fram[0] = 1 | |
# write values 0 thru 4 with a list | |
fram[0:4] = [0,1,2,3] | |
""" | |
if self.write_protected: | |
raise RuntimeError("FRAM currently write protected.") | |
if isinstance(address, int): | |
if not isinstance(value, int): | |
raise ValueError("Data must be a single integer for single addresses") | |
if not 0 <= address < self._max_size: | |
raise ValueError( | |
"Address '{0}' out of range. It must be 0 <= address < {1}.".format( | |
address, self._max_size | |
) | |
) | |
self._write(address, value, self._wraparound) | |
elif isinstance(address, slice): | |
if not isinstance(value, (bytes, bytearray, list, tuple)): | |
raise ValueError( | |
"Data must be bytes, bytearray, list, " | |
"or tuple for multiple addresses" | |
) | |
if (address.start is None) or (address.stop is None): | |
raise ValueError("Boundless slices are not supported") | |
if (address.step is not None) and (address.step != 1): | |
raise ValueError("Slice stepping is not currently available.") | |
if (address.start < 0) or (address.stop > self._max_size): | |
raise ValueError( | |
"Slice '{0}:{1}' out of range. All addresses must be 0 <= address < {2}.".format( # pylint: disable=line-too-long | |
address.start, address.stop, self._max_size | |
) | |
) | |
if len(value) < (len(range(address.start, address.stop))): | |
raise ValueError( | |
"Cannot set values with a list smaller than the number of indexes" | |
) | |
self._write(address.start, value, self._wraparound) | |
def _read_address(self, address, read_buffer): | |
# Implemented by subclass | |
raise NotImplementedError | |
def _write(self, start_address, data, wraparound): | |
# Implemened by subclass | |
raise NotImplementedError | |
class EEPROM_I2C(EEPROM): | |
"""I2C class for EEPROM. | |
:param: ~busio.I2C i2c_bus: The I2C bus the EEPROM is connected to. | |
:param: int address: I2C address of EEPROM. Default address is ``0x50``. | |
: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. | |
""" | |
# pylint: disable=too-many-arguments | |
def __init__(self, i2c_bus, address=0x53, write_protect=False, wp_pin=None): | |
from adafruit_bus_device.i2c_device import ( # pylint: disable=import-outside-toplevel | |
I2CDevice as i2cdev, | |
) | |
self._i2c = i2cdev(i2c_bus, address) | |
super().__init__(_MAX_SIZE_I2C, write_protect, wp_pin) | |
def _read_address(self, address, read_buffer): | |
write_buffer = bytearray(2) | |
write_buffer[0] = address >> 8 | |
write_buffer[1] = address & 0xFF | |
with self._i2c as i2c: | |
i2c.write_then_readinto(write_buffer, read_buffer) | |
return read_buffer | |
def _write(self, start_address, data, wraparound=False): | |
# Decided against using the chip's "Page Write", since that would require | |
# doubling the memory usage by creating a buffer that includes the passed | |
# in data so that it can be sent all in one `i2c.write`. The single-write | |
# method is slower, and forces us to handle wraparound, but I feel this | |
# is a better tradeoff for limiting the memory required for large writes. | |
buffer = bytearray(3) | |
if not isinstance(data, int): | |
data_length = len(data) | |
else: | |
data_length = 1 | |
data = [data] | |
if (start_address + data_length) > self._max_size: | |
if wraparound: | |
pass | |
else: | |
raise ValueError( | |
"Starting address + data length extends beyond" | |
" FRAM maximum address. Use ``write_wraparound`` to" | |
" override this warning." | |
) | |
with self._i2c as i2c: | |
for i in range(0, data_length): | |
if not (start_address + i) > self._max_size - 1: | |
buffer[0] = (start_address + i) >> 8 | |
buffer[1] = (start_address + i) & 0xFF | |
else: | |
buffer[0] = ((start_address + i) - self._max_size + 1) >> 8 | |
buffer[1] = ((start_address + i) - self._max_size + 1) & 0xFF | |
buffer[2] = data[i] | |
i2c.write(buffer) | |
time.sleep(0.005) | |
# pylint: disable=no-member | |
@EEPROM.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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# SPDX-FileCopyrightText: Copyright (c) 2021 David Glaude | |
# | |
# SPDX-License-Identifier: Unlicense | |
import board | |
import adafruit_st25dv16 | |
i2c = board.I2C() | |
eeprom = adafruit_st25dv16.EEPROM_I2C(i2c) | |
# Value Protocol | |
# ----- -------- | |
# 0x00 No prepending is done ... the entire URI is contained in the URI Field | |
# 0x01 http://www. | |
# 0x02 https://www. | |
# 0x03 http:// | |
# 0x04 https:// | |
#Goal: https://circuitpython.org/ | |
#head=0x04 | |
#str="circuitpython.org/" | |
#Goal: https://learn.adafruit.com/adafruit-st25dv16k-i2c-rfic-eeprom-breakout | |
head=0x04 | |
str="learn.adafruit.com/adafruit-st25dv16k-i2c-rfic-eeprom-breakout" | |
#Goal: https://www.poureva.be/spip.php?article997 | |
#head=0x02 | |
#str="poureva.be/spip.php?article997" | |
l=len(str) | |
buf = bytearray ([0xe1, 0x40, 0x40, 0x05, 0x03, 0x00, 0xd1, 0x01, 0x00, 0x55]) | |
buf[5] = (l+5) | |
buf[8] = (l+1) | |
eeprom[0:len(buf)]=buf | |
eeprom[len(buf)]=head | |
k=len(buf)+1 | |
eeprom[k:k+l]=bytearray(str) | |
eeprom[k+l]=0xfe | |
print("length: {}".format(len(eeprom))) | |
for i in range(0, 5): | |
j = i * 16 | |
hex_string = ":".join("%02x" % b for b in eeprom[j:j+15]) | |
print(j, "> ", hex_string, "> ", eeprom[j:j+15]) | |
while True: | |
pass |
Thanks @racer161
This piece of code is kind of abandon (from my side), I hope it helped or I hope your piece will help other, so it is very unlikely if you don't find the parent library and contribute an example to it.
I am pretty sure my code is a steal from one example in Adafruit Circuit Python Library.
Or could it be this: https://github.com/markmcgookin/pico-i2c-rfid
So far I don't trace the origin, something adafruit circuitpython i2c eeprom on github?
Like this: https://github.com/adafruit/Adafruit_CircuitPython_24LC32
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
you might like to have this wrapper as well