IoT - Modular - I2C.cpp

From The TinkerNet Wiki
Jump to navigation Jump to search

#includes, Defines, etc...

1 #include "libraries.h"
2 #include "functions.h"

I2C_Test()

 1 bool I2C_Test(int SDA, int SCL)
 2 {
 3     debug_SectionTitle("I2C Test &/or repair...");
 4 
 5     bool SCL_state = (digitalRead(SCL) == HIGH);
 6     bool SDA_state = (digitalRead(SDA) == HIGH);
 7 
 8     if (SCL_state && SDA_state)
 9     {
10         debug_LineOut("I2C is good.");
11         return (true);
12     }
13     else
14     {
15         if (!SCL_state)
16             debug_Trouble("SCL is LOW.");
17         if (!SDA_state)
18             debug_Trouble("SDA is LOW.");
19         debug_Action("Clearing I2C");
20 
21         switch (I2C_ClearBus(SDA, SCL))
22         {
23         case 0:
24             debug_LineOut("I2C is clear.");
25             return (true);
26             break;
27         case 1:
28             debug_Trouble("I2C bus error. Could not clear");
29             debug_Trouble("SCL clock line held low");
30             break;
31         case 2:
32             debug_Trouble("I2C bus error. Could not clear SCL clock");
33             debug_Trouble("line held low by slave clock stretch");
34             break;
35         case 3:
36             debug_Trouble("I2C bus error. Could not clear");
37             debug_Trouble("SDA data line held low");
38             break;
39         }
40         debug_Trouble("++++++++++++++++ STOPPING!!! +++++++++++++++++");
41         while (true) // Slam on da brakes!
42             blinkLED(100);
43         return (false);
44     }
45 }

I2C_ClearBus()

 1 /**
 2  * This routine turns off the I2C bus and clears it
 3  * on return SCA and SCL pins are tri-state inputs.
 4  * You need to call Wire.begin() after this to re-enable I2C
 5  * This routine does NOT use the Wire library at all.
 6  *
 7  * returns 0 if bus cleared
 8  *         1 if SCL held low.
 9  *         2 if SDA held low by slave clock stretch for > 2sec
10  *         3 if SDA held low after 20 clocks.
11  * 
12  * Source:  http://www.forward.com.au/pfod/ArduinoProgramming/I2C_ClearBus/index.html
13  */
14 
15 int I2C_ClearBus(int SDA, int SCL)
16 {
17 #if defined(TWCR) && defined(TWEN)
18     TWCR &= ~(_BV(TWEN)); // Disable the Atmel 2-Wire interface
19                           // so we can control the SDA and SCL pins directly
20 #endif
21 
22     pinMode(SDA, INPUT_PULLUP); // Make SDA (data) and SCL (clock) pins Inputs with pullup.
23     pinMode(SCL, INPUT_PULLUP);
24 
25     delay(2500); // Wait 2.5 secs. This is strictly only necessary on the first power
26     // up of the DS3231 module to allow it to initialize properly,
27     // but is also assists in reliable programming of FioV3 boards as it gives the
28     // IDE a chance to start uploaded the program
29     // before existing sketch confuses the IDE by sending Serial data.
30 
31     boolean SCL_LOW = (digitalRead(SCL) == LOW); // Check is SCL is Low.
32     if (SCL_LOW)
33     {             //If it is held low Arduno cannot become the I2C master.
34         return 1; //I2C bus error. Could not clear SCL clock line held low
35     }
36 
37     boolean SDA_LOW = (digitalRead(SDA) == LOW); // vi. Check SDA input.
38     int clockCount = 20;                         // > 2x9 clock
39 
40     while (SDA_LOW && (clockCount > 0))
41     { //  vii. If SDA is Low,
42         clockCount--;
43         // Note: I2C bus is open collector so do NOT drive SCL or SDA high.
44         pinMode(SCL, INPUT);        // release SCL pullup so that when made output it will be LOW
45         pinMode(SCL, OUTPUT);       // then clock SCL Low
46         delayMicroseconds(10);      //  for >5uS
47         pinMode(SCL, INPUT);        // release SCL LOW
48         pinMode(SCL, INPUT_PULLUP); // turn on pullup resistors again
49         // do not force high as slave may be holding it low for clock stretching.
50         delayMicroseconds(10); //  for >5uS
51         // The >5uS is so that even the slowest I2C devices are handled.
52         SCL_LOW = (digitalRead(SCL) == LOW); // Check if SCL is Low.
53         int counter = 20;
54         while (SCL_LOW && (counter > 0))
55         { //  loop waiting for SCL to become High only wait 2sec.
56             counter--;
57             delay(100);
58             SCL_LOW = (digitalRead(SCL) == LOW);
59         }
60         if (SCL_LOW)
61         {             // still low after 2 sec error
62             return 2; // I2C bus error. Could not clear.
63                       // SCL clock line held low by slave clock stretch for >2sec
64         }
65         SDA_LOW = (digitalRead(SDA) == LOW); //   and check SDA input again and loop
66     }
67     if (SDA_LOW)
68     {             // still low
69         return 3; // I2C bus error. Could not clear. SDA data line held low
70     }
71 
72     // else pull SDA line low for Start or Repeated Start
73     pinMode(SDA, INPUT);        // remove pullup.
74     pinMode(SDA, OUTPUT);       // and then make it LOW i.e. send an I2C Start or Repeated start control.
75                                 // When there is only one I2C master a Start or Repeat Start
76                                 // has the same function as a Stop and clears the bus.
77                                 // A Repeat Start is a Start occurring after a Start with
78                                 // no intervening Stop.
79     delayMicroseconds(10);      // wait >5uS
80     pinMode(SDA, INPUT);        // remove output low
81     pinMode(SDA, INPUT_PULLUP); // and make SDA high i.e. send I2C STOP control.
82     delayMicroseconds(10);      // x. wait >5uS
83     pinMode(SDA, INPUT);        // and reset pins as tri-state inputs which is the default state on reset
84     pinMode(SCL, INPUT);
85     return 0; // all ok
86 }