I am using i2c to access a SE95D, a MAX7111 and a PCA 9548A.
The Tempsensor and the DIO Mux work fine they both use 2 byte access.
The PCA9548A needs a one byte read this seems to cause a irq loop when calling the write one byte.
So the sequence is
i2cMasterReceiveTimeout(current_i2c_drv, deviceAdress, f_pCmd->data, 1,100);
i2cMasterTransmitTimeout(current_i2c_drv, deviceAdress, f_pCmd->data, 1, 0, 0, 100);
the transmit never returns and chibios locks up.
When I stop with the jtag debugger I can see that
static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp)
is called high frequently.
I get event=65 and regSR2 3 which seems to be a switch value which is not served.
This is the function:
Code: Select all
static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
I2C_TypeDef *dp = i2cp->i2c;
uint32_t regSR2 = dp->SR2;
uint32_t event = dp->SR1;
/* Interrupts are disabled just before dmaStreamEnable() because there
is no need of interrupts until next transaction begin. All the work is
done by the DMA.*/
switch (I2C_EV_MASK & (event | (regSR2 << 16))) {
case I2C_EV5_MASTER_MODE_SELECT:
if ((i2cp->addr >> 8) > 0) {
/* 10-bit address: 1 1 1 1 0 X X R/W */
dp->DR = 0xF0 | (0x6 & (i2cp->addr >> 8)) | (0x1 & i2cp->addr);
} else {
dp->DR = i2cp->addr;
}
break;
case I2C_EV9_MASTER_ADD10:
/* Set second addr byte (10-bit addressing)*/
dp->DR = (0xFF & (i2cp->addr >> 1));
break;
case I2C_EV6_MASTER_REC_MODE_SELECTED:
dp->CR2 &= ~I2C_CR2_ITEVTEN;
dmaStreamEnable(i2cp->dmarx);
dp->CR2 |= I2C_CR2_LAST; /* Needed in receiver mode. */
if (dmaStreamGetTransactionSize(i2cp->dmarx) < 2)
dp->CR1 &= ~I2C_CR1_ACK;
break;
case I2C_EV6_MASTER_TRA_MODE_SELECTED:
dp->CR2 &= ~I2C_CR2_ITEVTEN;
dmaStreamEnable(i2cp->dmatx);
break;
case I2C_EV8_2_MASTER_BYTE_TRANSMITTED:
/* Catches BTF event after the end of transmission.*/
if (dmaStreamGetTransactionSize(i2cp->dmarx) > 0) {
/* Starts "read after write" operation, LSB = 1 -> receive.*/
i2cp->addr |= 0x01;
dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
return;
}
dp->CR2 &= ~I2C_CR2_ITEVTEN;
dp->CR1 |= I2C_CR1_STOP;
wakeup_isr(i2cp, RDY_OK);
break;
default:
break;
}
/* Clear ADDR flag. */
if (event & (I2C_SR1_ADDR | I2C_SR1_ADD10))
(void)dp->SR2;
}
I find it strange that the default path is not doing anything.
Any ideas if this bug is already fixed?
I am using 2.6.1.
Thanks a lot for helping.
Rgards
Michael