I2C Bus Architecture
The SkyWalker-1 uses a single I2C bus connecting the FX2 microcontroller (master) to three slave devices. The FX2’s hardware I2C controller handles all bus transactions through XRAM-mapped registers.
FX2 I2C Controller
Section titled “FX2 I2C Controller”| SFR | Address | Function |
|---|---|---|
| I2CS | 0xE678 (XRAM) | I2C control/status register |
| I2DAT | 0xE679 (XRAM) | I2C data register |
| I2CTL | 0xE67A (XRAM) | I2C control (speed selection) |
I2CS Control/Status Bits
Section titled “I2CS Control/Status Bits”| Bit | Name | Function |
|---|---|---|
| bmSTART | bit 7 | Write: initiate START condition |
| bmSTOP | bit 6 | Write: initiate STOP condition |
| bmLASTRD | bit 5 | Write: signal last read byte (NACK after next read) |
| bmDONE | bit 2 | Read: byte transfer complete |
| bmACK | bit 1 | Read: ACK received from slave |
| bmBERR | bit 0 | Read: bus error detected |
Bus Speed
Section titled “Bus Speed”The I2C bus operates at 400 kHz. The speed is set through two mechanisms:
- C2 EEPROM header — Config byte at offset 7 = 0x40, which the FX2 boot ROM uses to configure the I2C speed during initial EEPROM read.
- Firmware/software — I2CTL =
bm400KHZ(written by the custom firmware and init table).
Known Bus Devices
Section titled “Known Bus Devices”| 7-bit Address | Wire Write | Wire Read | Identity |
|---|---|---|---|
| 0x08 | 0x10 | 0x11 | BCM4500 demodulator |
| 0x10 | 0x20 | 0x21 | Tuner or LNB controller |
| 0x51 | 0xA2 | 0xA3 | Configuration EEPROM (24Cxx-family) |
These addresses were confirmed via the I2C_BUS_SCAN command (0xB4) in custom firmware v3.01.0, which probes all 7-bit addresses from 0x01 to 0x77.
BCM4500 Demodulator (0x08)
Section titled “BCM4500 Demodulator (0x08)”The primary device for all demodulation operations. Register access uses the indirect register protocol through registers 0xA6, 0xA7, and 0xA8. Direct registers 0xA2, 0xA4, and 0xF9 provide status information.
The v2.13 firmware also probes alternate addresses 0x7F and 0x3F at startup to detect which demodulator variant is present.
Tuner/LNB Controller (0x10)
Section titled “Tuner/LNB Controller (0x10)”Likely a tuner IC or LNB controller. In normal operation, the BCM4500 accesses this device internally for tuning. It is also directly addressable on the shared I2C bus. The kernel driver does not directly communicate with this device.
Configuration EEPROM (0x51)
Section titled “Configuration EEPROM (0x51)”A 24Cxx-family serial EEPROM that stores:
- Device serial number (read by GET_SERIAL_NUMBER, 0x93)
- Hardware platform ID (read by GET_FPGA_VERS, 0x95)
- Calibration data
Bus Topology
Section titled “Bus Topology” FX2 I2C Master (I2CS/I2DAT/I2CTL) | +----------+-----------+ | | | BCM4500 Tuner/LNB EEPROM (0x08) (0x10) (0x51)All three devices share the same SCL/SDA lines. The FX2’s hardware I2C controller manages bus arbitration and clock stretching detection.
Combined Write-Read Protocol
Section titled “Combined Write-Read 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 in 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 byte | | +---------------- BCM4500 ACKs its device 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 device 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 SFR Sequence for Combined Read
Section titled “FX2 SFR Sequence for Combined Read”// Phase 1: Write register addressI2CS |= bmSTART; // Generate STARTI2DAT = 0x10; // Write: device addr + W// wait bmDONE, check bmACKI2DAT = 0xA2; // Write: register address// wait bmDONE, check bmACK
// Phase 2: Read with repeated STARTI2CS |= 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 clearTimeout Protection
Section titled “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. If a slave holds SCL low or a bus error prevents bmDONE from asserting, the firmware hangs.
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 while bounding the worst case.