- Replace syslog() with finfo()/fwarn() to follow the NuttX subsystem
debug convention.
- Merge adjacent early-continue `if` branches in w25n_pick_free_spare
and w25n_scan_factory_bad.
- Add Input Parameters / Returned Value sections to the BBM helper
headers.
- Clarify why only -EIO triggers a remap retry in w25n_erase and
w25n_bwrite (block-level E-FAIL/P-FAIL vs. transient bus faults).
Signed-off-by: Julian Oes <julian@oes.ch>
Use the chip's built-in 20-entry non-volatile Bad Block Management
Look-Up Table (datasheet section 8.2.7) to transparently route around
bad blocks.
Init:
- Reserve the top 24 blocks of the array as a spare pool
- Clamp the MTD geometry to W25N_USER_BLOCKS = 1000 so upper layers
never see the spare area (125 MB usable instead of 128 MB)
- Force BUF=1 alongside enabling ECC. The W25N01GVxxIT variant
power-ups with BUF=0 (Continuous Read mode), in which Read Data
ignores the column address and always starts at byte 0 - which
silently broke any read targeting a non-zero column (OOB markers,
sub-page reads in w25n_read).
- Scan all 1024 blocks for factory bad markers (non-FFh at byte 0 of
the spare area of page 0) and remap any user-area bad blocks via the
A1h BBM command. Idempotent across reboots: blocks already present
in the LUT are skipped, so repeated scans don't consume LUT slots.
Runtime:
- On E-FAIL from w25n_block_erase or P-FAIL from w25n_program_execute,
allocate a spare and issue A1h, then retry the operation once. The
chip routes the retry to the spare PBA transparently. Data buffer is
reloaded on program retry.
- Uncorrectable read ECC is left as -EIO (soft errors shouldn't trigger
permanent remap, and remapping discards data we may still recover).
Safeguards against burning LUT slots on bogus bad blocks:
- w25n_pick_free_spare erases each candidate spare as an active proof
of life before returning it - the factory OOB marker alone isn't
trusted.
- w25n_bbm_swap rejects A1h with LBA outside the user area or PBA
outside the spare pool.
Stack discipline for the logger-thread hot path:
- The 20-entry cached LUT lives in the device struct, not on the stack.
- w25n_read_bbm_lut decodes 4 bytes at a time instead of reading the
full 80-byte LUT dump into a local buffer.
Boot diagnostics are emitted via syslog so they appear unconditionally:
- [w25n] BBM scan summary (new/remapped/unremapped/previously-remapped/
LUT slots used)
- [w25n] W25N01GV ready line with user blocks, spare count, geometry,
and actual SPI frequency
- [w25n] per-remap info and warnings on runtime E-FAIL/P-FAIL paths
Note: existing littlefs filesystems become unmountable because the
block count shrinks from 1024 to 1000; both PX4 board init.c paths
already mount with autoformat so they reformat on first boot after
this change.
Signed-off-by: Julian Oes <julian@oes.ch>
debug.h is a NuttX-specific, non-POSIX header. Placing it in the
top-level include/ directory creates naming conflicts with external
projects that define their own debug.h.
This commit moves the canonical header to include/nuttx/debug.h,
following the NuttX convention for non-POSIX/non-standard headers,
and updates all in-tree references.
A backward-compatibility shim is left at include/debug.h that
emits a deprecation #warning and re-includes <nuttx/debug.h>,
allowing out-of-tree code to continue building while migrating.
Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
Add MTD driver for Winbond W25N series SPI NAND flash.
Currently supports W25N01GV (1Gbit/128MB).
Features:
- Standard SPI interface with configurable frequency (up to 104 MHz)
- Hardware ECC enabled by default
- Block erase with sleep-based wait (releases SPI bus)
- Page read/write with busy-wait for fast operations
Limitations:
- No bad block management (BBM). Factory bad blocks and runtime bad
blocks are not tracked.
- No bad block table (BBT) scanning at initialization.
- No Quad SPI support (standard SPI only).
- No access to spare area (64 bytes/page) or OTP region.
Tested using:
- Board with STM32H743
- W25N01GV on SPI at 96 MHz with DMA enabled
- Flash mounted using littlefs
- Tested using sdbench:
- Sequential write speed of 1760 KB/s
- Sequential read speed of 4900 KB/s
Signed-off-by: Julian Oes <julian@oes.ch>