Saturday, November 9, 2013

I²C over HDMI

The Raspberry Pi contains several I²C interfaces for accessing peripherals such as sensors, DA-converters or EEPROMs. Two interfaces are accessible via P1 and P5. A third interface is integrated in the HDMI interface. It is disguised as Display Data Channel (DDC), but is nothing than a conventional I²C interface. The integration into the HDMI interface provides the possibility to transmit video, audio and control information via a single cable. Possible applications are reading out the capabilities of your monitor via EDID or controlling brightness and contrast.

In particular, it is interesting if you are planning to build a display for the Raspberry Pi. In this case it is very helpful to have an additional data channel for example to control a backlight circuit. Yet, it is more difficult to use than the other I²C interfaces of the Raspberry Pi and some precautions must be taken:

  • It might break your monitor irreparably: Via DDC it might be possible to set a monitor in an invalid state with no hope of recovery.
  • It might interfere with the GPU: The GPU of the Raspberry Pi claims full control over the DDC interface. Accessing it from the CPU might cause problems.
  • In contrast to the other I²C interfaces, it has a 5 V high level. You might want to use level shifting.

Physical Access

Since this interface is accessible via the HDMI connector, you can not just use jumper wires to access it. If the device you want to connect to, has an HDMI connector (e.g. if you want to control a monitor via DDC) you can skip this section. The same applies if it has a DVI connector, because a DVI-HDMI adapter forwards the according lines.

Building an own device is more complicated, because most HDMI connectors have 0.5 mm pitch SMD pins. For testing purposes it is more convenient to build an adapter from a HDMI cable. Get a short, cheap HDMI cable, cut it through and remove jacket and shield.

Now you have to solve a little riddle to match the pins to the correct wires. Apparently you can not rely on the colors. At least for my assignment I could not find any matching color scheme on the Internet. Therefore, I used a multimeter to identify which pin is connected to which wire. Have a look at Wikipedia to get the pin out. It helps to know, that the TMDS channels (Data 1-3, Clock) are seperately shielded. I soldered the wires to a pin header and can now access the HDMI interface via jumper cables. Luckily, there is also a 5 V line available that can be used to drive your circuit. Although, it must not consume much current (below 50 mA).

Kernel Patching

Because of these mentioned drawbacks, the current kernel does not support this I²C interface. You have to apply this patch to the rpi-3.10.y branch:

mkdir linux
cd linux
git init
git fetch git:// \
git checkout rpi-3.10.y

patch -p1 < 0001-Add-support-for-BSC2.patch

Then compile and copy it to the Raspberry Pi as described at You can now access this I²C interface as bus 2. The following should give you an overview about the I²C modules connected via HDMI.

sudo modprobe i2c-dev
sudo i2cdetect 2

Monday, November 4, 2013

I²C Level Shifting

A common problem with I²C is level shifting. For example the Raspberry Pi has a 3.3 V I²C interface. Connecting a 5 V I²C interface will break the Raspberry Pi. There are many possibilities, including explicit level shifting ICs. In this post I will describe a very elegant way that works quite nice and only uses two N-channel MOSFET transistors. Those should be part of every electronics toolbox. I use 2N7002 transistors, but many others should do the job, too. The source of this is an application note of NXP.

Easy I²C level shifting

The connection is the same for SDA and SCL line as depicted above. All SDA and SCL pins of 3.3 V devices should be connected to the source of the respective MOSFET while the pins of 5 V devices are connected to the drain. The gates should be connected to 3.3 V. The resistors are the I²C pull-up resistors that should be used anyway. You might want to experiment with other values to get more speed or better reliability. For me those values work quite good and enable a reliable connection of I²C devices at different voltages.

Theoretical Background

I²C is based on open collector outputs. Pull-up resistors to the positive supply make the default state high. Each IC connected to the bus can pull down the line to low. When no device accesses the I²C bus, the voltage is pulled up to the respective high voltage. This is 3.3 V on the left side and 5 V on the right side. Therefore, gate and source are on the same voltage level. No current can flow between drain and source, because the MOSFET channel is not conducting. Therefore, no damage will happen.

This changes when a 3.3 V device pulls down the line. The voltage between gate and source (Vgs) rises to 3.3 V. Now current flows from drain to source until the drain is pulled down, too. Both sides are now at low level as intended by the 3.3 V device. When a 5 V device wants to pull down the line, the process is slightly different. Since a MOSFET contains an implicit body diode, current starts flowing as soon as the source voltage is higher than the drain voltage. Vgs rises and the voltage is further pulled down until both sides are at low level.