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.
Command Format
Section titled “Command Format”USB SETUP: bmRequestType = 0x40 (Vendor, Host-to-Device, OUT) bRequest = 0x86 (TUNE_8PSK) wValue = 0x0000 wIndex = 0x0000 wLength = 10EP0 Payload Layout
Section titled “EP0 Payload Layout”| Byte | Content | Encoding |
|---|---|---|
| [0] | Symbol Rate byte 0 | Little-endian LSB |
| [1] | Symbol Rate byte 1 | |
| [2] | Symbol Rate byte 2 | |
| [3] | Symbol Rate byte 3 | Little-endian MSB |
| [4] | Frequency byte 0 | Little-endian LSB |
| [5] | Frequency byte 1 | |
| [6] | Frequency byte 2 | |
| [7] | Frequency byte 3 | Little-endian MSB |
| [8] | Modulation Type | 0—9 (see table below) |
| [9] | Inner FEC Rate | Index 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.
Firmware Parameter Parsing
Section titled “Firmware Parameter Parsing”The firmware reads the 10-byte payload from EP0BUF (XRAM 0xE740—0xE749) and stores:
| Source | Destination | Notes |
|---|---|---|
| EP0BUF[8] (modulation) | IRAM 0x4D | Direct copy |
| EP0BUF[9] (FEC rate) | IRAM 0x4F | Direct copy |
| EP0BUF[4—7] (frequency) | XRAM 0xE0DB—0xE0DE | Byte-reversed (LE to BE) |
| EP0BUF[0—3] (symbol rate) | XRAM 0xE0CB—0xE0CE | Byte-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.
; Read modulation type and FEC rateMOV DPTR, #0xE748 ; EP0BUF[8] = modulation typeMOVX A, @DPTRMOV 0x4D, A ; Store to IRAM 0x4DINC DPTR ; DPTR = 0xE749MOVX A, @DPTR ; EP0BUF[9] = FEC rateMOV 0x4F, A ; Store to IRAM 0x4FModulation Dispatch
Section titled “Modulation Dispatch”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.
Dispatch Table (Rev.2)
Section titled “Dispatch Table (Rev.2)”| Entry | Target | Modulation |
|---|---|---|
| 0 | 0x08B7 | DVB-S QPSK |
| 1 | 0x08DF | Turbo QPSK |
| 2 | 0x08FA | Turbo 8PSK |
| 3 | 0x0915 | Turbo 16QAM |
| 4 | 0x0947 | DCII Combo |
| 5 | 0x094F | DCII I-stream |
| 6 | 0x0957 | DCII Q-stream |
| 7 | 0x095F | DCII Offset QPSK |
| 8 | 0x0887 | DSS QPSK |
| 9 | 0x0887 | DVB 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.
Modulation Handler Details
Section titled “Modulation Handler Details”DVB-S QPSK (Index 0)
Section titled “DVB-S QPSK (Index 0)”| Parameter | Value |
|---|---|
| FEC table base | XRAM 0xE0F9 |
| Max FEC index | 7 |
| Modulation type register | 0x09 |
| Turbo flag | 0x00 (off) |
| Demod mode | 0x10 (standard) |
| bmDCtuned | Cleared |
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:
XRAM[0xE0EB] = XRAM[0xE0F9 + FEC_index] | 0x80;// Out-of-range default: 0x8CTurbo QPSK (Index 1)
Section titled “Turbo QPSK (Index 1)”| Parameter | Value |
|---|---|
| FEC table base | XRAM 0xE0B7 |
| Max FEC index | 5 |
| Modulation type register | 0x09 |
| Turbo flag | 0x01 (on) |
| Demod mode | 0x10 |
| bmDCtuned | Cleared |
Turbo 8PSK (Index 2)
Section titled “Turbo 8PSK (Index 2)”| Parameter | Value |
|---|---|
| FEC table base | XRAM 0xE0B1 |
| Max FEC index | 5 |
| Modulation type register | 0x09 |
| Turbo flag | 0x01 (on) |
| Demod mode | 0x10 |
| bmDCtuned | Cleared |
Turbo 16QAM (Index 3)
Section titled “Turbo 16QAM (Index 3)”| Parameter | Value |
|---|---|
| FEC table base | XRAM 0xE0BC |
| Max FEC index | 1 |
| Modulation type register | 0x09 |
| Turbo flag | 0x01 (on) |
| Demod mode | 0x10 |
| bmDCtuned | Cleared |
All four DCII variants share a common post-processing path but set different demod mode values:
| Modulation | Index | Demod Mode (0xE0F5) |
|---|---|---|
| DCII Combo | 4 | 0x10 |
| DCII Offset QPSK | 7 | 0x11 |
| DCII I-stream (split) | 5 | 0x12 |
| DCII Q-stream (split) | 6 | 0x16 |
Common DCII parameters:
| Parameter | Value |
|---|---|
| FEC table base | XRAM 0xE0BD |
| Max FEC index | 9 |
| FEC code rate register | 0xFC (fixed for all DCII) |
| Turbo flag | 0x00 (off) |
| bmDCtuned | Set (0x40 OR’d into config status) |
The DCII modulation type register (0xE0EC) is loaded from the lookup table at 0xE0BD + FEC_index, unlike other modulations which use the fixed value 0x09.
XRAM Configuration Summary
Section titled “XRAM Configuration Summary”After modulation dispatch, four XRAM registers hold the BCM4500 configuration:
| XRAM Address | Register Name | DVB-S QPSK | Turbo (Q/8/16) | DCII | DSS/BPSK |
|---|---|---|---|---|---|
| 0xE0EB | FEC Code Rate | Table lookup | Table lookup | 0xFC (fixed) | Lookup OR 0x80 |
| 0xE0EC | Modulation Type | 0x09 | 0x09 | From DCII table | 0x09 |
| 0xE0F5 | Demod Mode | 0x10 | 0x10 | 0x10/0x11/0x12/0x16 | 0x10 |
| 0xE0F6 | Turbo Flag | 0x00 | 0x01 | 0x00 | 0x00 |
FEC Rate Lookup Tables
Section titled “FEC Rate Lookup Tables”These tables are populated at boot from the CODE-space init table:
| XRAM Base | Modulation | Max Index | Code Rates |
|---|---|---|---|
| 0xE0F9 | DVB-S QPSK, DSS, BPSK | 7 | 1/2, 2/3, 3/4, 5/6, 7/8, auto, none |
| 0xE0B7 | Turbo QPSK | 5 | Turbo-specific rates |
| 0xE0B1 | Turbo 8PSK | 5 | Turbo-specific rates |
| 0xE0BC | Turbo 16QAM | 1 | Single code rate |
| 0xE0BD | DCII (all variants) | 9 | Combined code + modulation |
Complete Tuning Sequence
Section titled “Complete Tuning Sequence”The full sequence from host command to signal acquisition:
-
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.
-
TUNE_8PSK (0x86) — Host sends 10-byte payload via USB control transfer.
-
EP0BUF Parsing — Firmware reads modulation/FEC to IRAM, byte-reverses frequency/symbol rate to XRAM.
-
Modulation Dispatch — FEC lookup via jump table, XRAM configuration registers set.
-
GPIO P3.6 — DVB mode select pin driven based on modulation type.
-
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).
-
Signal Acquisition (host polling):
- GET_SIGNAL_LOCK (0x90): Poll until non-zero.
- GET_SIGNAL_STRENGTH (0x87): Read SNR value.
I2C Programming Details
Section titled “I2C Programming Details”The core I2C write function (FUN_CODE_1670 on Rev.2) implements the BCM4500 indirect register protocol:
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.