Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

202 lines
6.3 KiB

  1. /*
  2. I2C MODULE
  3. Copyright (C) 2017 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if I2C_SUPPORT
  6. #include <vector>
  7. std::vector<unsigned char> _i2c_locked;
  8. #if I2C_USE_BRZO
  9. #include "brzo_i2c.h"
  10. unsigned long _i2c_scl_frequency = 0;
  11. #else
  12. #include "Wire.h"
  13. #endif
  14. // -----------------------------------------------------------------------------
  15. // Private
  16. // -----------------------------------------------------------------------------
  17. int _i2cClearbus(int sda, int scl) {
  18. #if defined(TWCR) && defined(TWEN)
  19. // Disable the Atmel 2-Wire interface so we can control the SDA and SCL pins directly
  20. TWCR &= ~(_BV(TWEN));
  21. #endif
  22. // Make SDA (data) and SCL (clock) pins inputs with pullup
  23. pinMode(sda, INPUT_PULLUP);
  24. pinMode(scl, INPUT_PULLUP);
  25. delay(2500);
  26. // Wait 2.5 secs. This is strictly only necessary on the first power
  27. // up of the DS3231 module to allow it to initialize properly,
  28. // but is also assists in reliable programming of FioV3 boards as it gives the
  29. // IDE a chance to start uploaded the program
  30. // before existing sketch confuses the IDE by sending Serial data.
  31. // If it is held low the device cannot become the I2C master
  32. // I2C bus error. Could not clear SCL clock line held low
  33. boolean scl_low = (digitalRead(scl) == LOW);
  34. if (scl_low) return 1;
  35. boolean sda_low = (digitalRead(sda) == LOW);
  36. int clockCount = 20; // > 2x9 clock
  37. // While SDA is low for at most 20 cycles
  38. while (sda_low && (clockCount > 0)) {
  39. clockCount--;
  40. // Note: I2C bus is open collector so do NOT drive SCL or SDA high
  41. pinMode(scl, INPUT); // release SCL pullup so that when made output it will be LOW
  42. pinMode(scl, OUTPUT); // then clock SCL Low
  43. delayMicroseconds(10); // for >5uS
  44. pinMode(scl, INPUT); // release SCL LOW
  45. pinMode(scl, INPUT_PULLUP); // turn on pullup resistors again
  46. // do not force high as slave may be holding it low for clock stretching
  47. delayMicroseconds(10); // The >5uS is so that even the slowest I2C devices are handled
  48. // loop waiting for SCL to become high only wait 2sec
  49. scl_low = (digitalRead(scl) == LOW);
  50. int counter = 20;
  51. while (scl_low && (counter > 0)) {
  52. counter--;
  53. delay(100);
  54. scl_low = (digitalRead(scl) == LOW);
  55. }
  56. // If still low after 2 sec error
  57. // I2C bus error. Could not clear. SCL clock line held low by slave clock stretch for >2sec
  58. if (scl_low) return 2;
  59. sda_low = (digitalRead(sda) == LOW); // and check SDA input again and loop
  60. }
  61. // If still low
  62. // I2C bus error. Could not clear. SDA data line held low
  63. if (sda_low) return 3;
  64. // Pull SDA line low for "start" or "repeated start"
  65. pinMode(sda, INPUT); // remove pullup
  66. pinMode(sda, OUTPUT); // and then make it LOW i.e. send an I2C Start or Repeated start control
  67. // When there is only one I2C master a "start" or "repeat start" has the same function as a "stop" and clears the bus
  68. // A Repeat Start is a Start occurring after a Start with no intervening Stop.
  69. delayMicroseconds(10); // wait >5uS
  70. pinMode(sda, INPUT); // remove output low
  71. pinMode(sda, INPUT_PULLUP); // and make SDA high i.e. send I2C STOP control.
  72. delayMicroseconds(10); // wait >5uS
  73. pinMode(sda, INPUT); // and reset pins as tri-state inputs which is the default state on reset
  74. pinMode(scl, INPUT);
  75. // Everything OK
  76. return 0;
  77. }
  78. // -----------------------------------------------------------------------------
  79. // Utils
  80. // -----------------------------------------------------------------------------
  81. void i2cClearBus() {
  82. unsigned char sda = getSetting("i2cSDA", I2C_SDA_PIN).toInt();
  83. unsigned char scl = getSetting("i2cSCL", I2C_SCL_PIN).toInt();
  84. DEBUG_MSG_P(PSTR("[I2C] Clear bus (response: %d)\n"), _i2cClearbus(sda, scl));
  85. }
  86. bool i2cCheck(unsigned char address) {
  87. #if I2C_USE_BRZO
  88. brzo_i2c_start_transaction(address, _i2c_scl_frequency);
  89. brzo_i2c_ACK_polling(1000);
  90. return brzo_i2c_end_transaction();
  91. #else
  92. Wire.beginTransmission(address);
  93. return Wire.endTransmission();
  94. #endif
  95. }
  96. bool i2cGetLock(unsigned char address) {
  97. for (unsigned char i=0; i<_i2c_locked.size(); i++) {
  98. if (_i2c_locked[i] == address) return false;
  99. }
  100. _i2c_locked.push_back(address);
  101. DEBUG_MSG_P(PSTR("[I2C] Address 0x%02X locked\n"), address);
  102. return true;
  103. }
  104. bool i2cReleaseLock(unsigned char address) {
  105. for (unsigned char i=0; i<_i2c_locked.size(); i++) {
  106. if (_i2c_locked[i] == address) {
  107. _i2c_locked.erase(_i2c_locked.begin() + i);
  108. return true;
  109. }
  110. }
  111. return false;
  112. }
  113. unsigned char i2cFind(size_t size, unsigned char * addresses, unsigned char &start) {
  114. for (unsigned char i=start; i<size; i++) {
  115. if (i2cCheck(addresses[i]) == 0) {
  116. start = i;
  117. return addresses[i];
  118. }
  119. }
  120. return 0;
  121. }
  122. unsigned char i2cFind(size_t size, unsigned char * addresses) {
  123. unsigned char start = 0;
  124. return i2cFind(size, addresses, start);
  125. }
  126. unsigned char i2cFindAndLock(size_t size, unsigned char * addresses) {
  127. unsigned char start = 0;
  128. unsigned char address = 0;
  129. while (address = i2cFind(size, addresses, start)) {
  130. if (i2cGetLock(address)) break;
  131. start++;
  132. }
  133. return address;
  134. }
  135. void i2cScan() {
  136. unsigned char nDevices = 0;
  137. for (unsigned char address = 1; address < 127; address++) {
  138. unsigned char error = i2cCheck(address);
  139. if (error == 0) {
  140. DEBUG_MSG_P(PSTR("[I2C] Device found at address 0x%02X\n"), address);
  141. nDevices++;
  142. }
  143. }
  144. if (nDevices == 0) DEBUG_MSG_P(PSTR("[I2C] No devices found\n"));
  145. }
  146. void i2cSetup() {
  147. unsigned char sda = getSetting("i2cSDA", I2C_SDA_PIN).toInt();
  148. unsigned char scl = getSetting("i2cSCL", I2C_SCL_PIN).toInt();
  149. #if I2C_USE_BRZO
  150. unsigned long cst = getSetting("i2cCST", I2C_CLOCK_STRETCH_TIME).toInt();
  151. _i2c_scl_frequency = getSetting("i2cFreq", I2C_SCL_FREQUENCY).toInt();
  152. brzo_i2c_setup(sda, scl, cst);
  153. #else
  154. Wire.begin(sda, scl);
  155. #endif
  156. DEBUG_MSG_P(PSTR("[I2C] Using GPIO%d for SDA and GPIO%d for SCL\n"), sda, scl);
  157. }
  158. #endif