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.

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