I am having the same problem that is described above:
I'm using the MC9S08QG as a slave only. The master is an I2C communication module from NI and is only able to complete one read/write session. All subsequent attempts at the same communication fail. After watching the SDA and SCL lines with a scope, everything looks as it should: the master issues a start, calls the slave in write mode, sends a starting address, issues a restart, calls the slave in read mode, acknowledges each byte up until the last, which is not acknolwedged. The MC9S08QG then holds the SDA line low for some reason and no stop signal is seen on the scope.
The code I am using for the iic interrupt is posted below. It is almost the same as that provided in Freescale's AN3048.
__interrupt void isrViic(void)
{
/* Write your interrupt code here ... */
// clear interrupt bit
IICS_IICIF = 1;
// Always in slave operation
// check arbitration lost bit
if(IICS_ARBL)
{
// if ARBL set, clear it and check IAAS bit
IICS_ARBL = 1;
if(IICS_IAAS) // start and addressed as slave
{
iic_count = 0;
// if IAAS set, check SRW for address transfer
check_SRW();
}
else
{
// if IAAS not set, return from interrupt
}
}
else
{
// if ARBL not set, check IAAS bit
if(IICS_IAAS) // start and addressed as slave
{
iic_count = 0;
// if IAAS set, check SRW for address transfer
check_SRW();
}
else
{
// if IAAS not set, check TX or RX for data transfer
if(IICC_TX)
{
// if TX, check ACK from receiver
if(~IICS_RXAK)
{
// if ACK detected, transmit next byte
IICD = send_data(iic_regaddress++);
iic_count++;
}
else
{
// if ACK not detected, switch to RX mode, dummy read from IICD
IICC_TX = 0; // clears IAAS bit
IICD;
}
}
else
{
// if RX, read data from IICD and store
if(iic_count == 0)
{
// receive an address
iic_regaddress = IICD;
iic_count++;
}
else
{
// receive data
receive_data(iic_regaddress++);
iic_count++;
}
}
}
}
// need to leave SDA high so the bus will be free!
}
void check_SRW(void)
{
if(IICS_SRW)
{
// if set, set to transmit mode and write data to IICD
IICC_TX = 1;
IICD = send_data(iic_regaddress++);
iic_count++;
}
else
{
// if not set, set to receive mode and read dummy data from IICD
IICC_TX = 0;
IICD;
}
}
The "send_data" and "receive_data" functions just return the value to be written or save the received data.
As suggested by others, I'm able to basically reset the IIC module by toggling the IICC_IICEN bit in main(), but there must be a way to keep from getting into the situation where the SDA line is held low. Any help would be appreciated.
-NS