From 33f4dc065895181c2151c483e18f8d388542f378 Mon Sep 17 00:00:00 2001 From: Peter Hinch Date: Thu, 13 Feb 2020 14:01:02 +0000 Subject: [PATCH] Document support for extra flash chips. --- README.md | 35 +++++++++++++++-------- bdevice.py | 5 +--- flash/FLASH.md | 65 ++++++++++++++++++++++++++---------------- flash/flash_spi.py | 8 +----- flash/flash_test.py | 9 ++++++ flash/littlefs_test.py | 2 ++ 6 files changed, 76 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 35a04a1..38c8119 100644 --- a/README.md +++ b/README.md @@ -57,19 +57,30 @@ 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 | -|:------------:|:---------:|:---------:|:------:|:----------:|:-----------------------------:| -| Cypress | S25FL256L | SPI 4096 | 32MiB | Flash | [FLASH.md](./flash/FLASH.md) | -| Cypress | S25FL128L | SPI 4096 | 16MiB | 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.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 | 1895 | I2C n/a | 32KiB | FRAM | [FRAM.md](./fram/FRAM.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.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 | 1895 | I2C n/a | 32KiB | FRAM | [FRAM.md](./fram/FRAM.md) | -The flash driver now has the capability to support smaller chips. +The flash driver now has the capability to support a variety of chips. The +following have been tested to date: + +| Chip | Size (MiB) | +|:-----------------:|:----------:| +| Cypress S25FL256L | 32 | +| Cypress S25FL128L | 16 | +| Cypress S25FL064L | 8 | +| Winbond W25Q32JV | 4 | + +It is likely that other chips with 4096 byte blocks will work but I am unlikely +to be able to support hardware I don't possess. Users should check datasheets +for compatibility. ## 1.5 Performance diff --git a/bdevice.py b/bdevice.py index 748eb3d..5ea4bf0 100644 --- a/bdevice.py +++ b/bdevice.py @@ -63,10 +63,7 @@ class BlockDevice: return def readblocks(self, blocknum, buf, offset=0): - if blocknum < 0 or (offset + (blocknum << self._nbits)) > self._a_bytes: - print('rb', hex(blocknum), offset, hex(offset + (blocknum << self._nbits))) - else: - self.readwrite(offset + (blocknum << self._nbits), buf, True) + self.readwrite(offset + (blocknum << self._nbits), buf, True) def writeblocks(self, blocknum, buf, offset=0): self.readwrite(offset + (blocknum << self._nbits), buf, False) diff --git a/flash/FLASH.md b/flash/FLASH.md index 04ec201..3fec2e3 100644 --- a/flash/FLASH.md +++ b/flash/FLASH.md @@ -1,13 +1,21 @@ # 1. A MicroPython Flash memory driver +## 1.1 Device support + This driver supports the Cypress S25FL256L and S25FL128L chips, providing 32MiB and 16MiB respectively. These have 100K cycles of write endurance (compared to 10K for Pyboard Flash memory). These were the largest capacity available with a sector size small enough for microcontroller use. -Thanks to a patch from Daniel Thompson this now has the capability to support -smaller NOR Flash chips with 24-bit addressing. I lack the chips to test this -so am unable to support such use. The author tested on an XPX XT25F32B. +Thanks to a patch from Daniel Thompson this now supports a variety of NOR Flash +chips including those with 24-bit addressing. He tested an XPX XT25F32B; I +tested Winbond W25Q32JV 4MiB and Cypress S25FL064L 8MiB devices. + +It is likely that other chips with 4096 byte blocks will work but I am unlikely +to be able to support hardware I don't possess. Users should check datasheets +for compatibility. + +## 1.2 The driver Multiple chips may be used to construct a single logical nonvolatile memory module. The driver allows the memory either to be mounted in the target @@ -36,8 +44,8 @@ for facilitating effective hardware tests and for diagnostics. Any SPI interface may be used. The table below assumes a Pyboard running SPI(2) as per the test program. To wire up a single flash chip, connect to a Pyboard -as below. Pin numbers an 8 pin SOIC or WSON package. Inputs marked `nc` may be -connected to 3V3 or left unconnected. +as below. Pin numbers relate to an 8 pin SOIC or WSON package. Inputs marked +`nc` may be connected to 3V3 or left unconnected. | Flash | Signal | PB | Signal | |:-----:|:-------:|:---:|:------:| @@ -50,7 +58,7 @@ connected to 3V3 or left unconnected. | 7 | RESET/ | nc | - | | 8 | Vcc | 3V3 | 3V3 | -For multiple chips a separate CS pin must be assigned to each chip: each one +For multiple chips a separate CS pin must be assigned to each chip, each one being wired to a single chip's CS line. The test program assumes a second chip with CS connected to Y4. Multiple chips should have 3V3, Gnd, SCL, MOSI and MISO lines wired in parallel. @@ -61,7 +69,7 @@ to enable the voltage rail by issuing: machine.Pin.board.EN_3V3.value(1) time.sleep(0.1) # Allow decouplers to charge ``` -Other platforms may vary but the Cypress chips require a 3.3V supply. +Other devices may vary but the Cypress chips require a 3.3V supply. It is wise to add a pullup resistor (say 10KΩ) from each CS/ line to 3.3V. This ensures that chips are deselected at initial power up when the microcontroller @@ -85,9 +93,10 @@ Bus lines should be short and direct. 5. `wemos_flash.py` Test program running on a Wemos D1 Mini ESP8266 board. Installation: copy files 1 and 2 (3 - 5 are optional) to the target filesystem. -The `flash_test` script assumes two S25FL256L chips connected to SPI(2) with -CS/ pins wired to Pyboard pins Y4 and Y5. The `get_device` function may be -adapted for other setups and is shared with `littlefs_test`. +The `flash_test` script assumes two chips connected to SPI(2) with CS/ pins +wired to Pyboard pins Y4 and Y5. Device size is detected at runtime. The +`get_device` function may be adapted for other setups and is shared with +`littlefs_test`. For a quick check of hardware issue: ```python @@ -140,18 +149,20 @@ Arguments. In most cases only the first two mandatory args are required: 3. `size=None` Chip size in KiB. The size is read from the chip. If a value is passed, the actual size is compared with the passed value: a mismatch will raise a `ValueError`. A `ValueError` will also occur if chips in the array - have differing sizes. See table below for values. + have differing sizes. See table below for values of chips tested to date. 4. `verbose=True` If `True`, the constructor issues information on the flash devices it has detected. 5. `sec_size=4096` Chip sector size. 6. `block_size=9` The block size reported to the filesystem. The size in bytes is `2**block_size` so is 512 bytes by default. -Size values: -| Chip | Size | -|:---------:|:-----:| -| S25FL256L | 32768 | -| S25FL128L | 16384 | +Size values (KiB): +| Chip | Size | +|:-----------------:|:-----:| +| Cypress S25FL256L | 32768 | +| Cypress S25FL128L | 16384 | +| Cypress S25FL064L | 8192 | +| Winbond W25Q32JV | 4096 | ### 4.1.2 Methods providing byte level access @@ -195,8 +206,7 @@ print(flash[2000:2002]) # Returns a bytearray ``` Three argument slices are not supported: a third arg (other than 1) will cause an exception. One argument slices (`flash[:5]` or `flash[13100:]`) and negative -args are supported. See [section 4.2](./SPI.md#42-byte-addressing-usage-example) -for a typical application. +args are supported. #### 4.1.2.2 readwrite @@ -224,13 +234,18 @@ where `flash` is the `FLASH` instance. #### scan -Activate each chip select in turn checking for a valid device and returns the -number of flash devices detected. A `RuntimeError` will be raised if any CS -pin does not correspond to a valid chip. +Args: + 1. `verbose` `bool`. If `True` print information on chips detected. + 2. `size` `int` or `None`. If an `int` is passed a `ValueError` is thrown if + the detected chip size does not match the passed value. -Other than for debugging there is no need to call `scan()`: the constructor -will throw a `RuntimeError` if it fails to communicate with and correctly -identify each chip. +Activate each chip select in turn checking for a valid device and returns the +size in KiB of one instance of the flash devices detected. A `RuntimeError` +will be raised if any CS pin does not correspond to a valid chip. A +`ValueError` is thrown if the detected chips are not of the same size. + +Other than for debugging there is no need to call `scan()`: it is called by the +constructor. #### erase @@ -246,7 +261,7 @@ also [here](http://docs.micropython.org/en/latest/reference/filesystem.html#cust `writeblocks()` `ioctl()` -# 5. Test program flash_spi.py +# 5. Test program flash_test.py This assumes a Pyboard 1.x or Pyboard D with two chips wired to SPI(2) as above with chip selects connected to pins `Y4` and `Y5`. It provides the diff --git a/flash/flash_spi.py b/flash/flash_spi.py index 599bc94..c5093ec 100644 --- a/flash/flash_spi.py +++ b/flash/flash_spi.py @@ -152,16 +152,10 @@ class FLASH(FlashDevice): # Given an address, set current chip select and address buffer. # Return the number of bytes that can be processed in the current chip. def _getaddr(self, addr, nbytes): -# print(hex(addr), hex(self._a_bytes), hex(self._c_bytes), self._nbits, self._block_size, divmod(addr, self._c_bytes)) if addr >= self._a_bytes: -# print(hex(addr), hex(self._a_bytes), hex(self._c_bytes), self._nbits, self._block_size, divmod(addr, self._c_bytes)) raise RuntimeError("Flash Address is out of range") ca, la = divmod(addr, self._c_bytes) # ca == chip no, la == offset into chip - try: - self._ccs = self._cspins[ca] # Current chip select - except: - print(ca, la) - raise + self._ccs = self._cspins[ca] # Current chip select cmdlen = self._cmdlen mvp = self._mvp[:cmdlen] if cmdlen > 3: diff --git a/flash/flash_test.py b/flash/flash_test.py index f47d17d..c389a4b 100644 --- a/flash/flash_test.py +++ b/flash/flash_test.py @@ -159,3 +159,12 @@ def full_test(count=10): if g != data[n]: print('{} {:2x} {:2x} {:2x}'.format(n, data[n], g, got1[n])) break + +helpstr = '''Available tests: +test() Basic hardware test. +full_test(count=10) Full hardware test, count is no. of passes. +fstest(format=False) Check or create littlefs filesystem. +cptest() Copy 2 files to filesystem. +cp() Primitive copy routine. See docs. +''' +print(helpstr) diff --git a/flash/littlefs_test.py b/flash/littlefs_test.py index 36601e7..7d6b543 100644 --- a/flash/littlefs_test.py +++ b/flash/littlefs_test.py @@ -73,3 +73,5 @@ def main(): print('Rewrote', n, length) check_all() remove_all() + +print('main() to run littlefs test. Filesystem must exist.')