Skip to content

AP_Filesystem: add LittleFS support for Micron MT29Fxx SPI NAND#32146

Open
andyp1per wants to merge 2 commits intoArduPilot:masterfrom
andyp1per:pr-mt29f-littlefs
Open

AP_Filesystem: add LittleFS support for Micron MT29Fxx SPI NAND#32146
andyp1per wants to merge 2 commits intoArduPilot:masterfrom
andyp1per:pr-mt29f-littlefs

Conversation

@andyp1per
Copy link
Copy Markdown
Contributor

@andyp1per andyp1per commented Feb 8, 2026

Summary

  • Add WSPI driver for the Micron MT29F SPI NAND flash family (1G/2G/4G/8G densities), enabling LittleFS filesystem on boards with QUADSPI-connected NAND flash
  • Quad I/O mode (1-1-4) for both read and write data transfers, internal ECC enabled, reversed JEDEC ID byte order handling
  • Add littlefs:mt29f DATAFLASH directive support in the hwdef build script for WSPI-connected NAND flash

Test plan

  • Tested on SPRacingH7 board with MT29F1G01 NAND flash
  • Verified flash detection, LittleFS mount, and DataFlash logging
  • Verified quad SPI read/write transfers

@andyp1per andyp1per force-pushed the pr-mt29f-littlefs branch 4 times, most recently from 4b4e499 to 0cad205 Compare February 8, 2026 17:39
@andyp1per andyp1per changed the title AP_Filesystem: add LittleFS support for Micron MT29F SPI NAND AP_Filesystem: add LittleFS support for Micron MT29Fxx SPI NAND Feb 8, 2026
@andyp1per andyp1per requested a review from tpwrules February 8, 2026 17:48
Comment thread libraries/AP_Filesystem/AP_Filesystem_FlashMemory_LittleFS.cpp Outdated
Add WSPI driver for the Micron MT29F SPI NAND flash family, enabling
LittleFS filesystem on boards with QUADSPI-connected NAND flash.

Supported devices: MT29F1G/2G/4G/8G (1-8Gbit densities)

Features:
- Quad I/O mode (1-1-4) for both read and write data transfers
- Internal ECC enabled
- Reversed JEDEC ID byte order handling
Support 'littlefs:mt29fxx' in DATAFLASH directive for WSPI-connected
Micron MT29F SPI NAND flash chips.
Copy link
Copy Markdown
Contributor

@tpwrules tpwrules left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why this change is so large and complex. The commands are all the same as W25Nxx (except two little things) and the existing driver could have been reused with a two line change if the chip was wired to an existing SPI port.

Do you have an example hwdef? Can the board use a normal SPI port? I wouldn't think QSPI would provide a noticeable advantage, program times are high and the system is bottlenecked on USB on read.

Assuming QSPI is advantageous, there should just need to be a few defines in the transfer functions to switch between using the SPI object and the WSPI object. Then also W25Nxx would get WSPI support.

Peter is probably right that it's time to bring the flash driver out into a separate class though, LittleFS already has a clean separation. We only compile support for one flash driver in anyway so I don't understand the size concern.

// used by LittleFS
#define AP_FILESYSTEM_FLASH_JEDEC_NOR 1
#define AP_FILESYSTEM_FLASH_W25NXX 2
#define AP_FILESYSTEM_FLASH_WSPI_NAND 3
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this generic or specific to MT29FXX?

#endif

//#define AP_LFS_DEBUG
// Uncomment to enable debug output for WSPI NAND development
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is nonsense.

Comment on lines +651 to +686
#define SPINAND_CMD_RESET 0xFF
#define SPINAND_CMD_GET_FEATURE 0x0F
#define SPINAND_CMD_SET_FEATURE 0x1F
#define SPINAND_CMD_WRITE_ENABLE 0x06
#define SPINAND_CMD_PAGE_READ 0x13
#define SPINAND_CMD_READ_FROM_CACHE 0x03 // 1-1-1 mode
#define SPINAND_CMD_READ_FROM_CACHE_X4 0x6B // 1-1-4 mode (quad read)
#define SPINAND_CMD_PROGRAM_LOAD 0x02 // 1-1-1 mode
#define SPINAND_CMD_PROGRAM_LOAD_X4 0x32 // 1-1-4 mode (quad write)
#define SPINAND_CMD_PROGRAM_EXECUTE 0x10
#define SPINAND_CMD_BLOCK_ERASE 0xD8
#define SPINAND_CMD_READ_ID 0x9F

/* SPI NAND standard register addresses */
#define SPINAND_REG_PROTECTION 0xA0
#define SPINAND_REG_CONFIG 0xB0
#define SPINAND_REG_STATUS 0xC0

/* SPI NAND standard status register bits */
#define SPINAND_STATUS_OIP 0x01 // Operation In Progress
#define SPINAND_STATUS_WEL 0x02 // Write Enable Latch
#define SPINAND_STATUS_EFAIL 0x04 // Erase Fail
#define SPINAND_STATUS_PFAIL 0x08 // Program Fail

/* SPI NAND standard config register bits */
#define SPINAND_CONFIG_ECC_ENABLE (1 << 4)

/* MT29FXX timing */
#define SPINAND_TIMEOUT_RESET_MS 2 // tRST max
#define SPINAND_TIMEOUT_PAGE_READ_US 70 // tRD max (ECC enabled)
#define SPINAND_TIMEOUT_PAGE_PROGRAM_US 220 // tPROG typ (ECC enabled)
#define SPINAND_TIMEOUT_BLOCK_ERASE_MS 10 // tBERS max

/* MT29FXX geometry - common to all densities */
#define SPINAND_PAGE_SIZE 2048
#define SPINAND_BLOCK_SIZE (64 * SPINAND_PAGE_SIZE) // 128KB
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These, with the exception of timing and GET_FEATURE/SET_FEATURE, are the same as JEDEC and W25Nxx. We don't need to redefine all of them.

W25Nxx also takes 0x0F as an alias for READ_STATUS and 0x1F as an alias for WRITE_STATUS. So we could just use those opcodes on NAND flash. They don't appear supported on NOR devices.

# WSPI-connected NAND flash (Micron MT29F family: 1G/2G/4G/8G)
f.write('#define AP_FILESYSTEM_LITTLEFS_FLASH_TYPE AP_FILESYSTEM_FLASH_WSPI_NAND\n')
f.write('#define AP_FILESYSTEM_LITTLEFS_MT29FXX_ENABLED 1\n')
# Only disable FATFS if there's no SDMMC or SPI-connected SD card
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh? We can't support this. We do need to disable FATFS unconditionally.

@andyp1per
Copy link
Copy Markdown
Contributor Author

I don't understand why this change is so large and complex. The commands are all the same as W25Nxx (except two little things) and the existing driver could have been reused with a two line change if the chip was wired to an existing SPI port.

Its only larger because this is supporting QSPI. The board I have only supports QSPI. Really this is about adding QSPI support to littlefs rather than a specific chip, so perhaps the names need changing to suit.

Do you have an example hwdef? Can the board use a normal SPI port? I wouldn't think QSPI would provide a noticeable advantage, program times are high and the system is bottlenecked on USB on read.

Yes. And no it can't use SPI because the pins are different. The relevant bits look like this:

# QUADSPI for MT29F1 NAND dataflash
PB2  QUADSPI_CLK QUADSPI1
PD11 QUADSPI_BK1_IO0 QUADSPI1
PD12 QUADSPI_BK1_IO1 QUADSPI1
PE2  QUADSPI_BK1_IO2 QUADSPI1
PD13 QUADSPI_BK1_IO3 QUADSPI1
PB10 QUADSPI_BK1_NCS QUADSPI1

# QUADSPI device for MT29F1 NAND flash
# Format: QSPIDEV name bus mode speed size_pow2 ncs_clk_delay
# size_pow2=27 for 128MB (2^27 = 128M), ncs_clk_delay=1
QSPIDEV dataflash QUADSPI1 MODE3 50*MHZ 27 1
# Disable XIP mode - H743 has internal flash, no need for execute-in-place
# XIP prevents proper WSPI initialization for NAND flash
define HAL_XIP_ENABLED FALSE

# LittleFS DISABLED for testing - uncomment to enable
DATAFLASH littlefs:mt29f1

Assuming QSPI is advantageous, there should just need to be a few defines in the transfer functions to switch between using the SPI object and the WSPI object. Then also W25Nxx would get WSPI support.

Its not as easy as that. We are leveraging STM32's QSPI support (in the same way that we do for external flash) and it is that support that dictates the way the functions need to operate.

Peter is probably right that it's time to bring the flash driver out into a separate class though, LittleFS already has a clean separation. We only compile support for one flash driver in anyway so I don't understand the size concern.

That was my initial thought but it actually makes the PR much bigger and more complicated. We also have the AP_FlashIFace stuff which at some point should be factored to support this, but it only currently supports the model supported by NOR flash - so again a big refactor. The current changes have no size impact if not used and so I have concluded that refactoring here is more trouble than its worth.

@tpwrules
Copy link
Copy Markdown
Contributor

Thanks for confirming the pins are different.

Assuming QSPI is advantageous, there should just need to be a few defines in the transfer functions to switch between using the SPI object and the WSPI object. Then also W25Nxx would get WSPI support.

Its not as easy as that. We are leveraging STM32's QSPI support (in the same way that we do for external flash) and it is that support that dictates the way the functions need to operate.

Here I meant a hypothetical board with W25Nxx hooked up to the QSPI pins. I still see the operation as basically the same, it should just be functions that touch dev that need a bit of modification. No need for a whole new set of functions and commands.

@tridge
Copy link
Copy Markdown
Contributor

tridge commented Mar 11, 2026

I'm happy to see support for this, but I'll defer to @tpwrules and @andyp1per to sort out the details, both of you know far more than I do about this stuff

@tridge tridge removed the DevCallEU label Mar 11, 2026
Copy link
Copy Markdown
Contributor

@peterbarker peterbarker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm quite uncomfortable with extending this for wspi support.

We are duplicating more code - not just within this file as Thomas has pointed out, but we also have qspi support already in AP_FlashIface, the interface I think everybody thinks we should move to for LittleFS, bootloader and logging support.

At some stage we have to stop and clean things up, and I think this might be that point.

Comment on lines +719 to +724
AP_HAL::Device::CommandHeader hdr{};
hdr.cmd = cmd;
hdr.cfg = AP_HAL::WSPI::CFG_CMD_MODE_ONE_LINE |
AP_HAL::WSPI::CFG_ADDR_MODE_ONE_LINE |
AP_HAL::WSPI::CFG_ADDR_SIZE_24;
hdr.addr = addr;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please initialize these as a ```
const AP_HAL::Device::Commandhdr {
.
.
.
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants