boot2_w25q080: W25Q16RV applies only SR1 of the two-byte 01h write — QE never set, board does not boot #3159
Labels
No labels
bazel
bluetooth
board settings
boot_stage2
bug
build
c++
can't reproduce
clang
clib-interface
cmsis
code cleanliness
code size
compiler version issues
cyw43_driver
debug
discussion
documentation
duplicate
dynamic_clock
elf2uf2
enhancement
errata
filesystem
flash layout
floating point
FreeRTOS
hardware_adc
hardware_claim
hardware_clocks
hardware_dma
hardware_exception
hardware_flash
hardware_gpio
hardware_i2c
hardware_irq
hardware_pio
hardware_pwm
hardware_rcp
hardware_rtc
hardware_spi
hardware_sync
hardware_uart
hardware_vreg
hardware_watchdog
hardware_xosc
help wanted
host
IAR
installation
invalid
linker scripts
lto
lwip
mbedtls
missing API
needs reporter detail
networking
newlib
newlib-multicore
non-c
non-cmake
non-gcc
openocd
orphan PR
OS integration
pico_async_context
pico_base
pico_binary_info
pico_flash
picolibc
pico_lwip
pico_malloc
pico_multicore
pico_printf
pico_runtime
pico_stdio
pico_stdio_usb
pico_sync
pico_time
pico_util
pioasm
port
question
review
review2
rtos interop
runtime init
static library
svd
test
tinyusb
vscode
wifi integration
wontfix
No milestone
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
gh-raspberrypi/pico-sdk#3159
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
We build the WIZnet W5500-EVB-Pico family.We do not define a custom
PICO_BOARD, so we inheritpico.hand thereforeboot2_w25q080.S. That has always worked with the Winbond W25Q16JV we fit.Winbond has issued a termination notice for the W25Q16JV; the designated drop-in replacement is the W25Q16RV (
W25Q16JVZPIM→W25Q16RVCPJM, same WSON8 6x5mm package, same JEDEC IDEF 70 15).With the RV fitted the board does not boot at all — no UART output, no LED. BOOTSEL/UF2 flashing still works, so the part is fine on plain SPI. We traced it to
boot2_w25q080.S: it enables QE with the legacy two-byte01hSR write, and the RV applies only the first of those two data bytes — SR1 is written, the SR2 byte carrying QE is discarded. TheEBhquad read that follows then leaves the flash unresponsive. Measurements and code detail below.What we would like to know
We have a local fix working — our own boot2 using
31hand a bit test, selected withPICO_DEFAULT_BOOT_STAGE2_FILE. It boots on the RV board, and we are happy to keep it local. Before we do, two questions:pico.hselects this same boot2 — how do you plan to handle that when the substitution reaches it?Environment
W25Q16RVCPJM, JEDEC IDEF 70 15Measured
RAM-resident (
no_flash) diagnostic driving the QSPI lines directly, so it reports even when flash is unusable. We ran the same diagnostic on one board of each part:9Fh)EF 70 15EF 70 1535h) as found0x020x040115h)0x600x4001h+ 1 data byte (SR1)01h+ 2 data bytes (SR1, SR2) — what boot2 sends31h+ 1 data byte (SR2)Our RV sample shipped with QE = 0. To observe both data bytes of the two-byte write we put a marker in SR1 first (the TB bit, which protects nothing while BP = 0) and then replayed boot2's exact byte sequence on each part:
Both parts were restored to SR1 = 0x00, QE = 1 afterwards.
Three things follow: the parts are indistinguishable by JEDEC ID; the RV does not reject
01h, it truncates it to one data byte; and31his the only way to set QE that works on both, so a single boot2 can cover JV and RV.Two problems in boot2_w25q080.S
1. The SR2 byte of the two-byte write is discarded.
The RV accepts
01h, applies the first data byte to SR1, and discards the second, so QE is never set. (The JV applies both, which is why the same boot2 has always worked for us until now.) boot2 does not check the result and proceeds to theEBhquad read, driving IO2/IO3 while the device — QE still clear — treats them as/WPand/HOLD. The board is dead from there. We have not scoped the bus, but the sameEBhconfiguration works on the same part once QE is set: our patched boot2 differs only in using31h, and the RV board boots with it.The source already flags the risk of using this form:
On the RV that side effect happens while the intended effect does not: SR1 is overwritten with
0x00, clearing the block protection bits, and QE is still not set. And because of problem 2 below the skip path is never taken on this part, so by the code path that write is reissued on every boot.2. The skip check compares the whole byte.
Our RV reads SR2 bit 2 back as 1, so SR2 is
0x06once QE is set and this never matches — boot2 repeats a non-volatile SR write on every boot, which is what makes the SR1 side effect above permanent rather than one-off.tst r0, r2fixes it, and is safer generally: any non-QE bit a part happens to set defeats a full-byte compare.We have both parts on the bench here, so if there is anything you would like measured
before deciding, we can run it.
Thanks for your work on the SDK.
Best regards,
Grace