Close
0%
0%

Reversing Topfield TF5100 PVR Display Module

TF5100 has a UI board with 5 buttons, a re-flashable MCS51 based microcontroller, RTC with battery, and a cool VF-display

Public Chat
Similar projects worth following
The UI board of Topfield TF5100PVRc digital TV receiver contains 5 buttons (one of which is for power), a VF-display with 4 character 14-segment field for clock and text and 8 character 17-segment field for text. For button presses the modules sends the button code via serial line (19200 baud 8N1). The display can be controlled segment-wise with messages send to the module. In addition there is a real-time clock and IR remote receiver on the board.

The same VFD and probably same UI module is also on many other Topfield PVRs, so a plenty of those should be available for reuse.

See the details below for the serial communication protocol, messaging etc. In the files section there are two Python scripts that can be used to control the UI board, from PC, using, for example, a 5 V USB-Serial converter.

In the case one wants to use only the VFD, the log on its reverse-engineering gives its pin-out and describes how the segment and grid data is sent to the driver CIG in the module.

Connectors

  • JP1
    1. Brown: Vcc (+5 V)
    2. Red: TXD (UART data from UI to main board)
    3. Orange: RXD (UART data from main board to UI)
    4. Yellow: GND
    5. Green: Connected to microcontroller T0/P3.4 (Indication from the UI module to the main board, low = power on, high = power-off)
    6. Blue: VFD HV (+17 V) - Connected to JP1-1 (Purple)
  • JP2 (This is not needed. JP1-6 can be used for the VFD HV).
    1. Purple: VFD HV (+17V)
    2. Black: GND

The Vcc pin takes about 250 mA. The VFD HV pin takes about 9 mA when all segments are on.

Protocol

The UART settings are 19200 baud 8N1.

The communication appears to consist of <STX> <type|dlen> <data>{dlen} <ETX> packets where type is the high nybble of the second byte and dlen its low nybble giving the number of data bytes following it.

Writing to Display

Messages of type 9 are used to write to byte arrays that the on-board microcontroller uses to drive the VFD.

Message 0x02 0x9<len> <addr> <data_0>...<data_len-2> 0x03 writes the data bytes to array at the given address. Each of the three multiplexed data sets are 16 bytes long. Set 0 is at address 0x00, 1 at address 0x10, and 2 at address 0x20. Since one write is limited to 14 bytes of data the main board CPU writes each set with two writes: first 8 bytes to 0x[0-2]0 and then 8 bytes to address 0x[0-2]8. The first data byte of each set (0x[0-2]0) selects the grid and it is 0xC0, 0x3C, or 0x03 for sets 0, 1, and 2, respectively. The set 1 appears to contain largest number of segments and is probably for that reason allocated 4 outputs, while two other sets use 2 outputs. The rest (120) bits select the segments (1 on, 0 off)

Mapping of the segments

Zoom into the image to see the set (grid group) and segment mapping. Note that segment numbers map to bits in the messages so that bytes 0-6 are in the first message for the set and bytes 7-15 in the second. Bits are numbered so that msb is 0 and lsb is 7. Byte number is the segment number divided by 8 and the bit number is the remainder of the segment number when divided by 8.

Simple Display Driver

A display test program with a simple driver class is in tf5100ui-vfd-test.py

Special Display Controls

The display can be controlled also with shorter messages than full groups. The message 0x91 is special so that it can be used to clear the display (0x02 0x91 0x00 0x03) or it can be used to set groups of segments (like 0x02 0x91 0x01 0x03) up to turning all segments on with 0x02 0x91 0xff 0x03.

After clearing the display the bytes driving the grids (0x00, 0x10, and 0x20) have been set correctly. Then one can write to all other bytes or ranges of bytes any segment driving values with 0x20 0x9<L> <addr> <value>+ 0x03, where L is number of bytes -1, addr is the address of the first byte and value-bytes give the patterns (+ indicates like in regexp one or more values).

Real-Time Clock

The time from the real time clock can be read with message 0x02 0x10 0x03. The device responds with 0x00 0x02 0x13 <hr> <min> <sec> 0x03.

The whole real-time clock calendar can be read with message 0x02 0x30 0x03. To that the device responds with a 5-byte data that contains year, month, day, week day, hours, minutes, and seconds. The message looks like 0x00 0x02 0x25 <year[6:0]|month[3]> <month[2:0]|day[4:0]> <weekday[2:0]|hours[4:0]> <minutes> <seconds> 0x03. The year is 0..99, month 1..12, day 1..28..31 depending on month and leap year, weekday 0..6, hours 0..23, minutes and seconds 0..59.

This same message can be sent to the device to set the real-time clock to any allowable value. Incorrect dates appear to be adjusted to the next valid one. The device responds with 0x00 0x02 0x30 0x03.

If the real-time clock battery is dead the response to 0x02 0x30 0x03 is 0x00 0x02 0x15 ... (time response 0x1L , not calendar+time, 0x2L) with the calendar data invalid (year 101, month and day both 6, or other garbage), but the time is valid, counting up from the power-on.

The data sheet of the chip mentions that it has auto-calendar up to...

Read more »

tf5100-tests.py

A more complete python script for testing the TF5100PVRc UI board. Includes separate communication thread demo for how to handle button presses and IR commands asynchronously.

x-python - 19.69 kB - 08/10/2021 at 07:09

Download

tf5100ui-vfd-test.py

Python script for testing the display. The provided TF5100VFD class can be used as a simple display driver, and it contains ASCII fonts for bot the 4 character clock display and the 8 character text display fields.

text/x-python - 13.72 kB - 08/08/2021 at 15:17

Download

  • Reverse-Engineering the VFD

    Lauri Pirttiaho08/04/2021 at 16:03 0 comments

    Connectors

    • JP1
      1. Brown: Vcc (+5 V)
      2. Red: TXD (UART data from UI to main board)
      3. Orange: RXD (UART data from main board to UI)
      4. Yellow: GND
      5. Green: Connected to microcontroller T0/P3.4
      6. Blue: VFD HV (+17 V) - Connected to JP1-1(Purple)
    • JP2
      1. Purple: VFD HV (+17V)
      2. Black: GND

    Protocol

    The UART settings are 19200 baud 8N1.

    The communication appears to consist of <STX> <type|dlen> <data>{dlen} <ETX> packets where type is the high nybble of the second byte and dlen its low nybble giving the number of data bytes following it.

    Display

    The filament voltage (F1 positive, F2 ground) is about 3.58 V, fed from +5V via 4.7 Ω resistor and a PNP switch, so that the current is about 225 mA. The filaments are tilted for DC drive.

    The connector P[1:8] is:

    1. Serial data, clocked at rising edge of clock. Microcontroller pin P2.3. Possibly bit-banged SPI.
    2. +5 V
    3. Not connected. Appears to be serial data out from the CIG chip.
    4. Load strobe. Microcontroller pin P2.2. 400 ns pulse every 4 ms.
    5. <unknown> Microcontroller pin 2.1.
    6. Clock. Microcontroller pin P2.0. Rate 230 kHz, idle high.
    7. GND
    8. GND
    9. +16.6 V

    The data appears to be 1:3 multiplexed, 128 bits (16x8) for each group.

    The CIG chip is under the right hand side (raised) filament holder. Chip is bonded from two sides. Type unknown. This could be a 128-bit serial to parallel converter with high voltage outputs, similar to Supertex/Microchip HV583 (die bonding does not match the pads of HV583 so it likely is not that, though).

    Writing to Display

    Messages of type 9 are used to write to byte arrays that the on-board microcontroller uses to drive the VFD.

    Message 0x02 0x9<len> <addr> <data_0>...<data_len-2> 0x03 writes the data bytes to array at the given address. Each of the three multiplexed data sets are 16 bytes long. Set 0 is at address 0x00, 1 at address 0x10, and 2 at address 0x20. Since one write is limited to 14 bytes of data the main board CPU writes each set with two writes: first 8 bytes to 0x[0-2]0 and then 8 bytes to address 0x[0-2]8. The first data byte of each set (0x[0-2]0) selects the grid and it is 0xC0, 0x3C, or 0x03 for sets 0, 1, and 2, respectively. The set 1 appears to contain largest number of segments and is probably for that reason allocated 4 outputs, while two other sets use 2 outputs. The rest (120) bits select the segments (1 on, 0 off),mapping of which will be determined soon.

    The on-board microcontroller uses SPI-like protocol (by bit-banging as there is no SPI HW in that microcontroller) and feeds the bits in reverse order to the CIG of the VFD as can be seen by comparing the bit patterns in the logic waveforms.

    Mapping of the segments

    The display module was connected to a PC using a Cypress USB-to-serial break-out board, and a small Python script was used to step through all segments.

    #!/usr/bin/env python3
    
    from serial import Serial
    from time import sleep
    from sys import stdout
    
    msgs = [
        [0x02, 0x99, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03],
        [0x02, 0x99, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03],
        [0x02, 0x99, 0x10, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03],
        [0x02, 0x99, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03],
        [0x02, 0x99, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03],
        [0x02, 0x99, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03]
        ]
        
    def set(line, segment, val):
        if segment < 56:
            msg_index = 2 * line
            byte = 4 + segment // 8
        else:
            msg_index = 2 * line + 1
            byte = 3 + (segment - 56) // 8
        bit = 7 - segment % 8
        if val:
            msgs[msg_index][byte] |= 1 << bit
        else:
            msgs[msg_index][byte] &= ~(1 << bit)
        msgs[msg_index][byte] &= 0xff
        return bytes(bytearray(msgs[msg_index]))
    
    stdout.write('          ')
    stdout.flush()
        
    with Serial('COM7', 19200, timeout=1) as com7:
        for m in msgs:
            com7.write(m)
            sleep(0.2)
        sleep(1)
       
        for j in range(3):
            for i in range(120):
                stdout.write('\b\b\b\b\b\b\b\b\b\b')
                stdout.write('({:3d},{:3d})'.format(j,i))
                stdout.flush()
    ...
    Read more »

View project log

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates