Kinetis K10: Reset the I2C module

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 
已解决

Kinetis K10: Reset the I2C module

跳至解决方案
3,171 次查看
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.

标记 (4)
1 解答
1,703 次查看
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 项奖励
回复
2 回复数
1,703 次查看
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 项奖励
回复
1,704 次查看
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 项奖励
回复