Hello, I'm trying to port an I2C driver from KL05 to K32; while peripheral registers definition seem the same, the driver on K32 fails to switch from write to read: after writing slave and register address, instead of sending the read command it repeats the last write.
Does anybody know which are the differences between the two peripherals?
Thanx in advance.
Here is the code related:
// end of tx: check if read must be performed
if (ch->rx_length > 0)
{
// Generate restart
i2c->C1 |= (I2C_C1_RSTA_MASK | I2C_C1_TX_MASK);
// send slave address and read command
ch->state = I2C_RX_START;
i2c->D = ch->slave | 0x01;
}
And here is the full code of the ISR:
typedef struct
{
uint8_t slave; // slave address used for current communication
uint8_t tx_length; // number of bytes to write
uint8_t rx_length; // number of bytes to read
uint8_t index; // index of current array (write/read)
uint8_t state; // current operation
uint8_t* rx_data; // pointer to read data (at least rx_length allocated bytes)
uint8_t tx_data[I2C_MAX_MSG_SIZE]; // buffer of data to write
} I2C_Channel;
volatile I2C_Channel i2c_channels[I2C_TOT_DEVICES] = { 0, } ;
static I2C_Type* i2c_base_ptrs[] = I2C_BASE_ADDRS;
void isr_i2c(uint8_t channel)
{
I2C_Type* i2c = i2c_base_ptrs[channel];
I2C_Channel* ch = &i2c_channels[channel];
// check status register
uint8_t status = i2c->S;
// clear interrupt service flag
i2c->S = I2C_S_IICIF_MASK;
if (status & I2C_S_ARBL_MASK)
{
// lost arbitration (should not happen): stop i2c
i2c->S = I2C_S_ARBL_MASK; // clear arbl (by setting it)
i2c->C1 = 0x00;
ch->state = I2C_ERROR;
}
else
if (ch->state == I2C_TX)
{
if (status & I2C_S_RXAK_MASK)
{
// ACK not received
// Generate STOP (set MST=0), stay in tx mode, and disable further interrupts
i2c->C1 = (I2C_C1_IICEN_MASK | I2C_C1_TX_MASK);
ch->state = I2C_ERROR;
}
else
if (ch->index < ch->tx_length)
{
// write byte
i2c->D = ch->tx_data[ch->index];
ch->index++;
}
else
{
// end of tx: check if read must be performed
if (ch->rx_length > 0)
{
// Generate restart
i2c->C1 |= (I2C_C1_RSTA_MASK | I2C_C1_TX_MASK);
// send slave address and read command
ch->state = I2C_RX_START;
i2c->D = ch->slave | 0x01;
}
else
{
// Generate STOP (set MST=0), stay in tx mode, and disable further interrupts
i2c->C1 = (I2C_C1_IICEN_MASK | I2C_C1_TX_MASK);
ch->state = I2C_AVAILABLE;
}
}
}
else
if (ch->state == I2C_RX_START)
{
// switch to reading
ch->state = I2C_RX;
ch->index = 0;
i2c->C1 &= ~I2C_C1_TX_MASK; // switch to RX mode
if (ch->rx_length > 1)
{
i2c->C1 &= ~I2C_C1_TXAK_MASK; // ack next byte read
}
else
{
i2c->C1 |= I2C_C1_TXAK_MASK; // do not ACK the final read
}
// dummy read to start communication
*(ch->rx_data) = i2c->D;
}
else
if (ch->state == I2C_RX)
{
if (ch->index == ch->rx_length - 1)
{
// last read
// All the reads in the sequence have been processed (but note that the final data register
// read still needs to be done below!) Now the next thing is the end of a sequence; we need
// to switch to TX mode to avoid triggering another I2C read when reading the contents of
// the data register
i2c->C1 |= I2C_C1_TX_MASK;
// Perform the final data register read now that it's safe to do so
*(ch->rx_data + ch->index) = i2c->D;
// Generate STOP (set MST=0), stay in tx mode, and disable further interrupts
i2c->C1 = (I2C_C1_IICEN_MASK | I2C_C1_TX_MASK);
ch->state = I2C_AVAILABLE;
}
else
{
// read byte
*(ch->rx_data + ch->index) = i2c->D;
ch->index++;
if (ch->index == ch->rx_length - 1)
{
i2c->C1 |= I2C_C1_TXAK_MASK; // do not ACK the final read
}
else
{
i2c->C1 &= ~I2C_C1_TXAK_MASK; // ack next byte read
}
}
}
}