

One problem with my HDMI Ambilight project is that it can’t handle encrypted content, or more accurately, it can only handle encrypted content if I spend a lot of money and get an HDCP license, which would then allow me to buy the version of the ADV7611 chip that has built-in HDCP keys. While this doesn’t cause me much of a problem as I tend to watch almost everything via MythTV, with the TV on the HDMI port and the HDMI Light on the DVI port, it would be nice to be able to use an HDMI splitter between my AV receiver and TV instead, and have it still work on the odd occasion when I watch a BluRay directly.

Luckily, my post announcing HDMI Light version 2 was featured on Hackaday, where a couple of people pointed out that it’s actually quite easy to disable the encryption in some HDMI splitters, effectively turning them into HDCP strippers. Even more helpfully, RoyTheReaper described exactly how to disable the encryption in an HDMI splitter I had lying around in my junk box.

While his method works perfectly as far as disabling the decryption is concerned, it has the side effect of also disabling all of the nice little extras that come with HDMI like automatic input switching and controlling the AV receiver volume from the TV remote. What I needed to do was find a way to let the microcontroller in the splitter continue to do all the other things it does while stopping it from enabling encryption.



The Basic Hack

RoyTheReaper’s instructions work for splitters that are based on the chip sets from Explore Semiconductor, such as the EP9132 in the splitter I had on hand. These splitters contain two chips: the main HDMI splitter (EP9132), which is usually hidden under a heatsink, and a microcontroller (EPF011A) which communicates with the splitter via I2C.

As it turns out, the splitter’s outputs are unencrypted by default regardless of whether the incoming signal is encrypted or not, and all that’s needed to disable encryption of the splitter’s output is to stop the microcontroller from talking to the main splitter chip. This can be achieved via any of a number of different methods, such as:

Put the microcontroller into boot loader mode by pulling pin 16 up to 3.3V before powering up the rest of the board.

powering up the rest of the board. Remove the 0 Ohm resistors that connect the microcontroller to the splitter’s I2C bus, or if they’re not present, just cut the traces.

Completely remove the microcontroller from the board.

The photo above shows the result of trying the first of these methods, I’ve got my bench supply applying 3.3V to pin 16 of the microcontroller, the input signal is the encrypted output of my Bluray player and both the TV and HDMI Light are receiving an unencrypted version… Success!

Unfortunately though, the microcontroller isn’t just there to turn on the encryption, so while this works perfectly for eliminating the encryption, it breaks a whole lot of other stuff:

The volume control on the TV remote no longer controls the AV Receiver volume

When the TV is the content source, such as running its built in iPlayer app, the AV Receiver no longer switches input to the TV

Even after manually switching the input, the sound from the TV doesn’t get to the AV Receiver, it should be sent via the Audio Return Channel (ARC)

Every time I press play on the Bluray player, the TV switches to the HDMI-1 input, instead of staying on HDMI-2 where it will actually receive a signal

The Bluray player now refuses to play any 3D content as it doesn’t think the TV is 3D capable

Finding A More Targeted Hack

What I needed was to find a way to keep the microcontroller doing all the other things it usually does, while still stopping it from enabling encryption of the outputs. As its only connection to the splitter chip was via the I2C bus, maybe I could intercept any attempts to enable encryption…

The datasheet for the EP9132 is fairly easy to find, and looking through it I could see that there really weren’t very many registers at all. Out of the few registers that there were, one immediately jumped out as interesting, bit 0 of register 0x0F (TX_ENC_ON), 1 = enable transmitter encryption, 0 = disable transmitter encryption.

As this was using an I2C bus where the data line defaults high, and the master and slaves communicate by pulling the data line low for a zero and leaving it to float high for a one, I thought I should be able to override any attempt by the microcontroller to set this bit to one by forcing the data line low at the right time. Then the microcontroller would think it had enabled encryption and carry on doing everything else it was supposed to be doing.

To do this I decided to use an Atmel ATTINY9 microcontroller, which is a tiny SOT23 package device with 6 pins, an internal 8MHz clock, 1KB of program space and 32 bytes of RAM. I connected the ATTINY to the splitter’s I2C bus and wrote some code to look for writes to register 0x0F, and force the data line low for bit 0 whenever it saw one.

Unfortunately this didn’t quite work. The ATTINY did successfully find the writes to the register, and it did succeed in forcing bit 0 low, but straight afterwards the microcontroller in the splitter would issue an I2C STOP where it never did before.

It turns out that the splitter’s microcontroller was doing exactly what the I2C specification says it should. Whenever it wanted the data line to be high it left it floating and watched for anything else pulling it low, when it saw me pulling the line low it detected a collision and aborted the transaction.

I2C Override, Take 2

So… I couldn’t just stomp over whatever the splitter’s microcontroller did on the I2C bus…

One option would be to split the bus and have my microcontroller bridge between the two, that way the splitter’s microcontroller would be allowed to write a one to the bus on its side, but I’d write a zero to the bus on the other side.

The trouble with this approach is that it would be a lot more awkward to implement, rather than just soldering two wires to the splitter’s PCB I’d have to cut the traces, solder four wires and add another pair of pull-up resistors, so I wanted to try and find another way.

The next possibility that came to mind was overriding the I2C slave (the main splitter chip) instead of the I2C master (the microcontroller), would the slave detect a collision? Was there actually anything useful to override?

Going back to the datasheet, I found another interesting looking register, bit 4 of register 0x07 (RX_ENC_ON), 1 = receiver is decrypting, 0 = receiver is not decrypting. Sniffing the I2C bus with my oscilloscope showed that the microcontroller was constantly reading this register, so probably it would enable encryption on the outputs whenever it saw that the receiver was decrypting.

I updated the code in the ATTINY to target this new register, and… success! I got unencrypted output.

The image above shows this hack in action, the red trace is a debug signal from my microcontroller that is high while it is forcing the I2C data line low.

Hang On, It was Working A Minute Ago

Now that I’d found a working hack, I moved away from the ATTINY on the breadboard that I’d been using to experiment and programmed another one which I soldered into the splitter, dead-bug style. I then took the splitter downstairs to my main TV to try it out, but it didn’t work. After a bit of fiddling about I discovered that it only worked on the first output, the second output was still encrypted.

This shouldn’t have been possible, I was overriding all attempts to enable encryption regardless of the output port. Back up on the workbench I was eventually able to capture the problem on the oscilloscope. Occasionally, the override of the I2C data line was late.

The images above show this. In these images the top trace is the I2C clock, the one below is the I2C data line and the yellow trace is the debug signal that goes high while the override is in effect.

The left image shows a successfull override, the override begins in the middle of the low clock period and stays low until part way through the following clock low.

The middle image shows a late override. Here the override doesn’t start until after the clock has already gone high, which means that if the splitter’s microcontroller is reading the value of the bit right after the clock transition then it will see a one and not the zero I want it to see. Not only is it allowing the one bit through for part of the clock cycle, but having the data transition from low to high during the time when the clock is high is also an I2C START signal.

The right image shows how often the override was late. Out of 4096 overrides, 41 were late, and their distribution (which can be seen by the red parts of the blue bars at the bottom of the image) appeared random.

It took me a long time to work out what the problem was. To start with I was convinced that the problem was due to noise and/or ringing on the bus. Especially as touching the wires on the breadboard seemed to fix the problem, and the microcontroller that I’d soldered into the splitter had twice as many late overrides as the one on the breadboard.

I tried adding a decoupling cap across the microcontroller’s power supply, and I added a series resistor between the microcontroller and the I2C clock. This seemed to fix the one on the breadboard, but the one soldered into the splitter still had a problem.

Eventually I worked out what the real problem was… my microcontroller was a bit too slow. It turns out that with an 8 MHz clock the ATTINY doesn’t have very many clock ticks, and therefore instructions, for each clock on the I2C bus. In my code I had the following loop:

// wait for clk low prevPins = pins; while((pins = PINB) & PIN_CLK) { // if data changes while clock is high then bail out // as it's a stop or a start if((pins & PIN_DAT) != (prevPins & PIN_DAT)) return 0; prevPins = pins; }

When the ATTINY was successfully overriding the bit, the clock was already low when the loop condition was first checked, and therefore the loop body was never executed. When the override was late, the clock wasn’t yet low and the loop body was executed once. With an 8 MHz clock the timing is so tight that executing those couple of lines in the loop body accounts for the observed delay.

The fix was simply to remove the body of the loop:

// wait for clk low prevPins = pins; while((pins = PINB) & PIN_CLK) ;

While this isn’t quite as correct as the original version as it won’t detect a START or STOP condition in the middle of the byte, that’s incredibly unlikely to happen, especially as this bit of code only runs during the transfer of the value of one specific register.

Fixing The Audio Return Channel (ARC)

After taking it back down to my main TV, things were looking much better.

Now I had both outputs reliably unencrypted and the majority of the niceties of HDMI were working. The TV was no longer switching to HDMI-1 when playing a Bluray, the TV remote could control the AV Receivers volume, the AV Receiver would switch to the TV input when running the iPlayer app on the TV… but I still wasn’t getting audio going back from the TV to the AV Receiver.

So, next I took a look through the HDMI specification (which is annoyingly hard to find a copy of) to see how the Audio Return Channel is supposed to work. From there I found that there were at least two things necessary for it to work:

The TV and AV Receiver had to discover that they were both ARC capable via the CEC (Consumer Electronics Control) bus. This is the same bus used for all the on/off, input switching, volume control, etc. so that part should be working. The actual audio could either be transferred via a single ended signal using the Utility pin (pin 6), or it could be transferred via a differential signal using both the Utility pin and the Hotplug pin. Looking at the splitter PCB, I could see that the Utility pin wasn’t connected to anything, which certainly helped explain why ARC wasn’t working.

If the TV was using differential signalling then there wasn’t much I could do, the Hotplug pin is already in use in the splitter for it’s primary function, which is to indicate that a cable is plugged in and that there is something on the end of it, by being pulled up to 5V. Even if I properly understood how to mix half of the differential audio signal onto a line pulled up to 5V (which I don’t), I’m sure the necessary modifications to the splitter would be quite extensive.

However, if the TV was using single ended signalling then I should be able to simply connect the Utility pin on the input of the splitter to the Utility pin on output 1. After using a bit of enamelled wire as shown in the image above, I got lucky and it works!

Still No 3D

At this point I had a splitter working nearly perfectly, the only thing missing was 3D support.

Unfortunately, from what I could tell from the specs, this should just be a case of the TV declaring itself capable via EDID, and if that wasn’t getting through then the splitter most likely didn’t understand that part of the EDID data and wasn’t passing it through.

So the lack of 3D wasn’t actually anything to do with the hack, the splitter just wasn’t 3D capable. Which only left one option… try again with another splitter…

I did a search on Amazon for a HDMI-1.4 and 3D compliant splitter and bought a Dynamode 2 port splitter. Initial testing without the hack looked good, 3D and everything else (with the exception of ARC, but I knew how to fix that) was working. Inside there was an EP9132, excellent! But… just after I installed the hack MCU… one of the HDMI connectors broke! One of the contacts had de-laminated.

As I couldn’t really send back a unit I’d already taken a soldering iron to, I bought another one… only to have the connector contacts de-laminate after a single insertion! Don’t buy Dynamode splitters, they’re cheap and nasty junk!

So… this time it was off to Ebay, where I found an unbranded splitter that was apparently 3D capable and fully HDMI-1.4 compliant. Without the hack this one was doing 3D fine, but no ARC, and no CEC either. Looking inside I could see that both CEC and ARC pins weren’t connected, but both could easily be fixed with a bit of enamelled wire. There was an Explore chip set too, but this time it was an EP9142 rather than EP9132.

Updating The Hack For The EP9142

After adding the wires to patch though the CEC and ARC signals, and programming and installing yet another ATTINY, I tried out this new splitter with some encrypted content. It didn’t work, I got a picture on the TV but the port connected to my HDMI Light was not giving a picture and the LED for that port was flashing. It looked like the microcontroller in this new splitter was still able to tell that the input signal was encrypted even with the hack overriding the RX_ENC_ON flag.

I went looking for a copy of the datasheet for the EP9142, which proved a lot harder to find than the one for the EP9132. I’ve still not found a downloadable copy but the Chinese Baidu search engine has a cached copy that can be viewed in its online PDF viewer (maybe there’s a download button there somewhere? it’s all in Chinese so I can’t tell).

The EP9142 has a few more registers exposed, but none of them looked particularly interesting. Eventually though, aided by finding a copy of the source code for the reference implementation firmware, I worked out what was happening.

As well as watching the RX_ENC_ON flag to see when the splitter chip is receiving encrypted content, the microcontroller in the new splitter was watching the RX_M0_RDY flag in bit 0 of register 0x40. This flag signals the end of HDCP negotiation between the receiver in the splitter chip and the video source. When the microcontroller sees this flag set it blanks the video output of the transmitters by setting TX_MUTE flag in register 0x08, and then begins an HDCP handshake with the devices connected to the transmitters. It only re-enables the video output by resetting the TX_MUTE flag once it successfully completes a HDCP handshake.

This explains why the TV was still getting a picture. It’s HDCP capable, so it completed the handshake and the output was un-muted. My HDMI Light on the other hand is not HDCP capable and would not have responded to the handshake, leading to the output remaining muted and the LED on the splitter flashing.

After updating the hack code to also override the RX_M0_RDY flag I was able to get unencrypted video output to any device.

Finally, Everything Works!

With that last change I now finally have a fully functional HDMI splitter that always outputs decrypted video. It has working CEC so on/off control, automatic input switching and AV Reciever volume control from the TV remote all work. The Audio Return Channel is working so the TV can send audio back to the AV Receiver, and 3D is working too.

The Files

The code for the ATTINY microcontroller can be found in my github repository here:

https://github.com/esar/hdmi-splitter-hack

Applying the hack should be as simple as programming an ATTINY9, connecting VCC and GND to a 3.3V supply within the splitter, connecting pin 1 to the I2C clock signal and connecting pin 3 to the I2C data signal.

The Splitters

In case it helps anyone find a suitable splitter here are the splitters that I’ve been using:

Neet 2 Way HDMI Smart Splitter

Dynamode 2 Port HDMI Splitter

This is the splitter that I started with, it’s based on the EP9132, CEC is functional straight out of the box, the utility pin is not connected so ARC can’t work without patching it through. If it wasn’t for the lack of 3D support this splitter would have been perfect. This exact model doesn’t seem to be available any more, it’s possible that the replacement is 3D capable.

Unbranded Ebay Special

Don’t buy this splitter! Functionality wise it’s fine, everything works bar ARC, but the connectors are junk, they’re also through-hole making them really hard to replace (I did try). It’s also advertised as being HDMI 1.4 compliant, but it uses the EP9132 which is not. It’s also enormous, you could fit 5 or 6 of the Neet splitters inside it.

This is the splitter that I’m now using. It’s based on the EP9142 chip, neither the CEC or Utility pins are connected but they’re easy to patch. I now have everything working with this splitter.