Driver and Command Line Shell for Winbond W25Q128 16MByte Serial FLASH Device

Modern microcontroller come with plenty of internal FLASH memory. On the other side, many high performance MCUs as the NXP i.MX RT are ‘flashless’, because the silicon process for high performance cores is not matching the FLASH memory technology, so they are using external serial SPI or Quad-SPI (QSPI) memory instead.

Winbond w25q128 breakout board

Winbond w25q128 Serial Flash Breakout Board

Why not using an external SPI FLASH for a ‘normal’ microcontroller too?

The typical usage of external SPI flash memory is using it to load or store data. With the addition of a small external device on the SPI bus I can easily add several MBytes of memory to the microcontroller. Such SPI memory devices are very inexpensive: I ordered a few breakout modules with Winbond W25Q128 (16 MByte) from AliExpress for $1.50 each. The device uses the following pins:

  • VCC: 3.3V
  • GND
  • DO: SPI MISO
  • DI: SPI MOSI
  • CS: SPI Chip Select

A red LED on the breakout module indicates if the board is powered.

Usually I use micro-SD cards for logging data. They are easily available, provide nearly ‘unlimited’ storage and with the FatFS file system I can easily exchange data with the host. But it needs space on the PCB, the SD card socket needs to be accessible, the socket is a mechanical component and has its costs plus is not very reliable in an environment with vibrations and subject of corrosion. Using a FLASH chip might be the better solution.

I have created a driver with a command line interface: that way I can read/write data of the SPI FLASH memory device. An Eclipse example project is available on GitHub (check the links at the end of this article).

The example is running on an ARM Cortex-M4 from NXP (Kinetis K20DX128), but easily can be ported for any other microcontroller.

using w25q128 with k20dx128

using w25q128 with k20dx128

The project includes a command line shell:

command line shell for serial flash

command line shell for serial flash

With the shell I can read/write the serial flash:

serial flash read and write

serial flash read and write

The ‘status’ command gives information about the device found:

device status

device status

Summary

I have now a working driver for using the Winbond W25Q128 16 MByte serial/SPI flash chip. The driver is still in an early stage, and I might update it to support other Flash devices too. With the command line interface I can read/write the memory. In a next step I plan to use the memory with a file system, more about this in a future article. The project is available on GitHub (see links below).

Happy Winbonding 🙂

Links

11 thoughts on “Driver and Command Line Shell for Winbond W25Q128 16MByte Serial FLASH Device

  1. No reason you couldn’t put a FAT file system on the flash chip, no different than an SD card in serial mode. I’ve also used SD cards in memory mode (emulates a simple flash memory). For a project that needed to save several counters on a regular basis I wrote the counters as sequential blocks in the flash. On boot it would scan from the top down to find the last block. When the flash was full, only then would I erase it and start at the beginning. This way even with the cheap flash that’s only good for 10,000 erase cycles, you still have a very long time before burnout.

    Like

    • Yes, using a file system like FatFS has many benefits. For me the biggest one is having the ability to exchange easily data with a host machine (swap out the card, insert it into a host PC, …).
      I have used I2C EEPROMs as ‘raw’ memory block devices in a similar way you describe, with a very simple header and data structure.
      This works very well for small data. But having a file system makes things easier for the application, and for that W25Q128 I’m working on getting littleFS on it. Making goog progress, so I could hopefully post an update on this the next days or so.

      Like

  2. Hi Erich,

    I think I sent you one of my projects that has my SPI flash driver. You’re welcome to use and adapt that one if it’s any use to you – there’s nothing sensitive there. spiflash.c is the main part, and there’s a FatFs interface in diskio.c. The way it’s set up now it also requires cache.c, which implements a write-back cache that can drastically speed up file system access.

    I think I took out support for Micron multi-die parts, but I’ve got that around somewhere. Never liked working with them. I’ve gone through several iterations of this driver, starting with a thin interface for the W25P16 around 10 or 12 years ago. It’s not super fancy, but flash_write() will take data of any length and do as many page writes as necessary, and flash_erase() will erase a given range using the most appropriate sector sizes.

    You might also have cache_ftl.c. That one implements a flash translation layer to make flash writes faster and safer. Writes go to already-erased sectors and the relocation table uses a journal to guarantee integrity. It’s not thoroughly tested yet and I’m not sure its behavior will be correct when the drive fills up, and it really needs to support the trim ioctl for efficiency.

    I use the W25Q128 in a product where flash I/O bandwidth is a major bottleneck, so the spi_block_read() function has had a fair amount of optimization. It can either use DMA if it’s running FreeRTOS and other tasks can run while it’s reading, or it can block and use polling mode and will switch to 16-bit transfers if you’re reading more than a few bytes, which gives a performance gain of about 6% by eliminating an idle bit between words.

    For now, the cache.c module doesn’t cache on reads and will only read from cache if the block is already cached because of a write – it normally reads around the cache. I’m planning to add an option for cached reads that will use DMA to continue the read to fill up the cache block in the background, so it’ll return the requested LBA and then if the following LBA is requested it’ll already have a head start, and might have finished it already.

    If you use NXP’s SPI drivers, especially the DMA ones, watch out – they have a ton of overhead and give horrible performance for short transactions, like if you’re sending a write enable command and then a page write and address separately. To get decent performance you have to either queue up everything with the hardware CS control enabled so that the whole transaction is done through DMA (which is a pain) or use a lightweight method to do the setup parts.

    mass_storage.c implements an MSD interface for the SPI flash, but it’s written for the abandoned Freescale bare metal 5.0 beta stack so I don’t know how applicable it is. If you poke around in the USB stack’s MSD class driver you’ll see I’ve made some tweaks and it’ll detect when the local file system driver has modified the disk contents and will send a removable media change notification to the host. On Windows you still have to hit ‘refresh’ to see changed contents, but it works. It doesn’t go the other way, though – it gets the lock and unlock signals from the host, but so far I haven’t found a way to force FatFs to invalidate its cached data. Each file object (if it’s not in tiny mode) has its own LBA-sized cache and there’s no registry of open files so I’d probably have to be a modification to FatFs itself to attach a counter to the object and force a reload from flash when it’s accessed.

    Like

    • Hi Scott,
      many thanks for all the details! My driver is not that sophisticated yet, and for the current project I don’t need to write lots of data, so bandwidth is not a concern (yet?). I’ll have to dig out that project you reference to see the details. Initially I wanted to go with FatFS as file system too, but my project will be battery operated and unfortunately it might turn off any time. So what I’m looking into is using littleFS: it is does not provide interoperability as FatFS, but includes power-loss features plus some kind of wear leveling (still have to investigate the details).

      Like

      • If you do need FAT compatibility and you’re just writing log data or something, you can do it more safely by expanding the new file first. That way FatFs isn’t constantly updating the FAT with each write, and you can also tell it to try to allocate a contiguous block. If it succeeds, you can get the address of the allocation and bypass FatFs entirely and guarantee that it’s not changing the FAT or directory entry when you make your log writes.

        I wonder if anyone has a FAT emulation layer available for littleFS or something similar – something that would generate an LBA at a time worth of data, synthesizing the FAT and directory entries on the fly. Seems feasible for read-only access, at least. Translating FAT writes would get more complicated.

        If you end up doing USB MSD access with FAT, beware the dirty bit. Desktop OSes like to set a bit in the MBR to track whether the volume was removed safely or not. If you’re using a simple driver and it has to erase and rewrite the whole sector for that single bit change, it makes the system vulnerable to corruption from power loss, particularly if it’s USB powered and you get an intermittent connection while plugging it in. My driver (at least in some versions) deals with that by intercepting MBR writes and tracking that bit in RAM so that reads are consistent (and the host OS won’t freak out if it’s trying to format and verify or something) but it doesn’t actually have to erase and rewrite the sector.

        Like

        • Good suggestion about expanding the file. This is what I do by default with appending data, followed by periodic sync/flush to get the data written on the card.
          In case of data loss, I have the ability to read the card with raw block accesses.
          I have added a command line interface to littleFS, that way I can list directories and files, and might end up in a command line way to send data to the host.
          I have encountered that dirty bit already with my bootloader project, thanks for the reminder.

          Like

      • As soon as you start using a FS on your NOR it will perform erase command while you write file so write will start to be randomly slow

        Like

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.