SPI Flash goodness

Ive got 3 flash chips with “Serial Flash Discoverable Parameter (SFDP)” tables, a standard way of determining the properties of a chip. I guess it is helpful to determine how to read and program a chip (capacity, block size, etc).

Honestly, it is not something I’ve worked with before and I’m pretty excited.

I have three chips on breakout boards (but I’m also thirsting after a SOIC ZIF socket). Two variants from Puya, and the same Winbond chip that is used in the Bus Pirate.

SPI> [0x9f r:3]
CS Enabled
TX: 0x9F
RX: 0x85 0x60 0x15
CS Disabled
SPI>

Most flash chips support 0x9f ID command.There’s also a legacy 90 command.

This is the Puya chip. The output matches the first line.

0x5a is the SFDP command. In this chip the table is 0x68 bytes long, and the three byte address sent after the command determines where in the table we start reading.

SPI> [0x5a 0x00:4 r:0x68]
CS Enabled
TX: 0x5A 0x00 0x00 0x00 0x00
RX: 0x53 0x46 0x44 0x50 0x00 0x01 0x01 0xFF
0x00 0x00 0x01 0x09 0x30 0x00 0x00 0xFF
0x85 0x00 0x01 0x03 0x60 0x00 0x00 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xE5 0x20 0xF1 0xFF 0xFF 0xFF 0xFF 0x00
0x44 0xEB 0x08 0x6B 0x08 0x3B 0x80 0xBB
0xEE 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0xFF
0xFF 0xFF 0x00 0xFF 0x0C 0x20 0x0F 0x52
0x10 0xD8 0x08 0x81 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0x00 0x36 0x50 0x16 0x9E 0xF9 0x77 0x64
CS Disabled

And there’s the table data. Easy-peas (thanks autocorrect!).

0x53 0x46 0x44 0x50

There’s the signature, big-endian format.

0x00 0x01 0x01 0xFF

Some info

  • Minor revision: 0x00
  • Major revision 0x01
  • parameter headers: 0x01
  • 0xff (assume end of header marker)

0x00 0x00 0x01 0x09 0x30 0x00 0x00 0xFF

Location of a table:

  • JEDEC header # 0x00
  • Minor: 0x00
  • Major: 0x01
  • Length: 0x09 (in Dwords, so 18 bytes? 4*9=36)
  • Parameter table starts at 00 00 30
  • 0xff End of header marker?

0x85 0x00 0x01 0x03 0x60 0x00 0x00 0xFF

Another table location (manuf?):

  • manuf ID: 0x85 (I downloaded a list, there is a continuation code I don’t understand at this point)
  • version = 01 00
  • another param table length 03 = 6 bytes? 3 * 4 = 12
  • Where is it? 00 00 06
  • 0xff end marker

0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF

Looks to be 24 bytes of 0xff?

JEDEC flash parameter table (0x30)

SPI> [ 0x5a 0 0 0x30 0 r:18]
CS Enabled
TX: 0x5A
TX: 0 0
TX: 0x30
TX: 0
RX: 0xE5 0x20 0xF1 0xFF 0xFF 0xFF 0xFF 0x00
0x44 0xEB 0x08 0x6B 0x08 0x3B 0x80 0xBB
0xEE 0xFF
CS Disabled
SPI>

Read from address 00 00 03 + dummy byte (0), then read 36 bytes of the first table.

image

Datasheet for a different chip is nicer. It breaks down the 18 bytes of the first section into 9 topical tables. Useful, but not particularly interesting.

Vendor data table

3 * 4 = 12 bytes of vendor data

SPI> [ 0x5a 0 0 0x60 0 r:12]
CS Enabled
TX: 0x5A
TX: 0 0
TX: 0x60
TX: 0
RX: 0x00 0x36 0x50 0x16 0x9E 0xF9 0x77 0x64
0xFC 0xCB 0xFF 0xFF
CS Disabled
SPI>

Now we get to some good stuff.

  • 3600 = 3.6v max
    image

  • 1650 = 1.65v min (datasheet is wrong?)

  • no reset, has hold, has deep sleep, has sw reset, reset instruction is 0x99, has resume, has read wrap

  • warp read instruction: 0x77

  • etc.

Cool!

I found a list of manufacturer codes in the glasgow firmware, which they ripped from the JEDEC pdf with a python script.

There is a concept of banks and a continuation code to expand the 0-127 possible manufacturer IDs, but it seems to just be part of the PDF list, not actually implemented in hardware? I’m not sure on this point, but now I’m ready to write some code.

RES (reset from deep sleep ID)

SPI> [0xb9] D:10 [0xab 0x00:3 r]
CS Enabled
TX: 0xB9
CS Disabled
Delay: 10ms
CS Enabled
TX: 0xAB 0x00 0x00 0x00
RX: 0x14
CS Disabled
SPI>

REMS

SPI> [0x90 0x00:3 r:2]
CS Enabled
TX: 0x90 0x00 0x00 0x00
RX: 0x85 0x14
CS Disabled
SPI>

RDID

SPI> [0x9f r:3]
CS Enabled
TX: 0x9F
RX: 0x85 0x60 0x15
CS Disabled
SPI>

image

Three other forms of ID in various states of legacy. We should probe them all.

Macro (1) - read legacy IDs:

SPI> A 0; A 1
IO0 set to OUTPUT: 1
IO1 set to OUTPUT: 1

Don’t forget to set HOLD and WP high.

SPI> (1)
Probing:
Resume ID (0xAB): 14
REMS ID (0x90): Manufacturer ID: 85, Device ID: 14
Read ID (0x9f): Manufacturer ID: 85, Type: 60, Capacity: 15
SPI>

Got the raw legacy IDs, will worry about decoding them later. I’m more interested in the extended information.


Now we’re getting somewhere:

SPI> (1)
Probing:
Resume ID (0xAB): 14
REMS ID (0x90): Manufacturer ID: 85, Device ID: 14
Read ID (0x9f): Manufacturer ID: 85, Type: 60, Capacity: 15
Read SFDP (0x5a): found 0x50444653
Version: 1.0
Number of headers: 2
Param Table 0
Type: manufacturer (00)
Version: 1.0
Length: 36 bytes
Address: 0x000030
Fetching table…
e5 20 f1 ff ff ff ff 00 44 eb 08 6b 08 3b 80 bb ee ff ff ff ff ff 00 ff ff ff 00 ff 0c 20 0f 52 10 d8 08 81
Param Table 1
Type: manufacturer (85)
Version: 1.0
Length: 12 bytes
Address: 0x000060
Fetching table…
00 36 50 16 9e f9 77 64 fc cb ff ff
Vcc: max 3600mV, min 1650mV
HW pins: #Reset 0, #Hold 1
Deep Power Down (DPDM): 1
SW reset: 1, opcode f9
Suspend/Resume: Program 1, Erase 1
Wrap Read mode: 0, opcode 64, length fc
Individual block lock: 1, nonvolatile 1, opcode ff, volatile default UNprotected 1
Secured OTP: 1
Read lock: 1
Permanent lock: 1
SPI>

SPI> A 0; A 1
IO0 set to OUTPUT: 1
IO1 set to OUTPUT: 1
SPI> (1)
Probing:
Resume ID (0xAB): 14
REMS ID (0x90): Manufacturer ID: 85, Device ID: 14
Read ID (0x9f): Manufacturer ID: 85, Type: 60, Capacity: 15
Read SFDP (0x5a): found 0x50444653
Version: 1.0
Number of headers: 2
Param Table 0
Type: manufacturer (00)
Version: 1.0
Length: 36 bytes
Address: 0x000030
Fetching table…
e5 20 f1 ff ff ff ff 00 44 eb 08 6b 08 3b 80 bb ee ff ff ff ff ff 00 ff ff ff 00 ff 0c 20 0f 52 10 d8 08 81
Block/sector 4K erase: 1
4K erase instruction: 20
Address bytes: 0
Density: 16777215
1-1-2 fast read: 1
1-1-2 fast read instruction: 3b
1-2-2 fast read: 1
1-2-2 fast read instruction: bb
1-4-4 fast read: 1
1-4-4 fast read instruction: eb
1-1-4 fast read: 1
1-1-4 fast read instruction: 6b
2-2-2 fast read: 0
4-4-4 fast read: 0
Erase 1 size: 12
Erase 1 instruction: 20
Erase 2 size: 15
Erase 2 instruction: 52
Erase 3 size: 16
Erase 3 instruction: d8
Erase 4 size: 8
Erase 4 instruction: 81
Param Table 1
Type: manufacturer (85)
Version: 1.0
Length: 12 bytes
Address: 0x000060
Fetching table…
00 36 50 16 9e f9 77 64 fc cb ff ff
Vcc: max 3600mV, min 1650mV
HW pins: #Reset 0, #Hold 1
Deep Power Down (DPDM): 1
SW reset: 1, opcode 99
Suspend/Resume: Program 1, Erase 1
Wrap Read mode: 1, opcode 77, length 64
Individual block lock: 0, nonvolatile 0, opcode ff, volatile default UNprotected 0
Secured OTP: 1
Read lock: 0
Permanent lock: 0

That’s a lot of info! The values are not correct yet, it displays raw values instead of the calculated values.

While I was looking for an open source struct for the PTP table, I can across a universal flash write/read script at github that looks like a good candidate to add. (I still had to write my own struct)

This will be SPI mode macro (1) in the latest firmware.

1 Like

SFUD Start initialize Serial Flash Universal Driver(SFUD) V1.1.0.
SFUD You can get the latest version on GitHub - armink/SFUD: An using JEDEC's SFDP standard serial (SPI) flash universal driver library | 一款使用 JEDEC SFDP 标准的串行 (SPI) Flash 通用驱动库 .
SFUD The flash device manufacturer ID is 0x85, memory type ID is 0x60, capacity ID is 0x15.
SFUD Check SFDP header is OK. The reversion is V1.0, NPN is 1.
SFUD Check JEDEC basic flash parameter header is OK. The table id is 0, reversion is V1.0, length is 9, parameter table pointer is 0x000030.
SFUD JEDEC basic flash parameter table info:
SFUD MSB-LSB 3 2 1 0
SFUD [0001] 0xFF 0xF1 0x20 0xE5
SFUD [0002] 0x00 0xFF 0xFF 0xFF
SFUD [0003] 0x6B 0x08 0xEB 0x44
SFUD [0004] 0xBB 0x80 0x3B 0x08
SFUD [0005] 0xFF 0xFF 0xFF 0xEE
SFUD [0006] 0xFF 0x00 0xFF 0xFF
SFUD [0007] 0xFF 0x00 0xFF 0xFF
SFUD [0008] 0x52 0x0F 0x20 0x0C
SFUD [0009] 0x81 0x08 0xD8 0x10
SFUD 4 KB Erase is supported throughout the device. Command is 0x20.
SFUD Write granularity is 64 bytes or larger.
SFUD Target flash status register is non-volatile.
SFUD 3-Byte only addressing.
SFUD Capacity is 2097152 Bytes.
SFUD Flash device supports 4KB block erase. Command is 0x20.
SFUD Flash device supports 32KB block erase. Command is 0x52.
SFUD Flash device supports 64KB block erase. Command is 0xD8.
SFUD Flash device supports 0KB block erase. Command is 0x81.
[SFUD]Found a PUYA flash chip. Size is 2097152 bytes.
SFUD Flash device reset success.
[SFUD]SST25VF016B flash device initialized successfully.
Success!
Erase the SST25VF016B flash data finish. Start from 0x00000000, size is 1024.
Write the SST25VF016B flash data finish. Start from 0x00000000, size is 1024.
Read the SST25VF016B flash data success. Start from 0x00000000, size is 1024. The data is:
Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[00000000] 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[00000010] 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
[00000020] 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
[00000030] 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
[00000040] 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
[00000050] 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
[00000060] 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
[00000070] 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
[00000080] 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
[00000090] 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
[000000A0] A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
[000000B0] B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
[000000C0] C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
[000000D0] D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
[000000E0] E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
[000000F0] F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
[00000100] 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[00000110] 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
[00000120] 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
[00000130] 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
[00000140] 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
[00000150] 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
[00000160] 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
[00000170] 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
[00000180] 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
[00000190] 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
[000001A0] A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
[000001B0] B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
[000001C0] C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
[000001D0] D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
[000001E0] E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
[000001F0] F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
[00000200] 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[00000210] 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
[00000220] 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
[00000230] 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
[00000240] 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
[00000250] 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
[00000260] 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
[00000270] 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
[00000280] 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
[00000290] 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
[000002A0] A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
[000002B0] B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
[000002C0] C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
[000002D0] D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
[000002E0] E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
[000002F0] F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
[00000300] 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
[00000310] 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
[00000320] 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
[00000330] 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
[00000340] 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
[00000350] 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
[00000360] 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
[00000370] 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
[00000380] 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
[00000390] 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
[000003A0] A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
[000003B0] B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
[000003C0] C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
[000003D0] D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
[000003E0] E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
[000003F0] F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF

The SST25VF016B flash test is success.
SPI>

I added SFUD, a universal serial flash ID/program/read library. It is working, but I need to combine this with my previous work and clean everything up. Looks like good stuff.