ian
November 26, 2025, 12:10pm
1
DDR4 SPD plank arrived, and a used SODIMM just fell through the mail slot.
The wrong header was soldered
Still need to figure out the 9volt supply, probably a 9 volt battery.
SA1 is held high to ground A1 pin, then we can read out the 256 bytes of contents with [0b10100001 r:256].
2 Likes
ian
November 26, 2025, 1:19pm
2
Set page and address
DDR4 SPD chips typically have 2 pages of 256 bytes each.
Send 0b0110+1100 to set page 0, requires 2 dummy bytes
Send 0b1010+0000 then the address to read from (0x00)
Send 0b1010+0001 then read 256 bytes
Repeat to read page 1
I2C> [0b01101100 0b0 0b0] D:1 [0b10100000 0] D:1 [0b10100001 r:256]
Read page 0.
I2C> [0b01101110 0b0 0b0] D:1 [0b1010000 0] D:1 [0b10100001 r:256]
Read page 1.
Decode a bit
0x23 ACK 0x11 ACK 0x0C ACK 0x03 ACK 0x84 ACK 0x19 ACK 0x00 ACK 0x08 ACK
Let’s decode that first row. I’m using simtester reference and the JEDEC standard (free account required).
0x23 = 0b00100011
bits 6:4 = 010 = 512 bytes total
bits 3:0 = 0011 = 384 bits actually used
0x11 = version.revision = 1.1
0x0c = DDR4 SDRAM device type
0x03 = SO-DIMM module type
0x84 = 0b10000100
bits 7:6 = 4 bank groups
bits 5:4 = 4 banks address bits
bits 3:0 = 4Gb capacity per die
0x19 = 0b00011001
bits 5:3 = 15 row address bits
bits 2:0 = 10 column address bits
0x00 = single die
0x08 = 0b00001000
bits 5:4 = 8192*tREFI max active window
bits 3:0 = unlimited maximum active count
2 Likes
ian
November 26, 2025, 1:33pm
3
Page 1 info
0x01 ACK 0x98 ACK 0x05 ACK 0x18 ACK 0x38 ACK 0x84 ACK 0x24 ACK 0xA0 ACK
0x92 ACK 0x41 ACK 0x43 ACK 0x52 ACK 0x32 ACK 0x34 ACK 0x44 ACK 0x34 ACK
0x53 ACK 0x37 ACK 0x53 ACK 0x38 ACK 0x4D ACK 0x42 ACK 0x2D ACK 0x34 ACK
0x20 ACK 0x20 ACK 0x20 ACK 0x20 ACK 0x20 ACK 0x00 ACK 0x80 ACK 0x2C ACK
0x42 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK
0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x88 ACK
0x07 ACK 0x38 ACK 0x31 ACK 0x35 ACK 0x33 ACK 0x31 ACK 0x37 ACK 0x33 ACK
0x00 ACK 0x00 ACK 0x01 ACK 0x01 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK
Starting at byte 320 (page 1) we find some module info.
0x9801 = module JEDEC ID = kingston
0x05 = manuf. location
0x18 0x38 = manufacturing year/week (matches label)
0x84 0x24 0xA0 0x92 = serial number (no match)
0x41 0x43 0x52 0x32 0x34 0x44 0x34 0x53 0x37 0x53 0x38 0x4D 0x42 0x2D 0x34 0x20 0x20 0x20 0x20 0x20 = Module serial number (I bet this is ASCII)
Yes: ACR24D4S7S8MB-4 (matches label)
0x00 = revision 0
0x2c80 = DRAM chip manuf. ID = Micron
0x42 = DRAM stepping
0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK
0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x88 ACK
0x07 ACK 0x38 ACK 0x31 ACK 0x35 ACK 0x33 ACK 0x31 ACK 0x37 ACK 0x33 ACK
0x00 ACK 0x00 ACK 0x01 ACK 0x01 ACK 0x00 ACK 0x00 ACK 0x00 ACK 0x00 ACK
Now several rows of manufacturer specific data.
1 Like
ian
November 26, 2025, 4:04pm
4
There are four protected ranges in the EEPROM. If protection is enabled the chip with respond to the RPSx command with NACK, if not then ACK.
The ACK/NAK happens after the address. Two additional dummy bytes are required.
I2C> [0b01100011 0b0 0b0] [0b01101001 0b0 0b0] [0b01101011 0b0 0b0] [0b01100001 0b0 0b0]
I2C START
TX: 0b01100011 NACK 0b00000000 NACK 0b00000000 NACK
I2C STOP
I2C START
TX: 0b01101001 NACK 0b00000000 NACK 0b00000000 NACK
I2C STOP
I2C START
TX: 0b01101011 ACK 0b00000000 NACK 0b00000000 NACK
I2C STOP
I2C START
TX: 0b01100001 ACK 0b00000000 NACK 0b00000000 NACK
I2C STOP
I2C>
It appears blocks 0 and 1 are protected, while 2 and 3 are unprotected. That seems pretty normal.
The next step should probably be to make a full backup of the SPD What I actually want to do is hook up the 9volt supply and change the protection bits. Backup first though, backup first
3 Likes
ian
November 27, 2025, 3:54pm
6
Used the generic i2c dump command to backup the DDR4 SPD to files. Noticed that i2c did not actually have save to file enabled, so I’ll push that shortly.
[0b01101100 0b0 0b0]
i2c dump -a 0x50 -w 1 -r 0x00 -b 256
[0b01101110 0b0 0b0]
i2c dump -a 0x50 -w 1 -r 0x00 -b 256
Command to dump to hex viewer.
DDR4.zip (497 Bytes)
Here’s the contents if you’d like to have a look, perhaps with this editor GUI for ddr4 .
Now that we have a backup, let’s do the fun bits with the 9 volt programming voltage (lock and unlock block protection).
2 Likes
ian
November 28, 2025, 12:24pm
7
I2C> [0b01101011 0b0 0b0]
I2C START
TX: 0b01101011 ACK 0b00000000 NACK 0b00000000 NACK
Check the protected status of block 2. ACK = not protected.
I2C> [ 0b01101010 0b 0b ]
I2C START
TX: 0b01101010 NACK 0b00000000 NACK 0b00000000 NACK
I2C STOP
Try to enable protection on block two, without 9 volts on SA0. NACK = unsuccessful.
I2C> [ 0b01101010 0b 0b ]
I2C START
TX: 0b01101010 ACK 0b00000000 ACK 0b00000000 ACK
I2C STOP
Enable 9 volts on SA0 pin, then try to protect the block again. No blue smoke = success! ACK = success!
I2C> [0b01101011 0b0 0b0]
I2C START
TX: 0b01101011 NACK 0b00000000 NACK 0b00000000 NACK
I2C STOP
Check the protected status again, NACK = protected!
Notice some voltage droop when driving the optocoupler.
This is the current circuit for enabling 9volts.
I think this is a good change for the next revision. Enable the optocoupler via a FET instead of from the Bus Pirate pin directly.
Also add high voltage feedback to Bus Pirate with zener protection diode so we can check that 9V HV programming supply.
I gained a lot of my understanding from this project , which has a SA1 control circuit. This may be needed for older DDR, but it seems useless on the DDR4 board. I’m going to remove SA1 control.
1 Like
ian
November 28, 2025, 12:30pm
8
I also think a hole in the board right here might be nice. Big enough for a zip-tie to hold the 9volt power cable to the board so it doesn’t get lost in the parts bin.
2 Likes
ian
November 28, 2025, 3:23pm
9
From social media: Small addition of a pull-down resistor on the FET (Q1) to keep it from floating when not connected.
2 Likes
I had to do that on my blank plank glitcher. The gate on the FET floated when I disconnected the plank momentarily and burned out the small FET shorting the target to ground. Oops.
Edited: gate, not base. It’s a FET, not a BJT
1 Like
ian
November 29, 2025, 12:44pm
11
ddr4 dump command up and running.
The proper thing to do is build a ddr framework to reuse for every version, but at this stage I’m just enjoying writing bespoke code for each. Maybe we can do a framework later, or maybe this is good enough.
I2C> ddr4 probe
Block 0: Locked
Block 1: Locked
Block 2: Unlocked
Block 3: Unlocked
I2C>
Lock status.
ETA: Locking and unlocking blocks:
ETA: Read contents to file:
I2C> ddr4 read -f ddr4.bin
Read SPD NVM to file: ddr4.bin
Success :)
I2C>
Verify SPD against file:
I2C> ddr4 verify -f ddr4.bin
Verifying SPD NVM against file: ddr4.bin
Success :)
I2C>
Verify file CRC:
I2C> ddr4 crc -f ddr4.bin
Checking CRC for bytes 0-125, file: ddr4.bin
CRC verify
Stored CRC (bytes 126:127): 0x34 0x9E
Calculated CRC: 0x34 0x9E
CRC okay :)
I2C>
Patch correct CRC into file:
I2C> ddr4 patch -f ddr4e.bin
Checking CRC for bytes 0-125, file: ddr4e.bin
Stored CRC (bytes 126:127): 0x00 0x00
Calculated CRC: 0x34 0x9E
Patching CRC in file to: 0x34 0x9E
File patched successfully :)
Verifying patched file CRC:
CRC verify
Stored CRC (bytes 126:127): 0x34 0x9E
Calculated CRC: 0x34 0x9E
CRC okay :)
I2C>
TODO:
write from file
probe (show stats)
read to file
verify against file
check CRC
patch CRC in file
2 Likes
ian
November 29, 2025, 5:18pm
12
Read a data sheet for a DDR1/2/3 EEPROM. Seems really similar to DDR4, I could see them becoming part of a combined DDR framework which could make implementation really fast.
The older eeprom is where manipulation of address pin 1 seems to come into play.
I’ll try to source a full set of common sockets and have boards made up for the remaining DDR versions.