Haven’t had much time to update the blog lately. All week I’ve been quietly grinding away at two basic issues: PAL VBI support for the em28xx chip, and identifying/addressing the HVR-1600 performance problem.

I often get questions from users along the lines of “how do you make boards work?”. Reverse engineering is a bit of a black art, but I figured I would offer some insight as to how the process works. If you don’t actually care how tuners are designed and how we figure out how to make them work, stop reading now. If this stuff interests you, read on, and feel free to put something in the comments if you want to see more posts of this nature. I’m still gauging whether there is enough interest in this topic for me to go through the work associated with writing about it.

So let’s take a step back for a moment: what am I trying to accomplish? In this case, there have been reports for quite a while that the Linux tuning performance of the HVR-1600 is worse than under Windows. In fact, people have pointed out that the SNR being reported is about 3dB lower under Linux. This results in visual artifacts being displayed, as well as not being able to hold a signal lock on weaker signals.

In this case, my suspicion is that either the mxl5005s silicon tuner or the cx24227 demodulator is not being configured properly. So the logical approach would be to see how it’s programmed under Windows, and compare that to how it’s programmed under Linux.

But then I hear you screaming, “But wait! You don’t have the source code to the Windows driver, so how do you know how the tuner and demod are configured?” Well, that depends. If it were a USB device, I would use a tool such as SniffUSB 2.0 to capture the USB traffic, and then decode the i2c traffic to see how the register is programmed. In this case, it’s a PCI card, so I cannot just look at the bus. Now what?

“When in doubt, use brute force.”

This next step needs you to think like a hardware developer. Hardware designs don’t work overnight. They aren’t magical, and like software they can have problems and need to be debugged. As a result, hardware engineers often add what are known as “test points” to a printed circuit board design. This makes it easier for him/her to poke around with an oscilloscope or attach debugging hardware. On debug boards, test points have pins attached. On production hardware, the test points are often still there but they simply don’t populate the board with the pins, since they are not needed and add cost to the bill of materials.

So, were the Hauppauge engineers who designed the HVR-1600 thinking about how they were going to be able to debug the design? Apparently so:

[lightbox title=”Em28xx PAL VBI” href=”../../blog/wp-content/uploads/2009/10/hvr1600tp-300×225.jpg”] [/lightbox]

Oh look, two through-holes on the board marked “TP10” and “TP11”, right next to the EEPROM? Could those pins expose the HVR-1600’s i2c bus? Yup.

But don’t I need thousands of dollars worth of special hardware in order to read the i2c bus? Well, logic analyzers used to be really expensive, but now you can get a very capable logic analyzer for less than $200. In fact, I bought my Saleae Logic from SparkFun Electronics for $149.95. Break out your soldering iron, hook up a couple of pins, and start capturing i2c traffic. This approach lets you record the traffic using the same method regardless of whether you are under Windows or Linux. The logic analyzer even has the ability to decode the i2c traffic and export the data in CSV format to a text file:

Time [s],Event

"1.5155000",Start

"1.5155200",Setup write to 0x19. +ACK

"1.5156900",Wrote 0xF2 to 0x19. +ACK

"1.5158650",Wrote 0x00 to 0x19. +ACK

"1.5160350",Wrote 0x00 to 0x19. +ACK

"1.5162200",Stop

"1.5162250",Start

"1.5162450",Setup write to 0x19. +ACK

"1.5164200",Wrote 0xFA to 0x19. +ACK

"1.5165900",Wrote 0x00 to 0x19. +ACK

"1.5167650",Wrote 0x00 to 0x19. +ACK

"1.5169450",Stop

...



The raw data isn’t particularly easy on the eyes, but with a bit of Perl-Fu, you can turn it into something much more manageable:



0xF2 0x00 0x00

0xFA 0x00 0x00

...



A look at the existing s5h1409 driver shows that the first byte is the register address, followed by a 16-bit value. Since we are interested in the state the registers were left in when I stopped the capture, we need to weed out all the older register writes. Perl comes to the rescue again. Just spin over the file, and load the values in to a hash with the first byte as the key:

while (my $line = <FILE>) { chomp $line; my @vals = split / /, $line; $final{$vals[0]} = \@vals; }

Take the resulting captures for both Windows and Linux, pass it through sort and diff, and what do we get?



root@ubuntumb:~/1600traces# diff nbcwin1.txt.final nbclin1.txt.final

26,27c26

< 22 0x2F

< 25 0x36

---

> 22 0x3F



We went from a 1780 line analyzer capture, down to a file with 94 mxl5005s registers writes, down to a five line file showing the two mxl5005s registers that are programmed differently. Total code required: 64 lines of Perl.

The diff for the s5h1409 register was a little longer (eight registers), but it’s still much easier to use some regex magic to avoid having to hand inspect and compare over two hundred register writes.

As a test, we can now just hack a few register writes into the driver right after the tuning command and see if it works…. Yup. I’m now getting an extra 3dB compared to before I tweaked the driver. Now I just have to work backward and understand why the Linux driver programmed the chip with different values.

Total time spent from plugging in my soldering iron to verifying the 3dB improvement under Linux: most of Sunday afternoon.

I hope some of you have found this little tutorial informative/educational. If so, feel free to leave a comment saying so, as this will tell me whether anybody actually cares about this stuff and whether I should write about it in the future.