Tool to recover from an I2C bus lockup on the KL25Z

Dependents:   Ejerc_slave_I2c

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers I2C_busreset.cpp Source File

I2C_busreset.cpp

00001 /**************************************************************************************************
00002  *****                                                                                        *****
00003  *****  Name: KL25Z I2C_busreset.cpp                                                          *****
00004  *****  Date: 24/11/2013                                                                      *****
00005  *****  Auth: Frank Vannieuwkerke                                                             *****
00006  *****  Func: library for unblocking I2C bus on KL25Z board                                   *****
00007  *****  Info: MPL3115A2-AN4481                                                                *****
00008  **************************************************************************************************/
00009 
00010 #include "I2C_busreset.h"
00011 
00012 void I2C_busreset(void)
00013 {
00014     if((PORTE->PCR[1] & PORT_PCR_MUX(6)) && (PORTE->PCR[0] & PORT_PCR_MUX(6)))
00015     {
00016         I2C1->C1 &= 0x7f;                 // Disable I2C1 bus
00017         PORTE->PCR[1] = PORT_PCR_MUX(1);  // PTE1 Alt1 (pin)
00018         PORTE->PCR[0] = PORT_PCR_MUX(1);  // PTE0 Alt1 (pin)
00019         if((PTE->PDIR & 0x3) != 3)        // When PTE0 / PTE1 are not 1 : I2C1 bus lock-up
00020         {
00021             PTE->PDDR |= 0x2;             // Set PTE1 as a GPIO output so we can bit bang it
00022             PTE->PDOR |= 0x2;             // Set PTE1 (SCL) pin high;
00023             wait_ms(1);
00024             while(!(PTE->PDIR & 0x1))     // bit bang SCL until the offending device releases the bus
00025             {   
00026                 PTE->PDOR &= 0xfffffffd;  // Set PTE1 (SCL) pin low;
00027                 wait_ms(1);
00028                 PTE->PDOR |= 0x2;         // Set PTE1 (SCL) pin high;
00029                 wait_ms(1);
00030             }
00031         }
00032         // Reinstate I2C1 bus pins
00033         PORTE->PCR[1] = PORT_PCR_MUX(6);  // PTE1 Alt6 (SCL)
00034         PORTE->PCR[0] = PORT_PCR_MUX(6);  // PTE0 Alt6 (SDA)
00035         I2C1->C1 |= 0x80;                 // Enable I2C1 bus
00036     }
00037 
00038     if((PORTE->PCR[24] & PORT_PCR_MUX(5)) && (PORTE->PCR[25] & PORT_PCR_MUX(5)))
00039     {
00040         I2C0->C1 &= 0x7f;                 // Disable I2C0 bus
00041         PORTE->PCR[24] = PORT_PCR_MUX(1); // PTE24 Alt1 (pin)
00042         PORTE->PCR[25] = PORT_PCR_MUX(1); // PTE25 Alt1 (pin)
00043         if((PTE->PDIR & 0x03000000) != 0x03000000)  // When PTE24 / PTE25 are not 1 : I2C0 bus lock-up
00044         {
00045             PTE->PDDR |= 0x01000000;      // Set PTE24 as a GPIO output so we can bit bang it
00046             PTE->PDOR |= 0x01000000;      // Set PTE24 (SCL) pin high;
00047             wait_ms(1);
00048             while(!(PTE->PDIR & 0x1))     // bit bang SCL until the offending device releases the bus
00049             {   
00050                 PTE->PDOR &= 0xfeffffff;  // Set PTE24 (SCL) pin low;
00051                 wait_ms(1);
00052                 PTE->PDOR |= 0x01000000;  // Set PTE24 (SCL) pin high;
00053                 wait_ms(1);
00054             }
00055         }
00056         // Reinstate I2C0 bus pins
00057         PORTE->PCR[24] = PORT_PCR_MUX(5); // PTE24 Alt6 (SCL)
00058         PORTE->PCR[25] = PORT_PCR_MUX(5); // PTE25 Alt6 (SDA)
00059         I2C0->C1 |= 0x80;                 // Enable I2C0 bus
00060     }
00061 }