Playing with DDC I2C – Part 2

In Part 1 I could read the EDID of my LG TV with couple of C code lines. Of course that’s quite boring, so I’m going to use it to read and program an I2C EEPROM I had lying around.


As my laptop has a full-size HDMI and I had one damaged matching cable lying around, I decided to use this interface.

First thing first, getting the pinout of the HDMI connector! For this purpose, is one of my favorite source of information. It’s quite complete and even has infos on some exotic plugs.
During my search for infos on the Internet I found another similar project probably more Apple-oriented, and they also have a very nice and clean pinout:

HDMI, DVI and VGA I2C pinout.

The problem with HDMI is, there is not standard color code for cables. This means you have to check all wires with a multimeter to know who’s who. In the end my cable had the following wiring:

Wire Color Function Pin
shield GND 17
Brown SDA 16
Yellow SCL 15
Red +5V 18

Quite strangely this coding seems to be quite common in cheap HDMI cables on aliexpress… who knows. But you’d better check your own cable!

Now with an old breadboard and some tape I hooked up the 24C02N 256 Bytes EEPROM I salvaged from an older project (there’s also a much bigger 1Mbit 24LC1025 next to it awaiting for it’s fate), all quick and dirty:

Not my cleanest work.

Not my cleanest work.

EEPROM Protocol

The interface with the EEPROM is quite close to what you get from the regular file manipulation functions from stdio. Each time you read data from it, an internal file pointer is updated to the next data, just as it would work with the fgetc() function. There is another function that updates this pointer to a specified location, just like fseek() would do.
Of course, the comparison stops there. For instance, maximum 8 Bytes can be written in a row, and there is no way to read where the file pointer is. Also, the file pointer will rollover past the EEPROM capacity, no EOF flag here! The main functions are the following:

  • Read data : read 1 to 256 Bytes in a row
  • Set the file pointer
  • Set the file pointer + write 1 to 8 Bytes (it has to be page-aligned)

Although minimal, the functions set is just enough to drive our tiny EEPROM.

Playing with 256 Bytes

There isn’t much you can put in a 256Bytes EEPROM, really. Generally it’s the kind of chip you use in embedded electronics to store simple static parameters, like a MAC address or a serial number for example. You can also find similar ones in the Serial Presence Detect of your PC’s RAM sticks.
Still it’s a simple component to start with!
I’ll probably play with OLED screens and stuff later 🙂

Reading the EEPROM

This is really close to the EDID dump we did in Part 1. Only difference here is that you need to set the file pointer of the EEPROM first! Otherwise, you have no track of what byte comes from where. So we just had to add the following lines:

 buffer[0] = 0;
if(write(file, buffer, 1) != 1)
printf("error: %s\n", strerror(errno));

Basically this is writing one Byte on the I2C bus, at the EEPROM address. This will set the file pointer address to the beginning of the memory, so next byte we will read will be the first one.

The code is on GitHub for the most curious of you.

Writing the EEPROM

Now writing is a bit more complex, because of this page-aligned stuff. If you don’t care about speed, you could simply rely solely on the ‘write single byte’ function “fputc()” and call it in a loop; but EEPROM is sloooow… each write takes 5ms according to the documentation. Given timing cannot be guaranteed, you better take some room (I choose 8ms).

Now funny thing: the EEPROM has an internal write pointer you set at the beginning of the write function. For each Byte you write in the EEPROM, the 3 Less Significant Bits of the pointer are incremented. Here are a couple of examples:

Write address Lenght Bytes written
0 8 0, 1, 2, 3, 4, 5, 6, 7
5 2 5, 6
5 5 5, 6, 7, 0, 1

Yup, this stupid file pointer rolls over at (address % 8) == 0… So, if you start writing at address 0, (or 8, 16 …) you can write 8 Bytes, but if you start at address 5 (13, 21…) you can write only 3 Bytes. So, we need to determine how many bytes we can write with two lines:

nbytes = 8 - (address % 8);
nbytes = (len < nbytes ? len : nbytes); // choose min

First, we set nbytes as the maximum length we can safely write without roll over. Then we keep the min with the length that remains to write. Simple!

The ee24c02_write() does most of the job. It cuts a big write in multiple ones that respect the boundaries of those 8-Bytes pages. Then the page write function simply writes the I2C slave address, then the file address, then the 1 to 8 bytes of data to write into the EEPROM.

As always, the code is available on GitHub.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s