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.

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