Skip to content

Enable flash#434

Open
jinwjinl wants to merge 1 commit into
vivoblueos:mainfrom
jinwjinl:enable-flash
Open

Enable flash#434
jinwjinl wants to merge 1 commit into
vivoblueos:mainfrom
jinwjinl:enable-flash

Conversation

@jinwjinl

@jinwjinl jinwjinl commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Enable to read and write nor-flash. It has been verified by connecting W25Q64 in ESP32C3. Note:
CS : GPIO5,
DI : GPIO9,
DO : GPIO10,
CLK : GPIO8.

@jinwjinl

jinwjinl commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

build_prs #434 vivoblueos/external#27

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

❌ Job failed. Failed jobs: build_and_check_boards (failure), see https://github.com/vivoblueos/kernel/actions/runs/28585965485.

@jinwjinl

jinwjinl commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

build_prs #434 vivoblueos/external#27

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

✅ All jobs completed successfully, see https://github.com/vivoblueos/kernel/actions/runs/28586350982.

@han-jiang277

Copy link
Copy Markdown
Contributor
  1. spi_flash.rs:162 — Silent partial read on erase-block boundary
    read_blocks returns Ok(()) after copying only the in-cache portion of a multi-sector buffer that crosses an erase-block boundary. Block::read passes the full multi-sector buffer in one call, so any read spanning two erase blocks while the first is dirty delivers truncated data with no error signal.
  2. esp32_gpio.rs:68 — GPIO 1 << PIN overflows for PIN ≥ 26
    GpioOut::DATA is 26 bits wide. For PIN in [26, 31] the bit is masked to 0 — the pin is never driven. For PIN ≥ 32Rust panics (debug) or wraps to pin PIN % 32 (release). No compile-time bound exists.

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.

We need to confirm whether these commands are specific to the W25Q80 or are generic (common to other flash chips).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

These command codes are JEDEC 25-series SPI NOR Flash standard commands, not specific to the W25Q80. The file header is marked with //! JEDEC 25-series SPI NOR Flash command layer., consistent with the Winbond W25Q80 datasheet, and also applicable to chips conforming to the same standard, such as W25Q64 / W25Q128.

Refer to the Linux kernel include/linux/mtd/spi-nor.h: https://raw.githubusercontent.com/torvalds/linux/master/include/linux/mtd/spi-nor.h

@jinwjinl

Copy link
Copy Markdown
Contributor Author

Description

This commit enables driving an SPI NOR flash on ESP32-C3 and registers it as a block device through the device-discovery mainline (define_bus! / register_device / probe_driver / InitDriver::init), the same framework the bme280 sensor already uses. The previous init_block_devices path that registered the block device directly is replaced.

Registration path

The flash block device is no longer registered directly by init_block_devices. Instead it goes through the device-discovery mainline, mirroring bme280 so that other SPI devices can plug in through the same framework:

  1. Bus declaration (boards/seeed_xiao_esp32c3/mod.rs): define_bus! declares spi2_bus (type BlockSpi<Spi2Impl, Esp32GpioOutputPin>) with a flash device carrying SpiFlashConfig::new(name). BlockSpi holds &'static references to the SPI peripheral and the CS pin, manages CS timing internally, and implements embedded_hal::spi::SpiDevice (via BusWrapper<BlockSpi>) as the transport for the flash command layer.
  2. Initialization (init_spi_bus, #[cfg(spi_core)]): configure pins → BlockSpi::newBus::new stored in SPI2_BUS (Once) → register_device enrolls the devices declared by define_bus! onto the bus → probe_driver(&SpiFlashDriverModule) lets the driver module self-match an enrolled device.
  3. Probe & register (drivers/flash/spi_flash.rs): SpiFlashDriverModule::probe matches DeviceData::Native + SpiFlashConfig; SpiFlashConfig::init reads the JEDEC ID, computes capacity, builds SpiFlashBlockDriver, and finally DeviceManager::register_device registers the block device into the device manager. InitDriver/DriverModule are generic over impl<T: PlatPeri + Spi<SpiConfig, ()>, G: PlatPeri + OutputPin>, decoupled from any specific board.
  4. Entry (boot.rs): #[cfg(spi_core)] boards::init_spi_bus() replaces the former #[cfg(enable_block)] init_block_devices().

spi_bus_adapter.rs is superseded by block_spi.rs: the old SpiBusAdapter did not implement BusInterface and so could not enter Bus::new, and the SpiBus (no CS) + ExclusiveDevice-wraps-CS ownership model conflicts with the shared BusWrapper used by the mainline. BlockSpi internalizes CS plus the shared lock to resolve this.

Review feedback

  • silent partial read on erase-block boundary​: read_blocks now loops while buf_off < buf.len(), chunking at erase-block granularity. On a cache hit it copies from erase_buf; on a miss it reads directly into buf via flash_cmd.read. It advances buf_off/cur_block until the whole buffer is filled before returning Ok(()), so a cross-boundary read no longer truncates silently.
  • GPIO ​1 << PIN ​overflow​: Esp32GpioOutputPin::new adds a runtime assert!(pin < 26) matching GpioOut::DATA NUMBITS(26), rejecting PIN ≥ 26 (and eliminating the PIN ≥ 32 UB).

Configuration

  • enable_block is retained (FATFS depends on it).
  • New SPI_CORE (default n) gates init_spi_bus and its boot call.
  • New USE_EMBEDDED_HAL_V1 gates the SpiDevice impl for BusWrapper<BlockSpi> and the flash InitDriver/DriverModule impls.
  • esp32c3 defconfig sets CONFIG_SPI_CORE=y.

Verification

  • esp32c3 release builds with 0 errors / 0 warnings.
  • On hardware: boots cleanly, log shows SPI flash JEDEC ID / capacity, shell is stable, and the data mount point reads/writes correctly.

Note

The stack size on the ESP32C3 is currently insufficient; executing init_vfs will trigger a panic.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants