lpcware

I2C slave doesn't see stop condiction

Discussion created by lpcware Employee on Jun 15, 2016
Latest reply on Jun 15, 2016 by lpcware
Content originally posted in LPCWare by shoeloader on Mon Jul 07 07:22:01 MST 2014
I am trying to implement a high level I2C protocol specified by a customer.
The protocol is multimaster and messages have a variable length.
I use two lpc800's to test the protocol.
Device A sends a request message to Device B.
Device B correctly receives this message and acks every byte (nacking corrupt messages is allowed though).
Now Device B has to switch to master mode and send a message to Device A.
The problem is I can't detect the end of the message send by Device A.
The length of the message is can be found out by looking in the content of the message, but
I prefer to keep the  I2C driver as simple as possible and use the stop condition as a trigger
to process the message and to send a response (later I want to specify time-out conditions as well).

From what I understand the datasheet tells me I can use SLVDESEL to detect a stop condition.


Quote:

SLVDESEL
Slave Deselected flag.
This flag will cause an interrupt when set if enabled via INTENSET. This flag can be cleared by writing a 1 to this bit.
0:
Not deselected. The Slave function has not become deselected. This does not mean that it is currently selected. That information can be found in the SLVSEL flag.
1:
Deselected. The Slave function has become deselected. This is specifically caused by the SLVSEL flag changing from 1 to 0. See the description of SLVSEL for details on when that event occurs.




Quote:

SLVSEL
Slave selected flag. SLVSEL is set after an address match when software tells the Slave function to acknowledge the address.It is cleared when another address cycle presents an address that does not match an enabled address on the Slave function, when slave software decides to NACK a matched address, or when there is a Stop detected on the bus. SLVSEL is not cleared if software NACKs data.



The driver I use is interrupt based.


//add-on i2c handler
void I2C_IRQHandler(void){ 
 
  uint32_t intstat = LPC_I2C->INTSTAT; 
  uint32_t stat = LPC_I2C->STAT; 
  uint32_t mater_state;
  uint32_t slave_state;

[...]
 
  if(intstat & I2C_STAT_SLVPENDING){
    slave_state = stat & I2C_STAT_SLVSTATE;
   
    if(slave_state== I2C_STAT_SLVST_ADDR){

      if(i2c_rx_data_available){
        LPC_I2C->SLVCTL = I2C_SLVCTL_SLVNACK; // nack address: still processing data
      }
      else{
        LPC_I2C->SLVCTL = I2C_SLVCTL_SLVCONTINUE; // ack address 
        if(add_on_rx_size){
          add_on_rx_size=0;
        }    
        add_on_rx[add_on_rx_size]=add_on_address<<1;       
        ++add_on_rx_size;       
      }         
    }
    else if(slave_state== I2C_STAT_SLVST_RX){
      if(add_on_rx_size>=add_on_max_rx_size){
        LPC_I2C->SLVCTL = I2C_SLVCTL_SLVNACK; // nack data  
      }
      else{
        add_on_rx[add_on_rx_size]=LPC_I2C->SLVDAT;
        ++add_on_rx_size;     
        LPC_I2C->SLVCTL = I2C_SLVCTL_SLVCONTINUE; // ack data            
      }
    }   
   
    if(stat&I2C_STAT_SLVDESEL){  
      LPC_I2C->STAT=I2C_STAT_SLVDESEL;//clear flag
      while(1);//test to see where stop condition is detected
    }
   
  }
}


The weird thing is that the SLVDESEL flag is set after the address byte of the second message.
So I receive and ack a complete message. A stop occurs. Another message is send to the slave.
I ack the address. Then the SLVDESEL flag is set before I got a chance to ack the second byte.

How do I detect a stop condition using i2c interrupts?

Outcomes