DiSEqC Protocol
The SkyWalker-1 implements DiSEqC (Digital Satellite Equipment Control) via Timer2-based GPIO bit-bang on the FX2 microcontroller. The algorithm is identical across all firmware versions — only the data pin assignment changes per PCB revision.
Protocol Diagrams
Section titled “Protocol Diagrams”The following diagrams document the Genpix BDA driver’s DiSEqC extended property interface:
Signal Architecture
Section titled “Signal Architecture”The firmware does not generate the 22 kHz carrier directly. GPIO P0.3 gates an external 22 kHz oscillator circuit on the PCB:
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 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.
Timer2 Configuration
Section titled “Timer2 Configuration”All firmware versions configure Timer2 identically during USB descriptor setup:
| Parameter | Value | Notes |
|---|---|---|
| T2CON | 0x04 | Auto-reload mode, timer running |
| RCAP2H | 0xF8 | Reload high byte |
| RCAP2L | 0x2F | Reload low byte (reload = 63535) |
| CKCON.T2M | 0 | Timer2 clock = 48 MHz / 12 = 4 MHz |
Tick period calculation:
FX2 master clock = 48 MHzCKCON.T2M = 0 -> Timer2 clock = 48 MHz / 12 = 4 MHzCount per overflow = 65536 - 63535 = 2001Tick period = 2001 / 4,000,000 = 500.25 us ~ 500 usTick frequency ~ 2.0 kHzTimer2 runs continuously from power-on and is never stopped or reconfigured. It serves as a stable 500 us timebase for all DiSEqC operations.
Manchester Encoding
Section titled “Manchester Encoding”Each DiSEqC bit consists of 3 Timer2 ticks (3 x 500 us = 1.5 ms):
Data ‘0’ — 2/3 tone, 1/3 silence (1.0 ms carrier + 0.5 ms 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 (0.5 ms carrier + 1.0 ms 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)Bit Symbol Implementation
Section titled “Bit Symbol Implementation”Decompiled 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}The wait_TF2() function is the lowest-level timing primitive — a busy-wait on the Timer2 overflow flag:
void wait_TF2(void) { while (TF2 == 0) {} // Poll Timer2 overflow flag TF2 = 0; // Clear flag for next tick}Byte Transmission
Section titled “Byte Transmission”Each DiSEqC byte is 9 bits: 8 data bits (MSB first) + 1 odd parity bit.
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: '1' if even count diseqc_bit_symbol(); // Transmit parity bit}Timing per byte: 9 bits x 1.5 ms = 13.5 ms
DiSEqC Command Sequence
Section titled “DiSEqC Command Sequence”The full command flow for sending a DiSEqC message via vendor command 0x8D (SEND_DISEQC_COMMAND):
-
Read wLength from USB SETUP packet (
0xE6BE) to determine message byte count -
Disable 22 kHz carrier by clearing P0.3 (ensuring a clean start state)
-
Pre-transmission delay of 15 Timer2 ticks (7.5 ms) for LNB voltage settling
-
Transmit message bytes if wLength > 0: iterate through EP0BUF, sending each byte via Manchester-encoded bit-bang (8 data bits + odd parity, 3 Timer2 ticks per bit)
-
Or send tone burst if wLength == 0:
wValue == 0: Tone Burst A (25 Timer2 ticks = 12.5 ms of unmodulated carrier)wValue != 0: Tone Burst B (transmitted as0xFFbyte pattern through the bit-bang function)
USB Command Format
Section titled “USB Command Format”Full DiSEqC Message (3-6 bytes)
Section titled “Full DiSEqC Message (3-6 bytes)”USB SETUP: bmRequestType = 0x40 (vendor, host-to-device) bRequest = 0x8D (SEND_DISEQC_COMMAND) wValue = msg[0] (framing byte, typically 0xE0 or 0xE1) wIndex = 0x0000 wLength = message length (3-6)
EP0 Data: Byte 0: Framing byte (e.g., 0xE0 = command from master, no reply expected) Byte 1: Address byte (e.g., 0x10 = any LNB, 0x11 = LNB 1) Byte 2: Command byte (e.g., 0x38 = Write N0, committed switch port) Byte 3: Data byte 0 (optional, port selection bits) Byte 4: Data byte 1 (optional) Byte 5: Data byte 2 (optional)Tone Burst (Mini DiSEqC)
Section titled “Tone Burst (Mini DiSEqC)”USB SETUP: bmRequestType = 0x40 bRequest = 0x8D wValue = 0x00 (Burst A) or 0x01 (Burst B) wIndex = 0x0000 wLength = 0 (zero length signals tone burst mode)Windows BDA Driver Interface
Section titled “Windows BDA Driver Interface”The Windows driver exposes DiSEqC through a BDA extended property GUID:
// {0B5221EB-F4C4-4976-B959-EF74427464D9}#define STATIC_KSPROPSETID_BdaExtendedProperty \ 0x0B5221EB, 0xF4C4, 0x4976, 0xB9, 0x59, 0xEF, 0x74, 0x42, 0x74, 0x64, 0xD9The DiSEqC command structure:
typedef enum enSimpleToneBurst { SEC_MINI_A, SEC_MINI_B} SIMPLE_TONE_BURST;
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 commands, set ucMessageLength = 1 and ucMessage[0] to either SEC_MINI_A (0x00) or SEC_MINI_B (0x01).
Data Pin Assignment Per Version
Section titled “Data Pin Assignment Per Version”The DiSEqC algorithm is identical across all firmware versions. Only the data pin changes per PCB revision:
| Firmware Version | Data Pin | Carrier Pin | Byte Transmit Function | Bit Symbol Function | Timer Wait |
|---|---|---|---|---|---|
| v2.06 | P0.7 | P0.3 | 0x2098 | 0x23B5 | 0x24C6 |
| Rev.2 v2.10 | P0.4 | P0.3 | FUN_CODE_07d1 | FUN_CODE_213c | FUN_CODE_225f |
| v2.13 FW1 | P0.0 | P0.3 | FUN_CODE_2060 | FUN_CODE_22f3 | func_0x2431 |
| Custom v3.01.0 | P0.7 | P0.3 | diseqc_tone_burst() | (inline) | (inline) |
CPU Clock Compensation
Section titled “CPU Clock Compensation”The delay function used before DiSEqC transmission adjusts its loop count based on the FX2 CPU clock speed:
void delay(byte high, byte low) { byte clkspd = CPUCS & 0x18; // CPUCS[4:3] = clock speed bits if (clkspd == 0x00) { // 12 MHz: halve the count // Adjust high:low /= 2 } else if (clkspd == 0x10) { // 48 MHz: double the count // Adjust high:low *= 2 } // 24 MHz (0x08): use count as-is while (high:low > 0) { wait_TF2(); high:low--; }}The pre-DiSEqC delay call is delay(0, 0x0F) = 15 ticks x 500 us = 7.5 ms. This allows the LNB voltage to stabilize before DiSEqC signaling begins.
Complete Timing Summary
Section titled “Complete Timing Summary”| Parameter | Value | Source |
|---|---|---|
| Timer2 clock | 4 MHz (48 MHz / 12) | CKCON default, T2M=0 |
| Timer2 reload | 0xF82F | RCAP2H:RCAP2L |
| Tick period | 500.25 us | (65536 - 63535) / 4 MHz |
| Bit period | 1.5 ms (3 ticks) | DiSEqC Manchester encoding |
| Byte period | 13.5 ms (9 bits) | 8 data + 1 parity |
| Tone burst duration | 12.5 ms (25 ticks) | Mini-command A/B |
| Pre-TX settling delay | 7.5 ms (15 ticks) | Voltage stabilization |
| 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 |
| 3-byte DiSEqC message | ~48 ms total | 7.5 ms settle + 3 x 13.5 ms |
| 6-byte DiSEqC message | ~88.5 ms total | 7.5 ms settle + 6 x 13.5 ms |