Master Reference
Genpix SkyWalker-1 Master Hardware and Firmware Reference
Section titled “Genpix SkyWalker-1 Master Hardware and Firmware Reference”Consolidated technical reference for the Genpix SkyWalker-1 DVB-S USB 2.0 satellite receiver. Derived from Linux kernel driver analysis (dvb_usb_gp8psk), Ghidra firmware reverse engineering (v2.06, v2.10 Rev.2, v2.13 FW1/FW2/FW3), Windows BDA driver source review, and custom firmware development (v3.01.0, SDCC + fx2lib).
Table of Contents
Section titled “Table of Contents”- Hardware Overview
- USB Interface
- Vendor Command Reference
- Configuration Status Byte
- Boot Sequence
- BCM4500 Demodulator Interface
- Tuning Protocol
- GPIF Streaming Path
- LNB and DiSEqC Control
- GPIO Pin Map
- Firmware Versions
- I2C Bus Architecture
- Custom Firmware v3.01.0
- DVB-S2 Incompatibility
- Kernel Driver Notes
- Firmware Storage Formats
- Debugging Reference
- Sources
1. Hardware Overview
Section titled “1. Hardware Overview”The Genpix SkyWalker-1 is a standalone USB 2.0 DVB-S satellite receiver built around two ICs:
| Component | Part | Role |
|---|---|---|
| MCU | Cypress CY7C68013A (FX2LP) | USB 2.0 Hi-Speed controller, 8051 core at 48 MHz |
| Demodulator | Broadcom BCM4500 | DVB-S / Turbo / DCII / DSS demodulator, 128-pin MQFP |
| EEPROM | 24Cxx-family (I2C address 0x51) | FX2 firmware storage, serial number, calibration |
| Tuner/LNB | Unknown IC (I2C address 0x10) | Tuner or LNB controller on shared I2C bus |
The FX2 handles USB communication, LNB control, DiSEqC signaling, and orchestrates tuning via I2C commands to the BCM4500. The BCM4500 performs RF demodulation, forward error correction, and outputs an MPEG-2 transport stream on an 8-bit parallel bus. The FX2’s GPIF engine transfers the transport stream directly into a USB bulk endpoint with zero firmware intervention in the data path.
1.1 Supported Modulations
Section titled “1.1 Supported Modulations”| Index | Modulation | Constant | FEC Family |
|---|---|---|---|
| 0 | DVB-S QPSK | ADV_MOD_DVB_QPSK | Viterbi + Reed-Solomon |
| 1 | Turbo-coded QPSK | ADV_MOD_TURBO_QPSK | Turbo |
| 2 | Turbo-coded 8PSK | ADV_MOD_TURBO_8PSK | Turbo |
| 3 | Turbo-coded 16QAM | ADV_MOD_TURBO_16QAM | Turbo |
| 4 | Digicipher II Combo | ADV_MOD_DCII_C_QPSK | DCII |
| 5 | Digicipher II I-stream (split) | ADV_MOD_DCII_I_QPSK | DCII |
| 6 | Digicipher II Q-stream (split) | ADV_MOD_DCII_Q_QPSK | DCII |
| 7 | Digicipher II Offset QPSK | ADV_MOD_DCII_C_OQPSK | DCII |
| 8 | DSS QPSK | ADV_MOD_DSS_QPSK | Viterbi + Reed-Solomon |
| 9 | DVB-S BPSK | ADV_MOD_DVB_BPSK | Viterbi + Reed-Solomon |
DVB-S2 is not supported. See Section 14.
1.2 RF Specifications
Section titled “1.2 RF Specifications”| Parameter | Value |
|---|---|
| IF frequency range | 950 — 2150 MHz |
| Symbol rate | 256 Ksps — 30 Msps |
| Input connector | IEC F-type female |
| LNB voltage | 13V / 18V (or 14V / 19V with USE_EXTRA_VOLT) |
| LNB current | 450 mA continuous, 750 mA burst |
| Switch control | 22 kHz, Tone Burst, DiSEqC 1.0/1.2, Legacy Dish Network |
1.3 Board Block Diagram
Section titled “1.3 Board Block Diagram” +--[ I2C EEPROM 0x51 ] | USB 2.0 HS | I2C Bus (400 kHz) Host PC <----> [ CY7C68013A FX2LP ] <-----> [ BCM4500 Demod 0x08 ] | 8051 @ 48 MHz | | | GPIF Engine |<-----------+ 8-bit parallel TS | EP2 Bulk IN | | GPIO (P0/P3) |---> [ 22 kHz Osc ] ---> LNB/Coax | |---> [ LNB Voltage Ctrl ] +-----------------+ | +--[ Tuner/LNB IC 0x10 ]2. USB Interface
Section titled “2. USB Interface”2.1 VID/PID Table
Section titled “2.1 VID/PID Table”All Genpix products share VID 0x09C0:
| PID | Product | cold_ids | warm_ids | Notes |
|---|---|---|---|---|
| 0x0200 | 8PSK-to-USB2 Rev.1 Cold | Yes | No | Requires FW01 upload to RAM |
| 0x0201 | 8PSK-to-USB2 Rev.1 Warm | No | Yes | Requires FW02 (BCM4500 firmware) |
| 0x0202 | 8PSK-to-USB2 Rev.2 | No | Yes | Boots from EEPROM |
| 0x0203 | SkyWalker-1 | No | Yes | Boots from EEPROM |
| 0x0204 | SkyWalker-1 (alternate) | No | Yes | Boots from EEPROM |
| 0x0205 | SkyWalker-2 | — | — | Not in kernel 6.16.5 |
| 0x0206 | SkyWalker CW3K | No | Yes | Requires CW3K_INIT (0x9D) |
PID 0x0203 was added to the kernel device table after v6.6.1.
2.2 USB Endpoints and Streaming Properties
Section titled “2.2 USB Endpoints and Streaming Properties”| Property | Value |
|---|---|
| Control endpoint | EP0 (default, vendor requests) |
| Bulk IN endpoint | EP2 (0x82) — MPEG-2 transport stream |
| Generic bulk CTRL endpoint | 0x01 (BCM4500 FW02 upload, Rev.1 only) |
| URB count | 7 |
| URB buffer size | 8192 bytes each |
| Stream type | USB_BULK |
| FX2 controller type | CYPRESS_FX2 |
2.3 Warm Boot Behavior
Section titled “2.3 Warm Boot Behavior”The SkyWalker-1 (PID 0x0203) enumerates directly as a “warm” device. The DVB-USB framework skips firmware download when cold_ids is NULL. No host-side firmware files are required.
| Device | PID | Needs FW01? | Needs FW02? | Boot Source |
|---|---|---|---|---|
| Rev.1 Cold | 0x0200 | Yes | — | RAM (empty) |
| Rev.1 Warm | 0x0201 | No | Yes | RAM (FW01 loaded) |
| Rev.2 | 0x0202 | No | No | EEPROM |
| SkyWalker-1 | 0x0203 | No | No | EEPROM |
| SkyWalker CW3K | 0x0206 | No | No | EEPROM |
The firmware files dvb-usb-gp8psk-01.fw and dvb-usb-gp8psk-02.fw were never open-sourced or included in linux-firmware.
3. Vendor Command Reference
Section titled “3. Vendor Command Reference”All vendor commands use USB control transfers:
- USB Type:
USB_TYPE_VENDOR - Timeout: 2000 ms (kernel driver)
- Retry: Up to 3 attempts for IN operations if partial data received
- Data buffer maximum: 80 bytes (kernel driver state structure)
3.1 Stock Command Table (0x80—0x9D)
Section titled “3.1 Stock Command Table (0x80—0x9D)”The vendor command dispatcher at CODE:0056 validates bRequest in the range 0x80—0x9D (30 entries) and dispatches via an indexed jump table at CODE:0076. Rev.2 supports only 0x80—0x9A (27 entries).
| Cmd | Name | Dir | wValue | wIndex | wLength | Purpose | v2.06 | Rev.2 | v2.13 |
|---|---|---|---|---|---|---|---|---|---|
| 0x80 | GET_8PSK_CONFIG | IN | 0 | 0 | 1 | Read configuration status byte | OK | OK | OK |
| 0x81 | SET_8PSK_CONFIG | OUT | varies | 0 | 0 | Set config (reserved) | STALL | STALL | STALL |
| 0x82 | (reserved) | — | — | — | — | Reserved | STALL | STALL | STALL |
| 0x83 | I2C_WRITE | OUT | dev_addr | reg_addr | N | Write to I2C device | OK | OK | OK |
| 0x84 | I2C_READ | IN | dev_addr | reg_addr | N | Read from I2C device | OK | OK | OK |
| 0x85 | ARM_TRANSFER | OUT | 0/1 | 0 | 0 | Start (1) / stop (0) MPEG-2 stream | OK | OK | OK |
| 0x86 | TUNE_8PSK | OUT | 0 | 0 | 10 | Set tuning parameters (Section 7) | OK | OK | OK |
| 0x87 | GET_SIGNAL_STRENGTH | IN | 0 | 0 | 6 | Read SNR and diagnostics | OK | OK | Changed |
| 0x88 | LOAD_BCM4500 | OUT | 1 | 0 | 0 | Initiate BCM4500 FW download | STALL | STALL | STALL |
| 0x89 | BOOT_8PSK | IN | 0/1 | 0 | 1 | Power on (1) / off (0) demodulator | OK | OK | OK |
| 0x8A | START_INTERSIL | IN | 0/1 | 0 | 1 | Enable (1) / disable (0) LNB supply | OK | OK | OK |
| 0x8B | SET_LNB_VOLTAGE | OUT | 0/1 | 0 | 0 | 13V (0) or 18V (1) | OK | OK | OK |
| 0x8C | SET_22KHZ_TONE | OUT | 0/1 | 0 | 0 | Tone off (0) or on (1) | OK | OK | OK |
| 0x8D | SEND_DISEQC_COMMAND | OUT | msg[0] | 0 | len | DiSEqC message or tone burst | OK | OK | OK |
| 0x8E | SET_DVB_MODE | OUT | 1 | 0 | 0 | Enable DVB-S mode | STALL | STALL | STALL |
| 0x8F | SET_DN_SWITCH | OUT | cmd7bit | 0 | 0 | Legacy Dish Network switch protocol | OK | OK | OK |
| 0x90 | GET_SIGNAL_LOCK | IN | 0 | 0 | 1 | Read signal lock status | OK | OK | OK |
| 0x91 | I2C_ADDR_ADJUST | IN | 0/1 | 0 | 1 | Inc/dec internal counter (debug) | OK | OK | OK |
| 0x92 | GET_FW_VERS | IN | 0 | 0 | 6 | Read firmware version + build date | OK | OK | OK |
| 0x93 | GET_SERIAL_NUMBER | IN | 0 | 0 | 4 | Read 4-byte serial from EEPROM | OK | OK | OK |
| 0x94 | USE_EXTRA_VOLT | OUT | 0/1 | 0 | 0 | Enable +1V LNB boost (14V/19V) | OK | OK | OK |
| 0x95 | GET_FPGA_VERS | IN | 0 | 0 | 1 | Read EEPROM hardware/platform ID | OK | OK | OK |
| 0x96 | SET_LNB_GPIO_MODE | OUT | 0/1 | 0 | 0 | Configure LNB GPIO output enables | OK | OK | OK |
| 0x97 | SET_GPIO_PINS | OUT | bitmap | 0 | 0 | Direct write to LNB GPIO pins | OK | OK | OK |
| 0x98 | GET_GPIO_STATUS | IN | 0 | 0 | 1 | Read LNB feedback GPIO pin | OK | OK | OK |
| 0x99 | GET_DEMOD_STATUS | IN | 0 | 0 | 1 | Read BCM4500 register 0xF9 | STALL | Proto | OK |
| 0x9A | INIT_DEMOD | OUT | 0 | 0 | 0 | Trigger demod re-init (3 attempts) | STALL | Proto | OK |
| 0x9B | (reserved) | — | — | — | — | Reserved | STALL | N/A | STALL |
| 0x9C | DELAY_COMMAND | OUT | delay | 0 | 0 | Host-controlled tuning delay + poll | STALL | N/A | OK |
| 0x9D | CW3K_INIT / SET_MODE_FLAG | OUT | 0/1 | 0 | 0 | CW3K init or conditional demod reset | OK | N/A | Changed |
Status key: OK = implemented. STALL = routes to stall handler. Proto = partial/prototype. N/A = out of range (Rev.2 supports 0x80—0x9A only). Changed = implementation differs between versions.
Driver usage notes:
- The Linux driver only sends LOAD_BCM4500 (0x88) for Rev.1 Warm (PID 0x0201). On SkyWalker-1,
bm8pskFW_Loadedis already set and 0x88 STALLs. - The Linux driver only sends CW3K_INIT (0x9D) for SkyWalker CW3K (PID 0x0206).
3.2 Vendor Command Dispatch Mechanism
Section titled “3.2 Vendor Command Dispatch Mechanism”The vendor command dispatcher at CODE:0056 (identical code address across v2.06, v2.13, and Rev.2) follows this logic:
1. Check bmRequestType bit 6: if not set, not a vendor request -> handle standard2. Read bRequest from SETUPDAT[1]3. Subtract 0x80 (command base offset)4. Compare against maximum: < 0x1E (v2.06/v2.13) or < 0x1B (Rev.2)5. If in range: double the index (2 bytes per entry) and JMP @A+DPTR to jump table6. If out of range: route to STALL handlerThe jump table at CODE:0076 contains 2-byte AJMP targets. Each entry points to the handler for commands 0x80 through 0x9D (or 0x9A for Rev.2).
Jump table layout (first 6 entries shown, Rev.2):
CODE:0076: 01C1 ; 0x80 GET_8PSK_CONFIG -> 0x01C1CODE:0078: 034B ; 0x81 SET_8PSK_CONFIG -> 0x034B (STALL)CODE:007A: 034B ; 0x82 (reserved) -> 0x034B (STALL)CODE:007C: 0103 ; 0x83 I2C_WRITE -> 0x0103CODE:007E: 00D9 ; 0x84 I2C_READ -> 0x00D9CODE:0080: 00C2 ; 0x85 ARM_TRANSFER -> 0x00C2...3.3 Custom Firmware Commands (0xB0—0xB6)
Section titled “3.3 Custom Firmware Commands (0xB0—0xB6)”Commands added in custom firmware v3.01.0:
| Cmd | Name | Dir | wValue | wIndex | wLength | Purpose |
|---|---|---|---|---|---|---|
| 0xB0 | SPECTRUM_SWEEP | OUT | 0 | 0 | 10 | Step through freq range, read SNR at each step |
| 0xB1 | RAW_DEMOD_READ | IN | reg | 0 | 1 | Read BCM4500 indirect register |
| 0xB2 | RAW_DEMOD_WRITE | OUT | reg | data | 0 | Write BCM4500 indirect register |
| 0xB3 | BLIND_SCAN | OUT | 0 | 0 | 16 | Try symbol rates at given freq, report lock |
| 0xB4 | I2C_BUS_SCAN | IN | 0 | 0 | 16 | Probe all 7-bit addresses, return 16-byte bitmap |
| 0xB5 | I2C_RAW_READ | IN | addr7 | reg | N | Combined write-read from any I2C device |
| 0xB6 | I2C_DIAG | IN | page | 0 | 8 | Step-by-step indirect register diagnostic |
3.4 Detailed Parameter Formats
Section titled “3.4 Detailed Parameter Formats”0x87 GET_SIGNAL_STRENGTH: Returns 6 bytes. Bytes 0—1 are a 16-bit SNR value (little-endian, dBu * 256 units). Bytes 2—5 are reserved/diagnostic. SNR scaling from Windows BDA driver: if snr_raw <= 0x0F00: strength = snr_raw * 17; else strength = 0xFFFF. Version differences: v2.06 polls 3 registers (0xA2, 0xA8, 0xA4) up to 6 times; v2.13 consolidates to 1 register.
0x8D SEND_DISEQC_COMMAND: When wLength > 0, the payload is a standard DiSEqC message (3—6 bytes) with wValue = msg[0] (framing byte, typically 0xE0 or 0xE1). When wLength == 0: wValue == 0 sends tone burst A; wValue != 0 sends tone burst B. See Section 9.
0x8F SET_DN_SWITCH: wValue carries a 7-bit Dish Network switch command, bit-banged LSB-first on GPIO P0.4. The 8th bit (0x80) of the original switch command controls LNB voltage and is sent separately via SET_LNB_VOLTAGE (0x8B).
0x92 GET_FW_VERS: Returns 6 bytes of hardcoded constants:
Byte 0: version minor_minor (e.g., 0x04)Byte 1: version minor (e.g., 0x06)Byte 2: version major (e.g., 0x02)Byte 3: build day (e.g., 0x0D = 13)Byte 4: build month (e.g., 0x07 = July)Byte 5: build year - 2000 (e.g., 0x07 = 2007)Full version = byte[2] << 16 | byte[1] << 8 | byte[0]. Build date = (2000 + byte[5]) / byte[4] / byte[3].
0x93 GET_SERIAL_NUMBER: Returns 4 bytes read from I2C EEPROM at device address 0x51 (7-bit), extracted at 8-bit intervals using a shift/rotate routine.
0x94 USE_EXTRA_VOLT: wValue=1 writes 0x6A to XRAM 0xE0B6; wValue=0 writes 0x62. The difference is bit 3 (0x08), which controls the voltage boost on the LNB power regulator.
0x95 GET_FPGA_VERS: Reads from I2C EEPROM at 0x51. Despite the name, there is no FPGA on the SkyWalker-1 — this returns a hardware platform ID. v2.06 reads EEPROM offset 0x31 (2 bytes); v2.13/Rev.2 read offset 0x00 (1 byte).
0xB0 SPECTRUM_SWEEP: 10-byte EP0 payload: [start_freq(u32 LE kHz), stop_freq(u32 LE kHz), step_khz(u16 LE)]. Programs BCM4500 at each frequency step, reads SNR, packs u16 LE results into EP2 bulk FIFO.
0xB3 BLIND_SCAN: 16-byte EP0 payload: [freq_khz(u32 LE), sr_min(u32 LE sps), sr_max(u32 LE sps), sr_step(u32 LE sps)]. Returns 8 bytes on lock [freq_khz(4) + sr_locked(4)] or 1 byte 0x00 if no lock found.
0xB4 I2C_BUS_SCAN: Returns a 16-byte bitmap (128 bits for addresses 0x00—0x77). Each bit position corresponds to a 7-bit address; bit set = ACK received. Known devices on the SkyWalker-1 bus:
| Address | Identity |
|---|---|
| 0x08 | BCM4500 demodulator (7-bit; wire addresses 0x10 write / 0x11 read) |
| 0x10 | Tuner or LNB controller |
| 0x51 | Configuration EEPROM (24Cxx-family) |
4. Configuration Status Byte
Section titled “4. Configuration Status Byte”Returned by GET_8PSK_CONFIG (0x80). Stored in IRAM at a version-dependent address.
Bit 7 (0x80): bmArmed - MPEG-2 stream transfer armed / GPIF activeBit 6 (0x40): bmDCtuned - DC offset tuning complete (set for DCII modes)Bit 5 (0x20): bmSEL18V - 18V LNB voltage selected (else 13V)Bit 4 (0x10): bm22kHz - 22 kHz tone activeBit 3 (0x08): bmDVBmode - DVB mode enabledBit 2 (0x04): bmIntersilOn - LNB power supply enabledBit 1 (0x02): bm8pskFW_Loaded - BCM4500 firmware loaded (always set on SkyWalker-1)Bit 0 (0x01): bm8pskStarted - Device booted and running| Firmware | IRAM Address |
|---|---|
| v2.06 | 0x6D |
| Rev.2 v2.10.4 | 0x4E |
| v2.13 | 0x4F |
The kernel driver checks these bits to decide which initialization steps to perform. On the SkyWalker-1 after a successful BOOT_8PSK, config_status = 0x03 (STARTED + FW_LOADED).
5. Boot Sequence
Section titled “5. Boot Sequence”5.1 Kernel Driver Boot Flow
Section titled “5.1 Kernel Driver Boot Flow”1. GET_8PSK_CONFIG (0x80) -- read config status byte |-- Check bit 0: bm8pskStarted?
2. If not started: |-- BOOT_8PSK (0x89, wValue=1) |-- GET_FW_VERS (0x92) -- read firmware version
3. If bit 1 clear (bm8pskFW_Loaded): |-- LOAD_BCM4500 (0x88) -- Rev.1 Warm only; STALLs on SkyWalker-1
4. If bit 2 clear (bmIntersilOn): |-- START_INTERSIL (0x8A, wValue=1) -- enable LNB power supply
5. SET_DVB_MODE (0x8E, wValue=1) -- STALLs on all SkyWalker-1 FW versions
6. ARM_TRANSFER (0x85, wValue=0) -- abort any pending MPEG transfer
7. Device ready for tuning5.2 BCM4500 Boot Sequence (BOOT_8PSK, 0x89)
Section titled “5.2 BCM4500 Boot Sequence (BOOT_8PSK, 0x89)”As implemented in bcm4500_boot() in custom firmware v3.01.0, reverse-engineered from stock v2.06 FUN_CODE_1D4F + FUN_CODE_0ddd:
Step Action GPIO/I2C Duration---- ------------------------------------ ----------------- --------1 Assert BCM4500 RESET P0.5 = LOW --2 Power on P0.1 = HIGH -- P0.2 = LOW3 Wait for power settle -- 30 ms4 Release RESET P0.5 = HIGH --5 Wait for BCM4500 POR + ROM boot -- 50 ms6 I2C probe (read register 0xA2) I2C read 0x08:0xA2 ~0.1 ms7 Write init block 0 to page 0 I2C write 0xA6/A7/A8 ~2 ms8 Write init block 1 to page 0 I2C write 0xA6/A7/A8 ~2 ms9 Write init block 2 to page 0 I2C write 0xA6/A7/A8 ~1 ms10 Set config_status = 0x03 -- --Total boot time: approximately 90 ms (30 ms power + 50 ms POR + ~10 ms I2C).
5.3 BCM4500 Initialization Data
Section titled “5.3 BCM4500 Initialization Data”Three register initialization blocks are written to BCM4500 indirect registers (page 0x00) via the 0xA6/0xA7/0xA8 protocol. Data extracted from stock v2.06 firmware FUN_CODE_0ddd:
| Block | Start Register | Length | Data (hex) |
|---|---|---|---|
| 0 | 0x06 | 7 bytes | 06 0b 17 38 9f d9 80 |
| 1 | 0x07 | 8 bytes | 07 09 39 4f 00 65 b7 10 |
| 2 | 0x0F | 3 bytes | 0f 0c 09 |
Each block is written as: page select (0xA6 = 0x00), data bytes to 0xA7, trailing zero to 0xA7, then commit (0xA8 = 0x03). The firmware polls 0xA8 until the command completes before proceeding to the next block.
5.4 FX2 CPUCS Recovery
Section titled “5.4 FX2 CPUCS Recovery”The FX2’s CPUCS register at 0xE600 controls the 8051 run/halt state. The standard vendor request bRequest=0xA0 (RAM read/write) is handled by the FX2 boot ROM in silicon, not by user firmware. This means fw_load.py can reload firmware over a completely hung device:
sudo python3 tools/fw_load.py load firmware/build/skywalker1.ihx --wait 3Writing 0x01 to CPUCS halts the CPU. New code is written to RAM. Writing 0x00 restarts it. The device re-enumerates with the new firmware.
6. BCM4500 Demodulator Interface
Section titled “6. BCM4500 Demodulator Interface”6.1 I2C Addressing
Section titled “6.1 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 SFRs | I2CS, I2DAT, I2CTL |
| 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, which is the standard I2C convention for 7-bit address 0x08.
The v2.13 firmware probes addresses 0x7F and 0x3F at startup (INT0 handler) to detect which demodulator variant is present. These may be alternative I2C address configurations or addresses for different demodulator sub-systems.
6.2 Direct Registers
Section titled “6.2 Direct Registers”Accessed via standard I2C write/read to the BCM4500’s device address:
| Register | Function |
|---|---|
| 0xA2 | Status register (polled for readiness during boot) |
| 0xA4 | Lock/ready register; bit 5 (0x20) = signal locked |
| 0xA6 | Indirect page/address select |
| 0xA7 | Indirect data register (read/write) |
| 0xA8 | Indirect command register |
| 0xF9 | Demod status (read by v2.13 GET_DEMOD_STATUS / INT0 polling) |
6.3 Indirect Register Protocol
Section titled “6.3 Indirect Register Protocol”The BCM4500 uses an indirect register access scheme through three directly-addressable registers:
Indirect Write Sequence:
1. I2C WRITE to 0x08, register 0xA6 <- page_number (typically 0x00)2. I2C WRITE to 0x08, register 0xA7 <- data bytes (N bytes, auto-increment)3. I2C WRITE to 0x08, register 0xA8 <- 0x03 (execute indirect write)4. Poll register 0xA8 until bit 0 clear (command complete)5. Optionally read back register 0xA7 to verifyIndirect Read Sequence:
1. I2C WRITE to 0x08, register 0xA6 <- target_register2. I2C WRITE to 0x08, register 0xA7 <- 0x00 (placeholder)3. I2C WRITE to 0x08, register 0xA8 <- 0x01 (execute indirect read)4. Short delay (~1 ms)5. I2C READ from 0x08, register 0xA7 <- result byte6.4 Indirect Protocol Auto-Increment
Section titled “6.4 Indirect Protocol Auto-Increment”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 in one I2C WRITE operation (without issuing STOP between bytes), the BCM4500 internally advances its data buffer pointer after each byte. This allows writing an entire initialization block in a single I2C transaction:
I2C transaction: START -> 0x10 (write) -> 0xA7 (reg) -> data[0] -> data[1] -> ... -> data[N-1] -> STOPThe firmware exploits this for initialization blocks and tuning data, reducing I2C overhead compared to byte-by-byte writes.
Stock firmware init block write sequence (from FUN_CODE_0ddd):
1. I2C WRITE: [0x10] [0xA6] [0x00] -- Page select = 02. I2C WRITE: [0x10] [0xA7] [data0..dataN] -- Multi-byte data (auto-increment)3. I2C WRITE: [0x10] [0xA7] [0x00] -- Trailing zero (stock firmware quirk)4. I2C WRITE: [0x10] [0xA8] [0x03] -- Commit indirect write5. Poll: I2C READ [0xA8] until bit 0 clear -- Wait for completionThe trailing zero write (step 3) appears in all stock firmware versions. Its purpose is unclear — it may zero-pad the data buffer or serve as an end-of-data marker within the BCM4500’s indirect register engine.
6.5 Demodulator Scan
Section titled “6.5 Demodulator Scan”The tune function (stock firmware) tries up to 3 different I2C address configurations per attempt, with 3 outer retries (up to 9 total I2C programming attempts). This supports hardware variants where the BCM4500 may appear at different bus addresses.
v2.13 adds a boot-time probe: INT0 polls addresses 0x7F and 0x3F up to 40 times (0x28), setting flag _1_4 if neither responds. This prevents tuning attempts on boards with absent demodulators.
6.6 BCM4500 FEC Architecture
Section titled “6.6 BCM4500 FEC Architecture”The BCM4500 contains two FEC decoder paths:
-
Advanced Modulation Turbo FEC Decoder: Iterative turbo code decoder supporting QPSK (rates 1/4, 1/2, 3/4), 8PSK (rates 2/3, 3/4, 5/6, 8/9), 16QAM (rate 3/4), with Reed-Solomon (t=10) outer code.
-
Legacy DVB/DIRECTV/DCII-Compliant FEC Decoder: Concatenated Viterbi inner decoder (convolutional code, rates 1/2 through 7/8) + Reed-Solomon outer decoder.
There is no LDPC or BCH decoder hardware. See Section 14.
7. Tuning Protocol
Section titled “7. Tuning Protocol”7.1 TUNE_8PSK Command Format (0x86)
Section titled “7.1 TUNE_8PSK Command Format (0x86)”The host sends a 10-byte OUT payload via USB control transfer:
USB SETUP: bmRequestType=0x40, bRequest=0x86, wValue=0, wIndex=0, wLength=10
EP0BUF 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 Section 1.1) [9] Inner FEC Rate Index into modulation-specific tableSymbol Rate is in samples per second (sps). The Windows driver multiplies ksps by 1000.
Frequency is the IF frequency in kHz (950000—2150000), computed by the host as (RF_freq - LO_freq) * multiplier.
7.2 Firmware EP0BUF Parsing
Section titled “7.2 Firmware EP0BUF 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) | 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 so values can be written directly to the demodulator via I2C.
7.3 Modulation Dispatch
Section titled “7.3 Modulation Dispatch”After parsing, the firmware validates the modulation type (bounds check < 10) and dispatches via a 20-byte jump table (10 entries x 2 bytes) at CODE:0873. Each handler:
- Validates the FEC index against the maximum for that modulation
- Looks up a preconfigured byte from an XRAM FEC rate table
- Writes configuration to four XRAM registers (0xE0EB, 0xE0EC, 0xE0F5, 0xE0F6)
Modulation jump table (from Rev.2 at CODE:0873):
| Entry | AJMP 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) |
DSS and DVB BPSK share the same handler. Their FEC lookup uses the same table (0xE0F9) but ORs the result with 0x80 to distinguish them from DVB-S QPSK.
7.4 FEC Rate Lookup Tables
Section titled “7.4 FEC Rate Lookup Tables”Populated from the CODE-space init table at boot:
| XRAM Base | Modulation | Max FEC 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 |
7.5 BCM4500 XRAM Configuration After Dispatch
Section titled “7.5 BCM4500 XRAM Configuration After Dispatch”| XRAM Addr | Register | DVB-S QPSK | Turbo (Q/8/16) | DCII | DSS/BPSK |
|---|---|---|---|---|---|
| 0xE0EB | FEC Code Rate | Table lookup | Table lookup | 0xFC (fixed) | Table 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 |
DCII Demod Mode values:
| Modulation | Index | XRAM 0xE0F5 |
|---|---|---|
| DCII Combo | 4 | 0x10 |
| DCII I-stream | 5 | 0x12 |
| DCII Q-stream | 6 | 0x16 |
| DCII Offset QPSK | 7 | 0x11 |
DSS (8) and DVB BPSK (9) share the DVB-S QPSK handler; they use the same FEC table but OR the lookup value with 0x80.
7.6 Complete Tuning Sequence (Host to Satellite)
Section titled “7.6 Complete Tuning Sequence (Host to Satellite)”=== Phase 1: LNB Configuration (separate vendor commands) ===1. SET_LNB_VOLTAGE (0x8B) -- GPIO P0.4 (no I2C) H / Circular-L -> wValue=1 (18V) V / Circular-R -> wValue=0 (13V)2. SET_22KHZ_TONE (0x8C) -- GPIO P0.3 (no I2C) High band -> wValue=1 (tone on) Low band -> wValue=0 (tone off)3. SEND_DISEQC_COMMAND (0x8D) -- if multi-switch needed
=== Phase 2: Tune Command ===4. TUNE_8PSK (0x86) -- 10-byte payload
=== Phase 3: Firmware Internal Processing ===5. EP0BUF parsing: mod/FEC to IRAM, freq/SR byte-reversed to XRAM6. Modulation dispatch: FEC lookup, XRAM config registers set7. GPIO P3.6: DVB mode select
=== Phase 4: BCM4500 I2C Programming (3 outer retries x 3 I2C addresses) ===8. Poll BCM4500 ready: I2C READ regs 0xA2, 0xA8, 0xA49. Write page: I2C WRITE reg 0xA6 <- 0x0010. Write config: I2C WRITE reg 0xA7 <- [freq, SR, FEC, mod, demod params]11. Execute: I2C WRITE reg 0xA8 <- 0x03 (indirect write command)12. Poll completion: I2C READ regs 0xA8, 0xA213. Verify: I2C READ reg 0xA7 (read-back compare)
=== Phase 5: Signal Acquisition (host polling) ===14. GET_SIGNAL_LOCK (0x90) -- poll until non-zero15. GET_SIGNAL_STRENGTH (0x87) -- read SNR7.7 Signal Lock and Strength
Section titled “7.7 Signal Lock and Strength”GET_SIGNAL_LOCK (0x90): Returns 1 byte from BCM4500 register 0xA4. Bit 5 (0x20) indicates signal lock. The kernel driver interprets any non-zero value as locked and reports FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER.
GET_SIGNAL_STRENGTH (0x87): Returns 6 bytes. Bytes 0—1 = 16-bit SNR (LE, dBu * 256). SNR scaling: snr_raw * 17 maps 0x0000—0x0F00 to 0—65535 (100% at SNR >= 0x0F00).
8. GPIF Streaming Path
Section titled “8. GPIF Streaming Path”8.1 Data Flow
Section titled “8.1 Data Flow”BCM4500 Cypress FX2 (CY7C68013A) USB HostDemodulator P3.5 GPIF Engine EP2 FIFO EP2 (0x82) (I2C:0x08) <-----> (Master Read) (AUTOIN) ------------> Bulk IN 8-bit 0xE4xx wfm 4x buffer 7 URBs parallel 8-bit x 8KBThe path is fully hardware-managed. The GPIF engine reads data from the BCM4500’s 8-bit parallel transport stream output directly into the EP2 FIFO. The AUTOIN bit causes automatic USB commit when the FIFO buffer is full. The FLOWSTATE engine re-triggers GPIF transactions when buffer space becomes available. No firmware intervention occurs in the data path after initial setup.
8.2 Key Register Configuration
Section titled “8.2 Key Register Configuration”All values are identical across the three stock firmware versions:
| Register | Address | Value | Function |
|---|---|---|---|
| IFCONFIG | 0xE601 | 0xEE | Internal 48 MHz clock, GPIF master, async, debug |
| EP2FIFOCFG | 0xE618 | 0x0C | AUTOIN=1, ZEROLENIN=1, 8-bit data path |
| REVCTL | 0xE60B | 0x03 | NOAUTOARM + SKIPCOMMIT |
| CPUCS | 0xE600 | bits [4:3]=10 | 48 MHz CPU clock |
| FLOWSTATEA | 0xE668 | OR 0x09 | FSEN (flow state enable) + FS[3] |
| GPIFIE | 0xE65C | OR 0x3D | Waveform, TC, DONE, FIFO flag, WF2 interrupts |
IFCONFIG decode (0xEE = 1110_1110):
| Bit | Name | Value | Meaning |
|---|---|---|---|
| 7 | IFCLKSRC | 1 | Internal clock source |
| 6 | 3048MHZ | 1 | 48 MHz IFCLK frequency |
| 5 | IFCLKOE | 1 | IFCLK pin drives output (clock to BCM4500) |
| 4 | IFCLKPOL | 0 | Non-inverted clock polarity |
| 3 | ASYNC | 1 | Asynchronous GPIF (RDY pin handshaking) |
| 2 | GSTATE | 1 | Debug state output on PORTE |
| 1:0 | IFCFG | 10 | GPIF internal master mode |
8.3 ARM_TRANSFER Sequences
Section titled “8.3 ARM_TRANSFER Sequences”Start streaming (wValue=1):
- Set config_byte bit 7 (streaming active)
- Load GPIF transaction count: GPIFTCB3:2 = 0x8000 (effectively infinite)
- Reset GPIF address and EP2 FIFO byte count
- Assert P3.5 LOW (BCM4500 transport stream enable)
- Wait for initial GPIF transaction (poll GPIFTRIG bit 7)
- De-assert P3.5 HIGH
- Trigger continuous GPIF read: GPIFTRIG = 0x04 (read into EP2)
- Set P0.7 LOW (streaming indicator)
Stop streaming (wValue=0):
- Set P0.7 HIGH (streaming stopped)
- Write EP2FIFOBCH = 0xFF (force-flush current buffer)
- Wait for GPIF idle (poll GPIFTRIG bit 7)
- Write OUTPKTEND = 0x82 (skip/discard partial EP2 packet)
- Clear config_byte bit 7 (streaming inactive)
- Set P3 bits 7:5 = 1 (de-assert all BCM4500 control lines)
8.4 Throughput Analysis
Section titled “8.4 Throughput Analysis”| Metric | Value |
|---|---|
| USB 2.0 HS bulk theoretical | 480 Mbps |
| USB 2.0 HS bulk practical | ~280 Mbps (~35 MB/s) |
| GPIF engine theoretical | 48 MHz x 8 bits = 384 Mbps |
| Typical DVB-S TS rate | 1—5 MB/s |
| Maximum DVB-S2 rate (hypothetical) | ~7.25 MB/s (58 Mbps) |
The USB/GPIF path has approximately 5x headroom even at maximum theoretical DVB-S2 data rates. The bottleneck for supported modes is the satellite link, not the USB data path.
8.5 FIFO Reset Sequence
Section titled “8.5 FIFO Reset Sequence”All endpoint FIFOs are reset during initialization using the Cypress-prescribed procedure:
FIFORESET = 0x80 ; NAKALL: NAK all host transfers during resetFIFORESET = 0x02 ; Reset EP2 FIFOFIFORESET = 0x04 ; Reset EP4 FIFOFIFORESET = 0x06 ; Reset EP6 FIFOFIFORESET = 0x08 ; Reset EP8 FIFOFIFORESET = 0x00 ; Release NAKALLThree NOP instructions (mandatory SYNCDELAY) are inserted between each write per Cypress TRM requirements.
8.6 EP2 Endpoint Configuration
Section titled “8.6 EP2 Endpoint Configuration”EP2CFG = 0xE2; // valid=1, dir=IN, type=BULK, size=512, buf=DOUBLE| Bit | Value | Meaning |
|---|---|---|
| 7 (VALID) | 1 | Endpoint enabled |
| 6 (DIR) | 1 | IN (device to host) |
| 5:4 (TYPE) | 10 | Bulk transfer |
| 3 (SIZE) | 0 | 512-byte packets |
| 1:0 (BUF) | 10 | Double-buffered |
EP4, EP6, EP8 are disabled (&= ~bmVALID).
8.7 Interrupt Handling
Section titled “8.7 Interrupt Handling”INT4 and INT6 (GPIF/FIFO events) share a common handler that sets a software flag (_0_1) and clears EXIF.4. The main loop polls this flag, enters CPU idle mode (PCON.0) between events, and checks EP2CS for buffer availability before re-arming the GPIF.
Main loop structure (from v2.06 FUN_CODE_2297):
void main_loop_poll(void) { if (_0_1) { // GPIF/FIFO event pending _0_1 = 0; // Clear flag if (EP2CS & bmEPFULL) { // EP2 buffer full? // Wait for host to read EP2 } } else { PCON |= 0x01; // CPU idle until next interrupt }}8.8 Prior IFCONFIG Value
Section titled “8.8 Prior IFCONFIG Value”During early initialization, IFCONFIG is temporarily set to 0xCA before the final 0xEE:
| Value | Decode | Difference from 0xEE |
|---|---|---|
| 0xCA | 1100_1010 | GSTATE=0, ASYNC=0 |
| 0xEE | 1110_1110 | GSTATE=1, ASYNC=1 (final) |
The temporary value disables async mode and debug state output during FIFO setup.
9. LNB and DiSEqC Control
Section titled “9. LNB and DiSEqC Control”9.1 LNB Voltage
Section titled “9.1 LNB Voltage”LNB voltage is controlled via GPIO P0.4. No I2C is involved.
| wValue | Voltage | GPIO P0.4 | Polarization |
|---|---|---|---|
| 0 | 13V | LOW | Vertical / Circular-Right |
| 1 | 18V | HIGH | Horizontal / Circular-Left |
USE_EXTRA_VOLT (0x94) enables a +1V boost (13V->14V, 18V->19V) for long cable runs by writing to XRAM 0xE0B6 (0x62=normal, 0x6A=boosted; bit 3 is the difference).
9.2 22 kHz Tone
Section titled “9.2 22 kHz Tone”Controlled via GPIO P0.3. P0.3 gates an external 22 kHz oscillator on the PCB. The firmware does not generate the 22 kHz carrier directly.
| wValue | State | GPIO P0.3 | Band |
|---|---|---|---|
| 0 | OFF | LOW | Low band (9.75 GHz LO on universal LNB) |
| 1 | ON | HIGH | High band (10.6 GHz LO on universal LNB) |
9.3 DiSEqC Protocol Implementation
Section titled “9.3 DiSEqC Protocol Implementation”All firmware versions implement DiSEqC via Timer2-based GPIO bit-bang. The algorithm is identical across versions; only the data pin differs per PCB revision.
Timer2 configuration (identical across all versions):
| Parameter | Value |
|---|---|
| T2CON | 0x04 (auto-reload, running) |
| RCAP2H:RCAP2L | 0xF82F (reload = 63535) |
| CKCON.T2M | 0 (Timer2 clock = 48 MHz / 12 = 4 MHz) |
| Tick period | (65536 - 63535) / 4 MHz = 500.25 us |
DiSEqC timing parameters:
| Parameter | Value |
|---|---|
| Bit period | 1.5 ms (3 Timer2 ticks) |
| Byte period | 13.5 ms (9 bits: 8 data + 1 parity) |
| Tone burst A/B | 12.5 ms (25 ticks) |
| Pre-TX settling delay | 7.5 ms (15 ticks) |
| Data ‘0’ | 1.0 ms tone + 0.5 ms silence (2/3 duty cycle) |
| Data ‘1’ | 0.5 ms tone + 1.0 ms silence (1/3 duty cycle) |
| Carrier frequency | 22 kHz (external oscillator, gated by P0.3) |
Manchester encoding (decompiled from Rev.2 FUN_CODE_213c):
Each DiSEqC bit = 3 Timer2 ticks: Tick 1: inter-bit gap (carrier OFF via P0.3 = 0) Tick 2: carrier ON (P0.3 = 1) Tick 3: if data_pin='1', carrier OFF early; if '0', carrier stays ON End: carrier always OFFDiSEqC bit waveforms:
Data '0' (2/3 tone, 1/3 silence): Tick 1 Tick 2 Tick 3 (500 us) (500 us) (500 us)P0.3: _____|========|========|________| ^tone ON ^tone OFF (setup gap) (1.0 ms carrier) (0.5 ms silence)
Data '1' (1/3 tone, 2/3 silence): Tick 1 Tick 2 Tick 3 (500 us) (500 us) (500 us)P0.3: _____|========|________|________| ^tone ON ^tone OFF early (setup gap) (0.5 ms carrier) (1.0 ms silence)Decompiled bit symbol function (from Rev.2 FUN_CODE_213c):
void diseqc_bit_symbol(void) { wait_TF2(); // Tick 1: inter-bit gap (500 us) P0 |= 0x08; // P0.3 = 1 -> 22 kHz carrier ON wait_TF2(); // Tick 2: carrier period (500 us) if (data_pin != 0) { // If data = '1': P0 &= 0xF7; // P0.3 = 0 -> carrier OFF (short pulse) } wait_TF2(); // Tick 3: final period (500 us) P0 &= 0xF7; // P0.3 = 0 -> carrier always OFF at end}Decompiled byte transmission (from Rev.2 FUN_CODE_07d1):
void diseqc_send_byte(char first_byte, byte data) { byte ones_count = 0; if (first_byte == 0) TF2 = 0; // Sync timer on first byte
for (char i = 8; i > 0; i--) { // 8 bits, MSB first if (data & 0x80) { data_pin = 1; // Set data = '1' diseqc_bit_symbol(); ones_count++; } else { data_pin = 0; // Set data = '0' diseqc_bit_symbol(); } data <<= 1; // Next bit } data_pin = ~ones_count & 1; // Odd parity diseqc_bit_symbol(); // Transmit parity bit}Timing per byte: 9 bits x 1.5 ms = 13.5 ms
Tone burst (mini DiSEqC): 25 consecutive Timer2 ticks of carrier (12.5 ms). Tone burst A: wValue==0 and wLength==0. Tone burst B: wValue!=0 and wLength==0.
Timer tick wait (TF2 polling, identical across all versions):
void wait_TF2(void) { while (TF2 == 0) {} // Poll Timer2 overflow flag TF2 = 0; // Clear flag for next tick}9.4 DiSEqC Signal Architecture
Section titled “9.4 DiSEqC Signal Architecture”FX2 Firmware External Hardware Coax Cable+------------------+ +--------------------+ +------------------+| P0.3 (carrier) |---->| 22 kHz oscillator |---->| LNB power line || (enable/disable) | | (gated by P0.3) | | (13V/18V + tone) || | | | | || P0.x (data bit) | | (internal firmware | | || (firmware only) | | logic only) | | |+------------------+ +--------------------+ +------------------+The data pin (P0.7 / P0.4 / P0.0 depending on firmware version) is used only internally by the firmware’s Manchester encoding logic. It controls whether the carrier gate signal is cut short or held for the full bit period.
9.5 Windows BDA Driver DiSEqC Interface
Section titled “9.5 Windows BDA Driver DiSEqC Interface”The Windows driver exposes DiSEqC through a BDA extended property:
// GUID: {0B5221EB-F4C4-4976-B959-EF74427464D9}typedef struct __DISEQC_COMMAND { UCHAR ucMessage[6]; // Framing, Address, Command, Data[0..2] UCHAR ucMessageLength; // 3-6 for DiSEqC; 1 for tone burst} DISEQC_COMMAND;For tone burst: ucMessageLength=1, ucMessage[0]=SEC_MINI_A (0x00) or SEC_MINI_B (0x01).
9.6 SET_DN_SWITCH (0x8F) — Legacy Dish Network
Section titled “9.6 SET_DN_SWITCH (0x8F) — Legacy Dish Network”A 7-bit serial command bit-banged on GPIO P0.4:
- Assert P0.4 HIGH (start pulse), delay ~32 cycles
- De-assert P0.4, delay ~8 cycles
- Shift out 7 bits LSB-first via P0.4, ~8 cycle delays between bits
The kernel calls this via dishnetwork_send_legacy_command. Bit 7 (0x80) of the original switch command selects LNB voltage and is sent separately via SET_LNB_VOLTAGE.
10. GPIO Pin Map
Section titled “10. GPIO Pin Map”10.1 Port 0 / Port A (SFR 0x80, IOA)
Section titled “10.1 Port 0 / Port A (SFR 0x80, IOA)”| Pin | v2.06 | Rev.2 v2.10 | v2.13 | Custom v3.01.0 |
|---|---|---|---|---|
| P0.0 | — | LNB control (0x97) | DiSEqC data | — |
| P0.1 | Power enable | Power enable | Power enable | Power enable |
| P0.2 | Power disable | Power disable (init=0x84) | Power disable | Power disable |
| P0.3 | 22 kHz tone | 22 kHz tone | 22 kHz tone | 22 kHz tone |
| P0.4 | LNB 13V/18V | LNB 13V/18V + DiSEqC data | LNB 13V/18V | LNB 13V/18V |
| P0.5 | BCM4500 RESET | GPIO status input (0x98) | BCM4500 RESET | BCM4500 RESET |
| P0.6 | — | GPIO control (0x97) | — | — |
| P0.7 | DiSEqC data | Streaming indicator | Streaming indicator | DiSEqC data + streaming |
10.2 Port 3 / Port D (SFR 0xB0, IOD)
Section titled “10.2 Port 3 / Port D (SFR 0xB0, IOD)”| Pin | Function | Notes |
|---|---|---|
| P3.0 | Init HIGH | |
| P3.4 | GPIO control | Used by Rev.2 FUN_CODE_1fcf |
| P3.5 | TS_EN | Transport stream enable: LOW=active, HIGH=idle |
| P3.6 | DVB mode | BCM4500 mode select; DiSEqC direction (Rev.2) |
| P3.7 | BCM4500 control | De-asserted (HIGH) when streaming stops |
10.3 Port B (XRAM-mapped IOB)
Section titled “10.3 Port B (XRAM-mapped IOB)”Used by internal debug commands 0x96—0x98:
| Pin | v2.06/v2.13 | Rev.2 |
|---|---|---|
| IOB.0 | GPIO status input (0x98) | — |
| IOB.1 | LNB control (0x97) | — |
| IOB.2 | LNB control (0x97) | — |
| IOB.3 | LNB GPIO mode (0x96) | — |
| IOB.4 | — | LNB GPIO mode (0x96) + control (0x97) |
10.4 DiSEqC Data Pin Summary
Section titled “10.4 DiSEqC Data Pin Summary”| Firmware Version | Data Pin | Carrier Pin |
|---|---|---|
| v2.06 | P0.7 | P0.3 |
| Rev.2 v2.10 | P0.4 | P0.3 |
| v2.13 | P0.0 | P0.3 |
| Custom v3.01.0 | P0.7 | P0.3 |
The carrier pin (P0.3) is the same across all versions.
10.5 Initial GPIO State
Section titled “10.5 Initial GPIO State”| Register | Value | Decode |
|---|---|---|
| IOA (P0) | 0x84 | P0.7=1 (idle), P0.2=1 (power disable active) |
| IOD (P3) | 0xE1 | P3.7:5=1 (controls idle), P3.0=1 |
| OEA | 0xBE | P0.1-5,7 as outputs |
11. Firmware Versions
Section titled “11. Firmware Versions”11.1 Version Table
Section titled “11.1 Version Table”| Firmware | Version ID | Build Date | PID | Functions | Binary Size | SP |
|---|---|---|---|---|---|---|
| v2.06.04 | 0x020604 | 2007-07-13 | 0x0203 | 61 | 9,472 bytes | 0x72 |
| Rev.2 v2.10.04 | 0x020A04 | 2010-03-12 | 0x0202 | 107 | 8,843 bytes | 0x4F |
| v2.13.01 (FW1) | 0x020D01 | 2010-03-12 | 0x0203 | 82-88 | 9,322 bytes | 0x50 |
| v2.13.02 (FW2) | 0x020D01 | 2010-03-12 | 0x0203 | 83 | 9,377 bytes | 0x50 |
| v2.13.03 (FW3) | 0x020D01 | 2010-03-12 | 0x0203 | 83 | 9,369 bytes | 0x52 |
| Custom v3.01.0 | 0x030100 | 2026-02-12 | 0x0203 | N/A | ~3 KB (RAM) | N/A |
Rev.2 v2.10 targets PID 0x0202 (different product). The v2.13 sub-variants target different SkyWalker-1 hardware sub-revisions. Custom v3.01.0 is compiled with SDCC + fx2lib and loaded into FX2 RAM (not flashed to EEPROM).
11.2 Kernel Version Constants
Section titled “11.2 Kernel Version Constants”From gp8psk-fe.h:
GP8PSK_FW_REV1 = 0x020604 (v2.06.4)GP8PSK_FW_REV2 = 0x020704 (v2.07.4)If fw_vers >= GP8PSK_FW_REV2, the kernel enables Rev.2-specific code paths. The v2.10 and v2.13 firmwares are newer than either kernel constant.
11.3 Key Architectural Differences
Section titled “11.3 Key Architectural Differences”| Feature | v2.06 | Rev.2 v2.10 | v2.13 |
|---|---|---|---|
| Vendor commands | 30 (0x80—0x9D) | 27 (0x80—0x9A) | 30 (0x80—0x9D) |
| INT0 handler | USB re-enumeration | USB re-enumeration | Demod availability polling |
| Demod probe at boot | No | No | Yes (40 attempts at 0x7F + 0x3F) |
| Retry loops | No | No | Yes (20-attempt with checksum verify) |
| HW revision detection | No | Yes (descriptor walker) | Yes (flag _1_3) |
| DiSEqC data pin | P0.7 | P0.4 | P0.0 |
| Config byte IRAM | 0x6D | 0x4E | 0x4F |
| Descriptor base | 0x1200 | 0x0E00 | 0x0E00 |
| Init table address | CODE:0B46 | CODE:0B48 | CODE:0B88 |
| BCM4500 status poll | 3 registers | 3 registers | 1 register (consolidated) |
| Anti-tampering string | No | No | Yes (at firmware offset 0x1880) |
| New commands | — | 0x99/0x9A proto | 0x99, 0x9A, 0x9C |
| 0x9D behavior | HW revision mode | N/A (out of range) | Conditional demod reset |
11.4 v2.13 Sub-Variant Differences
Section titled “11.4 v2.13 Sub-Variant Differences”The three v2.13 sub-variants target fundamentally different hardware interfaces:
| Aspect | FW1 (v2.13.1) | FW2 (v2.13.2) | FW3 (v2.13.3) |
|---|---|---|---|
| Demod interface | I2C bus | Parallel bus (P0/P1) | Parallel bus (enhanced) |
| Bus protocol | I2C START/STOP/ACK | Single-phase P1 read | Dual-phase P1 read + OR accumulate |
| Stack pointer | 0x50 | 0x50 | 0x52 |
| P0 init | 0xa4 | 0xa4 | 0xa0 |
| Status register | INTMEM 0x4F | INTMEM 0x4F | INTMEM 0x51 |
| Config source | Hardcoded | External (0xE080-0xE08E) | External (0xE080-0xE08E) |
| Binary distance from FW1 | — | 3,993 bytes | 3,789 bytes |
| Binary distance from FW2 | 3,993 bytes | — | 1,525 bytes |
FW1 uses standard I2C master-mode transactions. FW2/FW3 use a parallel data bus with P0 for control signals (chip select, read strobe) and P1 for 8-bit data. FW3 adds dual-phase reading with OR-accumulation, likely for a demodulator chip with different bus timing. The updater program selects the correct sub-variant based on hardware detection.
11.5 Binary Comparison Matrix
Section titled “11.5 Binary Comparison Matrix”Byte-level similarity (percentage of matching bytes within shared length):
| v2.06 | v2.13.1 | v2.13.2 | v2.13.3 | Rev.2 | |
|---|---|---|---|---|---|
| v2.06 | — | 4.8% | 4.3% | 4.3% | 6.0% |
| v2.13.1 | — | 57.2% | 59.4% | 8.0% | |
| v2.13.2 | — | 83.5% | 5.8% | ||
| v2.13.3 | — | 5.8% | |||
| Rev.2 | — |
The very low similarity between major versions (4—8%) indicates complete recompilation with different linker configurations. Functions relocate even when logic is identical.
11.6 Anti-Tampering (v2.13 Only)
Section titled “11.6 Anti-Tampering (v2.13 Only)”At firmware offset 0x1880, all v2.13 sub-variants contain:
"Tampering is detected. Attempt is logged. Warranty is voided ! \n"Followed by I2C register write commands (01 10 aa 82 02 41 41 83). This string and mechanism are absent from v2.06 and Rev.2.
11.7 Rev.2 as Transitional Firmware
Section titled “11.7 Rev.2 as Transitional Firmware”Rev.2 v2.10.4 sits architecturally between v2.06 and v2.13:
- Adopted v2.13’s descriptor base (0x0E00) and similar stack pointer
- Retained v2.06’s INT0 USB re-enumeration behavior
- Has the most functions (107) but smallest binary (~8.8 KB) due to granular decomposition
- Lacks v2.13’s demodulator polling, retry loops, and additional vendor commands
11.8 Key Function Correspondence Across Versions
Section titled “11.8 Key Function Correspondence Across Versions”| v2.06 Function | Rev.2 Function | v2.13 Function | Role |
|---|---|---|---|
main (0x188D) | main (0x155F) | main_entry (0x170D) | RESET vector: clear IRAM, process init table |
FUN_CODE_09a7 | FUN_CODE_09a9 | FUN_CODE_0800 | Main init + main loop |
FUN_CODE_13c3 | FUN_CODE_10d9 | FUN_CODE_11ab | USB/peripheral descriptor setup |
FUN_CODE_032a | FUN_CODE_0319 | FUN_CODE_034e | Standard USB request handler |
FUN_CODE_0056 | vendor_cmd_dispatch | FUN_CODE_0056 | Vendor request dispatcher (identical code) |
FUN_CODE_2297 | — | FUN_CODE_21ec | Main loop poll (USB IRQ processing) |
FUN_CODE_1919 | FUN_CODE_0d7c | FUN_CODE_1800 | GPIF/FIFO management |
FUN_CODE_1d4f | — | — | v2.06 demod init (GPIO-based) |
| — | — | FUN_CODE_1d4b | v2.13 demod init (I2C write to 0x7F/0xF0) |
FUN_CODE_0ddd | FUN_CODE_0c64 | FUN_CODE_0ca4 | BCM4500 firmware loader |
FUN_CODE_2000 | — | FUN_CODE_208d | BCM4500 status polling |
FUN_CODE_1dfb | FUN_CODE_1bda | FUN_CODE_14b9 | Delay loop (clock-speed-aware) |
INT0_vec (0x0003) | INT0_ISR (0x0003) | INT0_vector (0x0003) | INT0 handler (different purpose) |
| — | — | FUN_CODE_2239 | v2.13 I2C single-byte read helper |
| — | — | FUN_CODE_2031 | v2.13 USB reconnect function |
| — | — | FUN_CODE_1799 | v2.13 demod signature verification |
| — | — | FUN_CODE_1ac6 | v2.13 tuning acquisition sequence |
11.9 INT0 Handler Evolution
Section titled “11.9 INT0 Handler Evolution”The INT0 interrupt vector (CODE:0003) was repurposed between firmware versions:
v2.06 and Rev.2 — USB Re-enumeration:
void INT0_vec(void) { if (flag == 0) CPUCS |= 0x08; // CPUCS bit 3 else CPUCS |= 0x0A; // CPUCS bits 3+1 delay(5, 0xDC); // ~1500 cycles EPIRQ = 0xFF; // Clear endpoint IRQs USBIRQ = 0xFF; // Clear USB IRQs EXIF &= 0xEF; // Clear external interrupt flag CPUCS &= 0xF7; // Clear CPUCS bit 3}Pulses CPUCS.3 to trigger a controlled USB re-enumeration, then clears all pending interrupts.
v2.13 — Demodulator Availability Polling:
void INT0_vector(void) { for (counter = 0x28; counter != 0; counter--) { // 40 attempts byte result = I2C_read(0x7F); // Demod address A if (result != 0x01) { result = I2C_read(0x3F); // Demod address B if (result != 0x01) break; } } no_demod_flag = (counter == 0); // Set if loop exhausted}Polls two I2C addresses (0x7F, 0x3F) to detect which demodulator variant is present. The no_demod_flag prevents tuning attempts on boards with absent or failed demodulators.
In v2.13, the USB re-enumeration code was moved to FUN_CODE_2031 and called as a normal function before the main loop starts, freeing INT0 for demodulator polling.
11.10 v2.13 Integrity Verification
Section titled “11.10 v2.13 Integrity Verification”v2.13 performs two integrity checks during initialization, absent from v2.06 and Rev.2:
Demodulator Signature Verification (FUN_CODE_1799):
- Writes 4 bytes to I2C device 0x7F, register 0xF0
- Reads 5 bytes from register 0x0A (stepping by 2), each character
- Subtracts 0x30 (‘0’) from each byte (ASCII to binary)
- Sums values and compares against expected parameter (0x021C)
- Up to 20 retry attempts
Descriptor Checksum Verification (FUN_CODE_1ca0):
- Iterates bytes 6 through 0x29 (36 bytes) of a descriptor block
- Computes running sum, compares against 0x0706
- Iterates bytes 0x2C through 0x4F (36 bytes) of same block
- Computes second sum, compares against 0x0686
- Up to 20 retry attempts
Both checks call FUN_CODE_1ac6(100) (tuning acquisition with 100 ms delay) as a recovery action if verification fails after all attempts.
11.11 XRAM Initialization Table
Section titled “11.11 XRAM Initialization Table”All firmware versions initialize XRAM peripheral registers from a table stored in CODE space. The table is processed at startup before entering the main loop.
Table format (all versions):
Each entry: [addr_hi] [addr_lo] [data_byte]Terminator: [0x00] [0x00] (address 0x0000)The parser reads 3 bytes at a time: a 16-bit XRAM address (big-endian) and a data byte. It writes the byte to the address until it encounters address 0x0000.
Key XRAM registers initialized from the table:
| XRAM Address | Register | Typical Value | Purpose |
|---|---|---|---|
| 0xE604 | FIFORESET | 0x80 | Start FIFO reset sequence |
| 0xE601 | IFCONFIG | 0xCA | Initial interface config (overwritten later) |
| 0xE610 | EP2CFG | 0xE2 | EP2 bulk IN, 512-byte, double-buffered |
| 0xE612 | EP4CFG | 0x00 | EP4 disabled |
| 0xE618 | EP2FIFOCFG | 0x0C | AUTOIN, ZEROLENIN, 8-bit |
| 0xE620 | REVCTL | 0x03 | NOAUTOARM + SKIPCOMMIT |
| 0xE67A | I2CTL | 0x01 | I2C 400 kHz |
| 0xE68A | EP0BCH | 0x00 | EP0 byte count high = 0 |
Init table addresses by version:
| Firmware | Table Address |
|---|---|
| v2.06 | CODE:0B46 |
| Rev.2 | CODE:0B48 |
| v2.13 | CODE:0B88 |
11.12 Main Loop Architecture
Section titled “11.12 Main Loop Architecture”All firmware versions use the same main loop structure: poll the SUDAV (setup data available) interrupt flag, process vendor commands, then idle the CPU until the next interrupt.
v2.06 (simplified decompilation):
void main_loop(void) { // FUN_CODE_09a7 // 1. Process init table from CODE:0B46 // 2. Call FUN_CODE_13c3 (USB/peripheral setup) // 3. EA = 1 (global interrupts enable)
while (1) { if (sudav_flag) { handle_setupdata(); // Process USB SETUP packet sudav_flag = 0; } if (gpif_flag) { handle_gpif_event(); gpif_flag = 0; } else { PCON |= 0x01; // CPU idle until next interrupt } }}The SUDAV ISR simply sets sudav_flag = 1 and clears the interrupt. All actual USB processing happens in the main loop context.
12. I2C Bus Architecture
Section titled “12. I2C Bus Architecture”12.1 FX2 I2C Controller
Section titled “12.1 FX2 I2C Controller”The FX2’s I2C master controller is a hardware peripheral accessed through SFRs:
| SFR | Address | Function |
|---|---|---|
| I2CS | 0xE678 (XRAM) | I2C control/status register |
| I2DAT | 0xE679 (XRAM) | I2C data register |
| I2CTL | 0xE67A (XRAM) | I2C control (speed selection) |
Key I2CS bits: bmSTART (initiate START), bmSTOP (initiate STOP), bmLASTRD (signal last read byte), bmDONE (transaction byte complete), bmACK (ACK received), bmBERR (bus error).
12.2 Bus Speed
Section titled “12.2 Bus Speed”The I2C bus speed is 400 kHz, set via:
- C2 EEPROM header config byte = 0x40 (at boot)
- I2CTL = bm400KHZ (in custom firmware)
12.3 Known Bus Devices
Section titled “12.3 Known Bus Devices”| 7-bit Address | Wire Write/Read | Identity |
|---|---|---|
| 0x08 | 0x10 / 0x11 | BCM4500 demodulator |
| 0x10 | 0x20 / 0x21 | Tuner or LNB controller |
| 0x51 | 0xA2 / 0xA3 | Configuration EEPROM (24Cxx-family) |
The EEPROM at 0x51 stores: device serial number (read by GET_SERIAL_NUMBER 0x93), hardware platform ID (read by GET_FPGA_VERS 0x95), and calibration data.
12.4 Combined Write-Read (Repeated START) Protocol
Section titled “12.4 Combined Write-Read (Repeated START) Protocol”All BCM4500 register reads use the I2C combined write-read protocol with a repeated START condition. This is required because the BCM4500 uses a register-addressed protocol where the register number must be sent as a write phase before the read phase:
Complete I2C transaction for reading register 0xA2 from device 0x08:
Phase 1 (Write): [S] [0x10] [ACK] [0xA2] [ACK] | | | | | | | | | +-- BCM4500 ACKs register address | | | +--------- Register address | | +---------------- BCM4500 ACKs its address | +----------------------- Device address (0x08 << 1) = 0x10 (write) +---------------------------- START condition
Phase 2 (Read with Repeated START): [Sr] [0x11] [ACK] [DATA] [NACK] [P] | | | | | | | | | | | +-- STOP condition | | | | +--------- Master NACKs (last byte) | | | +---------------- Register data | | +----------------------- BCM4500 ACKs its address | +------------------------------ Device address (0x08 << 1 | 1) = 0x11 (read) +------------------------------------ REPEATED START (no STOP between phases)The repeated START (Sr) is essential. A STOP between phases would release the bus, and the BCM4500 would lose the register address context.
FX2 I2C SFR sequence for combined read (from custom firmware):
I2CS |= bmSTART; // Generate STARTI2DAT = 0x10; // Write: device addr + W// wait bmDONE, check bmACKI2DAT = 0xA2; // Write: register address// wait bmDONE, check bmACKI2CS |= bmSTART; // Generate REPEATED START (no STOP first!)I2DAT = 0x11; // Write: device addr + R// wait bmDONE, check bmACKI2CS |= bmLASTRD; // Signal this is the last read bytetmp = I2DAT; // Dummy read (triggers first clock burst)// wait bmDONEI2CS |= bmSTOP; // Generate STOP after readingdata = I2DAT; // Read actual data byte// wait bmSTOP to clear12.5 I2C STOP Corruption Bug
Section titled “12.5 I2C STOP Corruption Bug”Sending I2CS |= bmSTOP when no I2C transaction is active (no prior START issued, bus idle) corrupts the FX2 I2C controller’s internal state machine. The bmSTOP bit may not self-clear, and subsequent START conditions fail to detect ACK from slaves.
This was the root cause of the firmware hang in custom v3.01.0 during boot. The stock firmware’s “bus reset” step:
/* BROKEN: */I2CS |= bmSTOP;i2c_wait_stop();was removed. The correct approach is to simply proceed with a new START condition. If the bus is idle (after power-on or after the previous transaction completed normally), the START succeeds and the controller enters its normal operating state. The Cypress TRM does not document STOP as a standalone bus-reset mechanism.
12.6 Timeout Protection
Section titled “12.6 Timeout Protection”The fx2lib I2C functions poll bmDONE with no timeout:
while (!(I2CS & bmDONE) && !cancel_i2c_trans);Since cancel_i2c_trans is never set during normal operation, these loops are effectively infinite. The custom firmware replaces all fx2lib I2C functions with timeout-protected wrappers:
#define I2C_TIMEOUT 6000
static BOOL i2c_wait_done(void) { WORD timeout = I2C_TIMEOUT; while (!(I2CS & bmDONE)) { if (--timeout == 0) return FALSE; } return TRUE;}A WORD counter of 6000 decremented in a tight SDCC-compiled loop at 48 MHz gives approximately 5—10 ms per wait. At 400 kHz I2C, a single byte transfer takes 22.5 us, so the timeout provides over 200x margin for normal operations.
13. Custom Firmware v3.01.0
Section titled “13. Custom Firmware v3.01.0”13.1 Overview
Section titled “13.1 Overview”Custom replacement firmware built with SDCC and fx2lib. Loaded into FX2 RAM for testing via fw_load.py (not flashed to EEPROM).
| Property | Value |
|---|---|
| Toolchain | SDCC + fx2lib |
| Source | firmware/skywalker1.c (1351 lines) |
| Version ID | 0x030100 |
| Build date | 2026-02-12 |
| Load method | RAM upload via tools/fw_load.py |
13.2 Stock-Compatible Commands
Section titled “13.2 Stock-Compatible Commands”The custom firmware implements all commands needed for the kernel driver: GET_8PSK_CONFIG (0x80), ARM_TRANSFER (0x85), TUNE_8PSK (0x86), GET_SIGNAL_STRENGTH (0x87), BOOT_8PSK (0x89), START_INTERSIL (0x8A), SET_LNB_VOLTAGE (0x8B), SET_22KHZ_TONE (0x8C), SEND_DISEQC (0x8D), GET_SIGNAL_LOCK (0x90), GET_FW_VERS (0x92), USE_EXTRA_VOLT (0x94).
13.3 Custom Commands
Section titled “13.3 Custom Commands”| Command | Function |
|---|---|
| SPECTRUM_SWEEP (0xB0) | Step through frequency range reading signal energy |
| RAW_DEMOD_READ (0xB1) | Read any BCM4500 indirect register |
| RAW_DEMOD_WRITE (0xB2) | Write any BCM4500 indirect register |
| BLIND_SCAN (0xB3) | Try symbol rates at a frequency looking for lock |
| I2C_BUS_SCAN (0xB4) | Probe all 7-bit I2C addresses |
| I2C_RAW_READ (0xB5) | Read from any I2C device address |
| I2C_DIAG (0xB6) | Step-by-step indirect register read diagnostic |
13.4 Debug Boot Modes
Section titled “13.4 Debug Boot Modes”The BOOT_8PSK (0x89) command supports incremental debug modes via wValue:
| wValue | Action | Result |
|---|---|---|
| 0x80 | No-op: return config_status and boot_stage | Works |
| 0x81 | GPIO + power + delays only (no I2C) | Works |
| 0x82 | GPIO + power + I2C probe (bmSTOP removed) | Works |
| 0x83 | GPIO + power + probe + init block 0 | Works |
| 0x84 | I2C-only probe (chip already powered) | Works |
| 0x85 | Same as 0x82 without bmSTOP | Works |
| 0x01 | Full boot (production) | Works |
| 0x00 | Shutdown | Works |
These modes were used to isolate the I2C STOP corruption bug (see Section 12.4).
13.5 Key Implementation Patterns
Section titled “13.5 Key Implementation Patterns”I2C Combined Read (repeated START):
static BOOL i2c_combined_read(BYTE addr, BYTE reg, BYTE len, BYTE *buf) { I2CS |= bmSTART; I2DAT = addr << 1; // START + write address // ... wait for DONE, check ACK ... I2DAT = reg; // Register address // ... wait for DONE, check ACK ... I2CS |= bmSTART; I2DAT = (addr << 1) | 1; // REPEATED START + read address // ... read len bytes with LASTRD/STOP on final byte ...}BCM4500 Init Block Write:
static BOOL bcm_write_init_block(const __code BYTE *data, BYTE len) { bcm_direct_write(BCM_REG_PAGE, 0x00); // Page select i2c_write_multi_timeout(BCM4500_ADDR, BCM_REG_DATA, len, data); // Data bcm_direct_write(BCM_REG_DATA, 0x00); // Trailing zero bcm_direct_write(BCM_REG_CMD, BCM_CMD_WRITE); // Commit (0x03) return bcm_poll_ready(); // Wait for completion}14. DVB-S2 Incompatibility
Section titled “14. DVB-S2 Incompatibility”14.1 Definitive Conclusion
Section titled “14.1 Definitive Conclusion”The SkyWalker-1’s inability to receive DVB-S2 is a fundamental hardware limitation of the BCM4500 demodulator silicon. The BCM4500 was designed before the DVB-S2 standard was ratified (March 2005) and contains no LDPC or BCH decoder hardware. No firmware update can add DVB-S2 support.
14.2 FEC Architecture Comparison
Section titled “14.2 FEC Architecture Comparison”| Feature | BCM4500 (SkyWalker-1) | DVB-S2 Requirement |
|---|---|---|
| Inner FEC | Viterbi (DVB-S) or Turbo (proprietary) | LDPC |
| Outer FEC | Reed-Solomon (t=10) | BCH |
| Block size | Convolutional / short turbo blocks | 64,800 or 16,200 bits |
| Decoder type | Trellis (Viterbi) or iterative turbo | Iterative belief propagation |
| Hardware IP | Hardwired Viterbi + turbo silicon | Requires dedicated LDPC engine |
14.3 Evidence
Section titled “14.3 Evidence”From firmware analysis:
- The firmware modulation dispatch table has exactly 10 entries (0—9), with no DVB-S2-specific modes. The bounds check at CODE:0866 rejects values >= 10.
- No LDPC/BCH code rate values exist in any FEC lookup table. The XRAM tables at 0xE0B1, 0xE0B7, 0xE0BC, 0xE0BD, and 0xE0F9 contain only Viterbi rates (1/2 through 7/8), turbo rates, and DCII combined codes.
- No DVB-S2-specific register addresses appear in any I2C traffic. The BCM4500 is programmed exclusively through indirect registers 0xA6/0xA7/0xA8 with page 0x00.
From Windows BDA driver source:
SkyWalker1TunerFilter.cpp(line 1070):else if(ulNewInnerFecType == BDA_FEC_VITERBI)— only Viterbi FEC is accepted; any other type returnsSTATUS_INVALID_PARAMETER.SkyWalker1Control.cpp(line 292):ucCommand[8] = ADV_MOD_DVB_QPSK;— the driver hardcodes modulation type 0 (DVB-S QPSK) regardless of application request.SkyWalker1Control.h(lines 64—74): modulation constants cap atADV_MOD_DVB_BPSK(9). No value 10+ exists.
From datasheets:
- The BCM4500 datasheet describes exactly two FEC paths: “an advanced modulation turbo decoder” and “a DVB/DIRECTV/DCII-compliant FEC decoder.” No third path for LDPC/BCH.
- BCM4500 specification: 128-pin MQFP, 3.3V I/O, 1.8V digital, symbol rate 256 Ksps to 30 Msps. No mention of LDPC, BCH, or DVB-S2.
14.4 Broadcom DVB-S2 Chip Timeline
Section titled “14.4 Broadcom DVB-S2 Chip Timeline”| Chip | Year | DVB-S2? | Notes |
|---|---|---|---|
| BCM4500 | ~2003 | No | Turbo FEC + legacy Viterbi/RS |
| BCM4501 | 2006 | Yes | First dual-tuner DVB-S2; LDPC/BCH |
| BCM4505 | 2007 | Yes | Single-channel, 65nm |
| BCM4506 | 2007 | Yes | Dual-channel, 65nm |
Broadcom restricted BCM4501/4505/4506 sales to set-top box manufacturers, preventing Genpix from using them.
14.5 What Genpix Did
Section titled “14.5 What Genpix Did”Released the SkyWalker-3, replacing the BCM4500 with a different demodulator (likely STMicroelectronics STV0903). The trade-off: gained DVB-S2 LDPC/BCH support, lost proprietary turbo-FEC support (turbo codes are Broadcom/EchoStar proprietary).
14.6 USB Data Path is Not the Bottleneck
Section titled “14.6 USB Data Path is Not the Bottleneck”The GPIF/USB 2.0 path has approximately 5x headroom for DVB-S2 rates (~58 Mbps max vs ~280 Mbps USB practical throughput). The 8-bit transport stream interface uses the same MPEG-TS format (188-byte packets). The bottleneck is the demodulator silicon.
15. Kernel Driver Notes
Section titled “15. Kernel Driver Notes”15.1 Module Names
Section titled “15.1 Module Names”dvb_usb_gp8psk— USB transport and device managementgp8psk_fe— DVB frontend (demodulation, tuning)
15.2 Kernel Driver Race Condition
Section titled “15.2 Kernel Driver Race Condition”The kernel module auto-loads via udev when VID:PID 09C0:0203 appears on the USB bus (every FX2 re-enumeration after firmware load). The driver races with test tools and sends its own BOOT_8PSK command.
Symptoms:
- “resource busy” or “entity not found” errors from test scripts
- BCM4500 enters unexpected state from partial kernel initialization
- Kernel driver detaches mid-test
Fix: Blacklist the module:
blacklist dvb_usb_gp8pskblacklist gp8psk_feThen unload: sudo modprobe -r dvb_usb_gp8psk gp8psk_fe
15.3 FPGA Version Failure
Section titled “15.3 FPGA Version Failure”gp8psk: usb in 149 operation failed.gp8psk: failed to get FPGA versionCommand 0x95 (GET_FPGA_VERS, decimal 149) fails on some SkyWalker-1 units. The driver logs the failure but continues normally.
15.4 Commands Used by Kernel Driver
Section titled “15.4 Commands Used by Kernel Driver”| Command | Usage | Notes |
|---|---|---|
| 0x80 GET_8PSK_CONFIG | Boot check | Always |
| 0x83 I2C_WRITE | BCM4500 reg writes | Via frontend ops |
| 0x84 I2C_READ | BCM4500 reg reads | Via frontend ops |
| 0x85 ARM_TRANSFER | Stream start/stop | Always |
| 0x86 TUNE_8PSK | Frequency tuning | Via frontend ops |
| 0x87 GET_SIGNAL_STRENGTH | SNR readback | Via frontend ops |
| 0x88 LOAD_BCM4500 | BCM4500 FW load | Rev.1 Warm only (STALLs on SW-1) |
| 0x89 BOOT_8PSK | Power on/off | Always |
| 0x8A START_INTERSIL | LNB power | Always |
| 0x8B SET_LNB_VOLTAGE | 13V/18V | Via frontend ops |
| 0x8C SET_22KHZ_TONE | Tone control | Via frontend ops |
| 0x8D SEND_DISEQC | DiSEqC messages | Via frontend ops |
| 0x8F SET_DN_SWITCH | Legacy Dish switch | Via send_legacy_dish_cmd callback |
| 0x90 GET_SIGNAL_LOCK | Lock status | Via frontend ops |
| 0x92 GET_FW_VERS | Version check | Boot only |
| 0x94 USE_EXTRA_VOLT | +1V boost | Via enable_high_lnb_voltage callback |
| 0x95 GET_FPGA_VERS | Platform ID | Boot only |
| 0x9D CW3K_INIT | CW3K init | PID 0x0206 only |
16. Firmware Storage Formats
Section titled “16. Firmware Storage Formats”16.1 Cypress C2 EEPROM Boot Format
Section titled “16.1 Cypress C2 EEPROM Boot Format”The SkyWalker-1 firmware is stored in Cypress C2 IIC second-stage boot format, read by the FX2’s internal boot ROM on power-up.
Header (8 bytes):
| Offset | Size | Field | SkyWalker-1 Value |
|---|---|---|---|
| 0 | 1 | Marker | 0xC2 (external memory, large code model) |
| 1 | 2 | VID (LE) | 0x09C0 |
| 3 | 2 | PID (LE) | 0x0203 |
| 5 | 2 | DID (LE) | 0x0000 |
| 7 | 1 | Config | 0x40 (400 kHz I2C) |
Code segments: 2-byte length (BE) + 2-byte target address (BE) + data. Maximum segment size: 1023 bytes (FX2 I2C boot ROM buffer limit). All SkyWalker-1 variants use 10 segments.
Terminator: 0x80xx (high bit set) + 2-byte entry point address (0xE600 = CPUCS).
Segment layout (all SkyWalker-1 variants):
Segment Address Length------- ------- ------1 0x0000 1023 Contains reset vector, interrupt handlers2 0x03FF 10233 0x07FE 10234 0x0BFD 10235 0x0FFC 10236 0x13FB 10237 0x17FA 10238 0x1BF9 10239 0x1FF8 102310 0x23F7 varies (115--265 bytes depending on version)16.2 Decoded C2 Headers
Section titled “16.2 Decoded C2 Headers”| File | VID | PID | Segments | Code Size | Entry |
|---|---|---|---|---|---|
| skywalker1_eeprom.bin (v2.06) | 0x09C0 | 0x0203 | 10 | 9,472 bytes | 0xE600 |
| sw1_v213_fw_1_c2.bin (v2.13.1) | 0x09C0 | 0x0203 | 10 | 9,322 bytes | 0xE600 |
| sw1_v213_fw_2_c2.bin (v2.13.2) | 0x09C0 | 0x0203 | 10 | 9,377 bytes | 0xE600 |
| sw1_v213_fw_3_c2.bin (v2.13.3) | 0x09C0 | 0x0203 | 10 | 9,369 bytes | 0xE600 |
| rev2_v210_fw_1_c2.bin (Rev.2) | 0x09C0 | 0x0202 | 9 | 8,843 bytes | 0xE600 |
16.3 DVB-USB Binary Hexline Format (Kernel FW01)
Section titled “16.3 DVB-USB Binary Hexline Format (Kernel FW01)”The format the kernel expects for dvb-usb-gp8psk-01.fw (only needed for Rev.1 Cold, PID 0x0200):
Record structure: Offset Size Field 0 1 len - Number of data bytes 1 1 addr_lo - Target address low byte 2 1 addr_hi - Target address high byte 3 1 type - 0x00=data, 0x01=EOF, 0x04=extended addr 4 len data[] - Payload bytes 4+len 1 chk - Checksum byte16.4 FW02 Chunk Format (BCM4500 Firmware)
Section titled “16.4 FW02 Chunk Format (BCM4500 Firmware)”Only needed for Rev.1 Warm (PID 0x0201):
Chunk format: Byte 0: payload_length (N) Bytes 1-3: header/address bytes Bytes 4..N+3: payload data Terminator: single byte 0xFF Maximum chunk size: 64 bytes (USB control transfer limit)Command 0x88 (LOAD_BCM4500) initiates the transfer. Each chunk is sent via bulk endpoint 0x01. On the SkyWalker-1, 0x88 routes to STALL (BCM4500 firmware is in ROM).
16.5 Format Incompatibility
Section titled “16.5 Format Incompatibility”C2 (EEPROM) and hexline (kernel FW01) are structurally different containers. They cannot be used interchangeably, but the payload data is identical. A C2 file can be converted to hexline by stripping the 8-byte header, splitting segments into 16-byte records, and appending an EOF record.
17. Debugging Reference
Section titled “17. Debugging Reference”17.1 I2C STOP Corruption Root Cause
Section titled “17.1 I2C STOP Corruption Root Cause”The root cause of the initial firmware hang was traced through incremental debug modes:
| wValue | Action | Result | Diagnosis |
|---|---|---|---|
| 0x82 | GPIO + power + bmSTOP + probe | Fails | bmSTOP corrupts controller |
| 0x85 | GPIO + power + probe (no bmSTOP) | Works | Confirms bmSTOP is the cause |
| 0x84 | I2C probe only (chip already powered) | Works | BCM4500 is alive; I2C function is correct |
Key finding: mode 0x84 succeeds immediately after 0x82 fails, proving the BCM4500 was alive the whole time. The FX2 I2C controller was in a bad state, not the bus or slave.
17.2 Boot Results After Fix
Section titled “17.2 Boot Results After Fix”| Metric | Value |
|---|---|
| Boot time | ~90 ms total |
| config_status | 0x03 (STARTED + FW_LOADED) |
| boot_stage | 0xFF (COMPLETE) |
| Direct registers 0xA2-0xA8 | All return 0x02 (powered, not locked) |
| Signal lock | 0x00 (no lock — dish not aimed) |
| USB responsiveness | No hang; fully responsive throughout |
17.3 Test Tools
Section titled “17.3 Test Tools”Located in tools/ directory:
| Script | Purpose |
|---|---|
test_boot_debug.py | Sends debug modes 0x80—0x83 sequentially |
test_i2c_debug.py | Powers on via 0x81, runs bus scans, tests probe timing |
test_i2c_isolate.py | Tests re-reset and insufficient delay as failure causes |
test_i2c_pinpoint.py | Definitive test: compares 0x84, 0x85, and 0x82 |
fw_load.py | RAM firmware loader (halt CPU, write, restart) |
17.4 FX2 Register Quick Reference
Section titled “17.4 FX2 Register Quick Reference”| Address | Name | Notes |
|---|---|---|
| 0xE600 | CPUCS | CPU control/status; write 0x01 to halt, 0x00 to run |
| 0xE601 | IFCONFIG | Interface configuration (GPIF mode, clock) |
| 0xE60B | REVCTL | Revision control (NOAUTOARM, SKIPCOMMIT) |
| 0xE618 | EP2FIFOCFG | EP2 FIFO configuration (AUTOIN, 8-bit) |
| 0xE678 | I2CS | I2C control/status |
| 0xE679 | I2DAT | I2C data |
| 0xE67A | I2CTL | I2C speed control |
| 0xE6B8 | SETUPDAT[0] | bmRequestType |
| 0xE6B9 | SETUPDAT[1] | bRequest |
| 0xE6BA | SETUPDAT[2] | wValueL |
| 0xE6BB | SETUPDAT[3] | wValueH |
| 0xE6BC | SETUPDAT[4] | wIndexL |
| 0xE6BD | SETUPDAT[5] | wIndexH |
| 0xE6BE | SETUPDAT[6] | wLengthL |
| 0xE6BF | SETUPDAT[7] | wLengthH |
| 0xE68A | EP0BCH | EP0 byte count high |
| 0xE68B | EP0BCL | EP0 byte count low (write triggers transfer) |
| 0xE740 | EP0BUF | EP0 data buffer start |
| 0xE0B6 | (custom) | LNB voltage control register (XRAM) |
18. Sources
Section titled “18. Sources”Firmware Analysis
Section titled “Firmware Analysis”- Ghidra decompilation/disassembly of five firmware images:
- v2.06.04 (Ghidra port 8193) — extracted from SkyWalker-1 EEPROM
- Rev.2 v2.10.04 (Ghidra port 8197) — extracted from Rev.2 hardware
- v2.13.01 FW1 (Ghidra port 8194) — extracted from Windows updater
- v2.13.02 FW2 (Ghidra port 8195) — extracted from Windows updater
- v2.13.03 FW3 (Ghidra port 8196) — extracted from Windows updater
- Firmware dumps:
firmware-dump/
Driver Source
Section titled “Driver Source”- Linux kernel 6.16.5:
drivers/media/usb/dvb-usb/gp8psk.c,gp8psk.h,gp8psk-fe.c,gp8psk-fe.h - Linux kernel:
drivers/media/usb/dvb-usb/dvb-usb-firmware.c - Windows BDA driver:
SkyWalker1_Final_Release/Source/SkyWalker1Control.cpp - Windows BDA driver:
SkyWalker1_Final_Release/Include/SkyWalker1Control.h,SkyWalker1CommonDef.h
Hardware Documentation
Section titled “Hardware Documentation”- BCM4500 Datasheet: DatasheetQ, Elcodis
- BCM4501 Product Page: Broadcom
- Cypress CY7C68013A (FX2LP) Technical Reference Manual
- Genpix Electronics: https://www.genpix-electronics.com/index.php?act=viewDoc&docId=9
- Genpix SkyWalker-3 specifications: https://www.genpix-electronics.com/what-is-skywalker-3.html
- Device
dmesgoutput from running SkyWalker-1 hardware
Analysis Reports (This Project)
Section titled “Analysis Reports (This Project)”gp8psk-driver-analysis.md— Linux kernel driver analysisfirmware-analysis-v206-vs-v213.md— v2.06 vs v2.13 firmware comparisonrev2-deep-analysis.md— Rev.2 deep function inventory (107 functions)gpif-streaming-analysis.md— GPIF/MPEG-2 streaming pathtuning-protocol-analysis.md— TUNE_8PSK protocol deep divevendor-commands-unknown.md— Vendor command decode (0x8F, 0x91—0x98)kernel-fw01-analysis.md— Kernel firmware format and EEPROM bootfirmware-dump/fw_v213_comparison_report.md— v2.13 sub-variant comparisondvb-s2-investigation.md— DVB-S2 incompatibility investigationdocs/boot-debug-findings.md— Boot/I2C debugging findingsdocs/diseqc/diseqc-skywalker-1.md— DiSEqC Windows BDA interfacefirmware/skywalker1.c— Custom firmware v3.01.0 source