FLASH and EEPROM memory tools
ch341A SPI/I2C programmer
git clone https://github.com/plumbum/ch341eeprom
cd ch341eeprom
edit Makefile, replace "clang" with "gcc", appears to work
make
...and we have a tool that seems to work.
git clone https://review.coreboot.org/flashrom.git
cd flashrom
apt-get install libpci-dev
make
./flashrom --programmer ch341a_spi
...seems to work
test chip not autodetected:
Probing for Sanyo unknown Sanyo SPI chip, 0 kB: probe_spi_rdid_generic: id1 0x5e, id2 0x4014
Probing for Winbond unknown Winbond (ex Nexcom) SPI chip, 0 kB: probe_spi_rdid_generic: id1 0x5e, id2 0x4014
Probing for Generic unknown SPI chip (RDID), 0 kB: probe_spi_rdid_generic: id1 0x5e, id2 0x4014
Found Generic flash chip "unknown SPI chip (RDID)" (0 kB, SPI) on ch341a_spi.
Probing for Generic unknown SPI chip (REMS), 0 kB: probe_spi_rems: id1 0x5e, id2 0x13
Found Generic flash chip "unknown SPI chip (RDID)" (0 kB, SPI).
This flash part has status NOT WORKING for operations: PROBE READ ERASE WRITE
git clone https://github.com/danielkucera/ch341prog
cd ch341prog
make
...seems to work
windows software
https://www.neven.cz/kategorie/elektronicke-soucastky/elektronicky-vyvoj/programatori-a-prislusenstvi-k-programovani/eeprom-flash-bios-usb-programator-s-cipem-ch341a-spi/
https://uloz.to/!uAtRPqSpk/ch341a-programming-software-rar
...seems to work
test chip not autodetected, manual forcing of Winbond W25X40L gives successful read
(try with W25X80L, it's in fact 1-meg, not half-meg as the older ESP01 variants)
Device reported its revision [4.03]
Manufacturer ID: 5e
Memory Type: 40
Capacity: 14
Chip capacity is 1048576
the chip is XTX pn25f08b
1-megabyte
used in cheapo esp-01 modules
also used in Sonoff devices (also esp8266)
upgradable with WINBOND W25Q32FVSIG, from 1MB to 4MB
datasheet: http://www.xtxtech.com/upfile/2016082517095182.pdf
Table 8. PN25F08 ID Definition table
Operation Code M7-M0 ID15-ID8 ID7-ID0
9FH E0 40 14
90H E0 13
ABH 13
(BEWARE: PN25F08B has mfg id 0x5E instead of 0xE0)
apparently the newer Sonoffs use a different flash chip (PN25F08B) and it is then recommended to use these settings:
Generic ESP8266 module
Flash Mode: DOUT
Flash Frequency: 40MHz
CPU Frequency: 80MHz
Flash Size: 1M (512K SPIFFS)
Debug Port: Disabled
Debug Level: None
Reset Method: ck
Upload Speed: 115200
Had to flash it a few times before it worked
http://www.ti.com/lit/an/swra515/swra515.pdf
example of generic SPI flash requirements:
1.2 Supported Flash Types
For compatibility with the CC3x20 device, the serial flash device must support the following commands and format:
• Uniform sector erase size of 4K
• Command 0x9F (read the device ID [JEDEC]). Procedure: SEND 0x9F, READ 3 bytes
• Command 0x05 (read the status of the SFLASH). Procedure: SEND 0x05, READ 1 byte. Bit 0 is busy and bit 1 is write enable
• Command 0x06 (set write enable). Procedure: SEND 0x06, read status until write-enable bit is set
• Command 0xC7 (chip erase). Procedure: SEND 0xC7, read status until busy bit is cleared
• Command 0x03 (read data). Procedure: SEND 0x03, SEND 24-bit address, read n bytes
• Command 0x02 (write page). Procedure: SEND 0x02, SEND 24-bit address, write n bytes (n=1..256)
• Command 0x20 (sector erase). Procedure: SEND 0x20, SEND 24-bit address, read status until busy bit is cleared
static int spi_chip_erase_60(struct flashctx *flash)
/* This usually takes 1-85s, so wait in 1s steps. */
return spi_simple_write_cmd(flash, 0x60, 1000 * 1000);
}
static int spi_chip_erase_62(struct flashctx *flash)
/* This usually takes 2-5s, so wait in 100ms steps. */
return spi_simple_write_cmd(flash, 0x62, 100 * 1000);
}
static int spi_chip_erase_c7(struct flashctx *flash)
/* This usually takes 1-85s, so wait in 1s steps. */
return spi_simple_write_cmd(flash, 0xc7, 1000 * 1000);
}
int spi_block_erase_52(struct flashctx *flash, unsigned int addr,
unsigned int blocklen)
/* This usually takes 100-4000ms, so wait in 100ms steps. */
return spi_write_cmd(flash, 0x52, false, addr, NULL, 0, 100 * 1000);
}
* 32M (one die) for Micron
*/
int spi_block_erase_c4(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
/* This usually takes 240-480s, so wait in 500ms steps. */
return spi_write_cmd(flash, 0xc4, false, addr, NULL, 0, 500 * 1000);
}
* 64k for Macronix
* 32k for SST
* 4-32k non-uniform for EON
*/
int spi_block_erase_d8(struct flashctx *flash, unsigned int addr,
unsigned int blocklen)
/* This usually takes 100-4000ms, so wait in 100ms steps. */
return spi_write_cmd(flash, 0xd8, false, addr, NULL, 0, 100 * 1000);
}
* 4k for PMC
*/
int spi_block_erase_d7(struct flashctx *flash, unsigned int addr,
unsigned int blocklen)
/* This usually takes 100-4000ms, so wait in 100ms steps. */
return spi_write_cmd(flash, 0xd7, false, addr, NULL, 0, 100 * 1000);
}
int spi_block_erase_db(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
/* This takes up to 20ms usually (on worn out devices
up to the 0.5s range), so wait in 1ms steps. */
return spi_write_cmd(flash, 0xdb, false, addr, NULL, 0, 1 * 1000);
}
int spi_block_erase_20(struct flashctx *flash, unsigned int addr,
unsigned int blocklen)
/* This usually takes 15-800ms, so wait in 10ms steps. */
return spi_write_cmd(flash, 0x20, false, addr, NULL, 0, 10 * 1000);
}
int spi_block_erase_50(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
/* This usually takes 10ms, so wait in 1ms steps. */
return spi_write_cmd(flash, 0x50, false, addr, NULL, 0, 1 * 1000);
}
int spi_block_erase_81(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
/* This usually takes 8ms, so wait in 1ms steps. */
return spi_write_cmd(flash, 0x81, false, addr, NULL, 0, 1 * 1000);
}
int spi_block_erase_60(struct flashctx *flash, unsigned int addr,
unsigned int blocklen)
if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
msg_cerr("%s called with incorrect arguments\n",
__func__);
return -1;
}
return spi_chip_erase_60(flash);
}
int spi_block_erase_62(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
msg_cerr("%s called with incorrect arguments\n",
__func__);
return -1;
}
return spi_chip_erase_62(flash);
}
int spi_block_erase_c7(struct flashctx *flash, unsigned int addr,
unsigned int blocklen)
if ((addr != 0) || (blocklen != flash->chip->total_size * 1024)) {
msg_cerr("%s called with incorrect arguments\n",
__func__);
return -1;
}
return spi_chip_erase_c7(flash);
}
int spi_block_erase_21(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
/* This usually takes 15-800ms, so wait in 10ms steps. */
return spi_write_cmd(flash, 0x21, true, addr, NULL, 0, 10 * 1000);
}
int spi_block_erase_5c(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
/* This usually takes 100-4000ms, so wait in 100ms steps. */
return spi_write_cmd(flash, 0x5c, true, addr, NULL, 0, 100 * 1000);
}
int spi_block_erase_dc(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
/* This usually takes 100-4000ms, so wait in 100ms steps. */
return spi_write_cmd(flash, 0xdc, true, addr, NULL, 0, 100 * 1000);
}
QIO - SPI host uses the "Quad I/O Fast Read" command (EBh).
Four SPI pins are used to write the flash address part of the command, and to read flash data out.
Therefore these phases need a quarter the clock cycles compared to standard SPI.
QOUT - SPI host uses the "Quad Output Fast Read" command (6Bh). Four SPI pins are used to read the flash data out.
Slightly slower than QIO, because the address is written via the single MOSI data pin.
DIO - SPI host uses the "Dual I/O Fast Read" command (BBh).
Two SPI pins are used to write the flash address part of the command, and to read flash data out.
Therefore these phases need half the clock cycles compared to standard SPI.
DOUT - SPI host uses the "Dual Output Fast Read" command (3Bh). Two SPI pins are used to read flash data out.
Slightly slower than DIO, because the address is written via the single MOSI data pin.
In terms of performance: QIO > QOUT > DIO > DOUT (source) [ref]
SPI - Single-channel
dual-SPI
quad-SPI
QPI - Quad-channel
DTR - Dual Transfer Rate
RPMC - Replay-Protection Monotonic Counter
SFDP - Serial Flash Discoverable Parameters (command 0x5A) https://chromium.googlesource.com/chromiumos/platform/ec/+/master/include/sfdp.h
4-byte addressing: for over 128Mbit/16Mbyte, up to 32Gbit/Gbyte
SPI families
Winbond W25X - SPI, dualSPI; 4k/32k/64k erase
Winbond W25Q - superset of W25X; SPI, dualSPI, quadSPI, QPI; SFDP; 4k/32k/64k erase
flash equivalents
https://www.macronix.com/zh-tw/products/Documents/Macronix%20NOR%20and%20NAND%20Flash%20Cross%20Reference%20Guide.pdf
MX30LF1G18AC - Macronix
S34ML01G1 - Cypress
S34ML01G2 - Cypress
H27U1G8F2B - Hynix
H27U1G8F2C - Hynix
MT29F1G08ABADA - Micron
MT29F1G08ABAEA - Micron
K9F1G08U0D - Samsung
K9F1G08U0E - Samsung
W29N01GV - Winbond
W29N01HV - Winbond
If you have any comments or questions about the topic, please let me know here: |