The IIC problem in KL02

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

The IIC problem in KL02

753 Views
小勇邹
Contributor II

The KL02 works in master mode.

The IIC communication is failed when there is EMC disturbance.

The IIC communication is still failed when the EMC disturbance disappears.

The BUSY bit in register I2C1_S is always 1.It cannot be changed to 0.

It is only OK after the CPU resets.

Is there any method to restore the communication without resetting CPU when the EMC disturbance disappears?

Labels (1)
0 Kudos
4 Replies

464 Views
小勇邹
Contributor II

The description is wrong. I have modified it.

The KL02 works in master mode.

The IIC communication is failed when there is EMC disturbance.

The IIC communication is still failed when the EMC disturbance disappears.

The ARBL bit in register I2C1_S is always 1.It cannot be changed to 0. It becomes 1
again after I setting it to 0.The I2C1_S is 0x10 when the communication is
failed. But the I2C1_S is 0x84 when the communication is OK.

Is there any method to restore the communication without resetting CPU when the EMC disturbance disappears?

0 Kudos

464 Views
egoodii
Senior Contributor III

It seems likely the SLAVE is probably 'stuck mid transaction', and must be cleared from the bus in the 'usual' way -- which is to take manual (GPIO) control of the I2C lines, send eight clock edges and a 'stop'.

0 Kudos

464 Views
小勇邹
Contributor II

Dear Earl Goodrich II,

Thank you for your help.

How to send eight clock edges and a 'stop'?

Can you give me a simple example?

Best regards.

Robin Zou.

Robin-XiaoYong Zou

ABB Xiamen Low Voltage Equipment Company Limited

BU LPLS E&D China

No. 12-20,3rd Chuang Xin Road Xiamen SEZ,Fujian 361006 P.R.China

CN

Phone: +86 592 5767877

Telefax: +86 592 6038110

Mobile: +86 181-5089-3720

email: robin-xiaoyong.zou@cn.abb.com<mailto:robin-xiaoyong.zou@cn.abb.com>

0 Kudos

464 Views
egoodii
Senior Contributor III

The issue is that any time an I2C transaction is 'interrupted', the slave that was being addressed will be in some part of ITS bus-access sequence, and awaits clocking by the master to proceed.  It can be in a condition of driving SDA low (driving 'ack' for a write-byte, driving '0 data' for a read-byte), and as long as that is true the master in UNABLE to 'normally' access the bus -- it is 'busy'.  It is necessary to manually supply clocks (up to a full byte's worth, of course!) until the slave 'gives up' the data line, so that at that point you can force a 'stop' condition which will 'reset' ALL slave bus-access state machines.

The details are pretty well mired in your particulars -- which I/O, and what you would use for time-pacing.  But the general point is to restore the two pins (SCL and SDA) to I/O mode (open drain operation, of course!) and set the former SDA 'open' (not driven: input).  Then every 5us drive the pin formerly called SCL low, wait 5 more, then release it, and do that up to eight times until you sense (after the 5us delay just before the next attempt to drive low) SDA 'high'.  Then drive SDA low yourself, wait 5us, and release it back to high -- that last edge is the I2C 'stop' (SDA rising edge while SCL high).  See:

I2C device dead-lock recovery

An example for a K20 has completely different GPIO controls:

    uint32_t fault_cnt = 0;

  GPIOB_PDDR &= ~(uint32_t)(3<<2);  //Both as 'high', but inputs (OC)

    GPIOB_PSOR = 3<<2;

    PORTB_PCR2 = PORT_PCR_MUX(1);     //I2C0 SCL to I/O

    PORTB_PCR3 = PORT_PCR_MUX(1);     //I2C0 SDA to I/O

    time_delay(2);

    while( (GPIOB_PDIR & (3<<2)) != (3<<2) )  //NOT both pulled 'high'???

    { //We need to try 'clocking' the interface to get the slave to 'let go' of the data line

        //   technically, this can't exceed 8 '0' data bits, at which point the slave might finally expect the ACK/NACK

        //   BUT it is valid enough for us to just 'get control' of the data line and issue STOP to re-align ALL slaves

        GPIOB_PCOR = 1<<2;  //When we drive, make it a 'zero'

        GPIOB_PDDR |= 1<<2;  //Output now!

        time_delay(2);

        GPIOB_PDDR &= ~(uint32_t)(1<<2); //Float back high!

        time_delay(1);

        if( ++fault_cnt > 10 )  //Too many???

        {

            Os_LogDebug(OS_LOG_DEBUG_ERROR, "I2C0 failed to clear.\n");

            break;

        }

    }

    //Make a 'stop' condition -- a rising-edge on SDA while SCL is 'high'

    GPIOB_PCOR = 1<<2;

    GPIOB_PDDR |= 1<<2;  //Clock low

    time_delay(2);

    GPIOB_PCOR = 1<<3;

    GPIOB_PDDR |= 1<<3;  //Data low

    time_delay(1);

    GPIOB_PDDR &= ~(uint32_t)(1<<2); //Float clock back high!

    time_delay(1);

    GPIOB_PDDR &= ~(uint32_t)(1<<3); //Float data back high!

    time_delay(1);

0 Kudos