Playing with DDC I2C – Part 1

There is an interesting feature on VGA, HDMI or DVI ports called DDC. This is a simple communication channel between your screen and your computer that allows the latter to retrieve informations such as resolution and framerate.

Good thing about it, you can use it as a I2C bus (under Linux at least). As I figured it out later, I’m not the first one to do it (of course) and guys at POD-Bot did very similar stuff here. Anyway, having an I2C bus directly on my computer will allow me to connect lots of stuff to it.

Necessary Tools

There isn’t much, really. i2c-dev is probably already installed on your system, otherwise it should be available in most distro’s repos. All you really need is i2c-dev’s headers, and i2c-tools to scan and read I2C bus and devices.

Under ubuntu, (I use Kubuntu 14.04) two line in a terminal will get you all you need:

sudo apt-get install i2c-tools
sudo apt-get install libi2c-dev

Playing with EDID

Now I have i2c-dev ready, let’s load it

sudo modprobe i2c-dev
ls /dev/i2c-*

this gives me 8 i2c ports, from /dev/i2c-0 to /dev/i2c-7.  This is looking good!

Now, which one is on my HDMI connector?
Well, to figure it out, I used i2cdetect on each of the /dev/i2c-* devices:

sudo i2cdetect -y 0sudo i2cdetect -y 1...

Most of the busses seems to have no devices responding… which is quite weird as lots of power management chips on the mainboard (Fan controllers etc) use I2C/SMBus. Anyway, let’s plug in a HDMI screen and run the commands once more:

sudo i2cdetect -y 3
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

Aha! We have a device at address 0x50 on bus /dev/i2c-3, which is the address used for EDID chips. Now we have our bus, we can try reading it

sudo i2cdump -y 3 0x50
No size specified (using byte-data access)
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: 00 ff ff ff ff ff ff 00 1e 6d d7 3a 01 01 01 01 ........?m?:????
10: 02 0e 01 03 80 5d 34 96 0a f3 30 a7 54 42 aa 26 ?????]4???0?TB?&
20: 0f 48 4c ff fe 80 4c cf 31 5e 45 5e 61 59 71 40 ?HL.??L?1^E^aYq@
30: 71 4f 81 40 81 80 d6 09 80 a0 20 e0 2d 10 08 60 qO?@?????? ?-??`
40: 22 00 12 8e 21 08 08 18 8c 0a d0 8a 20 e0 2d 10 ".??!??????? ?-?
50: 10 3e 96 00 c4 8e 21 00 00 18 00 00 00 fc 00 4c ?>?.??!..?...?.L
60: 47 20 54 56 0a 20 20 20 20 20 20 20 00 00 00 fd G TV? ...?
70: 00 32 55 1f 45 0b 00 0a 20 20 20 20 20 20 01 cb .2U?E?.? ??
80: 02 03 1a 72 23 09 07 02 47 81 03 05 14 13 12 04 ???r#???G???????
90: 83 01 00 00 65 03 0c 00 10 00 01 1d 80 18 71 1c ??..e??.?.????q?
a0: 16 20 58 2c 25 00 c4 8e 21 00 00 9e 01 1d 80 d0 ? X,%.??!..?????
b0: 72 1c 16 20 10 2c 25 80 c4 8e 21 00 00 9e 01 1d r?? ?,%???!..???
c0: 00 bc 52 d0 1e 20 b8 28 55 40 c4 8e 21 00 00 1e .?R?? ?(U@??!..?
d0: 8c 0a d0 90 20 40 31 20 0c 40 55 00 c4 8e 21 00 ???? @1 ?@U.??!.
e0: 00 18 01 1d 00 72 51 d0 1e 20 6e 28 55 00 c4 8e .???.rQ?? n(U.??
f0: 21 00 00 1e 00 00 00 00 00 00 00 00 00 00 00 50 !..?...........P

You can read “LG TV” in the data so we’re probably good!

I2C access in C

Using libi2c-device, It’s not really difficult to do. You don’t have to write Kernel drivers or anything, which simplifies greatly the development. For really simple cases (no repeated START conditions for example), the “API” will be very simple:

open: open file /dev/i2c-n and get a file descriptor id
ioctl(file, I2C_SLAVE, address):  set the I2C slave (device) address (this is the only tricky part)
read/write: read and write bytes to the I2C device

All in all, a single C source file barely makes it to 50 lines of code, including error handling etc. I did not bothered copying it here, GitHub is better for displaying source code.
Funny enough, similar program is around 5 lines of code in python 🙂

Here is the output of my tiny program:

sudo ./edid.bin /dev/i2c-3
DATAT :
00 FF FF FF FF FF FF 00 1E 6D D7 3A 01 01 01 01
02 0E 01 03 80 5D 34 96 0A F3 30 A7 54 42 AA 26
0F 48 4C FF FE 80 4C CF 31 5E 45 5E 61 59 71 40
71 4F 81 40 81 80 D6 09 80 A0 20 E0 2D 10 08 60
22 00 12 8E 21 08 08 18 8C 0A D0 8A 20 E0 2D 10
10 3E 96 00 C4 8E 21 00 00 18 00 00 00 FC 00 4C
47 20 54 56 0A 20 20 20 20 20 20 20 00 00 00 FD
00 32 55 1F 45 0B 00 0A 20 20 20 20 20 20 01 CB
02 03 1A 72 23 09 07 02 47 81 03 05 14 13 12 04
83 01 00 00 65 03 0C 00 10 00 01 1D 80 18 71 1C
16 20 58 2C 25 00 C4 8E 21 00 00 9E 01 1D 80 D0
72 1C 16 20 10 2C 25 80 C4 8E 21 00 00 9E 01 1D
00 BC 52 D0 1E 20 B8 28 55 40 C4 8E 21 00 00 1E
8C 0A D0 90 20 40 31 20 0C 40 55 00 C4 8E 21 00
00 18 01 1D 00 72 51 D0 1E 20 6E 28 55 00 C4 8E
21 00 00 1E 00 00 00 00 00 00 00 00 00 00 00 50

Yep, that looks pretty much like the result of i2cdump!

Checkout the source code on my GitHub repository

Advertisements

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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