Greetings all,
I've been battling this for a while and not getting too far.
The problem is the KL05 receives the correct address from the master, ACKs it, then something very odd happens to the following byte. I have not been able to work out why.
A KL03 used to work perfectly in the KL05's place (using the KL05 now due to parts shortages).
The KL05 is running off the internal clock at 20Mhz, the bus clock div is 1 (also 20Mhz).
Attached is a image of the I2C signals. The address byte, and then the odd first data byte.
The pins and I2C peripheral are setup as following:
//i2c pin setup
PORTA->PCR[4] = PORT_PCR_MUX(0x02);
PORTA->PCR[3] = PORT_PCR_MUX(0x02);
//setup i2c hardware slave
CLOCK_EnableClock(kCLOCK_I2c0);
//set slave addr, no ranage
I2C0->A1 = 0x38 << 1U;
I2C0->RA = 0;
I2C0->C2 = 0;
//speed (I2C speed of master is ~315kHz)
I2C0->F = I2C_F_MULT(0) | I2C_F_ICR(6);
//glitch filter value, stop hold enable, and stop int
I2C0->FLT = I2C_FLT_FLT(0) | I2C_FLT_STOPF_MASK | I2C_FLT_STOPIE_MASK;
//reset all flags
I2C0->S = 0xFFU;
//enable slave, and slave int
I2C0->C1 = I2C_C1_IICEN_MASK | I2C_C1_IICIE_MASK;
//enable
NVIC_SetPriority(I2C0_IRQn, 1);
EnableIRQ(I2C0_IRQn);
The interrupt handler looks like:
void I2C0_IRQHandler(void)
{
//I2C IRQ handler
volatile uint8_t data = 0;
volatile uint8_t status;
bool doTransmit = false;
static bool isBusy = false;
//read flags
status = I2C_SlaveGetStatusFlags(I2C0);
//clear interrupt service flag
I2C0->S = I2C_S_IICIF_MASK;
//arbitration lost?
if (status & I2C_S_ARBL_MASK)
{
//clear ARBL
I2C0->S = I2C_S_ARBL_MASK;
//set receive mode
I2C0->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
//nothing more to do
return;
}
//check NAK
if (status & I2C_S_RXAK_MASK)
{
//set receive mode
I2C0->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
//read dummy
data = I2C0->D;
//do something?
}
else
//Check address match
if (status & I2C_S_IAAS_MASK)
{
//slave transmit, master reading from slave
isBusy = true;
if (status & I2C_S_SRW_MASK)
{
//change direction to send data
I2C0->C1 |= I2C_C1_TX_MASK;
doTransmit = true;
}
else
{
//slave receive, master writing to us
//send ack
I2C0->C1 &= ~(I2C_C1_TXAK_MASK);
//read dummy to release the bus
data = I2C0->D;
//reset inbuf
indatac = 0;
}
//do something here?
}
else
//check transfer complete flag
if (status & I2C_S_TCF_MASK)
{
if (status & I2C_S_SRW_MASK)
{
//slave transmit, master reading from slave
doTransmit = true;
}
else
{
//slave receive, master writing to slave
//ack
I2C0->C1 &= ~I2C_C1_TXAK_MASK;
//get data
data = I2C0->D;
indata[indatac++] = data;
}
}
else
{
//read dummy to release bus
data = I2C0->D;
}
//send data if there is the need
if (doTransmit)
{
//send data
if (!sendComplete)
{
I2C0->D = outdata[outdatac++];
}
else
{
//switch to receive mode
I2C0->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
//read dummy to release bus
data = I2C0->D;
}
}
//done
}

Anyone have any ideas what's going on here?
Thanks in advance.