peterhinch / micropython_eeprom

MicroPython device drivers for memory chips (EEPROM, FRAM, Flash, SPIRAM)
MIT License
73 stars 33 forks source link

Understanding Nomenclature for Flash Sector, Blocks, Pages #30

Open thestumbler opened 2 months ago

thestumbler commented 2 months ago

I'm struggling to get a larger 1GB NAND flash working with the library.

I first figured out that the READ_ID command didn't follow the same rule as the code was expecting, and memory size was being scanned incorrectly. Put a temporary patch in for that (see below) and now I'm simply not able to get it to work. Similar to reports from others here who have tried adding unknown flash chips -- it seems to read and write, but it doesn't persist across a reset nor power cycle.

But before I get deeper into that, I'm struggling to match the terminology of Micron with that of the library / block driver / VFSLFS2. Specifically, Micron describes the memory organization as:

The library code manages four categories of sizes:

I'd appreciate any guidance for sorting out these seemingly different naming conventions. I've tried too many combinations of the above, all without success.

Here's the snippet where I patched the scan function to try to get started

    # **** API SPECIAL METHODS ****
    # Scan: return chip size in KiB as read from ID.
    def scan(self, verbose, size):
        mvp = self._mvp
        for n, cs in enumerate(self._cspins):
            mvp[:] = b"\0\0\0\0\0\0"
            mvp[0] = _RDID
            cs(0)
            self._spi.write_readinto(mvp[:4], mvp[:4])
            cs(1)
            print( f'0x{mvp[0]:02x} ' \
                   f'0x{mvp[1]:02x} ' \
                   f'0x{mvp[2]:02x} ' \
                   f'0x{mvp[3]:02x} ' \
            )
            if mvp[2]==0x2c: # exception for Micron 1G/2G/4G/8G NAND
              # MFR byte = 0x2c = Micron MT29F1G01 (1Gb version P/N)
              #                           e2
              # size=1Gb, ID byte = 14h   30
              # size=2Gb, ID byte = 24h   31
              # size=4Gb, ID byte = 36h   32
              # size=8Gb, ID byte = 46h   33
              e2 = 29 + ((mvp[3] & 0xf0) >> 4) 
              scansize = (1 << e2) 
              print(f'power of two {e2},   size {scansize:,}')
            else:
              scansize = 1 << (mvp[3] - 10)
            if size is None:
                size = scansize  # Save size of 1st chip
            if size != scansize:  # Mismatch passed size or 1st chip.
                raise ValueError(f"Flash size mismatch: expected {size}KiB, found {scansize}KiB")
            if not 0x10 < mvp[3] < 0x22:
                raise ValueError(f"Invalid chip size {size}KiB. Specify size arg.")
        if verbose:
            s = "{} chips detected. Total flash size {}MiB."
            n += 1
            print(s.format(n, (n * size) // 1024))
        return size
peterhinch commented 2 months ago

I did look into supporting larger chips and decided it was impractical. The chip you are using has a block size of 136K. This is the smallest amount that can be erased. Consequently my driver would require a contiguous buffer of 136K which is quite unrealistic on most microcontrollers.

My driver uses buffering because it is part of a family of drivers supporting multiple chip types; it also supports usage other than in a filesystem. @robert-hh has pointed out that, to support littlefs, buffering is not required. He has published this driver which is unbuffered and would make a better starting point for large devices. I believe his driver only supports a single chip rather than an array.

I suggest you investigate this approach.

thestumbler commented 2 months ago

Okay. That makes sense. And it clicks with one of my experiments where it failed allocating a 128 KiB memory buffer. I thought I had just screwed up the various size definitions. But based on your reply, I had them correct.

I will investigate that project as you say. I would still like to get your take on the various definitions, just for my knowledge.

This is the new Bus Pirate 5 board, and I am trying to write a simple proof of concept collection of MP modules (it has been substantially successful and easy so far). Maybe I'll give your project a quick whirl on the Bus Pirate 6 beta unit, which has about double the RAM, and see if it flies.

Thanks -Chris

thestumbler commented 2 months ago

By the way, Peter, I am using your project for talking to an SPI serial EEPROM. It is one that isn't officially supported, I suspect because it is so small -- the Atmel 25080 8 Kib (1024 x 8 configuration). I didn't choose this myself, but it happened to be on a small evaluation board I'm using for testing. I get the warning possible unsupported chip. Size: 1KiB. Despite this, it seems to work just fine. image

peterhinch commented 2 months ago

The terminology used in my code is: 1 size The size of a single chip (not the whole array) in KiB.

  1. sec_size The size in bytes of the smallest erasable block (== the necessary buffer size).
  2. block_size The block size reported to the filesystem. Size in bytes == 2**block_size.
  3. page_size This is only relevant to non-Flash chips. EEPROMS have a small RAM buffer. This is the size in bytes of this buffer.

Note that block_size has nothing to do with the physical chip. The ioctl reports a block size which I think once referred to the size of a sector on disk. The value is 9 by convention.

thestumbler commented 1 month ago

@peterhinch Here's a writeup I did mentioning this package. Which reminds me, I have a pull request I need to make for the small sized EEPROM. I'll try to do that this week. -Chris https://hackaday.com/2024/10/15/experimenting-with-micropython-on-the-bus-pirate-5/