Kinetis K10: Reset the I2C module

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

Kinetis K10: Reset the I2C module

Jump to solution
3,153 Views
Dilebo
Contributor III

Hello,

I have an issue with the I2C module.

Context:

µC K10 is the Master, linked to only one slave.

I configured the Power Management Controller to reset on a Low Voltage Detect (PMC_LVDSC1[LVDRE]).

This is what happens:

When the tension rises slowly, the µC boots, then the I2C communication starts but it is stopped by the hardware reset (due to the Low Voltage Detect).

Then, when the tension is high enough, the I2C is locked in a busy mode.

Untitled drawing.png

Tested solutions:

I tested the SoftReset function from the BareMetal Drivers.

/*  Do a Soft Reset of EEPROM (necessary if EEPROM had been left in the midlle of one transaction)

* @param none

* @return none

*/

void EEP_I2C0_SoftReset(void)

{

  if ((I2C0_S & I2C_S_BUSY_MASK) != 0) {

      i2c_Stop(I2C0);

  }

  I2C0_S |= I2C_S_IICIF_MASK;        // Clear remaining flags

  I2C0_S |= I2C_S_ARBL_MASK;

  /* send start signal */

  i2c_Start(I2C0);

  Pause();

  /* send ID with W/R bit */

  i2c_write_byte(I2C0, 0xFF);

  i2c_Wait_interrupt(I2C0);

  Pause();

  /* Do a repeated start */

  i2c_Start(I2C0);

  Pause();

  /* Send stop */

  i2c_Stop(I2C0);

  i2c_busy(I2C0); // wait for bus to be "free"

  I2C0_S |= I2C_S_IICIF_MASK;        // Clear remaining flags

  I2C0_S |= I2C_S_ARBL_MASK;

}

I tested the solution from Yuri Muhin: Re: I2C reset

Any help would be welcome.

Tags (4)
1 Solution
1,685 Views
Dilebo
Contributor III

Hello Jorge Gonzalez,

Thank you for your answer.

Yes I was talking about the I2Cx_S[BUSY] bit.

I mixed the two solutions from my first post and came up with the following :

        if (I2C_IS_BUSY(base))

        {

            /*Bus already busy => cancel previous operation*/

            /* send start signal */

            I2C_C1_REG(base) &= ~I2C_C1_IICEN_MASK;

            I2C_C1_REG(base) |= I2C_C1_TX_MASK;    /* Set transmit (TX) mode */

            I2C_C1_REG(base) |= I2C_C1_MST_MASK;    /* START signal generated */

            I2C_C1_REG(base) |= I2C_C1_IICEN_MASK;

            /* send write command to release SDA line*/

            I2C_C1_REG(base) |= I2C_C1_MST_MASK;    /* set MASTER mode */

            I2C_C1_REG(base) |= I2C_C1_TX_MASK;    /* Set transmit (TX) mode */

            I2C_D_REG(base) = 0xFF;

            while ((I2C_S_REG(base) & I2C_S_IICIF_MASK) == 0U) {}  /* wait interrupt      */

            I2C_S_REG(base) |= I2C_S_IICIF_MASK;                    /* clear interrupt bit  */

            /* Clear arbitration error flag*/

            I2C_S_REG(base) |= I2C_S_ARBL_MASK;

            /* Send start */

            I2C_C1_REG(base) &= ~I2C_C1_IICEN_MASK;

            I2C_C1_REG(base) |= I2C_C1_TX_MASK;    /* Set transmit (TX) mode */

            I2C_C1_REG(base) |= I2C_C1_MST_MASK;    /* START signal generated */

            I2C_C1_REG(base) |= I2C_C1_IICEN_MASK;

            /*Wait until start is send*/

            Pause();

            /* Send stop */

            I2C_C1_REG(base) &= ~I2C_C1_IICEN_MASK;

            I2C_C1_REG(base) |= I2C_C1_MST_MASK;

            I2C_C1_REG(base) &= ~I2C_C1_MST_MASK;  /* set SLAVE mode */

            I2C_C1_REG(base) &= ~I2C_C1_TX_MASK;    /* Set Rx */

            I2C_C1_REG(base) |= I2C_C1_IICEN_MASK;

            while (I2C_IS_BUSY(base))

            {

              /* wait */

            }

            /* Clear arbitration error & interrupt flag*/

            I2C_S_REG(base) |= I2C_S_IICIF_MASK;

            I2C_S_REG(base) |= I2C_S_ARBL_MASK;

        }

This is working.

And if it can help anyone, I found this application note : http://cache.freescale.com/files/microcontrollers/doc/app_note/AN4803.pdf?fpsp=1&WT_TYPE=Application...

With a tI2C_fault I2C_Restore(void)  function. But I didn't try it.

It is roughly the same thing as my solution, but driving the signals SCL/SDA in GPIO mode.

View solution in original post

0 Kudos
Reply
2 Replies
1,685 Views
Jorge_Gonzalez
NXP Employee
NXP Employee

Hi Dilebo:

What do you mean exactly with busy?

Do you mean the status bit I2Cx_S[BUSY] stays at 1? or that the SCL line is held low?

These are different situations. In the first case if your K10 is the master, then the code you posted should take you out of the busy state once you call i2c_stop(). In the second case, if some of the slaves holds the line, then this is a hardware problem. Or it could be a combination of both, your K10 master trying to send stop signal and the slave holding down either of SDA or SCL bus lines.

Sorry If I did not understand well your situation.

Regards!

Jorge Gonzalez

0 Kudos
Reply
1,686 Views
Dilebo
Contributor III

Hello Jorge Gonzalez,

Thank you for your answer.

Yes I was talking about the I2Cx_S[BUSY] bit.

I mixed the two solutions from my first post and came up with the following :

        if (I2C_IS_BUSY(base))

        {

            /*Bus already busy => cancel previous operation*/

            /* send start signal */

            I2C_C1_REG(base) &= ~I2C_C1_IICEN_MASK;

            I2C_C1_REG(base) |= I2C_C1_TX_MASK;    /* Set transmit (TX) mode */

            I2C_C1_REG(base) |= I2C_C1_MST_MASK;    /* START signal generated */

            I2C_C1_REG(base) |= I2C_C1_IICEN_MASK;

            /* send write command to release SDA line*/

            I2C_C1_REG(base) |= I2C_C1_MST_MASK;    /* set MASTER mode */

            I2C_C1_REG(base) |= I2C_C1_TX_MASK;    /* Set transmit (TX) mode */

            I2C_D_REG(base) = 0xFF;

            while ((I2C_S_REG(base) & I2C_S_IICIF_MASK) == 0U) {}  /* wait interrupt      */

            I2C_S_REG(base) |= I2C_S_IICIF_MASK;                    /* clear interrupt bit  */

            /* Clear arbitration error flag*/

            I2C_S_REG(base) |= I2C_S_ARBL_MASK;

            /* Send start */

            I2C_C1_REG(base) &= ~I2C_C1_IICEN_MASK;

            I2C_C1_REG(base) |= I2C_C1_TX_MASK;    /* Set transmit (TX) mode */

            I2C_C1_REG(base) |= I2C_C1_MST_MASK;    /* START signal generated */

            I2C_C1_REG(base) |= I2C_C1_IICEN_MASK;

            /*Wait until start is send*/

            Pause();

            /* Send stop */

            I2C_C1_REG(base) &= ~I2C_C1_IICEN_MASK;

            I2C_C1_REG(base) |= I2C_C1_MST_MASK;

            I2C_C1_REG(base) &= ~I2C_C1_MST_MASK;  /* set SLAVE mode */

            I2C_C1_REG(base) &= ~I2C_C1_TX_MASK;    /* Set Rx */

            I2C_C1_REG(base) |= I2C_C1_IICEN_MASK;

            while (I2C_IS_BUSY(base))

            {

              /* wait */

            }

            /* Clear arbitration error & interrupt flag*/

            I2C_S_REG(base) |= I2C_S_IICIF_MASK;

            I2C_S_REG(base) |= I2C_S_ARBL_MASK;

        }

This is working.

And if it can help anyone, I found this application note : http://cache.freescale.com/files/microcontrollers/doc/app_note/AN4803.pdf?fpsp=1&WT_TYPE=Application...

With a tI2C_fault I2C_Restore(void)  function. But I didn't try it.

It is roughly the same thing as my solution, but driving the signals SCL/SDA in GPIO mode.

0 Kudos
Reply