Fix BCM4500 I2C address and add hardware diagnostic commands
Correct BCM4500 I2C address from 0x10 (8-bit wire) to 0x08 (7-bit) since fx2lib shifts internally. Add i2c_combined_read() with repeated START for proper BCM4500 register access. Add I2C bus scan (0xB4), raw read (0xB5), and indirect protocol diagnostic (0xB6) commands. Single-transaction indirect reads/writes for BCM4500 register protocol. Verified on hardware: BCM4500 ACKs at 0x08, BOOT_8PSK returns config 0x03. Register reads still return zeros — BCM4500 needs DSP firmware loaded via LOAD_BCM4500 (0x88) before registers become functional.
This commit is contained in:
parent
5710584267
commit
890a38bfa0
@ -18,8 +18,8 @@
|
||||
|
||||
#define SYNCDELAY SYNCDELAY4
|
||||
|
||||
/* BCM4500 I2C address (7-bit) */
|
||||
#define BCM4500_ADDR 0x10
|
||||
/* BCM4500 I2C address (7-bit); 8-bit wire address is 0x10/0x11 */
|
||||
#define BCM4500_ADDR 0x08
|
||||
|
||||
/* BCM4500 indirect register protocol registers */
|
||||
#define BCM_REG_PAGE 0xA6
|
||||
@ -81,6 +81,68 @@ static __xdata BYTE i2c_rd[8];
|
||||
|
||||
/* ---------- BCM4500 I2C helpers ---------- */
|
||||
|
||||
/*
|
||||
* Combined I2C write-read with repeated START (no STOP between
|
||||
* write and read phases). Many I2C devices including the BCM4500
|
||||
* require this pattern instead of separate write+stop/read+stop.
|
||||
*
|
||||
* Sequence: START → addr+W → reg → RESTART → addr+R → data → STOP
|
||||
*/
|
||||
static BOOL i2c_combined_read(BYTE addr, BYTE reg, BYTE len, BYTE *buf) {
|
||||
BYTE i;
|
||||
BYTE tmp;
|
||||
|
||||
/* START + write address */
|
||||
I2CS |= bmSTART;
|
||||
I2DAT = addr << 1;
|
||||
while (!(I2CS & bmDONE))
|
||||
;
|
||||
if (!(I2CS & bmACK))
|
||||
goto fail;
|
||||
|
||||
/* Write register address */
|
||||
I2DAT = reg;
|
||||
while (!(I2CS & bmDONE))
|
||||
;
|
||||
if (!(I2CS & bmACK))
|
||||
goto fail;
|
||||
|
||||
/* REPEATED START + read address */
|
||||
I2CS |= bmSTART;
|
||||
I2DAT = (addr << 1) | 1;
|
||||
while (!(I2CS & bmDONE))
|
||||
;
|
||||
if (!(I2CS & bmACK))
|
||||
goto fail;
|
||||
|
||||
/* For single byte, set LASTRD before dummy read */
|
||||
if (len == 1)
|
||||
I2CS |= bmLASTRD;
|
||||
|
||||
/* Dummy read to trigger first clock burst */
|
||||
tmp = I2DAT;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
while (!(I2CS & bmDONE))
|
||||
;
|
||||
if (i == len - 2)
|
||||
I2CS |= bmLASTRD;
|
||||
if (i == len - 1)
|
||||
I2CS |= bmSTOP;
|
||||
buf[i] = I2DAT;
|
||||
}
|
||||
|
||||
while (I2CS & bmSTOP)
|
||||
;
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
I2CS |= bmSTOP;
|
||||
while (I2CS & bmSTOP)
|
||||
;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write one byte to a BCM4500 direct I2C register (subaddr).
|
||||
* This writes to the I2C register directly, not through the
|
||||
@ -92,49 +154,42 @@ static BOOL bcm_direct_write(BYTE reg, BYTE val) {
|
||||
}
|
||||
|
||||
/*
|
||||
* Read one byte from a BCM4500 direct I2C register.
|
||||
* Read one byte from a BCM4500 direct I2C register using
|
||||
* combined write-read with repeated START.
|
||||
*/
|
||||
static BOOL bcm_direct_read(BYTE reg, BYTE *val) {
|
||||
BYTE r = reg;
|
||||
if (!i2c_write(BCM4500_ADDR, 1, &r, 0, NULL))
|
||||
return FALSE;
|
||||
if (!i2c_read(BCM4500_ADDR, 1, val))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
return i2c_combined_read(BCM4500_ADDR, reg, 1, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a value to a BCM4500 indirect register.
|
||||
* Protocol:
|
||||
* 1. Write page/register to 0xA6
|
||||
* 2. Write data to 0xA7
|
||||
* 3. Write 0x03 to 0xA8 (execute write)
|
||||
* Single multi-byte I2C write to 0xA6 with auto-increment:
|
||||
* [0xA6] = page, [0xA7] = data, [0xA8] = 0x03 (write cmd)
|
||||
*/
|
||||
static BOOL bcm_indirect_write(BYTE reg, BYTE val) {
|
||||
if (!bcm_direct_write(BCM_REG_PAGE, reg))
|
||||
return FALSE;
|
||||
if (!bcm_direct_write(BCM_REG_DATA, val))
|
||||
return FALSE;
|
||||
if (!bcm_direct_write(BCM_REG_CMD, BCM_CMD_WRITE))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
BYTE start_reg = BCM_REG_PAGE;
|
||||
i2c_rd[0] = reg;
|
||||
i2c_rd[1] = val;
|
||||
i2c_rd[2] = BCM_CMD_WRITE;
|
||||
return i2c_write(BCM4500_ADDR, 1, &start_reg, 3, i2c_rd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a value from a BCM4500 indirect register.
|
||||
* Protocol:
|
||||
* 1. Write page/register to 0xA6
|
||||
* 2. Write 0x01 to 0xA8 (execute read)
|
||||
* 3. Read data from 0xA7
|
||||
* Protocol: single multi-byte I2C write to 0xA6 with auto-increment:
|
||||
* [0xA6] = page, [0xA7] = 0x00, [0xA8] = 0x01 (read cmd)
|
||||
* Then read the result from 0xA7.
|
||||
*/
|
||||
static BOOL bcm_indirect_read(BYTE reg, BYTE *val) {
|
||||
if (!bcm_direct_write(BCM_REG_PAGE, reg))
|
||||
BYTE start_reg = BCM_REG_PAGE;
|
||||
/* page, placeholder data, read command — written to A6,A7,A8 in one shot */
|
||||
i2c_rd[0] = reg;
|
||||
i2c_rd[1] = 0x00;
|
||||
i2c_rd[2] = BCM_CMD_READ;
|
||||
if (!i2c_write(BCM4500_ADDR, 1, &start_reg, 3, i2c_rd))
|
||||
return FALSE;
|
||||
if (!bcm_direct_write(BCM_REG_CMD, BCM_CMD_READ))
|
||||
return FALSE;
|
||||
if (!bcm_direct_read(BCM_REG_DATA, val))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
delay(1);
|
||||
return i2c_combined_read(BCM4500_ADDR, BCM_REG_DATA, 1, val);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -735,6 +790,113 @@ BOOL handle_vendorcommand(BYTE cmd) {
|
||||
do_blind_scan();
|
||||
return TRUE;
|
||||
|
||||
/* 0xB4: I2C_BUS_SCAN -- probe all 7-bit addresses, return 16-byte bitmap */
|
||||
case 0xB4: {
|
||||
BYTE a, byte_idx, bit;
|
||||
/* 128 addresses / 8 = 16 bytes bitmap */
|
||||
for (byte_idx = 0; byte_idx < 16; byte_idx++)
|
||||
EP0BUF[byte_idx] = 0;
|
||||
|
||||
for (a = 1; a < 0x78; a++) {
|
||||
/* Try START + address + write, see if ACK comes back */
|
||||
I2CS |= bmSTART;
|
||||
I2DAT = a << 1; /* write direction */
|
||||
while (!(I2CS & bmDONE))
|
||||
;
|
||||
if (I2CS & bmACK) {
|
||||
/* Device responded at this address */
|
||||
byte_idx = a >> 3;
|
||||
bit = a & 0x07;
|
||||
EP0BUF[byte_idx] |= (1 << bit);
|
||||
}
|
||||
I2CS |= bmSTOP;
|
||||
while (I2CS & bmSTOP)
|
||||
;
|
||||
}
|
||||
EP0BCH = 0;
|
||||
EP0BCL = 16;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* 0xB5: I2C_RAW_READ -- read N bytes from any I2C address
|
||||
* wValue = 7-bit I2C address, wIndex = register, wLength = bytes to read
|
||||
* Uses combined write-read with repeated START */
|
||||
case 0xB5: {
|
||||
BYTE i2c_addr_b5 = (BYTE)wval;
|
||||
BYTE i2c_reg_b5 = (BYTE)SETUP_INDEX();
|
||||
BYTE i2c_len_b5 = (BYTE)SETUP_LENGTH();
|
||||
BYTE ok;
|
||||
|
||||
if (i2c_len_b5 > 64) i2c_len_b5 = 64;
|
||||
|
||||
ok = i2c_combined_read(i2c_addr_b5, i2c_reg_b5, i2c_len_b5, EP0BUF);
|
||||
if (!ok) {
|
||||
BYTE fi;
|
||||
for (fi = 0; fi < i2c_len_b5; fi++)
|
||||
EP0BUF[fi] = 0xFF;
|
||||
}
|
||||
EP0BCH = 0;
|
||||
EP0BCL = i2c_len_b5;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* 0xB6: I2C_DIAG -- step-by-step indirect register read diagnostic
|
||||
* wValue = page/register to read
|
||||
* Returns 8 bytes: [write_A6_ok, readback_A6, write_A8_ok, readback_A8,
|
||||
* readback_A7, direct_read_A6, direct_read_A7, direct_read_A8] */
|
||||
case 0xB6: {
|
||||
BYTE target_reg = (BYTE)wval;
|
||||
BYTE diag[8];
|
||||
BYTE rb;
|
||||
|
||||
/* Step 1: Write target register to page select (0xA6) */
|
||||
diag[0] = bcm_direct_write(BCM_REG_PAGE, target_reg) ? 0x01 : 0x00;
|
||||
|
||||
/* Step 2: Read back 0xA6 to verify write */
|
||||
rb = 0xEE;
|
||||
i2c_combined_read(BCM4500_ADDR, BCM_REG_PAGE, 1, &rb);
|
||||
diag[1] = rb;
|
||||
|
||||
/* Step 3: Write read command (0x01) to 0xA8 */
|
||||
diag[2] = bcm_direct_write(BCM_REG_CMD, BCM_CMD_READ) ? 0x01 : 0x00;
|
||||
|
||||
/* Step 4: Read back 0xA8 to check command status */
|
||||
rb = 0xEE;
|
||||
i2c_combined_read(BCM4500_ADDR, BCM_REG_CMD, 1, &rb);
|
||||
diag[3] = rb;
|
||||
|
||||
/* Step 5: Small delay for command execution */
|
||||
delay(2);
|
||||
|
||||
/* Step 6: Read 0xA7 (data register) — this is the result */
|
||||
rb = 0xEE;
|
||||
i2c_combined_read(BCM4500_ADDR, BCM_REG_DATA, 1, &rb);
|
||||
diag[4] = rb;
|
||||
|
||||
/* Step 7: Read back all three control regs for final state */
|
||||
rb = 0xEE;
|
||||
i2c_combined_read(BCM4500_ADDR, BCM_REG_PAGE, 1, &rb);
|
||||
diag[5] = rb;
|
||||
rb = 0xEE;
|
||||
i2c_combined_read(BCM4500_ADDR, BCM_REG_DATA, 1, &rb);
|
||||
diag[6] = rb;
|
||||
rb = 0xEE;
|
||||
i2c_combined_read(BCM4500_ADDR, BCM_REG_CMD, 1, &rb);
|
||||
diag[7] = rb;
|
||||
|
||||
EP0BUF[0] = diag[0];
|
||||
EP0BUF[1] = diag[1];
|
||||
EP0BUF[2] = diag[2];
|
||||
EP0BUF[3] = diag[3];
|
||||
EP0BUF[4] = diag[4];
|
||||
EP0BUF[5] = diag[5];
|
||||
EP0BUF[6] = diag[6];
|
||||
EP0BUF[7] = diag[7];
|
||||
EP0BCH = 0;
|
||||
EP0BCL = 8;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user