Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Writing URI into st25dv16 from CircuitPython
# SPDX-FileCopyrightText: Copyright (c) 2021 Tim Cocks for Adafruit Industries
# SPDX-License-Identifier: MIT
CircuitPython driver for the I2C EEPROM of the Adafruit ST25DV16 Breakout
* Author(s): Tim Cocks
Implementation Notes
* `Adafruit ST25DV16K I2C RFID EEPROM Breakout - STEMMA QT / Qwiic <>`_
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
# * Adafruit's Bus Device library:
# * Adafruit's Register library:
# imports
import time
from micropython import const
__version__ = "0.0.0-auto.0"
__repo__ = "" ### 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.value = self._wp
self._wp_pin = wp_pin
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
def write_wraparound(self, value):
if not value in (True, False):
raise ValueError("Write wraparound must be 'True' or 'False'.")
self._wraparound = value
def write_protected(self):
"""The status of write protection. Default value on initialization is
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()
# 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
# read values 0 thru 9 with a slice
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(
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
"""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)
data_length = 1
data = [data]
if (start_address + data_length) > self._max_size:
if wraparound:
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
buffer[0] = ((start_address + i) - self._max_size + 1) >> 8
buffer[1] = ((start_address + i) - self._max_size + 1) & 0xFF
buffer[2] = data[i]
# pylint: disable=no-member
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
# 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://
buf = bytearray ([0xe1, 0x40, 0x40, 0x05, 0x03, 0x00, 0xd1, 0x01, 0x00, 0x55])
buf[5] = (l+5)
buf[8] = (l+1)
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:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment