diff --git a/.gitignore b/.gitignore index b6e4761..36f4f36 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,6 @@ dmypy.json # Pyre type checker .pyre/ + +# PyCharm IDE +.idea/ \ No newline at end of file diff --git a/README.md b/README.md index bc7cbd4..e7eca94 100644 --- a/README.md +++ b/README.md @@ -66,20 +66,21 @@ M95M02-DRMN6TP and M95M02-DWMN3TP/K. The latter has a wider temperature range. In the table below the Interface column includes page size in bytes. -| Manufacturer | Part | Interface | Bytes | Technology | Docs | -|:------------:|:---------:|:---------:|:-------:|:----------:|:-----------------------------:| -| Various | Various | SPI 4096 | <=32MiB | Flash | [FLASH.md](./flash/FLASH.md) | -| STM | M95M02-DR | SPI 256 | 256KiB | EEPROM | [SPI.md](./eeprom/spi/SPI.md) | -| Microchip | 25xx1024 | SPI 256 | 128KiB | EEPROM | [SPI.md](./eeprom/spi/SPI.md) | -| Microchip | 25xx512* | SPI 256 | 64KiB | EEPROM | [SPI.md](./eeprom/spi/SPI.md) | -| Microchip | 24xx512 | I2C 128 | 64KiB | EEPROM | [I2C.md](./eeprom/i2c/I2C.md) | -| Microchip | 24xx256 | I2C 128 | 32KiB | EEPROM | [I2C.md](./eeprom/i2c/I2C.md) | -| Microchip | 24xx128 | I2C 128 | 16KiB | EEPROM | [I2C.md](./eeprom/i2c/I2C.md) | -| Microchip | 24xx64 | I2C 128 | 8KiB | EEPROM | [I2C.md](./eeprom/i2c/I2C.md) | -| Adafruit | 4719 | SPI n/a | 512KiB | FRAM | [FRAM_SPI.md](./fram/FRAM_SPI.md) | -| Adafruit | 4718 | SPI n/a | 256KiB | FRAM | [FRAM_SPI.md](./fram/FRAM_SPI.md) | -| Adafruit | 1895 | I2C n/a | 32KiB | FRAM | [FRAM.md](./fram/FRAM.md) | -| Adafruit | 4677 | SPI n/a | 8MiB | SPIRAM | [SPIRAM.md](./spiram/SPIRAM.md) | +| Manufacturer | Part | Interface | Bytes | Technology | Docs | +|:------------:|:----------|:----------|:--------|:-----------|:----------------------------------| +| Various | Various | SPI 4096 | <=32MiB | Flash | [FLASH.md](./flash/FLASH.md) | +| STM | M95M02-DR | SPI 256 | 256KiB | EEPROM | [SPI.md](./eeprom/spi/SPI.md) | +| Microchip | 25xx1024 | SPI 256 | 128KiB | EEPROM | [SPI.md](./eeprom/spi/SPI.md) | +| Microchip | 25xx512* | SPI 256 | 64KiB | EEPROM | [SPI.md](./eeprom/spi/SPI.md) | +| Microchip | 24xx512 | I2C 128 | 64KiB | EEPROM | [I2C.md](./eeprom/i2c/I2C.md) | +| Microchip | 24xx256 | I2C 128 | 32KiB | EEPROM | [I2C.md](./eeprom/i2c/I2C.md) | +| Microchip | 24xx128 | I2C 128 | 16KiB | EEPROM | [I2C.md](./eeprom/i2c/I2C.md) | +| Microchip | 24xx64 | I2C 128 | 8KiB | EEPROM | [I2C.md](./eeprom/i2c/I2C.md) | +| Microchip | 24xx32 | I2C 32 | 4KiB | EEPROM | [I2C.md](./eeprom/i2c/I2C.md) | +| Adafruit | 4719 | SPI n/a | 512KiB | FRAM | [FRAM_SPI.md](./fram/FRAM_SPI.md) | +| Adafruit | 4718 | SPI n/a | 256KiB | FRAM | [FRAM_SPI.md](./fram/FRAM_SPI.md) | +| Adafruit | 1895 | I2C n/a | 32KiB | FRAM | [FRAM.md](./fram/FRAM.md) | +| Adafruit | 4677 | SPI n/a | 8MiB | SPIRAM | [SPIRAM.md](./spiram/SPIRAM.md) | Parts marked * have been tested by users (see below). The SPIRAM chip is equivalent to Espressif ESP-PSRAM64H. diff --git a/eeprom/i2c/I2C.md b/eeprom/i2c/I2C.md index c56d502..80fdce3 100644 --- a/eeprom/i2c/I2C.md +++ b/eeprom/i2c/I2C.md @@ -124,7 +124,8 @@ is detected or if device address lines are not wired as described in Arguments: 1. `i2c` Mandatory. An initialised master mode I2C bus created by `machine`. 2. `chip_size=T24C512` The chip size in bits. The module provides constants - `T24C64`, `T24C128`, `T24C256`, `T24C512` for the supported chip sizes. + `T24C32`, `T24C64`, `T24C128`, `T24C256`, `T24C512` for the supported +chip sizes. 3. `verbose=True` If `True`, the constructor issues information on the EEPROM devices it has detected. 4. `block_size=9` The block size reported to the filesystem. The size in bytes diff --git a/eeprom/i2c/eep_i2c.py b/eeprom/i2c/eep_i2c.py index 1a177d6..f96ce14 100644 --- a/eeprom/i2c/eep_i2c.py +++ b/eeprom/i2c/eep_i2c.py @@ -8,28 +8,32 @@ import time from machine import I2C, Pin from eeprom_i2c import EEPROM, T24C512 + # Return an EEPROM array. Adapt for platforms other than Pyboard or chips # smaller than 64KiB. def get_eep(): if uos.uname().machine.split(' ')[0][:4] == 'PYBD': Pin.board.EN_3V3.value(1) time.sleep(0.1) # Allow decouplers to charge + eep = EEPROM(I2C(2), T24C512) print('Instantiated EEPROM') return eep + # Dumb file copy utility to help with managing EEPROM contents at the REPL. def cp(source, dest): if dest.endswith('/'): # minimal way to allow dest = ''.join((dest, source.split('/')[-1])) # cp /sd/file /eeprom/ with open(source, 'rb') as infile: # Caller should handle any OSError - with open(dest,'wb') as outfile: # e.g file not found + with open(dest, 'wb') as outfile: # e.g file not found while True: buf = infile.read(100) outfile.write(buf) if len(buf) < 100: break + # ***** TEST OF DRIVER ***** def _testblock(eep, bs): d0 = b'this >' @@ -38,27 +42,29 @@ def _testblock(eep, bs): garbage = b'xxxxxxxxxxxxxxxxxxx' start = bs - len(d0) end = start + len(garbage) - eep[start : end] = garbage - res = eep[start : end] + eep[start: end] = garbage + res = eep[start: end] if res != garbage: return 'Block test fail 1:' + str(list(res)) end = start + len(d0) - eep[start : end] = d0 + eep[start: end] = d0 end = start + len(garbage) - res = eep[start : end] + res = eep[start: end] if res != b'this >xxxxxxxxxxxxx': return 'Block test fail 2:' + str(list(res)) start = bs end = bs + len(d1) - eep[start : end] = d1 + eep[start: end] = d1 start = bs - len(d0) end = start + len(d2) - res = eep[start : end] + res = eep[start: end] if res != d2: return 'Block test fail 3:' + str(list(res)) -def test(): - eep = get_eep() + +def test(eep = None): + eep = eep if eep else get_eep() + sa = 1000 for v in range(256): eep[sa + v] = v @@ -92,9 +98,10 @@ def test(): else: print('Test chip boundary skipped: only one chip!') + # ***** TEST OF FILESYSTEM MOUNT ***** -def fstest(format=False): - eep = get_eep() +def fstest(eep = None, format=False): + eep = eep if eep else get_eep() try: uos.umount('/eeprom') except OSError: @@ -107,15 +114,17 @@ def fstest(format=False): uos.VfsLfs2.mkfs(eep) # General try: - uos.mount(eep,'/eeprom') + uos.mount(eep, '/eeprom') except OSError: raise OSError("Can't mount device: have you formatted it?") print('Contents of "/": {}'.format(uos.listdir('/'))) print('Contents of "/eeprom": {}'.format(uos.listdir('/eeprom'))) print(uos.statvfs('/eeprom')) -def cptest(): # Assumes pre-existing filesystem of either type - eep = get_eep() + +def cptest(eep = None): # Assumes pre-existing filesystem of either type + eep = eep if eep else get_eep() + if 'eeprom' in uos.listdir('/'): print('Device already mounted.') else: @@ -130,14 +139,16 @@ def cptest(): # Assumes pre-existing filesystem of either type print('Contents of "/eeprom": {}'.format(uos.listdir('/eeprom'))) print(uos.statvfs('/eeprom')) + # ***** TEST OF HARDWARE ***** -def full_test(): - eep = get_eep() +def full_test(eep = None, block_size = 128): + eep = eep if eep else get_eep() page = 0 - for sa in range(0, len(eep), 128): - data = uos.urandom(128) - eep[sa:sa + 128] = data - if eep[sa:sa + 128] == data: + + for sa in range(0, len(eep), block_size): + data = uos.urandom(block_size) + eep[sa:sa + block_size] = data + if eep[sa:sa + block_size] == data: print('Page {} passed'.format(page)) else: print('Page {} readback failed.'.format(page)) diff --git a/eeprom/i2c/eeprom_i2c.py b/eeprom/i2c/eeprom_i2c.py index a468631..35e3f10 100644 --- a/eeprom/i2c/eeprom_i2c.py +++ b/eeprom/i2c/eeprom_i2c.py @@ -8,22 +8,27 @@ from micropython import const from bdevice import BlockDevice _ADDR = const(0x50) # Base address of chip +_MAX_CHIPS_COUNT = 8 T24C512 = const(65536) # 64KiB 512Kbits T24C256 = const(32768) # 32KiB 256Kbits T24C128 = const(16384) # 16KiB 128Kbits T24C64 = const(8192) # 8KiB 64Kbits +T24C32 = const(4096) # 4KiB 32Kbits + # Logical EEPROM device consists of 1-8 physical chips. Chips must all be the -# same size, and must have contiguous addresses starting from 0x50. +# same size, and must have contiguous addresses. class EEPROM(BlockDevice): def __init__(self, i2c, chip_size=T24C512, verbose=True, block_size=9): self._i2c = i2c - if chip_size not in (T24C64, T24C128, T24C256, T24C512): + if chip_size not in (T24C64, T24C128, T24C256, T24C512, T24C32): print('Warning: possible unsupported chip. Size:', chip_size) - nchips = self.scan(verbose, chip_size) # No. of EEPROM chips + nchips, min_chip_address = self.scan(verbose, chip_size) # No. of EEPROM chips super().__init__(block_size, nchips, chip_size) + + self._min_chip_address = min_chip_address self._i2c_addr = 0 # I2C address of current chip self._buf1 = bytearray(1) self._addrbuf = bytearray(2) # Memory offset into current chip @@ -31,16 +36,24 @@ class EEPROM(BlockDevice): # Check for a valid hardware configuration def scan(self, verbose, chip_size): devices = self._i2c.scan() # All devices on I2C bus - eeproms = [d for d in devices if _ADDR <= d < _ADDR + 8] # EEPROM chips + eeproms = [d for d in devices if _ADDR <= d < _ADDR + _MAX_CHIPS_COUNT] # EEPROM chips nchips = len(eeproms) if nchips == 0: raise RuntimeError('EEPROM not found.') - if min(eeproms) != _ADDR or (max(eeproms) - _ADDR) >= nchips: + + eeproms = sorted(eeproms) + if len(set(eeproms)) != len(eeproms): + raise RuntimeError('Duplicate addresses were found', eeproms) + + if (eeproms[-1] - eeproms[0] + 1) != len(eeproms): raise RuntimeError('Non-contiguous chip addresses', eeproms) + if verbose: - s = '{} chips detected. Total EEPROM size {}bytes.' + s = '{} chip(s) detected. Total EEPROM size {}bytes.' print(s.format(nchips, chip_size * nchips)) - return nchips + print(f"Chips addresses are: {eeproms}") + + return nchips, min(eeproms) def _wait_rdy(self): # After a write, wait for device to become ready self._buf1[0] = 0 @@ -61,7 +74,7 @@ class EEPROM(BlockDevice): ca, la = divmod(addr, self._c_bytes) # ca == chip no, la == offset into chip self._addrbuf[0] = (la >> 8) & 0xff self._addrbuf[1] = la & 0xff - self._i2c_addr = _ADDR + ca + self._i2c_addr = self._min_chip_address + ca pe = (addr & ~0x7f) + 0x80 # byte 0 of next page return min(nbytes, pe - la) @@ -75,7 +88,7 @@ class EEPROM(BlockDevice): assert npage > 0 if read: self._i2c.writeto(self._i2c_addr, self._addrbuf) - self._i2c.readfrom_into(self._i2c_addr, mvb[start : start + npage]) + self._i2c.readfrom_into(self._i2c_addr, mvb[start: start + npage]) else: self._i2c.writevto(self._i2c_addr, (self._addrbuf, buf[start: start + npage])) self._wait_rdy() @@ -83,3 +96,4 @@ class EEPROM(BlockDevice): start += npage addr += npage return buf +