Flash in Devices

Flash in Small Devices: Routers, Cameras and Watches

What routers, cameras, smartwatches and IoT boards boot from: SPI NOR and SPI NAND, partitions, bad blocks, UBI and power-loss handling.

On this page 7 sections

The GL.iNet GL-MT300N V2 router has 128MB of RAM and 16MB of flash, according to OpenWrt’s device page. A Linksys E8450 has 512MB of RAM and a 128MiB SPI NAND chip. Neither chip has a controller of its own, so the processor reads its bootloader, kernel and root file system straight off the chip. On NAND it also has to cope with bad blocks.

Two bare flash chips on a board with a partition bar below eachTwo flash chips sit on a board, a small one on the left and a larger one on the right, each with gold pins along its top and bottom edges. Below each chip is a bar split into partitions: a small boot segment, teal segments for the kernel and root, and a copper segment for writable data.GUIDE / FLASH IN DEVICESFlash on the smallest boardsSPI NOR · SPI NAND · UBI · littlefsBOARD

Parts 1 to 3 of this series cover managed flash, in UFS, eMMC and SD cards, where a controller hides that work, and Part 5, Flash in Phones and Tablets, covers how phone flash shares a package with RAM. Beyond NAND Part 1 covers how NOR cells work and how serial NOR runs from SPI to xSPI. This part covers what small devices do with the bare chips, which sizes they use, how the chip is carved into partitions, and who looks after wear.

A bare chip leaves the work to the host

Managed flash puts a controller beside the NAND, and a small board usually has none. NOR and SPI NAND are memory chips with a serial interface, and the host decides how to map, erase and protect them. This part follows four boards, from 4MB to 128MiB of flash. A PineTime smartwatch pairs 512KB inside its nRF52832 with an extra 4MB SPI NOR chip. OpenIPC’s test camera has 8MB of NOR, the GL-MT300N V2 has 16MB, and the E8450 has 128MiB of SPI NAND.

A bare chip leaves the work to the host

Flash on four boards runs from 4MB of NOR to 128MiB of NAND

Horizontal bars of flash on the board. PineTime smartwatch: 4MB of SPI NOR. OpenIPC test camera: 8MB of NOR. GL-MT300N V2 router: 16MB of NOR. Linksys E8450 router: 128MiB of SPI NAND.Board and device0326496128Flash on the board, MBPineTimesmartwatch4MBOpenIPC cameratest camera8MBGL-MT300N V2router16MBLinksys E8450router128MiBNOR flashSPI NAND flash
Figure 1 · The PineTime also has 512KB of flash inside its nRF52832. The E8450 capacity is listed in MiB, the unit the OpenWrt page uses. Source: Pine64 wiki; OpenIPC wiki; OpenWrt device pages.

Figure 1 splits those boards by chip type. NOR serves as code storage up to 16MB here and SPI NAND takes over at 128MiB, and OpenIPC says most IP cameras carry 8MB or 16MB of NOR or NAND, so these sizes are typical of the class and not records.

NOR holds the code a processor runs

A microcontroller often has little or no program flash of its own. Raspberry Pi’s RP2040 has none and runs cached execute-in-place from external QSPI memory, up to 16MB. That is why the code sits in NOR, where the processor can fetch from it directly, as execute in place explains.

On an ESP32 the flash layout is a table. ESP-IDF keeps the partition table at offset 0x8000, allows up to 95 entries in it, and gives it a 4KB sector. Its bootloader runs the app labeled factory by default, and that app sits at 0x10000, 64KB into the chip.

NOR holds the code a processor runs

ESP-IDF fits a factory app and two OTA slots on a 4MB chip

Two strips. The top strip is a 4MB flash chip drawn to scale: a small first region up to 0x10000, then a factory app of 1MB at 0x10000, ota_0 of 1MB at 0x110000, ota_1 of 1MB at 0x210000, and free space from 0x310000. The lower strip enlarges 0x8000 to 0x10000: the partition table at 0x8000, nvs of 0x4000 at 0x9000, otadata of 0x2000 at 0xd000 and phy_init of 0x1000 at 0xf000.01 THE 4MB CHIPfactory 1MBota_0 1MBota_1 1MBfree0x100000x1100000x2100000x31000002 ZOOM ON 0x8000 TO 0x10000tablenvs 0x4000otadata 0x2000phy_init0x80000x90000xd0000xf0000x10000app partitiontable and datafree spacezoom
Figure 2 · Drawn to scale. The partition table sits at 0x8000 and the first app at 0x10000; the layout ends at 0x310000, leaving the rest of the chip free. Source: Espressif, ESP-IDF Programming Guide, partition tables.

Figure 2 draws the table ESP-IDF calls a factory app with two OTA definitions. Sectors for NVS, otadata and phy_init come first, then three 1MB apps follow at 0x10000, 0x110000 and 0x210000. Everything ends at 0x310000, inside a 4MB chip with room to spare. Two OTA slots keep an update from overwriting the running app, a pattern Beyond NAND Part 1 covers under the update needs two copies.

A router or camera slices one chip into partitions

Linux sees a bare flash chip as named partitions of fixed size. On the GL-MT300N V2 the NOR holds a 192KiB bootloader, a 64KiB bootloader environment and 64KiB of factory data, and the other 16,064KiB belongs to firmware. Inside that firmware space the kernel takes about 2MiB, and rootfs_data takes the largest share at around 10MiB.

OpenIPC’s boot log for a Chacon camera shows a similar split on a 16MB XM25QH128A with 64KiB blocks. Its partitions are boot, env, kernel, rootfs and rootfs_data, and every boundary falls on a 64KiB multiple.

A router or camera slices one chip into partitions

Two 16MB NOR chips give most of their space to rootfs_data

Two bars of a 16MB NOR chip at the same scale. Router, GL-MT300N V2: a small boot region of u-boot 192KiB, env 64KiB and factory 64KiB, then a kernel of about 2MiB, a root file system of around 3.3MiB, and rootfs_data of around 10MiB filling the rest. Camera, OpenIPC on an XM25QH128A: boot 256KiB and env 64KiB, then a kernel of 2MiB, rootfs of 5MiB, and rootfs_data of about 8.7MiB filling the rest.01 GL-MT300N V2 ROUTERboot region: u-boot 192KiB, env 64KiB, factory 64KiBkernel2MiBrootfs3.3MiBrootfs_data, around 10MiB02 OPENIPC CAMERAboot region: boot 256KiB, env 64KiBkernel2MiBrootfs5MiBrootfs_data, about 8.7MiBwhole chip, 16MBboot and settingskernel and rootrootfs_data
Figure 3 · Both chips drawn at one scale. The router's rootfs_data is the rest of its 16MB chip after the partitions above it, which comes to around 10MiB. The camera's is about 8.7MiB. Source: OpenWrt GL-MT300N V2 device page; OpenIPC wiki, Chacon camera boot log.

Figure 3 draws the two 16MB chips at one scale, and both give most of the chip to the writable partition, about 10MiB on the router and about 8.7MiB on the camera. This guide reads that partition as the one that wears, since the others change only when firmware is updated.

SPI NAND adds capacity and bad blocks to manage

Winbond’s W25N01GV is a 1Gb serial SLC NAND with 65,536 pages of 2,048 bytes and 1,024 erasable blocks of 128KB. Its SPI clock runs up to 104MHz, equal to 416MHz on four data lines, with a 50MB/s continuous transfer rate. It comes in an 8-pad WSON or a 16-pin SOIC, so it fits where a NOR chip fits.

NAND also ships with bad blocks. Per the datasheet, up to 2% of blocks can be marked bad at shipment, a maximum of 20 on this part, and a user should scan the whole array for the factory markers. A bad block management command links a bad logical block to a spare physical one in a look-up table of up to 20 links, and the manufacturer may already have used some of those entries. A 1-bit ECC is on board.

SPI NAND adds capacity and bad blocks to manage

Up to 20 of the 1,024 blocks in a W25N01GV can ship bad

A grid of 1,024 squares, 32 by 32, each one a 128KB erasable block of a Winbond W25N01GV. Twenty squares are marked bad, the most the datasheet allows at shipment, which is 2% of the blocks. The look-up table can link up to 20 bad blocks to spare ones.1,024 blocksof 128KB each20 marked bad2% is the limit20 linksin the look-up tablegood blockblock marked bad
Figure 4 · Each square is one 128KB block. Which blocks are bad varies from chip to chip, so the positions drawn here are illustrative; the datasheet gives the 2% limit and the 20-block maximum. Source: Winbond W25N01GV datasheet, revision L.

Figure 4 draws each of the 1,024 blocks as a square and marks 20 of them bad. The look-up table has as many links as the worst case needs, so a chip that arrives with the maximum may have few links to spare. Winbond advises keeping a table of the factory bad blocks before the first erase or program.

Endurance is rated at more than 100,000 erase/program cycles on the strength of the on-chip ECC, with more than 10 years of retention. Beyond NAND Part 1 lists the NOR W25Q128JV at 100K cycles per sector and more than 20 years of retention. On paper the cycle ratings match, and the NAND figure assumes ECC is on. Retention is the larger gap, at more than 10 years against more than 20.

Raw NAND leans on UBI, and the E8450 shows why

Take the E8450. According to its OpenWrt page, the vendor layout puts a JFFS2 rootfs_data partition straight on the raw NAND, while OpenWrt’s UBI layout puts one UBI partition across the chip behind a 512KiB bl2 partition. The page says the vendor layout can no longer be kept since August 27, 2021, because it carries ECC errors from the factory that the new SPI NAND driver rejects.

UBI does that work. In the Linux MTD documentation, UBI is a wear-leveling and volume management layer that runs on top of an MTD device and hides wear and bad blocks from the file system above it. It stores an erase counter in a header in every physical eraseblock, which is why a flashing tool that is not UBI-aware can lose the counts. UBIFS is the file system on top, and its authors report it survived more than 100,000 power cuts in stress tests on OneNAND flash.

Raw NAND leans on UBI, and the E8450 shows why

UBI sits between the file systems and the raw NAND on an E8450

Four layers, top to bottom. File systems: a SquashFS root mounted at /rom and a UBIFS overlay mounted at /overlay. Below them, UBI, which does wear leveling and bad block handling and keeps erase counters. Below that, MTD partitions: a 512KiB bl2 boot partition outside UBI and the UBI partition that fills the rest of the chip. At the bottom, the 128MiB SPI NAND chip.SquashFS at /romUBIFS at /overlayUBIwear leveling, bad blocks, erase countersMTD bl2512KiBMTD UBI partitionthe rest of the chipSPI NAND chip128MiBfile system or partitionUBI layerflash
Figure 5 · OpenWrt's UBI layout for the Linksys E8450. The bl2 boot partition sits outside UBI, and UBI keeps an erase counter in every physical eraseblock. Source: OpenWrt Linksys E8450 device page; Linux MTD documentation.

Figure 5 stacks the layers. A SquashFS root is mounted at /rom and a UBIFS overlay at /overlay, and both sit in the UBI partition that fills the chip behind a 512KiB bl2 boot partition.

Wear and power loss on a microcontroller

UBI assumes Linux. littlefs targets microcontrollers instead. Its README lists copy-on-write operations that fall back to the last good state after a power cut, dynamic wear leveling with bad block detection, and RAM use that stays bounded as the file system grows. Metadata lives in small logs called metadata pairs, file data lives in copy-on-write structures, and the allocator spreads wear by limiting the erases allowed on a block per allocation.

Wear and power loss on a microcontroller

A copy-on-write update stays invisible until it is committed

Three panels. Panel 1, write a new copy: the old copy is current and a new copy is being written beside it. Panel 2, power cut here: the new copy is incomplete, and the old copy is still the last good state. Panel 3, commit: sync or close makes the new copy current, and the old copy is freed later.01 WRITE A NEW COPYold copycurrentnew copybeing writtenthe old copy staysthe current one02 POWER CUT HEREold copycurrentnew copyincompletea cut before commitleaves the old copyas the last good state03 COMMITold copyfreed laternew copycurrentsync or closemakes the new copythe current onecurrent copynot currentpower cut
Figure 6 · How littlefs treats an update: the new copy is written first and becomes current only at sync or close, so a power cut before then leaves the old copy as the last good state. Source: littlefs README.

Figure 6 shows why a power cut leaves the old file intact. An update goes to a new copy first and is committed only when sync or close is called, so a cut lands either before the commit, with the old copy still current, or after it. Remove and rename are atomic even on power loss.

Industrial managed flash guards against the same threat in hardware, which Part 4 covers.

Reading a chip marking

OpenIPC’s installation guide gives a rule for reading a flash chip. Digits in a model number are megabits, so 64 in EN25QH64 means 64Mb, or 8MB, and 128 means 16MB. A bootloader log does the lookup too. On one OpenIPC camera it printed a 16MB XM25QH128A with 64KiB blocks.

Reading a chip marking

The digits in a flash chip's model number are megabits

Two rows. In the first, the marking EN25QH64 has the digits 64, which mean 64Mb, which is 8MB after dividing by 8. In the second, the marking XM25QH128A has the digits 128, which mean 128Mb, which is 16MB after dividing by 8.01 MARKING02 DIGITS03 SIZEEN25QH64digits64Mb/ 88MBXM25QH128Adigits128Mb/ 816MBchip markingsize digitssize in bytes
Figure 7 · The rule is OpenIPC's: 64 in EN25QH64 means 64Mb, or 8MB, and 128 means 16MB. The XM25QH128A is the chip an OpenIPC camera reported in its boot log. Source: OpenIPC wiki installation guide and Chacon camera boot log.

The last figure turns two markings into sizes. Size is the first question and chip type is the second. NOR means code can run in place and partitions follow the erase sector. NAND means bad blocks, ECC and a layer such as UBI, and a rating such as 100,000 cycles should be checked for whether it assumes ECC.

That closes the series, and the hub page, Flash in Devices, lists all six parts.

Sources

Primary is the original paper, standard or datasheet. Secondary is a review, a vendor summary or a news report. Measured is my own test data.

Show all 11 sources, 11 primary