Skip to content

Tuning Protocol

The TUNE_8PSK vendor command (0x86) is the primary mechanism for programming the BCM4500 demodulator to receive a satellite signal. The command carries a 10-byte payload encoding frequency, symbol rate, modulation type, and FEC rate. The firmware parses this payload, dispatches to a modulation-specific handler, programs the BCM4500 via I2C, and the host then polls for signal lock.

See the Register Map for a consolidated lookup of all XRAM addresses and BCM4500 registers referenced on this page.

USB SETUP:
bmRequestType = 0x40 (Vendor, Host-to-Device, OUT)
bRequest = 0x86 (TUNE_8PSK)
wValue = 0x0000
wIndex = 0x0000
wLength = 10
ByteContentEncoding
[0]Symbol Rate byte 0Little-endian LSB
[1]Symbol Rate byte 1
[2]Symbol Rate byte 2
[3]Symbol Rate byte 3Little-endian MSB
[4]Frequency byte 0Little-endian LSB
[5]Frequency byte 1
[6]Frequency byte 2
[7]Frequency byte 3Little-endian MSB
[8]Modulation Type0—9 (see table below)
[9]Inner FEC RateIndex into modulation-specific table

Symbol Rate is in samples per second (sps). The Windows driver converts from ksps: ulTempSymbolRate = pDeviceParameter->ulSymbolRate * 1000. Valid range: 256,000 — 30,000,000 sps.

Frequency is the IF frequency in kHz (950,000 — 2,150,000), computed by the host as (RF_freq - LO_freq) * multiplier.

The firmware reads the 10-byte payload from EP0BUF (XRAM 0xE740—0xE749) and stores:

SourceDestinationNotes
EP0BUF[8] (modulation)IRAM 0x4DDirect copy
EP0BUF[9] (FEC rate)IRAM 0x4FDirect copy
EP0BUF[4—7] (frequency)XRAM 0xE0DB—0xE0DEByte-reversed (LE to BE)
EP0BUF[0—3] (symbol rate)XRAM 0xE0CB—0xE0CEByte-reversed (LE to BE)

The byte reversal converts host little-endian to BCM4500 big-endian, allowing values to be written directly to the demodulator via I2C without further conversion.

EP0BUF Read (Rev.2 at CODE:0802)
; Read modulation type and FEC rate
MOV DPTR, #0xE748 ; EP0BUF[8] = modulation type
MOVX A, @DPTR
MOV 0x4D, A ; Store to IRAM 0x4D
INC DPTR ; DPTR = 0xE749
MOVX A, @DPTR ; EP0BUF[9] = FEC rate
MOV 0x4F, A ; Store to IRAM 0x4F

After parsing, the firmware validates the modulation type (bounds check against 10) and dispatches via a 20-byte jump table (10 entries x 2 bytes) at CODE:0873. Values >= 10 are rejected silently.

EntryTargetModulation
00x08B7DVB-S QPSK
10x08DFTurbo QPSK
20x08FATurbo 8PSK
30x0915Turbo 16QAM
40x0947DCII Combo
50x094FDCII I-stream
60x0957DCII Q-stream
70x095FDCII Offset QPSK
80x0887DSS QPSK
90x0887DVB BPSK (shares DSS handler)

Each handler validates the FEC index, looks up a preconfigured byte from an XRAM table, and writes configuration to four XRAM registers.

ParameterValue
FEC table baseXRAM 0xE0F9
Max FEC index7
Modulation type register0x09
Turbo flag0x00 (off)
Demod mode0x10 (standard)
bmDCtunedCleared

FEC rates available (table at 0xE0F9): 1/2, 2/3, 3/4, 5/6, 7/8, auto, none.

DSS QPSK (Index 8) and DVB-S BPSK (Index 9)

Section titled “DSS QPSK (Index 8) and DVB-S BPSK (Index 9)”

DSS and DVB BPSK share the same handler at 0x0887. They use the same FEC table as DVB-S QPSK (0xE0F9) but OR the lookup value with 0x80 to distinguish them:

DSS/BPSK FEC Encoding
XRAM[0xE0EB] = XRAM[0xE0F9 + FEC_index] | 0x80;
// Out-of-range default: 0x8C

After modulation dispatch, four XRAM registers hold the BCM4500 configuration:

XRAM AddressRegister NameDVB-S QPSKTurbo (Q/8/16)DCIIDSS/BPSK
0xE0EBFEC Code RateTable lookupTable lookup0xFC (fixed)Lookup OR 0x80
0xE0ECModulation Type0x090x09From DCII table0x09
0xE0F5Demod Mode0x100x100x10/0x11/0x12/0x160x10
0xE0F6Turbo Flag0x000x010x000x00

These tables are populated at boot from the CODE-space init table:

XRAM BaseModulationMax IndexCode Rates
0xE0F9DVB-S QPSK, DSS, BPSK71/2, 2/3, 3/4, 5/6, 7/8, auto, none
0xE0B7Turbo QPSK5Turbo-specific rates
0xE0B1Turbo 8PSK5Turbo-specific rates
0xE0BCTurbo 16QAM1Single code rate
0xE0BDDCII (all variants)9Combined code + modulation

The full sequence from host command to signal acquisition:

  1. LNB Configuration (separate vendor commands, before TUNE_8PSK)

    • SET_LNB_VOLTAGE (0x8B): GPIO P0.4, no I2C. wValue=1 for 18V (H/Circular-L), wValue=0 for 13V (V/Circular-R).
    • SET_22KHZ_TONE (0x8C): GPIO P0.3, no I2C. wValue=1 for high band, wValue=0 for low band.
    • SEND_DISEQC_COMMAND (0x8D): If multi-switch is needed.
  2. TUNE_8PSK (0x86) — Host sends 10-byte payload via USB control transfer.

  3. EP0BUF Parsing — Firmware reads modulation/FEC to IRAM, byte-reverses frequency/symbol rate to XRAM.

  4. Modulation Dispatch — FEC lookup via jump table, XRAM configuration registers set.

  5. GPIO P3.6 — DVB mode select pin driven based on modulation type.

  6. BCM4500 I2C Programming (3 outer retries, each trying up to 3 I2C addresses):

    • Poll BCM4500 ready: I2C READ registers 0xA2, 0xA8, 0xA4.
    • Write page: I2C WRITE register 0xA6 with 0x00.
    • Write config data: I2C WRITE register 0xA7 with frequency, symbol rate, FEC, modulation, and demod parameters.
    • Execute: I2C WRITE register 0xA8 with 0x03 (indirect write command).
    • Poll completion: I2C READ registers 0xA8, 0xA2.
    • Verify: I2C READ register 0xA7 (read-back compare).
  7. Signal Acquisition (host polling):

    • GET_SIGNAL_LOCK (0x90): Poll until non-zero.
    • GET_SIGNAL_STRENGTH (0x87): Read SNR value.

The core I2C write function (FUN_CODE_1670 on Rev.2) implements the BCM4500 indirect register protocol:

BCM4500 Indirect Write (Decompiled)
void bcm4500_indirect_write(byte *data, byte count) {
// Wait for BCM4500 ready (poll regs 0xA2, 0xA8, 0xA4)
bus_wait_ready();
// Write page address (0x00) to register 0xA6
i2c_write(1, 0, 0xA6, 0x10); // [0x00]
// Write data to register 0xA7
i2c_write(count, 0, 0xA7, 0x10); // [data0..dataN]
// Write command (0x03 = indirect write) to 0xA8
i2c_write(1, 0, 0xA8, 0x10); // [0x03]
// Poll completion (regs 0xA8, 0xA2)
poll_write_complete();
// Verify: read back from 0xA7 and compare
verify_readback();
}

The demod scan function (FUN_CODE_1dd0) wraps this in a 3-address iteration loop, supporting hardware variants where the BCM4500 may respond at different I2C addresses. The outer tune function retries the entire scan up to 3 times.