BCM4500 Demodulator Interface
The Broadcom BCM4500 is a 128-pin MQFP satellite demodulator that handles RF demodulation, forward error correction, and MPEG-2 transport stream output. The FX2 communicates with it exclusively over the shared I2C bus using an indirect register protocol.
See the Register Map for a consolidated lookup of all BCM4500 and FX2 register addresses referenced on this page.
I2C Addressing
Section titled “I2C Addressing”| Parameter | Value |
|---|---|
| 7-bit I2C address | 0x08 |
| 8-bit write address | 0x10 |
| 8-bit read address | 0x11 |
| Bus speed | 400 kHz |
| FX2 I2C controller registers | I2CS (0xE678), I2DAT (0xE679), I2CTL (0xE67A) |
| Alternate probe addresses (v2.13) | 0x3F, 0x7F |
The custom firmware and kernel driver use the 7-bit address 0x08. The stock firmware writes addr << 1 = 0x10 for write and (addr << 1) | 1 = 0x11 for read, following standard I2C convention.
Direct Registers
Section titled “Direct Registers”These registers are accessed via standard I2C write/read to the BCM4500’s device address:
| Register | Function | Used By |
|---|---|---|
| 0xA2 | Status register (polled for readiness during boot) | Boot probe, signal strength |
| 0xA4 | Lock/ready register; bit 5 (0x20) = signal locked | Signal lock check |
| 0xA6 | Indirect page/address select | Indirect register protocol |
| 0xA7 | Indirect data register (read/write) | Indirect register protocol |
| 0xA8 | Indirect command register | Indirect register protocol |
| 0xF9 | Demod status (v2.13 only) | GET_DEMOD_STATUS (0x99) / INT0 polling |
Indirect Register Protocol
Section titled “Indirect Register Protocol”The BCM4500 uses an indirect register access scheme through three directly-addressable registers (0xA6, 0xA7, 0xA8). All tuning configuration, initialization data, and signal monitoring are performed through this protocol.
Indirect Write Sequence
Section titled “Indirect Write Sequence”-
Page select — I2C WRITE to 0x08, register 0xA6 with the page number (typically 0x00).
-
Data write — I2C WRITE to 0x08, register 0xA7 with N data bytes. The auto-increment feature allows writing multiple bytes in a single I2C transaction.
-
Execute — I2C WRITE to 0x08, register 0xA8 with value 0x03 (indirect write command).
-
Poll completion — I2C READ register 0xA8 until bit 0 clears (command complete).
-
Verify — Optionally I2C READ register 0xA7 to read back and compare.
// Step 1: Page selectI2C WRITE: [START] [0x10] [0xA6] [0x00] [STOP]
// Step 2: Data write (multi-byte, auto-increment)I2C WRITE: [START] [0x10] [0xA7] [data0] [data1] ... [dataN] [STOP]
// Step 3: Execute indirect writeI2C WRITE: [START] [0x10] [0xA8] [0x03] [STOP]
// Step 4: Poll until completeI2C READ: [START] [0x10] [0xA8] [Sr] [0x11] [result] [STOP] // Repeat until (result & 0x01) == 0Indirect Read Sequence
Section titled “Indirect Read Sequence”-
Address select — I2C WRITE to 0x08, register 0xA6 with the target register address.
-
Placeholder write — I2C WRITE to 0x08, register 0xA7 with value 0x00.
-
Execute — I2C WRITE to 0x08, register 0xA8 with value 0x01 (indirect read command).
-
Wait — Short delay (~1 ms) for the BCM4500 to fetch the data.
-
Read result — I2C READ from 0x08, register 0xA7 to get the result byte.
Auto-Increment Behavior
Section titled “Auto-Increment Behavior”The BCM4500’s data register (0xA7) supports auto-increment for multi-byte writes within a single I2C transaction. When writing N data bytes to 0xA7 without issuing STOP between bytes, the BCM4500 internally advances its data buffer pointer:
I2C transaction (single write, multiple data bytes): START -> 0x10 (write) -> 0xA7 (reg) -> data[0] -> data[1] -> ... -> data[N-1] -> STOPThe firmware uses this for initialization blocks and tuning data, reducing I2C bus overhead compared to byte-by-byte writes.
Stock Firmware Init Block Write Pattern
Section titled “Stock Firmware Init Block Write Pattern”The stock firmware uses a specific pattern for writing initialization blocks, extracted from FUN_CODE_0ddd:
// 1. Page select = 0I2C WRITE: [0x10] [0xA6] [0x00]
// 2. Multi-byte data (auto-increment)I2C WRITE: [0x10] [0xA7] [data0] [data1] ... [dataN]
// 3. Trailing zero (stock firmware quirk)I2C WRITE: [0x10] [0xA7] [0x00]
// 4. Commit indirect writeI2C WRITE: [0x10] [0xA8] [0x03]
// 5. Poll for completionI2C READ: [0xA8] until bit 0 clearDemodulator Scan
Section titled “Demodulator Scan”Tuning Retry (All Firmware Versions)
Section titled “Tuning Retry (All Firmware Versions)”The tune function wraps the BCM4500 I2C programming sequence in a two-level retry loop:
- Inner loop: tries up to 3 different I2C address configurations per attempt. This supports hardware variants where the BCM4500 may appear at different bus addresses.
- Outer loop: retries the entire inner scan up to 3 times.
This yields up to 3 × 3 = 9 total I2C programming attempts per tune command. The v2.13 firmware adds a 20-attempt retry with checksum verification on each individual I2C write within the programming step.
Boot-Time Probe (v2.13 Only)
Section titled “Boot-Time Probe (v2.13 Only)”The v2.13 firmware repurposed the INT0 interrupt handler (vector at CODE:0003) from USB re-enumeration to demodulator availability detection. The handler runs once during boot, before the main loop:
void INT0_vector(void) { for (counter = 0x28; counter != 0; counter--) { // 40 iterations byte result = I2C_read(0x7F); // Probe first alternate address if (result != 0x01) { result = I2C_read(0x3F); // Probe second alternate address if (result != 0x01) break; // Got a response — demod present } } no_demod_flag = (counter == 0); // True if all 40 attempts failed}If neither address responds after 40 iterations, no_demod_flag is set. This flag causes the firmware to skip all tuning attempts, avoiding I2C bus hangs on boards where the demodulator is absent or unpopulated.
no_demod_flag Behavior
Section titled “no_demod_flag Behavior”When the boot probe fails (all 40 attempts exhausted):
no_demod_flagis set to a non-zero value- The firmware enters its normal main loop but skips BCM4500 initialization
TUNE_8PSK(0x86) commands are accepted but silently fail (no I2C transactions issued)GET_SIGNAL_LOCK(0x90) returns 0x00 (unlocked)- The device remains functional for USB communication but cannot tune
This graceful degradation allows the host software to detect the condition via persistent lock failure rather than USB timeouts.
FEC Architecture
Section titled “FEC Architecture”The BCM4500 contains two FEC decoder paths:
Advanced Modulation Turbo FEC Decoder
Iterative turbo code decoder with the following code rates:
| Modulation | Supported Rates |
|---|---|
| QPSK | 1/4, 1/2, 3/4 |
| 8PSK | 2/3, 3/4, 5/6, 8/9 |
| 16QAM | 3/4 |
Outer code: Reed-Solomon (t=10).
These turbo codes are Broadcom/EchoStar proprietary and are not part of any open standard. They were used by Dish Network for high-definition satellite broadcasts.
Legacy DVB/DIRECTV/DCII-Compliant FEC Decoder
Concatenated decoder with:
| Stage | Type | Rates |
|---|---|---|
| Inner | Viterbi (convolutional code) | 1/2, 2/3, 3/4, 5/6, 7/8 |
| Outer | Reed-Solomon | Standard DVB-S parameters |
This decoder handles standard DVB-S QPSK, DVB-S BPSK, DSS QPSK, and all Digicipher II modes.
Modulation Mode Constants
Section titled “Modulation Mode Constants”The firmware uses a 10-entry dispatch table for modulation types. See Tuning Protocol for the full tuning sequence.
| Index | Modulation | FEC Path |
|---|---|---|
| 0 | DVB-S QPSK | Legacy (Viterbi + RS) |
| 1 | Turbo QPSK | Turbo |
| 2 | Turbo 8PSK | Turbo |
| 3 | Turbo 16QAM | Turbo |
| 4 | DCII Combo | Legacy |
| 5 | DCII I-stream | Legacy |
| 6 | DCII Q-stream | Legacy |
| 7 | DCII Offset QPSK | Legacy |
| 8 | DSS QPSK | Legacy (Viterbi + RS) |
| 9 | DVB-S BPSK | Legacy (Viterbi + RS) |
Indices 8 and 9 (DSS and DVB BPSK) share the same firmware handler. The FEC lookup uses the same table as DVB-S QPSK but ORs the result with 0x80 to distinguish them.