TSA5523 Tuner Modules from PC TV Cards

 Posted by:   Posted on:   Updated on:  2018-02-19T09:52:50Z

Use tuners from PCI TV cards for video and FM radio reception with Arduino or other I2C interface

Some of the previous posts show methods of generating analog video with microcontrollers and RF modulation of it using ready made modules. Analog video is no longer in use in most parts of the world. TV tuner cards for analog signals are no longer manufactured and old ones are difficult or impossible to install on newer computers because there are no drivers. Despite this, analog video capture devices are cheap and widely available. Most are USB dongles, with video and audio inputs, no tuner.

Since I had some old TV tuner cards that were no longer compatible with my PC or had poor performance, I decided to take the tuners out of them. To my surprise, different tuners from different manufacturers looked pretty much the same on the inside. All of them used the same integrated circuits. The tuners I found are actually complete receivers, with included demodulator. This means you can get analog audio and video straight from the module pins. There are also modules with FM support, with stereo decoder.

In the photo below, you can see two tuners. The top one has FM radio support. You can see that it's similar to the other, but the rightmost compartment has some additional filters for FM IF.

Tuners from TV cards
Tuners from TV cards
The tuners I got are Philips TCL2002MB-33F, LG TPI8PSB02P and LG TPI8PSB12P. The latter is TV only, with no radio support. Finding the pinout of these modules is not very hard if you analyze the board they came from. Anyway, further searching lead me to Philips FM1216, a similar tuner that uses the same ICs. Even without this, the datasheet for TSA5523 is available. This is the circuit that controls tuner frequency via I2C bus.

Functional modules of the TV tuner
Functional modules of the TV tuner
Let's take a look at how these modules work. The RF signal from antenna is split in three paths, then filtered and amplified for each of the frequency bands. There are three frequency bands. Band A is the lower half of VHF (this includes FM). Band B is the upper half of VHF and band C is UHF. For tuners with FM support, a switch connects FM antenna to band A input when FM mode is activated. The amplified and filtered signals are mixed with local oscillators. This happens inside TDA5737 IC. The PLL IC, TSA5523, samples frequency from the mixer and adjusts local oscillators. Coming out from the mixer, the selected IF signal is further amplified and filtered either by a TV SAW filter on 38.9 MHz or the FM IF filter on 10.7 MHz. Output from these filters enters TDA9809 or TDA9801 demodulator. The latter IC is TV demodulator only, while the other can demodulate FM radio too. If the tuner module has FM radio support, most probably it will have an extra IC, the TDA7040 for stereo decoding.

Pinout of TV tuner module TCL2002MB-33F
Pinout of TV tuner module TCL2002MB-33F
Before writing the software for communicating with the tuner, let's see how to wire it up. Above is the pinout for the TCL2002MB-33F tuner. Other tuners may or may not have all pins. I chose this one because it has FM support, therefore some additional pins for radio audio. There is a MUTE pin. This is not present on all devices, because TSA5523 features a GPIO port that can be used for this purpose. AFC and VT pins are in the same situation. AFC is sometimes sampled by TSA5523 integrated ADC input and VT is only for checking if the tuning voltage is present and changes according to frequency. SCL, SDA and AS are I2C bus pins. FMR and FML can be found only on tuner modules with FM stereo decoder. MPX contains baseband video signal straight from the demodulator, without any filters. This can be used by to decode VBI (teletext) data. CVBS is analog video output and AF is mono TV audio output. Some claim that while in FM mode, AF carries multiplexed audio with embedded RDS data. The modules is powered from 5V. The ground connects to the metal case.

Basic connection requires SCL and SDA to be connected to an I2C interface of a microcontroller, CVBS and AF to be connected to a capture card inputs via RCA jacks. All that's left is to power up the module.

According to datasheet, I2C address of TSA5523 is 0xC2 is AS pin is left floating. The IC has 4 write registers and 1 read register. Here is an overview.

Overview of TSA5523 registers
Overview of TSA5523 registers (refer to datasheet)
Divider bytes (DB1 and DB2) set frequency of the local oscillators. CP sets chargepump current and RSA/RSB set divider ratio (tuning step). Port bits P7, P5 and P4 select frequency bands. P3 controls muting. P2 and P0 control operating mode. When both are 0 (not set), the tuner works in TV mode. Setting P0 to 1 forces power down mode for TV demodulator.  To switch to FM mode, set P2 to 1. Then if you want to read ADC input, you will get AFC when P0 is 1 and received IF when P0 is 0. P1 forces mono mode. P6 should be 0, because it is configured as ADC input.

Read register contains some important bits. FL is 1 when tuner is locked to frequency. I1 reads mono/stereo status (1 means stereo). A2, A1 and A0 represent ADC readout.

Let's write some Arduino compatible code. First, for tuning TV channels. Control byte is set to 0xCA. This means CP=1 (higher chargepump current, recommended in TV mode) and RSA=0; RSB=1 (resulting in 31.25kHz frequency step). Ports bytes is set according to the band in which the frequency fits. To set frequency of local oscillator, IF is added to receiving frequency and the sum is divided by tuning step (31.25 in this configuration). The number 1245 in freq_khz formula comes from IF frequency 38900 divided by 31.25.
#define TSA5523_ADDR (0xC2 >> 1)
// tuner registers
byte db1, db2, cb, pb;

void tsa5523_setTVFrequency(uint32_t freq_khz) {
  // band bits
  if (freq_khz < 168000) pb = 0xA0; // band A, VHF-Lo
  else if (freq_khz < 448000) pb = 0x90; // band B, VHF-Hi
  else pb = 0x30; // band C, UHF

  // control
  cb = 0xCA;

  freq_khz = freq_khz / 31.25 + 1245;
  db1 = (freq_khz >> 8) & 0x7F;
  db2 = freq_khz & 0xFF;

  Wire.beginTransmission(TSA5523_ADDR);
  Wire.write(db1);
  Wire.write(db2);
  Wire.write(cb);
  Wire.write(pb);
  Wire.endTransmission();
}
In FM mode, we're always in band A. Chargepump can use lower current to improve SNR (set CP=0) and tuning step needs to be 50kHz to cover all channels. RSA and RSB are both 0. Some changes are required for ports byte. Band A (which includes FM) requires P7 and P5 to be set. P2 also needs to be 1. IF frequency is 10.7MHz now. The sum is divided by 50 (tuning step).
#define TSA5523_ADDR (0xC2 >> 1)
// tuner registers
byte db1, db2, cb, pb;

void tsa5523_setFMFrequency(uint32_t freq_khz) {
  pb = 0xa4; // band A only
  cb = 0x88;

  freq_khz += 10700;
  freq_khz /= 50;
  db1 = (freq_khz >> 8) & 0x7F;
  db2 = freq_khz & 0xFF;

  Wire.beginTransmission(TSA5523_ADDR);
  Wire.write(db1);
  Wire.write(db2);
  Wire.write(cb);
  Wire.write(pb);
  Wire.endTransmission();
}
To get tuner status, read one byte from the read address. If this status byte (SB) has bit 6 set, tuner is locked (SB & 0x40). Then you can assess bit 4 for stereo (SB & 0x10) and compute ADC readout (SB & 0x07). Note that ADC reads what you configured it with the ports byte.

Due to the capability of tuning to frequencies between 45 to 860 MHz, programming a button based user interface for Arduino is rather difficult. A future post will show a programming example of Windows application that uses CH341A to control this tuner.

8 comments :

  1. Thank you very much, Cornelius. This was very usefull.

    ReplyDelete
  2. much appreciated,just what iwas looking for!

    ReplyDelete
  3. Hi;
    I have tried your project and it is working, thank you. So how can we listen to narrow bands?

    ReplyDelete
    Replies
    1. It's difficult, but not impossible to listen to narrow band broadcasts or any other signals. You have to build a detector (demodulator) and connect its input at the output of the SAW filter. Obviously, the detector must be able to demodulate the frequency that passes through the filter.

      Delete
  4. Thanks for sharing! Can you help me with a Samsung tuner that has an SN761672A?
    I need to address it and control it. I have got some help but I'm still in the dark!

    ReplyDelete
    Replies
    1. By reading the datasheet it seems to me that SN761672A and TSA5523 are similar regarding I2C instructions. What kind of issues did you encounter?

      Delete
    2. Oh how kind of you to reply so soon! Believe me I downloaded a lot of examples and software related to tuners and arduino, I am immersed almost since 3 months. but I'm stuck in nowhere. Recently, I downloaded almost all FM1612 tuner projects and inos to learn from and find a starting point.
      just to learn how and where I can access the frequency compute it and display it. Really, your two examples summarize a lot but it shows a huge knowledge behind. I need to grasp the frequency at the outset and then make expansions, I'm stuck here!
      Today I wrote a demo code based on codes from FM1612(library, master, h etc) but once it came to set frequency or (Tuner.set(frq)) I got errors and the whole code became worthless. I am trying to get the tuner to receive (initialise)and to read the signal and from here increment/ decrement or search and display.
      Best regards
      p.s I am a hobbyist great electronic knowledge but in math and calculation a dummy!

      Delete
  5. /*Please help me tweak this code to be able to tune to 1 station*/
    #include
    #include
    LiquidCrystal_I2C lcd(0x27, 16, 2);
    #define SN761672A_ADDR (0xC2 >> 1)
    // tuner registers
    byte DB1, DB2, CB, BB;
    uint32_t freq_kHz;
    void setup()
    {
    Wire.begin();
    lcd.backlight();
    lcd.begin(16, 2);
    //Tuner_init();
    SN761672A_setTVFrequency(985000);
    lcd.setCursor(0,0);
    lcd.print("Station:");

    }

    void loop()
    {
    lcd.setCursor(8,0);
    lcd.print(freq_kHz);
    void SN761672A_setTVFrequency(uint32_t freq_kHz);
    }

    void SN761672A_setTVFrequency(uint32_t freq_kHz)
    {
    // band bits

    if (freq_kHz < 168000) BB = 0x00; // band A, VHF-Lo
    else if (freq_kHz < 448000) BB = 0x01; // band B, VHF-Hi
    else BB = 0x08; // band C, UHF

    // control
    CB = 0xCA;//11001010

    freq_kHz = freq_kHz / 31.25 + 1245;
    DB1 = (freq_kHz >> 8) & 0x1F;
    DB2 = freq_kHz & 0xFF;

    Wire.beginTransmission(SN761672A_ADDR);
    Wire.write(DB1);
    Wire.write(DB2);
    Wire.write(CB);
    Wire.write(BB);
    Wire.endTransmission();
    }

    ReplyDelete

Please read the comments policy before publishing your comment.