HOWTO: Fixing a broken EDID EEPROM with a Bus Pirate v4

This post is about fixing a broken EDID ROM in a monitor. There are several ways to do this. Typically this involves writing the EEPROM with the Windows only tool PowerStrip (see here for a HOWTO) . Here I want to present an alternative solution using the Dangerous Prototypes Bus Pirate - a device which every hardware hacker with self-respect should have anyway. You should already be tech-savvy to attempt this procedure.

Introduction

So I own 3 Samsung Syncmaster 2343BW with a staggering 2048×1152 pixels of resolution on 23″. When I bought them 3 years ago – this was really amazing. (Nowadays, such monitors are not even for sale anymore… but there is the ipad… Hopefully Apple sets a trend here for higher resolution…

So one of these monitors often suffers from a broken EDID EEPROM. Since this ROM is used to store all important information for Plug&Pray, the monitor not being detected anymore at all. I had this happen to me 3 times during warranty and they always exchanged the whole motherboard.  But unfortunately continues to appear after warranty, so I set out to fix it myself.

The problem

Linux error message

So from one Laptop docking to another my Linux kernel complains about

[15360.438628] Raw EDID:
[15360.438635]          00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[15360.438639]          14 12 01 03 80 33 1d 78 2a ee 91 a3 54 4c 99 26
[15360.438643]          0f 50 54 23 08 00 81 80 81 40 81 00 95 00 b3 00
[15360.438647]          01 01 01 01 01 01 3b 3d 00 a0 80 80 21 40 30 20
[15360.438651]          35 00 fe 1f 11 00 00 1a 00 00 00 fd 00 38 3c 1e
[15360.438655]          51 10 00 0a 20 20 20 20 20 20 00 00 00 fc 00 53
[15360.438659]          79 6e 63 4d 61 73 74 65 72 0a 20 20 00 00 00 ff
[15360.438663]          00 48 31 41 4b 35 30 30 30 30 30 0a 20 20 00 12
[15360.438671] i915 0000:00:02.0: HDMI-A-3: EDID block 0 invalid.

Ok, so the first 16 bytes have just been erased – beautiful! So presumably, if I fix these bytes my monitor will start working again.

Getting a correct EDID file

This chapter is about extracting a correct EDID file from the broken one. If you already have a correct EDID ROM (i.e. from a second monitor you own) and you want to flash it – just skip it.

Extracting the corrupted EDID ROM as binary

So first we have to get the broken EDID file. This is simple, since all the EEPROMs Linux finds are exposed to use under /sys/bus/i2c/devices/$bus-00$addr/eeprom. If you cannot find these devices your kernel is either too old or you do not have the eeprom module loaded. Depending on your computer there might be several eeproms, so let’s find the correct one with a bash one-liner:

for eeprom in /sys/bus/i2c/devices/*-0050/eeprom; do \
echo "\n\n#### Analyzing EEPROM $eeprom"; \
hexdump -C $eeprom; done

Might yield a lot of results, but just look for the broken one, i.e.

#### Analyzing EEPROM /sys/bus/i2c/devices/12-0050/eeprom
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000010  14 12 01 03 80 33 1d 78  2a ee 91 a3 54 4c 99 26  |.....3.x*...TL.&|
00000020  0f 50 54 23 08 00 81 80  81 40 81 00 95 00 b3 00  |.PT#.....@......|
00000030  01 01 01 01 01 01 3b 3d  00 a0 80 80 21 40 30 20  |......;=....!@0 |
00000040  35 00 fe 1f 11 00 00 1a  00 00 00 fd 00 38 3c 1e  |5............8<.|
00000050  51 10 00 0a 20 20 20 20  20 20 00 00 00 fc 00 53  |Q...      .....S|
00000060  79 6e 63 4d 61 73 74 65  72 0a 20 20 00 00 00 ff  |yncMaster.  ....|
00000070  00 48 31 41 4b 35 30 30  30 30 30 0a 20 20 00 12  |.H1AK500000.  ..|
00000080  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
00000100

OK, so we have the broken ROM in binary form. Let’s save it somewhere

cat /sys/bus/i2c/devices/12-0050/eeprom > broken_edid.bin

Luckily I the  monitor also has a VGA input where I could just read out the correct EDID:

#### Analyzing EEPROM /sys/bus/i2c/devices/3-0050/eeprom
00000000  00 ff ff ff ff ff ff 00  4c 2d 1e 04 33 32 59 4d  |........L-..32YM|
00000010  14 12 01 03 0e 33 1d 78  2a ee 91 a3 54 4c 99 26  |.....3.x*...TL.&|
00000020  0f 50 54 23 08 00 81 80  81 40 81 00 95 00 b3 00  |.PT#.....@......|
00000030  01 01 01 01 01 01 3b 3d  00 a0 80 80 21 40 30 20  |......;=....!@0 |
00000040  35 00 fe 1f 11 00 00 1a  00 00 00 fd 00 38 3c 1e  |5............8<.|
00000050  51 10 00 0a 20 20 20 20  20 20 00 00 00 fc 00 53  |Q...      .....S|
00000060  79 6e 63 4d 61 73 74 65  72 0a 20 20 00 00 00 ff  |yncMaster.  ....|
00000070  00 48 31 41 4b 35 30 30  30 30 30 0a 20 20 00 84  |.H1AK500000.  ..|
00000080  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
00000100

So let’s try edit  broken_edid.bin and insert the missing header (so the first line in the hex dump). You can easily to this with any Hex-Editor, if you don’t know one I can recommend Okteta. Once you think you have fixed your EDID file, save it as fixed_edid.bin.  You can check if you new file is valid with the edid-decode program (also in the Debian/Ubuntu repositories).

edid-decode fixed_edid.bin

Extracted contents:
header:          00 ff ff ff ff ff ff 00
serial number:   4c 2d 1f 04 33 32 59 4d 09 13
version:         01 03
basic params:    80 33 1d 78 2a
chroma info:     ee 91 a3 54 4c 99 26 0f 50 54
established:     23 08 00
standard:        81 80 81 40 81 00 95 00 b3 00 01 01 01 01 01 01
descriptor 1:    3b 3d 00 a0 80 80 21 40 30 20 35 00 fe 1f 11 00 00 1a
descriptor 2:    00 00 00 fd 00 38 3c 1e 51 10 00 0a 20 20 20 20 20 20
descriptor 3:    00 00 00 fc 00 53 79 6e 63 4d 61 73 74 65 72 0a 20 20
descriptor 4:    00 00 00 ff 00 48 39 58 53 32 30 36 33 39 31 0a 20 20
extensions:      00
checksum:        e4

Manufacturer: SAM Model 41f Serial Number 1297691187
Made week 9 of 2009
EDID version: 1.3
Digital display
Maximum image size: 51 cm x 29 cm
Gamma: 2.20
DPMS levels: Off
Supported color formats: RGB 4:4:4, YCrCb 4:2:2
First detailed timing is preferred timing
Established timings supported:
  640x480@60Hz
  800x600@56Hz
  800x600@60Hz
  1024x768@60Hz
Standard timings supported:
  1280x1024@60Hz
  1280x960@60Hz
  1280x800@60Hz
  1440x900@60Hz
  1680x1050@60Hz
Detailed mode: Clock 156.750 MHz, 510 mm x 287 mm
               2048 2096 2128 2208 hborder 0
               1152 1155 1160 1185 vborder 0
               +hsync -vsync
Monitor ranges: 56-60HZ vertical, 30-81kHz horizontal, max dotclock 160MHz
Monitor name: SyncMaster
  Serial number: H9XS206391
  Checksum: 0xe4

Manufacturer-specific extension block
Unknown extension block

Great! So no errors here! Now we go on flashing the EEPROM. Note that depending on what bits you changed you might have to also correct the check sum. This happens for example if you alter the serial number. But don’t worry, you will be warned by edid-decode and it calculates the correct check sum by itself. (Thanks Kaz for pointing that out.)

Flashing a new EDID in the EEPROM

Now that we have a correct EDID ROM we need to flash it. All modern monitors use a I2C bus which is exposed over its display connector. I won’t go into the details, this is just about what you need to do to read an write on the EEPROM.

Connecting the Bus Pirate to the monitor

If you have an old analog monitor connecting to the I2C bus is easy. You can just use 1-pin dual-female jumper wire (i.e. from Seed Studio) and connect the pins of the male Sub-D connector cable with the pins on the monitor. I ran into problems connecting to DVI though since these connectors have not the right pin size. So the easiest way is just to get a cheap passiv VGA to DVI adapter. Don’t worry about digital versus analog video signals – it does not matter since we are only interested in the I2C bus which is identical. If you have a HDMI monitor, I could imagine you can cascade a VGA-DVI and a DVI-HDMI connector. I have not tried that though.

The important pins on the VGA connector are:

Pin 9	PWR	+5V DC
Pin 10	GND	Ground (VSync, DDC)
Pin 12	SDA	I²C data
Pin 15	SCL	I²C clock

Which you can directly connect to your Bus Pirate (also see official I2C scheme)

PWR	-> 	+5V
GND	->	GND
SDA	->	MOSI
SCL	-> 	CLK

Talking to the EEPROM

Initialize the Bus Pirate

Now it’s time to talk to the EEPROM. Your monitor does not need to be switched on since it is supplied with 5V directly from the Bus Pirate. Use your preferred terminal program to connect to the Pirate. I personally like picocom.

picocom -b 115200 /dev/ttyACM0

picocom v1.4

port is        : /dev/ttyACM0
flowcontrol    : none
baudrate is    : 115200
parity is      : none
databits are   : 8
escape is      : C-a
noinit is      : no
noreset is     : no
nolock is      : no
send_cmd is    : ascii_xfr -s -v -l10
receive_cmd is : rz -vv

Terminal ready
HiZ>

 

Now, switch to the I2C at 100kHz and activated pull-ups:

HiZ>m
1. HiZ
2. 1-WIRE
3. UART
4. I2C
5. SPI
6. 2WIRE
7. 3WIRE
8. KEYB
9. LCD
10. PIC
11. DIO
x. exit(without change)

(1)>4
I2C mode:
 1. Software
 2. Hardware

(1)>1
Set speed:
 1. ~5KHz
 2. ~50KHz
 3. ~100KHz
 4. ~400KHz

(1)>3
Ready

I2C>e
Select Vpu (Pullup) Source:
 1) External (or None)
 2) Onboard 3.3v
 3) Onboard 5.0v

(1)>3
5V on-board pullup voltage enabled

Reading and writing to the EEPROM

Now, if you have never used I2C to talk to EEPROMs this might feel a bit awkward but just bear with me. There are two I2C address, one for reading (0xa1) and one for writing (0xa0) commands to.

Reading

So if you want to read from the EEPROM, you first have to write your address you want to start. The address counter of the EEPROM is internally increased for each bit you read. So let’s first try to set our start address to zero, the beginning of the EDID block.

I2C>[0xa0 0]
I2C START BIT
WRITE: 0xA0 ACK 
WRITE: 0x00 ACK 
I2C STOP BIT

So we the wrote the start address 0  to EEPROM.  If you do not see the ACK message for acknowledgment of the command you did something wrong in the wiring  or the pull-up configuration.

Now that we set the address we can read the EEPROM. Since my first eight bytes are all zero due to the corrupted ROM, it’s not so exiting and we continue reading some more byes.

I2C>[0xa1 r:8]
I2C START BIT
WRITE: 0xA1 ACK 
READ: 0x00  ACK 0x00  ACK 0x00  ACK 0x00  ACK 0x00  ACK 0x00  ACK 0x00  ACK 0x00 
NACK
I2C STOP BIT
I2C>[0xa1 r:8]
I2C START BIT
WRITE: 0xA1 ACK 
READ: 0x00  ACK 0x00  ACK 0x00  ACK 0x00  ACK 0x00  ACK 0x00  ACK 0x00  ACK 0x00 
NACK
I2C STOP BIT
I2C>[0xa1 r:8]
I2C START BIT
WRITE: 0xA1 ACK 
READ: 0x14  ACK 0x12  ACK 0x01  ACK 0x03  ACK 0x80  ACK 0x33  ACK 0x1D  ACK 0x78 
NACK
I2C STOP BIT
I2C>

Notice how we use the read address 0xa1 and ask the Bus Pirate to read 8 bytes in a row. Also note that we get the same result we also saw in the Linux kernel error message. Of course you could also start reading somewhere else in the ROM by just changing the start address.

 Writing

Now it’s time we write to the EEPROM. Notice that some monitors protect the EEPROM against writes – you might have to google on how to get into the service menu to deactivate the write protection. In my case, I could just write to it (which is probably why it gets corrupted in the first place…).

So remember that there there was the writing address 0xa0 and we used it to write the address counter to the place we wanted to start reading. Now, instead of reading we just continue to write:

I2C>[0xa0 0 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00]
I2C START BIT
WRITE: 0xA0 ACK 
WRITE: 0x00 ACK 
WRITE: 0x00 ACK 
WRITE: 0xFF ACK 
WRITE: 0xFF ACK 
WRITE: 0xFF ACK 
WRITE: 0xFF ACK 
WRITE: 0xFF ACK 
WRITE: 0xFF ACK 
WRITE: 0x00 ACK 
I2C STOP BIT

I2C>[0xa0 8 0x4C 0x2D 0x1E 0x04 0x33 0x32 0x59 0x4d]
I2C START BIT
WRITE: 0xA0 ACK 
WRITE: 0x08 ACK 
WRITE: 0x4C ACK 
WRITE: 0x2D ACK 
WRITE: 0x1E ACK 
WRITE: 0x04 ACK 
WRITE: 0x33 ACK 
WRITE: 0x32 ACK 
WRITE: 0x59 ACK 
WRITE: 0x4D ACK 
I2C STOP BIT
I2C>

Notice how this commands writes 8 bytes, starting at the addresses 0 and 8. Naturally, you could also just write only one byte if you want. In my case, this fixes the whole 16 bytes of the broken EDID header.

Conclusion

Now that the EDID is fixed you should be able to connect your monitor again and everything should work as before. Congratulations!

8 thoughts on “HOWTO: Fixing a broken EDID EEPROM with a Bus Pirate v4

  1. This is a great idea, but I’m not sure you’ve actually fixed your EDID at this point. I suspect if you only wrote bytes 0-15 of the other monitor’s EDID, you’ve borked the checksum, because some of those bytes are a serial # (going on to bytes 16-17). So you probably need to write 16-17 from the other monitor, and swipe its checksum also and write it into byte 127. (And of course, verify that no other data is different.) Alternatively, calculate the new checksum, which is pretty simple: sum up all bytes of the EDID except for the checksum byte, take the remainder from 256 and subtract from 256, and that’s your checksum byte — it should add up such that the sum of each 128 byte block is evenly divisible by 256.

    1. You are totally correct. I did this write up after I fixed the monitor. As I wrote I have several monitors and each monitor also has VGA. The VGA EDID of the broken monitor was still OK. Using that EDID you’ll naturally use the old serial number – and the check sum is fine. Unfortunately, I wrote the article after I had fixed the monitor and mixed it up a bit. I’ll fix the article accordingly.

      Btw: You won’t have to calculate the checksum yourself, edid-decode also warns you and gives the correct checksum.

      1. Ah, that’s handy then. I’ve just seen cases where the PC detects a valid EDID header (the 00 FF FF FF FF FF FF 00) and then when the checksum is bad, it tries again… and again… and never gives up and causes issues.

  2. Awesome writeup! I just fixed the checksum on my ViewSonic VX2025wm monitor. Linux kept choking on it because of the checksum so I calculated it and it was different than what was programmed. After replacing just that one byte, my monitor works like a champ! Many thanks for writing this up.

      1. YUP, I used my BP v3 and just modified the commands a bit to match. I have now had to do this to both of my monitors (same model) to fix this problem. I have even gone ahead and made a cable that has the 10pin header on one end and a VGA connector on the other, so all I have to do next time is plug it in rather than trying to pin it out. I am sure it will come in handy again some time… :)

        Thanks again for the awesome writeup!

  3. Hi Tamagotono,
    I used your site as reference to fix edid of my fujitsu siemens monitor.. it had single byte in name set to ff breaking checksum.. and I couldn’t use dvi connector on linux/windows without some configuration changes.
    I user Rasberry Pi instead buspirate

    I used raspbian:
    to see available addresses:
    i2cdetect -y 0
    to dump edid:
    i2cdump -y -r 0×00-0x7f 0 0×50
    and finally to set (in my case) wrong byte to right value:
    i2cset -y 0 0×50 0×78 0×44

    Just wanted to say thanks, and someone might find this info usefull

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>