Correct DiSEqC analysis and add complete timing chain documentation
Major correction: All firmware versions use GPIO bit-banging for DiSEqC, NOT I2C-based control as previously reported. Deep decompilation of the sub-functions (byte transmit, bit symbol, tone burst) across v2.06, Rev.2, and v2.13 reveals identical Manchester encoding algorithms with only the data GPIO pin changed per PCB revision: - v2.06: P0.7, Rev.2: P0.4, v2.13: P0.0 - P0.3 (22kHz carrier gate) unchanged across all versions New section 7: Complete DiSEqC timing chain analysis including: - Timer2 configuration (RCAP2=0xF82F, 4MHz clock, 500us tick) - Manchester encoding waveforms (3 ticks/bit, 1.5ms/bit, 667 baud) - Byte transmission (8 data + odd parity = 13.5ms) - Tone burst timing (25 ticks = 12.5ms) - CPU clock compensation in delay function - External 22kHz oscillator architecture
This commit is contained in:
parent
da08d1b099
commit
782f5a0e8d
@ -8,7 +8,7 @@ v2.13 is a significant evolution of the v2.06 firmware with 21 additional functi
|
|||||||
2. **Restructured INT0 handler** with active satellite front-end polling
|
2. **Restructured INT0 handler** with active satellite front-end polling
|
||||||
3. **I2C-based initialization** with retry logic for the satellite demodulator
|
3. **I2C-based initialization** with retry logic for the satellite demodulator
|
||||||
4. **Version-aware code paths** (hardware revision detection via descriptor byte)
|
4. **Version-aware code paths** (hardware revision detection via descriptor byte)
|
||||||
5. **Refactored DiSEqC implementation** using I2C-based bus control
|
5. **Refactored DiSEqC GPIO pin assignment** (data pin moved from P0.7 to P0.0, same bit-bang algorithm)
|
||||||
6. **Simplified BCM4500 status polling** (consolidated from 3 register reads to 1)
|
6. **Simplified BCM4500 status polling** (consolidated from 3 register reads to 1)
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -99,17 +99,19 @@ None were removed -- all commands that were STALL in v2.06 remain STALL in v2.13
|
|||||||
- v2.06 at 0x0140: Checks DAT_INTMEM_6D bit 0 (demod active), reads three I2C status registers (0xA2, 0xA8, 0xA4) to compute signal quality, loops up to 6 iterations polling for demod readiness
|
- v2.06 at 0x0140: Checks DAT_INTMEM_6D bit 0 (demod active), reads three I2C status registers (0xA2, 0xA8, 0xA4) to compute signal quality, loops up to 6 iterations polling for demod readiness
|
||||||
- v2.13 at 0x0162: Checks DAT_INTMEM_4F bit 0 (demod active), reads I2C but uses different function call chain (FUN_CODE_1278 vs FUN_CODE_0c97). Same overall logic with relocated internal variables.
|
- v2.13 at 0x0162: Checks DAT_INTMEM_4F bit 0 (demod active), reads I2C but uses different function call chain (FUN_CODE_1278 vs FUN_CODE_0c97). Same overall logic with relocated internal variables.
|
||||||
|
|
||||||
**0x8D - SEND_DISEQC_COMMAND (significantly changed)**
|
**0x8D - SEND_DISEQC_COMMAND (GPIO pin reassignment)**
|
||||||
- v2.06: `LCALL 0x23e0; LCALL 0x1e41` -- calls a GPIO-based DiSEqC implementation (0x1e41) that directly manipulates P0 port pins and uses timer-based bit-banging with FUN_CODE_2098 for tone modulation
|
- v2.06: `LCALL 0x23e0; LCALL 0x1e41` -- GPIO bit-bang DiSEqC via FUN_CODE_2098, data on **P0.7**, carrier on P0.3
|
||||||
- v2.13: `LCALL 0x231e; LCALL FUN_CODE_0dbc` -- calls an I2C-based DiSEqC implementation that:
|
- v2.13: `LCALL 0x231e; LCALL FUN_CODE_0dbc` -- GPIO bit-bang DiSEqC via FUN_CODE_2060, data on **P0.0**, carrier on P0.3
|
||||||
1. Reads wLength (0xE6BE) as message byte count
|
|
||||||
2. Pulls P0.3 low (power enable for DiSEqC bus)
|
|
||||||
3. Delays 15 units via FUN_CODE_14b9
|
|
||||||
4. If message bytes present: iterates through EP0BUF data, sending each byte via `func_0x2060` (I2C-based DiSEqC bus write)
|
|
||||||
5. If wValue == 0 and no bytes: calls `func_0x22b0` (tone burst command)
|
|
||||||
6. If wValue != 0 and no bytes: calls `func_0x2060(0, 0xFF)` (continuous tone)
|
|
||||||
|
|
||||||
This is a major architectural change: v2.06 uses GPIO bit-banging for DiSEqC, while v2.13 delegates DiSEqC to a dedicated I2C-connected controller chip.
|
Both versions use the identical algorithm:
|
||||||
|
1. Read wLength (0xE6BE) as message byte count
|
||||||
|
2. Clear P0.3 (disable 22kHz carrier)
|
||||||
|
3. Delay 15 ticks via delay function (7.5ms settling time)
|
||||||
|
4. If message bytes present: iterate through EP0BUF, sending each byte via Manchester-encoded bit-bang (8 data bits + odd parity, 3 Timer2 ticks per bit)
|
||||||
|
5. If wValue == 0 and no bytes: tone burst A (25 Timer2 ticks = 12.5ms)
|
||||||
|
6. If wValue != 0 and no bytes: tone burst B via byte transmit with 0xFF pattern
|
||||||
|
|
||||||
|
**CORRECTION**: Earlier analysis incorrectly identified v2.13 as using "I2C-based DiSEqC." Deep decompilation of the sub-functions (FUN_CODE_2060, FUN_CODE_22f3, FUN_CODE_22b0) reveals they are GPIO bit-bang implementations identical in algorithm to v2.06's FUN_CODE_2098 and FUN_CODE_2372. The only change is the data pin assignment (P0.7 -> P0.0), reflecting a different PCB layout.
|
||||||
|
|
||||||
**0x9D - SET_MODE_FLAG (different logic)**
|
**0x9D - SET_MODE_FLAG (different logic)**
|
||||||
- v2.06: Reads byte at descriptor_base + 10, checks if value is 4, 5, or 6, and conditionally sets bit flag 0x06 based on wValue - 1
|
- v2.06: Reads byte at descriptor_base + 10, checks if value is 4, 5, or 6, and conditionally sets bit flag 0x06 based on wValue - 1
|
||||||
@ -153,7 +155,7 @@ This is a major architectural change: v2.06 uses GPIO bit-banging for DiSEqC, wh
|
|||||||
| -- | `FUN_CODE_1ac6` (0x1AC6) | v2.13 tuning acquisition sequence |
|
| -- | `FUN_CODE_1ac6` (0x1AC6) | v2.13 tuning acquisition sequence |
|
||||||
| -- | `FUN_CODE_1e3c` (0x1E3C) | v2.13 demodulator full reset |
|
| -- | `FUN_CODE_1e3c` (0x1E3C) | v2.13 demodulator full reset |
|
||||||
| -- | `FUN_CODE_10d9` (0x10D9) | v2.13 demod status polling/init |
|
| -- | `FUN_CODE_10d9` (0x10D9) | v2.13 demod status polling/init |
|
||||||
| -- | `FUN_CODE_0dbc` (0x0DBC) | v2.13 I2C-based DiSEqC controller |
|
| -- | `FUN_CODE_0dbc` (0x0DBC) | v2.13 DiSEqC GPIO bit-bang wrapper (data on P0.0) |
|
||||||
|
|
||||||
### USB Descriptor Setup (FUN_CODE_13c3 vs FUN_CODE_11ab)
|
### USB Descriptor Setup (FUN_CODE_13c3 vs FUN_CODE_11ab)
|
||||||
|
|
||||||
@ -339,12 +341,16 @@ Direct I2C register read of demodulator register 0xF9, returned to host. This en
|
|||||||
### 5.4 Host-Controlled Tuning Delay (Command 0x9C)
|
### 5.4 Host-Controlled Tuning Delay (Command 0x9C)
|
||||||
Allows the host to invoke the tuning acquisition sequence with a configurable delay parameter. In v2.06, the tuning timing is entirely firmware-controlled with no host influence.
|
Allows the host to invoke the tuning acquisition sequence with a configurable delay parameter. In v2.06, the tuning timing is entirely firmware-controlled with no host influence.
|
||||||
|
|
||||||
### 5.5 I2C-Based DiSEqC Control
|
### 5.5 DiSEqC GPIO Pin Reassignment
|
||||||
v2.13 uses a dedicated I2C-connected DiSEqC controller chip rather than GPIO bit-banging:
|
All firmware versions use the same GPIO bit-bang algorithm for DiSEqC signaling. The only change is the data pin assignment per PCB revision:
|
||||||
- More precise DiSEqC timing (hardware-generated rather than software-timed)
|
|
||||||
- Support for reading DiSEqC reply messages (the I2C controller can buffer responses)
|
| Version | Data Pin | Carrier Pin | Byte Transmit | Bit Symbol | Timer Tick |
|
||||||
- Lower CPU overhead during DiSEqC transactions
|
|---------|----------|-------------|--------------|------------|------------|
|
||||||
- Better compatibility with DiSEqC 1.2 motor positioning commands that require precise timing
|
| 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 |
|
||||||
|
|
||||||
|
The algorithm is identical across all versions: Manchester-encoded bit-bang with Timer2-based timing, odd parity per byte, and 25-tick tone bursts for mini-commands.
|
||||||
|
|
||||||
### 5.6 Firmware/Descriptor Integrity Verification
|
### 5.6 Firmware/Descriptor Integrity Verification
|
||||||
v2.13 validates demodulator identification (ASCII version string checksum) and descriptor block integrity (two 36-byte checksums) before proceeding. If verification fails after 20 attempts, it falls back to a recovery sequence. v2.06 does no integrity checking.
|
v2.13 validates demodulator identification (ASCII version string checksum) and descriptor block integrity (two 36-byte checksums) before proceeding. If verification fails after 20 attempts, it falls back to a recovery sequence. v2.06 does no integrity checking.
|
||||||
@ -371,8 +377,195 @@ v2.13's 0x9D handler can trigger a full demodulator reset sequence (FUN_CODE_1e3
|
|||||||
| Descriptor base | 0x1200 | 0x0E00 |
|
| Descriptor base | 0x1200 | 0x0E00 |
|
||||||
| Config byte (IRAM) | 0x6D | 0x4F |
|
| Config byte (IRAM) | 0x6D | 0x4F |
|
||||||
| INT0 purpose | USB re-enumerate | Demod probe |
|
| INT0 purpose | USB re-enumerate | Demod probe |
|
||||||
| DiSEqC method | GPIO bit-bang | I2C controller |
|
| DiSEqC data pin | P0.7 (GPIO bit-bang) | P0.0 (GPIO bit-bang) |
|
||||||
| Demod init | Direct, no retry | 20-attempt retry |
|
| Demod init | Direct, no retry | 20-attempt retry |
|
||||||
| Integrity checks | None | Checksum verification |
|
| Integrity checks | None | Checksum verification |
|
||||||
| HW revision support | Single | Multi-revision (flag _1_3) |
|
| HW revision support | Single | Multi-revision (flag _1_3) |
|
||||||
| New vendor cmds | -- | 0x99, 0x9A, 0x9C |
|
| New vendor cmds | -- | 0x99, 0x9A, 0x9C |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. DiSEqC Timing Chain Analysis
|
||||||
|
|
||||||
|
### 7.1 Timer2 Configuration (Identical Across All Versions)
|
||||||
|
|
||||||
|
All firmware versions configure Timer2 identically during USB descriptor setup:
|
||||||
|
|
||||||
|
```
|
||||||
|
T2CON = 0x04 ; Auto-reload mode, internal clock, TR2=1 (running)
|
||||||
|
RCAP2H = 0xF8 ; Reload high byte
|
||||||
|
RCAP2L = 0x2F ; Reload low byte -> RCAP2 = 0xF82F = 63535
|
||||||
|
CKCON = 0x00 ; Default (T2M=0 -> Timer2 clock = CLKOUT/12)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Timer2 Clock Derivation:**
|
||||||
|
```
|
||||||
|
FX2 master clock = 48 MHz
|
||||||
|
CKCON.T2M = 0 -> Timer2 clock = 48 MHz / 12 = 4 MHz
|
||||||
|
Count per overflow = 65536 - 63535 = 2001
|
||||||
|
Tick period = 2001 / 4,000,000 = 500.25 us ~ 500 us
|
||||||
|
Tick frequency ~ 2.0 kHz
|
||||||
|
```
|
||||||
|
|
||||||
|
Timer2 runs continuously from power-on and is never stopped or reconfigured. It serves as a stable 500 us timebase for all DiSEqC operations.
|
||||||
|
|
||||||
|
### 7.2 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 to FX2 | | |
|
||||||
|
| (firmware only) | | firmware logic) | | |
|
||||||
|
+------------------+ +--------------------+ +------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
The firmware does NOT generate the 22 kHz carrier directly. P0.3 gates an external
|
||||||
|
22 kHz oscillator circuit on the PCB. The data pin (P0.7/P0.4/P0.0 depending on
|
||||||
|
version) is used only internally by the firmware to control the Manchester encoding
|
||||||
|
logic -- it tells the bit-symbol function whether to cut the carrier short or leave
|
||||||
|
it on for the full period.
|
||||||
|
|
||||||
|
### 7.3 Manchester Encoding (DiSEqC Bit Symbol)
|
||||||
|
|
||||||
|
Each DiSEqC bit consists of 3 Timer2 ticks (3 x 500 us = 1.5 ms):
|
||||||
|
|
||||||
|
**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)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Implementation (decompiled from Rev.2 FUN_CODE_213c):**
|
||||||
|
```c
|
||||||
|
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
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.4 Byte Transmission (8 Data Bits + Odd Parity)
|
||||||
|
|
||||||
|
Each DiSEqC byte is 9 bits: 8 data (MSB first) + 1 parity (odd).
|
||||||
|
|
||||||
|
**Implementation (decompiled from Rev.2 FUN_CODE_07d1):**
|
||||||
|
```c
|
||||||
|
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) { // Test MSB
|
||||||
|
data_pin = 1; // Set data = '1'
|
||||||
|
diseqc_bit_symbol(); // Transmit '1' symbol
|
||||||
|
ones_count++;
|
||||||
|
} else {
|
||||||
|
data_pin = 0; // Set data = '0'
|
||||||
|
diseqc_bit_symbol(); // Transmit '0' 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
|
||||||
|
|
||||||
|
### 7.5 Tone Burst (Mini DiSEqC Command)
|
||||||
|
|
||||||
|
For legacy 2-way satellite switches, a simple tone burst is used instead of a
|
||||||
|
full DiSEqC message. The burst is 25 Timer2 ticks of continuous carrier:
|
||||||
|
|
||||||
|
```c
|
||||||
|
void tone_burst_A(void) {
|
||||||
|
TF2 = 0; // Sync timer
|
||||||
|
wait_TF2(); // One tick gap
|
||||||
|
P0 |= 0x08; // P0.3 = 1 -> carrier ON
|
||||||
|
for (char i = 25; i > 0; i--) {
|
||||||
|
wait_TF2(); // 25 x 500 us = 12.5 ms
|
||||||
|
}
|
||||||
|
P0 &= 0xF7; // P0.3 = 0 -> carrier OFF
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Burst duration:** 25 x 500 us = 12.5 ms (matches DiSEqC spec)
|
||||||
|
|
||||||
|
### 7.6 Timer Tick Wait (TF2 Polling)
|
||||||
|
|
||||||
|
The lowest-level timing primitive is a busy-wait on Timer2 overflow:
|
||||||
|
|
||||||
|
```c
|
||||||
|
void wait_TF2(void) {
|
||||||
|
while (TF2 == 0) {} // Poll Timer2 overflow flag
|
||||||
|
TF2 = 0; // Clear flag for next tick
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This is identical across all versions (v2.06: 0x24C6, Rev.2: FUN_CODE_225f,
|
||||||
|
v2.13: func_0x2431). Timer2 overflows every 500.25 us, providing the fundamental
|
||||||
|
DiSEqC timebase.
|
||||||
|
|
||||||
|
### 7.7 CPU Clock Compensation (Delay Function)
|
||||||
|
|
||||||
|
The delay function used before DiSEqC transmission adjusts for CPU clock speed:
|
||||||
|
|
||||||
|
```c
|
||||||
|
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.
|
||||||
|
|
||||||
|
### 7.8 Complete DiSEqC 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 | 12.5 ms (25 ticks) | Mini-command A/B |
|
||||||
|
| Pre-TX delay | 7.5 ms (15 ticks) | Voltage settling |
|
||||||
|
| 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 |
|
||||||
|
| Carrier enable | P0.3 | All versions |
|
||||||
|
| Data pin (v2.06) | P0.7 | PCB revision A |
|
||||||
|
| Data pin (Rev.2) | P0.4 | PCB revision B |
|
||||||
|
| Data pin (v2.13) | P0.0 | PCB revision C |
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user