[MPC5606] Arbitration Lost Bit I2C Interrupt Routine

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

[MPC5606] Arbitration Lost Bit I2C Interrupt Routine

1,082 Views
josepgorgues
Contributor II

Hello everyone,

 

I am using the Flow-Chart of Typical I2C Interrupt Routine on MPC5606s Controller. We can write multiple bytes successfully. The problem is when we try to send a read command.

 

We send the slave and the register address that we want to read, then we generate a repeated START and we send the (slave address + Read bit), the slave send us the value of the register, after that the Arbitration Lost bit (IBAL) is set. We try to clear this bit on the Interrupt function but when we are outside this bit is set again. So we can only read 1 byte and then we cannot have access on I2C bus.

 

Any help will be appreciated.

 

Thank,

Josep

Labels (1)
0 Kudos
Reply
3 Replies

800 Views
PetrS
NXP TechSupport
NXP TechSupport

Hi,

So after you sent a repeated START and control word (slave address + Read bit) you should get IBIF set, or interrupt. Then you will select receive mode and do a dummy IBDR read to initiate byte data receiving. Slave will send data and Master get IBIF set again. Master should decide if initiate next byte read or generate STOP. In this time the IBAL is set, am I right? Does a Master switch over to slave? But if you clear the IBAL it should not be set again, unless Master want to drive the lines again. It could be great to check the I2C lines with a scope to see real signals.

BTW what kind of devices are on the bus? Just single Slave? What device is it?  

BR,Petr

0 Kudos
Reply

800 Views
josepgorgues
Contributor II

Hi,

I send the repeated Start and the control word (slave address + Read bit) then we clean the IBIF bit. When the IBIF is set again we change to  receive mode and do a dummy IBDR read to initiate byte data receiving. Slave send a data and Master get IBIF set. In this time the IBAL is set. The Master do not switch over to slave.

On the bus there are a EEPROM (M24C02), it is the only device on the bus.

On the I2C lines we can see the following signals, after that the SDA continues LOW and the SCL continues HIGH.

I2C_BusCom_Failure.PNG

The function of I2C interrupts is the following:

void I2C_Interupt(void)

{     uint8_t dummy;                                     // Dummy variable to read I2C

if(I2C_0.IBCR.B.MS==1)          /* If is in master mode              */

{

    if(I2C_0.IBCR.B.TX == 1)  /* If TX */

    {

       if(I2C_0.IBSR.B.RXAK==0)          /* If a acknowledge is received               */

       {

        entery++;

        ack_flag= 0;

        if(entery == 1)

        {

          I2C_0.IBDR.R = iic_addr;    /* Update IBDR, send internal address of I2C slave   */

        }

        else if (entery <= (iic_len+1))

        {

            I2C_0.IBCR.B.RSTA = 1;                                 // Set IBCR, generate repeated START

            I2C_0.IBDR.R = iic_buffer[entery-2];

            ack_flag = 1;  

        }

        else

        {

             rd_flag = 0;

            I2C_0.IBCR.B.TX = 0;                                  // Set IBCR, Receive mode select

            dummy = I2C_0.IBDR.R;                                  // initiates next byte data receiving

            entery_r = 0;       

        }

       }

    }

    else    /* If RX */

    {

      if(entery_r<(iic_rlen-1))

      {

        *(RData+entery_r) = I2C_0.IBDR.R;                        // Read the received byte from slave

        entery_r++;

      }

      else if(entery_r==(iic_rlen-1))

      {

         I2C_0.IBCR.B.NOACK = 1;                           // In the last byte, change the ACK for NOACK

      }

      else

      {

          I2C_0.IBCR.B.MS = 0;                                            // Set IBCR, Generate stop signal;

            I2C_0.IBCR.B.NOACK = 0;                                // Reset the NOACK to default value

      }

    }

}

else   /* Slave mode */

{

  if(I2C_0.IBSR.B.IBAL == 1)  /* Abitration Lost */

  {

    I2C_0.IBSR.B.IBAL = 1;

    I2C_0.IBCR.B.MS=0;

    if(I2C_0.IBSR.B.IAAS == 1)

    {

      if(I2C_0.IBSR.B.SRW == 1)

      {

        I2C_0.IBCR.B.TX = 1;                                  // Set IBCR, Receive mode select

      }

      else

      {

         I2C_0.IBCR.B.TX = 0;                                  // Set IBCR, Receive mode select

         dummy = I2C_0.IBDR.R;                                  // initiates next byte data receiving 

      }

    }

  }

  else  /* Abitration No Lost */

  {

    if(I2C_0.IBSR.B.IAAS == 1)

    {

        I2C_0.IBCR.B.TX = 1;                                  // Set IBCR, Receive mode select

    }

    else

    {

       if(I2C_0.IBCR.B.TX == 1)  /* If TX */

       {

          if(I2C_0.IBSR.B.RXAK==0)          /* If a acknowledge is received               */

          {

          entery++;

          ack_flag= 0;

          if(entery == 1)

          {

            I2C_0.IBDR.R = iic_addr;    /* Update IBDR, send internal address of I2C slave   */

          }

          else if (entery <= (iic_len+1))

          {

              I2C_0.IBCR.B.RSTA = 1;                                 // Set IBCR, generate repeated START

              I2C_0.IBDR.R = iic_buffer[entery-2];

              ack_flag = 1;          

          }

          else

          {

              rd_flag = 0;

              I2C_0.IBCR.B.TX = 0;                                  // Set IBCR, Receive mode select

              dummy = I2C_0.IBDR.R;                                  // initiates next byte data receiving

              entery_r = 0;

          }

          }

       }

       else

       {

          if(entery_r<(iic_rlen-1))

          {

            *(RData+entery_r) = I2C_0.IBDR.R;                        // Read the received byte from slave

            entery_r++;

          }

          else if(entery_r==(iic_rlen-1))

          {

            I2C_0.IBCR.B.NOACK = 1;                           // In the last byte, change the ACK for NOACK

          }

          else

          {

            I2C_0.IBCR.B.MS = 0;                                            // Set IBCR, Generate stop signal;

              I2C_0.IBCR.B.NOACK = 0;                                // Reset the NOACK to default value

          }

       }

    }

  }

}

 

  I2C_0.IBSR.B.IBIF=1;

 

}

Best Regards,

Josep

0 Kudos
Reply

800 Views
PetrS
NXP TechSupport
NXP TechSupport

Hi,

I think the reading part of Master mode is not completely correct. Try to use following one. I assume the iic_rlen specify the number of bytes to be read.

                …

                else

                {

                                rd_flag = 0;

                                I2C_0.IBCR.B.TX = 0;       // Set IBCR, Receive mode select

                               

                                if(iic_rlen==1) I2C_0.IBCR.B.NOACK = 1; // if just 1 byte is going to be read

                                                                                                                // NOACK next received byte

                                dummy = I2C_0.IBDR.R;                // initiates next byte data receiving

                                entery_r = 0;       

                }

      }

}

else    /* If RX */

{

                if(entery_r==(iic_rlen-2)

{

I2C_0.IBCR.B.NOACK = 1; // NOACK next received byte

                }

                if(entery_r==(iic_rlen-1)

{

I2C_0.IBCR.B.MS = 0;                      // Set IBCR, Generate stop signal;

I2C_0.IBCR.B.NOACK = 0;             // Reset the NOACK to default value

}

*(RData+entery_r) = I2C_0.IBDR.R; // Read the received byte from slave

                entery_r++;

}

Also for the IBAL and IBIF clearing use the register access. So

I2C_0.IBSR.R = 0x10;       // clear IBAL

I2C_0.IBSR.R = 0x02;       // clear IBIF

BR, Petr

0 Kudos
Reply