HDMI CEC interface

HDMI Consumer Electronics Control is a one wire bus which allows a CEC enabled device to control basic functionality of all other CEC enabled devices connected together.

I want to build an Arduino interface to the CEC bus for receiving and sending signals and controlling my home theater system via my HTPC connected to an Arduino.

While adept at software engineering, my EE skills are much more limited so I'm asking for help on how to best interface the Arduino to match the signalling of the CEC bus.

Here is the electrical specification according to the spec:

Description Value
Maximum Output Voltage Logic '0' +0.6v
Minimum Output Voltage Logic '0' 0v
Maximum Output Voltage Logic '1' +3.63v
Minimum Output Voltage Logic '1' 2.5v
High to Low Input Voltage Threshold
Logic '0'
Vcecin('0') >= +0.8v
Low to High Input Voltage Threshold
Logic '1'
Vcecin('1') <= +2.0v
Typical Input hysteresis +0.4v
Maximum rise time (10% to 90%) 250 microseconds
Maximum fall time (90% to 10%) 50 microseconds
Internal device pull-up: 27k ohms +- 5% or equivalent (eg a current source); or 25k ohms +- 10% when integrated

This has been done before with a (different) microcontroller here: rainshadowtech.com/default_files/HDMICECUSB.htm

If I can get past the electrical interface problems I have no doubt I can implement all of the bit signaling stuff in software.

Thanks!

Amazing timing, I've been looking into exactly the same application the last several days. Like you, I'm stronger on the software side than the hardware side.

I have some notes at: (new user, can't post link in first post, see followup post)
Just today I started to look at using Arduino for this, and google turned up your post.

As linked in my notes, NXP makes a CEC to i2c bridge chip. Arduino has an i2c library (Wire.h) that Keith writes about on his blog: (see follow up post for link)

The upside is that the NXP chip appears to be cheap (though I can't relocate the link where I saw a price).

The downside is that the NXP chip is in a TSSOP package, with .65mm lead spacing, far beyond my capabilities to solder into a circuit.

My thoughts at this point are investigating whether a site like SparkFun would be interested in selling DIP breakout board with the chip mounted, sort of like what Keith did here: (see followup post for link)

Here are the links I couldn't put in my first post:

Notes:
http://www.andrewncarr.com/hdmi-cec.html

Keith's i2c blog post:
http://www.neufeld.newton.ks.us/electronics/?p=241

Keith's breakout board post:
http://www.neufeld.newton.ks.us/electronics/?p=239

TSSOP isn't too hard if you have the right equipment. TSSOP breakout boards aren't hard to come by either. I haven't found a supplier that stocks the chip though.

A IC solution would be way preferable than a custom solution. I'll keep looking to see if I can find the chip.

I'm very interested in this project, too. I'd be happy to help with some of the code. Any updates on where to get the chip?

Also, would it be possible to generate the CEC through a software-only driver?

Thanks,

Richard.

I may have found a source:

They have 0 in stock, but a minimum order quantity of 1 unit. I just ordered 5, so we'll see if they come through. Only 1.68 each.

Definitely let us know if it ships! If it does, I'll place an order right away.

Hi,

the TDA9950 chip might make it somewhat simpler, but it isn't really necessary. It only handles the lower level of the CEC protocol (sending / receiving messages) and not even the EDID handling for obtaining the own physical address.
This can also be handled directly with two I/O pins of the Arduino.

I used the curcuit from the TDA9950 spec and made the following curcuit for the Arduino:

I haven't tested it yet, I only did some Spice simulation!

Here the LTSpice IV model of the curcuit:

Version 4
SHEET 1 1560 736
WIRE 1136 -208 864 -208
WIRE 512 -160 176 -160
WIRE 864 -160 864 -208
WIRE 864 -160 512 -160
WIRE 896 -160 864 -160
WIRE 512 -144 512 -160
WIRE 1136 -112 1136 -128
WIRE 864 -48 688 -48
WIRE 512 -16 512 -64
WIRE 176 0 176 -160
WIRE 384 80 304 80
WIRE 512 80 512 48
WIRE 512 80 448 80
WIRE 688 80 688 -48
WIRE 688 80 512 80
WIRE 1136 96 864 96
WIRE 864 128 864 96
WIRE 864 128 800 128
WIRE 928 128 864 128
WIRE 800 160 800 128
WIRE 1136 192 1136 176
WIRE 688 224 688 80
WIRE 512 256 512 80
WIRE 800 256 800 240
WIRE 928 256 800 256
WIRE 64 304 32 304
WIRE 176 304 176 80
WIRE 176 304 64 304
WIRE 192 304 176 304
WIRE 304 304 304 80
WIRE 304 304 272 304
WIRE 448 304 304 304
WIRE 800 320 800 256
WIRE 64 352 64 304
WIRE 688 368 688 304
WIRE 736 368 688 368
WIRE 752 368 736 368
WIRE 512 400 512 352
WIRE 688 416 688 368
WIRE 800 432 800 416
WIRE 880 512 800 512
WIRE 64 528 64 432
WIRE 512 544 512 480
WIRE 688 544 688 480
WIRE 800 544 800 512
WIRE 64 656 64 608
FLAG 32 304 CEC_OUT
IOPIN 32 304 In
FLAG 896 -160 VDD3.3V
IOPIN 896 -160 In
FLAG 864 -48 CEC_LINE
IOPIN 864 -48 BiDir
FLAG 512 544 0
FLAG 64 656 0
FLAG 800 544 0
FLAG 928 256 CEC_IN
IOPIN 928 256 Out
FLAG 688 544 0
FLAG 928 128 VDD5V
IOPIN 928 128 In
FLAG 1136 -112 0
FLAG 1136 192 0
FLAG 880 512 CEC_GND
IOPIN 880 512 BiDir
SYMBOL res 160 -16 R0
SYMATTR InstName R1
SYMATTR Value 20k
SYMBOL res 288 288 R90
WINDOW 0 0 56 VBottom 0
WINDOW 3 32 56 VTop 0
SYMATTR InstName R3
SYMATTR Value 100k
SYMBOL res 496 384 R0
SYMATTR InstName R4
SYMATTR Value 220
SYMBOL res 496 -160 R0
SYMATTR InstName R5
SYMATTR Value 27k
SYMBOL diode 496 -16 R0
WINDOW 0 49 28 Left 0
SYMATTR InstName D1
SYMATTR Value 1N4148
SYMBOL npn 448 256 R0
SYMATTR InstName Q1
SYMATTR Value BC547B
SYMBOL cap 448 64 R90
WINDOW 0 0 32 VBottom 0
WINDOW 3 32 32 VTop 0
SYMATTR InstName C2
SYMATTR Value 47p
SYMBOL voltage 64 336 R0
WINDOW 3 7 109 Left 0
WINDOW 123 0 0 Left 0
WINDOW 39 8 138 Left 0
SYMATTR InstName V2
SYMATTR Value PULSE(0 5 80m 3n 3n 500u 5000u 5)
SYMATTR SpiceLine Rser=100
SYMBOL npn 736 320 R0
SYMATTR InstName Q2
SYMATTR Value BC547B
SYMBOL res 784 416 R0
SYMATTR InstName R8
SYMATTR Value 1k
SYMBOL res 784 144 R0
SYMATTR InstName R10
SYMATTR Value 100k
SYMBOL res 672 208 R0
SYMATTR InstName R11
SYMATTR Value 1Meg
SYMBOL voltage 64 512 R0
WINDOW 3 8 109 Left 0
WINDOW 123 0 0 Left 0
SYMATTR InstName V1
SYMATTR Value PULSE(0 2.5 40m 10m 10m 2m 30m 1)
SYMATTR SpiceLine Rser=0
SYMBOL cap 672 416 R0
SYMATTR InstName C4
SYMATTR Value 47p
SYMBOL voltage 1136 -224 R0
WINDOW 3 41 54 Left 0
WINDOW 123 0 0 Left 0
SYMATTR InstName V3
SYMATTR Value 3.3
SYMATTR SpiceLine Rser=0
SYMBOL voltage 1136 80 R0
WINDOW 3 41 54 Left 0
WINDOW 123 0 0 Left 0
SYMATTR InstName V4
SYMATTR Value 5
SYMATTR SpiceLine Rser=0
TEXT 182 544 Left 0 !.tran 0 100m 0 startup
TEXT 856 288 Left 0 ;connect to ATMega pin PD2\n(pin 2 on Arduino board)
TEXT -176 240 Left 0 ;connect to ATMega pin PD3\n(pin 3 on Arduino board)
TEXT 192 504 Left 0 ;for test of the curcuit
TEXT 848 544 Left 0 ;connect to "DDC/CEC Ground"\npin of the HDMI cable
TEXT 840 -16 Left 0 ;connect to CEC pin\nof the HDMI cable
TEXT 912 160 Left 0 ;connect to +5V
TEXT 880 -128 Left 0 ;connect to +3.3V

The HDMI 1.3a specification (http://www.hdmi.org/download/HDMISpecification13a.pdf) describes the complete protocol. Maybe I have the time to play around with it.

MikeT

Hi Mike,
Looks like you've answered the original question of how to interface directly to the CEC bus!

The biggest advantages for the NXP chip as I see it is that it fully implements the the low level send/receive parts to spec, and also provides an interrupt pin to signal new activity. However, it still remains to be seen if the chip itself is available to mere mortals. That said, if you or someone else is capable of writing a good implementation I wouldn't complain about not having to solder a tssop chip! Wire.h might be a good starting point for design patterns.

I don't know what phil123's platform is, but I'm aiming for something I can use w/Linux. I'm thinking that it would be best to implement the higher level parts of the protocol on the PC side, and focus the Arduino code at providing a bridge.

Hi Andrew,

I want to use INT0 for a IRQ driven implementation, like a mixture of SoftwareSerial and Wire. From an application view there should be no difference between using the software solution and the TDA9950 solution.

There is another CEC to i2c chip from TI. The hardware is not so interesting, but the documentation of the state machines: http://focus.ti.com/lit/an/slaa377/slaa377.pdf

MikeT

Looks like I need to make a visit to Radio Shack. While the IC version would be easier to get going, I think ppl replicating this project would benefit much more from a direct Arduino implementation.

I ought to go down and see if radio shack has some equivalent NPN transistors and throw this together on my proto board. The first step would be to hook this thing up and interpret existing traffic. I have a CEC capable LG TV and a CEC capable sony bluray but I can't get them talking so I don't know how much useful traffic on the CEC wire I'll be able to get.

phil

Hi Phil,

the parts are not so critical. You can replace the 47pF capacitors by any value up to a maximum of 220pF.

The diode might be better replaced by a schottky type (1N5817, 1N5818, BAT54, ...) so the output voltage gets closer to 3.3V.

The only CEC component I own is a Sony TV KDL-46WE5B.

MikeT

Mike,
How important is the EDID communication beyond resolving our device ID? Looks like the rainshadowtech guy just polls the bus for a free ID and takes it, and the tv (sink) is typically device ID 0x00. As I understand it EDID is done over the DDC channel which is regular i2c, so in theory it shouldn't be too hard to properly resolve device ID etc.

As far as tapping into the CEC bus, there are two approaches:

  1. Function as a node, hdmi cable from our device to tv/etc
  2. Hijack the CEC pins between two connected devices and pass everything else through.

The first is probably better, less wiring involved and I imagine the tolerances are much stricter for the TMDS signals. This ties up an HDMI port, but they seem plentiful on most equipment these days.

As for communication, plugging into a device should expose the handshake responses. From what I've read, CEC is based on AVLink, each vendor has their own command set, not interoperable, though there was some initiative announced recently the define basic standards. I haven't seen much info on any vendors commands yet, mostly just focusing on the initial hurdle of being able to send and receive bytes to a device. I have a samsung tv myself. I'll start collecting whatever info I can find on the Bravia and AnyNet dialects.

That PDF is interesting, looks like the MSP430 is just a regular microcontroller, I discovered the TDA9950 is just software ontop of an NXP 8051 based microcontroller. Looks like a fully Arduino based implementation is the way to go.

Anyone recommend an easy to work with hdmi jack? I'll have to look through the Mouser catalog this evening and see what they've got.

Mike,
How important is the EDID communication beyond resolving our device ID? Looks like the rainshadowtech guy just polls the bus for a free ID and takes it, and the tv (sink) is typically device ID 0x00. As I understand it EDID is done over the DDC channel which is regular i2c, so in theory it shouldn't be too hard to properly resolve device ID etc.

My goal for CEC is to implement CEC functionality for an hdmi connected computer (HTPC) which itself doesn't support CEC. Therefore, the easiest thing for me is to find out the computer's physical address and act appropriately.

As far as tapping into the CEC bus, there are two approaches:

  1. Function as a node, hdmi cable from our device to tv/etc
  2. Hijack the CEC pins between two connected devices and pass everything else through.

Acting as a full node would also mean implementing DDC/EDID for our device. This would give it a physical address as a node but becomes much more complex.

I have a elbow HDMI connector (male and female connectors on it). I plan on cracking the case, tapping CEC and CEC/Ground and allowing all else to pass through unmolested. That shouldn't affect the TMDS signaling (I hope!).

The first is probably better, less wiring involved and I imagine the tolerances are much stricter for the TMDS signals. This ties up an HDMI port, but they seem plentiful on most equipment these days.

Table 4-27 indicates it is allowable for a root device to implement a separate CEC line for each hdmi input, although this is discouraged. This is probably not likely implemented.

As for communication, plugging into a device should expose the handshake responses. From what I've read, CEC is based on AVLink, each vendor has their own command set, not interoperable, though there was some initiative announced recently the define basic standards. I haven't seen much info on any vendors commands yet, mostly just focusing on the initial hurdle of being able to send and receive bytes to a device. I have a samsung tv myself. I'll start collecting whatever info I can find on the Bravia and AnyNet dialects.

I'm not familiar with AVLink, but hdmi 1.3a supports a wide range of standardized opcodes as well as options for vendor specific codes. That being said, my LG tv won't talk to my Sony bluray. Unfortunately, without two LG devices and two Sony devices, I probably won't be able to determine any vendor specific opcodes for these devices. My concern is that a device will ignore opcodes from another device that doesn't have a matching vendor id.

Looks like a fully Arduino based implementation is the way to go.

Anyone recommend an easy to work with hdmi jack? I'll have to look through the Mouser catalog this evening and see what they've got.

I agree. I'm going to breadboard a circuit today and try hooking it up with the purpose of strictly monitoring CEC traffic and start looking into decoding it. I've read through the wire protocol and it shouldn't be too hard to implement.

Hi Andrew,

How important is the EDID communication beyond resolving our device ID?

The physical address (which has to be obtained via the EDID information) is needed, when the physical wiring of the devices is relevant, for example when switching to a specific HDMI input. Just look at the opcodes which require a physical address as parameter like and .

MikeT

Spending some time reading the spec more closely, I see that logical address and physical address are separate. EDID isn't too bad, I captured the response from my samsung tv, it looks like it assigns address based on HDMI port ID (HDMI 3 got 3.0.0.0, HDMI 4 got 4.0.0.0). The addresses are 16 bit not 32 bit, the familiar IP octet style formatting threw me for a moment.

The second block has the CEA extension containing the vendor specific data block. Bytes 1E..1F are the CEC address assigned.

      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
-----------------------------------------------------
0  | 00 FF FF FF FF FF FF 00 4C 2D 57 03 00 00 00 00
1  | 22 11 01 03 80 10 09 78 0A 1D ED A7 53 34 AC 25
2  | 12 47 4A 20 00 00 01 01 01 01 01 01 01 01 01 01
3  | 01 01 01 01 01 01 02 3A 80 18 71 38 2D 40 58 2C
4  | 45 00 A0 5A 00 00 00 1E 01 1D 00 72 51 D0 1E 20
5  | 6E 28 55 00 A0 5A 00 00 00 1E 00 00 00 FD 00 17
6  | 3D 1A 44 17 00 0A 20 20 20 20 20 20 00 00 00 FC
7  | 00 53 41 4D 53 55 4E 47 0A 20 20 20 20 20 01 F3

-----------------------------------------------------
      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
-----------------------------------------------------
0  | 02 03 22 71 46 90 04 05 03 20 22 23 09 07 07 83
1  | 01 00 00 E2 00 0F E3 05 03 01 67 03 0C 00 40 00
2  | B8 2D 01 1D 80 18 71 1C 16 20 58 2C 25 00 A0 5A
3  | 00 00 00 9E 8C 0A D0 8A 20 E0 2D 10 10 3E 96 00
4  | A0 5A 00 00 00 18 00 00 00 00 00 00 00 00 00 00
5  | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6  | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
7  | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 31

So far I've only found HDMI headers with smt .5mm pin spacing. Not impossible, but not super convenient.

A solid implementation would wire the CEC pins, DDC pins, and the hotplug pin, and do EDID for address resolution when the hotplug pin is triggered.

http://www.chsinteractive.co.uk/electrical-components/plugs-sockets-adaptors/hdmi-connectors/hdmi-plug-chrome-finish-metal-case-solder-connections-with-rubber-cable-protector-unbranded.htm

Is that any use?

Hi,

I hacked a first version of the code, but I can't test it with real hardware, because I'm still waiting for my cables.

The examples communicates with itself. CECprint() transmits data and ISR(DATA_INT_VECT_NAME) receives data. It is still work in progress (see the TODO comments). I'm looking for a IRQ driven solution for the transmission which does the work without blocking the main sketch.

The sketch accepts the following single letter commands via the serial interface (115200 baud!), please look also at processSerialInput():
1: set the CEC output to logical HI (ATmega pin 0V)
2: set the CEC output to logical LOW (ATmega pin 5V)
-: decrement own CEC address
+: increment own CEC address
q: send one byte (header only)
w: send 3 bytes
e: send 16 bytes
r: reset the state machine

You can download the first version here:
http://www.5dot1.de/arduino/CEC1.zip

MikeT

Update to previous post. I added some real commands:
'a': send "Standby" to broadcast address (0x0F)
's': send "Standby" to TV address (0x00)
'd': send "Image View On" to TV address. Switches on the TV

Updated version can be found here:
http://www.5dot1.de/arduino/CEC2.zip

MikeT

Another update which is more reliable:
http://www.5dot1.de/arduino/CEC3.zip

MikeT