Custom Firmware v3.01
The custom firmware is an open-source replacement for the stock SkyWalker-1 FX2 firmware, built with the SDCC compiler and fx2lib library. It implements all stock vendor commands for kernel driver compatibility and adds diagnostic, spectrum sweep, blind scan, and raw register access capabilities. Custom
See also: v3.02 adds signal monitoring, tune-and-measure, and batch register read commands on top of this base.
Project Structure
Section titled “Project Structure”Directoryfirmware/
- skywalker1.c Main firmware source (1351 lines)
- Makefile SDCC build rules
- skywalker1.ihx Compiled Intel HEX output
Directorytools/
- fw_load.py FX2 RAM loader utility
- eeprom_flash.py EEPROM flash tool
Architecture Overview
Section titled “Architecture Overview”| Property | Value |
|---|---|
| Toolchain | SDCC 4.x + fx2lib |
| Target | Cypress CY7C68013A (FX2LP) |
| Load method | RAM upload via fw_load.py (USB 0xA0 vendor request) |
| Binary size | ~3 KB |
| Source lines | 1351 |
| DiSEqC data pin | P0.7 (matches v2.06 hardware) |
| BCM4500 I2C address | 0x08 (7-bit); wire address 0x10/0x11 |
Stock-Compatible Commands
Section titled “Stock-Compatible Commands”All stock vendor commands (0x80—0x94) are implemented for full compatibility with the Linux dvb_usb_gp8psk kernel driver:
| Command | Name | Implementation |
|---|---|---|
0x80 | GET_8PSK_CONFIG | Returns config_status byte (1 byte) |
0x85 | ARM_TRANSFER | Calls gpif_start() / gpif_stop() |
0x86 | TUNE_8PSK | Parses 10-byte EP0 payload, programs BCM4500 |
0x87 | GET_SIGNAL_STRENGTH | Reads 6 BCM4500 indirect registers |
0x89 | BOOT_8PSK | Full BCM4500 boot sequence (see below) |
0x8A | START_INTERSIL | Enables/disables LNB power supply |
0x8B | SET_LNB_VOLTAGE | Sets P0.4 for 13V/18V selection |
0x8C | SET_22KHZ_TONE | Sets P0.3 for 22 kHz oscillator gate |
0x8D | SEND_DISEQC | DiSEqC tone burst via Timer2 bit-bang |
0x90 | GET_SIGNAL_LOCK | Reads BCM4500 lock register 0xA4 |
0x92 | GET_FW_VERS | Returns version 0x030100, build date |
0x94 | USE_EXTRA_VOLT | Writes 0x62/0x6A to XRAM 0xE0B6 |
Custom Diagnostic Commands
Section titled “Custom Diagnostic Commands”Seven new vendor commands (0xB0—0xB6) extend the firmware with capabilities absent from all stock versions: New
| Command | Name | Direction | Payload | Purpose |
|---|---|---|---|---|
0xB0 | SPECTRUM_SWEEP | OUT+Bulk | 10 bytes EP0 | Step through frequencies, return power readings via EP2 |
0xB1 | RAW_DEMOD_READ | IN | 2 bytes | Read arbitrary BCM4500 indirect register |
0xB2 | RAW_DEMOD_WRITE | OUT | 3 bytes | Write arbitrary BCM4500 indirect register |
0xB3 | BLIND_SCAN | OUT+EP0 | 16 bytes EP0 | Sweep symbol rates at a frequency, report lock |
0xB4 | I2C_SCAN | IN | N bytes | Scan I2C bus for responsive devices |
0xB5 | GET_BOOT_STAGE | IN | 2 bytes | Read config_status + boot_stage |
0xB6 | GET_GPIO_STATE | IN | 3 bytes | Read IOA, IOB, IOD port registers |
Spectrum Sweep (0xB0)
Section titled “Spectrum Sweep (0xB0)”Steps through frequencies from start to stop, reading BCM4500 signal energy at each step. Results are packed as u16 LE values into EP2 bulk endpoint.
EP0BUF[0..3] start_freq (u32 LE, kHz)EP0BUF[4..7] stop_freq (u32 LE, kHz)EP0BUF[8..9] step_khz (u16 LE, default 1000 if 0)At each step, the firmware programs the BCM4500 frequency register via indirect write, waits 10 ms for settling, reads the SNR register pair, and packs the result into EP2 FIFO. When the buffer reaches 512 bytes, it is committed to the host.
Blind Scan (0xB3)
Section titled “Blind Scan (0xB3)”Sweeps symbol rates from sr_min to sr_max at a given frequency, checking for signal lock at each step.
EP0BUF[0..3] freq_khz (u32 LE)EP0BUF[4..7] sr_min (u32 LE, sps)EP0BUF[8..11] sr_max (u32 LE, sps)EP0BUF[12..15] sr_step (u32 LE, sps, default 1000000 if 0)Returns 8 bytes on lock (freq_khz[4] + sr_locked[4]), or 1 byte 0x00 if no lock found.
Raw Demod Access (0xB1 / 0xB2)
Section titled “Raw Demod Access (0xB1 / 0xB2)”Direct access to any BCM4500 indirect register, bypassing the stock firmware’s limited register set:
// wValue = register page, wIndex = register number// Returns 1 byte in EP0bcm_indirect_read(page, &val);EP0BUF[0] = val;// wValue = register page, wIndex = register number// EP0 data = 1 byte valuebcm_indirect_write(page, val);BCM4500 Boot Sequence
Section titled “BCM4500 Boot Sequence”The bcm4500_boot() function replicates the stock firmware’s initialization with added diagnostic instrumentation. The boot_stage variable tracks progress for debugging failed boots.
-
GPIO setup (
boot_stage = 1): Set P3.7/P3.6/P3.5 HIGH (control lines idle), assert BCM4500 RESET (P0.5 LOW) -
Power on (
boot_stage = 2): Enable power supply (P0.1 HIGH, P0.2 LOW), wait 30 ms for settling, release RESET (P0.5 HIGH), wait 50 ms for BCM4500 POR -
I2C probe (
boot_stage = 3): Read BCM4500 status register0xA2to verify the chip is alive on the I2C bus -
Init block 0 (
boot_stage = 4): Write 7-byte configuration block to BCM4500 page 0 indirect registers -
Init block 1 (
boot_stage = 5): Write 8-byte configuration block -
Init block 2 (
boot_stage = 6): Write 3-byte configuration block -
Success (
boot_stage = 0xFF): SetBM_STARTED | BM_FW_LOADEDin config status
BCM4500 Init Data
Section titled “BCM4500 Init Data”Three initialization blocks extracted from stock v2.06 firmware (FUN_CODE_0ddd):
static const __code BYTE bcm_init_block0[] = { 0x06, 0x0b, 0x17, 0x38, 0x9f, 0xd9, 0x80};static const __code BYTE bcm_init_block1[] = { 0x07, 0x09, 0x39, 0x4f, 0x00, 0x65, 0xb7, 0x10};static const __code BYTE bcm_init_block2[] = { 0x0f, 0x0c, 0x09};Each block is written to BCM4500 page 0 via the indirect register protocol: page select to 0xA6, data bytes to 0xA7, trailing zero to 0xA7, commit 0x03 to 0xA8, then poll for completion.
Debug Boot Modes
Section titled “Debug Boot Modes”The BOOT_8PSK command (0x89) accepts debug wValue parameters that execute partial boot sequences for incremental hardware debugging:
| wValue | Stage | What It Does | Success Marker |
|---|---|---|---|
0x80 | None | No-op, return current state | — |
0x81 | GPIO only | GPIO setup + power + reset, no I2C | 0xA1 |
0x82 | GPIO + probe | GPIO + I2C read of status register | 0xA2 |
0x83 | GPIO + probe + block 0 | GPIO + I2C + first init block | 0xA3 |
0x84 | I2C only | Probe without GPIO (chip must be powered) | 0xA4 |
0x85 | GPIO + probe (no bus reset) | Same as 0x82 without I2CS bmSTOP | 0xA5 |
0x01 | Full boot | Complete bcm4500_boot() sequence | 0xFF |
0x00 | Shutdown | Power off BCM4500 | — |
I2C Implementation
Section titled “I2C Implementation”The custom firmware implements I2C from scratch rather than using fx2lib’s I2C functions, providing full timeout protection:
#define I2C_TIMEOUT 6000 // ~5ms at 48MHz (4 clocks/cycle, ~12 MIPS)Key I2C functions:
| Function | Purpose |
|---|---|
i2c_wait_done() | Poll I2CS.bmDONE with 6000-count timeout |
i2c_wait_stop() | Poll I2CS.bmSTOP clear with timeout |
i2c_combined_read() | Write-then-read with repeated START (no intermediate STOP) |
i2c_write_timeout() | Single-byte write with timeout on each phase |
i2c_write_multi_timeout() | Multi-byte write with timeout |
BCM4500 Register Access
Section titled “BCM4500 Register Access”The BCM4500 uses an indirect register protocol through three I2C registers:
| Register | Address | Purpose |
|---|---|---|
| BCM_REG_PAGE | 0xA6 | Page/register select |
| BCM_REG_DATA | 0xA7 | Data read/write |
| BCM_REG_CMD | 0xA8 | Command trigger (0x01 = read, 0x03 = write) |
// 1. Write [page, 0x00, 0x01] to A6/A7/A8 in one I2C transaction// 2. Wait for command completion (poll A8 bit 0 == 0)// 3. Read result from A7GPIF Streaming
Section titled “GPIF Streaming”Transport stream data from the BCM4500 flows through the FX2’s GPIF engine into USB endpoint EP2:
IFCONFIG = 0xEE; // Internal 48MHz, GPIF master, async, clock outputEP2FIFOCFG = 0x0C; // AUTOIN, ZEROLENIN, 8-bitFLOWSTATE |= 0x09; // Enable flow state + FS[3]GPIFTCB3 = 0x80; // Transaction count = 0x80000000 (effectively infinite)The gpif_start() function arms the GPIF for continuous read into EP2, while gpif_stop() flushes the FIFO and de-asserts the BCM4500 control lines on P3.
GPIO Pin Map
Section titled “GPIO Pin Map”#define PIN_PWR_EN 0x02 // P0.1 -- power supply enable#define PIN_PWR_DIS 0x04 // P0.2 -- power supply disable#define PIN_22KHZ 0x08 // P0.3 -- 22kHz oscillator gate#define PIN_LNB_VOLT 0x10 // P0.4 -- LNB voltage select#define PIN_BCM_RESET 0x20 // P0.5 -- BCM4500 hardware reset#define PIN_DISEQC 0x80 // P0.7 -- DiSEqC dataInitial state after TD_Init():
IOA = 0x84(P0.7 HIGH, P0.2 HIGH — power disabled, streaming off)OEA = 0xBE(P0.1 through P0.5 and P0.7 as outputs)
Differences from Stock Firmware
Section titled “Differences from Stock Firmware”| Feature | Stock v2.06 | Custom v3.01 |
|---|---|---|
| Toolchain | Unknown (proprietary) | SDCC + fx2lib (open source) |
| I2C timeout | None (infinite spin) | 6000-count (~5 ms) |
| Boot diagnostics | None | Incremental debug modes |
| Custom commands | None | 7 (0xB0—0xB6) |
| Spectrum sweep | Not possible | 0xB0 via EP2 bulk |
| Blind scan | Not possible | 0xB3 with SR sweep |
| Raw register access | Not possible | 0xB1/0xB2 |
| I2C bus scan | Not possible | 0xB4 |
| GPIO read | Not possible | 0xB6 |
| Anti-tampering | Present (v2.13) | Removed |
| Source available | No | Yes (firmware/skywalker1.c) |
See the v3.02 comparison table for signal monitoring and batch register improvements added on top of v3.01.
Tuning Implementation
Section titled “Tuning Implementation”The do_tune() function parses the same 10-byte EP0 payload as the stock firmware:
// Byte-reverse symbol rate and frequency from LE to BEfor (i = 0; i < 4; i++) { tune_data[i] = EP0BUF[3 - i]; // Symbol rate (BE) tune_data[4 + i] = EP0BUF[7 - i]; // Frequency (BE)}tune_data[8] = EP0BUF[8]; // Modulation type (0-9)tune_data[9] = EP0BUF[9]; // FEC indextune_data[10] = 0x10; // Demod mode (standard)tune_data[11] = 0x00; // Turbo flagModulation-specific handling:
- Modulation types 1—3 (turbo modes): Set turbo flag
tune_data[11] = 0x01 - Modulation type 5: DCII I-stream, demod mode
0x12 - Modulation type 6: DCII Q-stream, demod mode
0x16 - Modulation type 7: DCII offset QPSK, demod mode
0x11