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.

379 lines
12 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. /*
  2. I2C MODULE
  3. Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if I2C_SUPPORT
  6. unsigned int _i2c_locked[16] = {0};
  7. #if I2C_USE_BRZO
  8. #include "brzo_i2c.h"
  9. unsigned long _i2c_scl_frequency = 0;
  10. #else
  11. #include "Wire.h"
  12. #endif
  13. // -----------------------------------------------------------------------------
  14. // Private
  15. // -----------------------------------------------------------------------------
  16. int _i2cClearbus(int sda, int scl) {
  17. #if defined(TWCR) && defined(TWEN)
  18. // Disable the Atmel 2-Wire interface so we can control the SDA and SCL pins directly
  19. TWCR &= ~(_BV(TWEN));
  20. #endif
  21. // Make SDA (data) and SCL (clock) pins inputs with pullup
  22. pinMode(sda, INPUT_PULLUP);
  23. pinMode(scl, INPUT_PULLUP);
  24. nice_delay(2500);
  25. // 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. // If it is held low the device cannot become the I2C master
  31. // I2C bus error. Could not clear SCL clock line held low
  32. boolean scl_low = (digitalRead(scl) == LOW);
  33. if (scl_low) return 1;
  34. boolean sda_low = (digitalRead(sda) == LOW);
  35. int clockCount = 20; // > 2x9 clock
  36. // While SDA is low for at most 20 cycles
  37. while (sda_low && (clockCount > 0)) {
  38. clockCount--;
  39. // Note: I2C bus is open collector so do NOT drive SCL or SDA high
  40. pinMode(scl, INPUT); // release SCL pullup so that when made output it will be LOW
  41. pinMode(scl, OUTPUT); // then clock SCL Low
  42. delayMicroseconds(10); // for >5uS
  43. pinMode(scl, INPUT); // release SCL LOW
  44. pinMode(scl, INPUT_PULLUP); // turn on pullup resistors again
  45. // do not force high as slave may be holding it low for clock stretching
  46. delayMicroseconds(10); // The >5uS is so that even the slowest I2C devices are handled
  47. // loop waiting for SCL to become high only wait 2sec
  48. scl_low = (digitalRead(scl) == LOW);
  49. int counter = 20;
  50. while (scl_low && (counter > 0)) {
  51. counter--;
  52. nice_delay(100);
  53. scl_low = (digitalRead(scl) == LOW);
  54. }
  55. // If still low after 2 sec error
  56. // I2C bus error. Could not clear. SCL clock line held low by slave clock stretch for >2sec
  57. if (scl_low) return 2;
  58. sda_low = (digitalRead(sda) == LOW); // and check SDA input again and loop
  59. }
  60. // If still low
  61. // I2C bus error. Could not clear. SDA data line held low
  62. if (sda_low) return 3;
  63. // Pull SDA line low for "start" or "repeated start"
  64. pinMode(sda, INPUT); // remove pullup
  65. pinMode(sda, OUTPUT); // and then make it LOW i.e. send an I2C Start or Repeated start control
  66. // When there is only one I2C master a "start" or "repeat start" has the same function as a "stop" and clears the bus
  67. // A Repeat Start is a Start occurring after a Start with no intervening Stop.
  68. delayMicroseconds(10); // wait >5uS
  69. pinMode(sda, INPUT); // remove output low
  70. pinMode(sda, INPUT_PULLUP); // and make SDA high i.e. send I2C STOP control.
  71. delayMicroseconds(10); // wait >5uS
  72. pinMode(sda, INPUT); // and reset pins as tri-state inputs which is the default state on reset
  73. pinMode(scl, INPUT);
  74. // Everything OK
  75. return 0;
  76. }
  77. // ---------------------------------------------------------------------
  78. // I2C API
  79. // ---------------------------------------------------------------------
  80. #if I2C_USE_BRZO
  81. void i2c_wakeup(uint8_t address) {
  82. brzo_i2c_start_transaction(_address, _i2c_scl_frequency);
  83. brzo_i2c_end_transaction();
  84. }
  85. uint8_t i2c_write_uint8(uint8_t address, uint8_t value) {
  86. uint8_t buffer[1] = {value};
  87. brzo_i2c_start_transaction(_address, _i2c_scl_frequency);
  88. brzo_i2c_write_uint8(buffer, 1, false);
  89. return brzo_i2c_end_transaction();
  90. }
  91. uint8_t i2c_write_buffer(uint8_t address, uint8_t * buffer, size_t len) {
  92. brzo_i2c_start_transaction(_address, _i2c_scl_frequency);
  93. brzo_i2c_write_uint8(buffer, len, false);
  94. return brzo_i2c_end_transaction();
  95. }
  96. uint8_t i2c_read_uint8(uint8_t address) {
  97. uint8_t buffer[1] = {reg};
  98. brzo_i2c_start_transaction(_address, _i2c_scl_frequency);
  99. brzo_i2c_read(buffer, 1, false);
  100. brzo_i2c_end_transaction();
  101. return buffer[0];
  102. };
  103. uint8_t i2c_read_uint8(uint8_t address, uint8_t reg) {
  104. uint8_t buffer[1] = {reg};
  105. brzo_i2c_start_transaction(_address, _i2c_scl_frequency);
  106. brzo_i2c_write_uint8(buffer, 1, false);
  107. brzo_i2c_read(buffer, 1, false);
  108. brzo_i2c_end_transaction();
  109. return buffer[0];
  110. };
  111. uint16_t i2c_read_uint16(uint8_t address) {
  112. uint8_t buffer[2] = {reg, 0};
  113. brzo_i2c_start_transaction(_address, _i2c_scl_frequency);
  114. brzo_i2c_read(buffer, 2, false);
  115. brzo_i2c_end_transaction();
  116. return (buffer[0] * 256) | buffer[1];
  117. };
  118. uint16_t i2c_read_uint16(uint8_t address, uint8_t reg) {
  119. uint8_t buffer[2] = {reg, 0};
  120. brzo_i2c_start_transaction(_address, _i2c_scl_frequency);
  121. brzo_i2c_write_uint8(buffer, 1, false);
  122. brzo_i2c_read(buffer, 2, false);
  123. brzo_i2c_end_transaction();
  124. return (buffer[0] * 256) | buffer[1];
  125. };
  126. void i2c_read_buffer(uint8_t address, uint8_t * buffer, size_t len) {
  127. brzo_i2c_start_transaction(address, _i2c_scl_frequency);
  128. brzo_i2c_read(buffer, len, false);
  129. brzo_i2c_end_transaction();
  130. }
  131. #else // not I2C_USE_BRZO
  132. void i2c_wakeup(uint8_t address) {
  133. Wire.beginTransmission((uint8_t) address);
  134. Wire.endTransmission();
  135. }
  136. uint8_t i2c_write_uint8(uint8_t address, uint8_t value) {
  137. Wire.beginTransmission((uint8_t) address);
  138. Wire.write((uint8_t) value);
  139. return Wire.endTransmission();
  140. }
  141. uint8_t i2c_write_buffer(uint8_t address, uint8_t * buffer, size_t len) {
  142. Wire.beginTransmission((uint8_t) address);
  143. Wire.write(buffer, len);
  144. return Wire.endTransmission();
  145. }
  146. uint8_t i2c_read_uint8(uint8_t address) {
  147. uint8_t value;
  148. Wire.beginTransmission((uint8_t) address);
  149. Wire.requestFrom((uint8_t) address, (uint8_t) 1);
  150. value = Wire.read();
  151. Wire.endTransmission();
  152. return value;
  153. };
  154. uint8_t i2c_read_uint8(uint8_t address, uint8_t reg) {
  155. uint8_t value;
  156. Wire.beginTransmission((uint8_t) address);
  157. Wire.write((uint8_t) reg);
  158. Wire.endTransmission();
  159. Wire.requestFrom((uint8_t) address, (uint8_t) 1);
  160. value = Wire.read();
  161. Wire.endTransmission();
  162. return value;
  163. };
  164. uint16_t i2c_read_uint16(uint8_t address) {
  165. uint16_t value;
  166. Wire.beginTransmission((uint8_t) address);
  167. Wire.requestFrom((uint8_t) address, (uint8_t) 2);
  168. value = (Wire.read() * 256) | Wire.read();
  169. Wire.endTransmission();
  170. return value;
  171. };
  172. uint16_t i2c_read_uint16(uint8_t address, uint8_t reg) {
  173. uint16_t value;
  174. Wire.beginTransmission((uint8_t) address);
  175. Wire.write((uint8_t) reg);
  176. Wire.endTransmission();
  177. Wire.requestFrom((uint8_t) address, (uint8_t) 2);
  178. value = (Wire.read() * 256) | Wire.read();
  179. Wire.endTransmission();
  180. return value;
  181. };
  182. void i2c_read_buffer(uint8_t address, uint8_t * buffer, size_t len) {
  183. Wire.beginTransmission((uint8_t) address);
  184. Wire.requestFrom(address, (uint8_t) len);
  185. for (int i=0; i<len; i++) buffer[i] = Wire.read();
  186. Wire.endTransmission();
  187. }
  188. #endif // I2C_USE_BRZO
  189. uint8_t i2c_write_uint8(uint8_t address, uint8_t reg, uint8_t value) {
  190. uint8_t buffer[2] = {reg, value};
  191. return i2c_write_buffer(address, buffer, 2);
  192. }
  193. uint8_t i2c_write_uint8(uint8_t address, uint8_t reg, uint8_t value1, uint8_t value2) {
  194. uint8_t buffer[3] = {reg, value1, value2};
  195. return i2c_write_buffer(address, buffer, 3);
  196. }
  197. uint8_t i2c_write_uint16(uint8_t address, uint8_t reg, uint16_t value) {
  198. uint8_t buffer[3];
  199. buffer[0] = reg;
  200. buffer[1] = (value >> 8) & 0xFF;
  201. buffer[2] = (value >> 0) & 0xFF;
  202. return i2c_write_buffer(address, buffer, 3);
  203. }
  204. uint8_t i2c_write_uint16(uint8_t address, uint16_t value) {
  205. uint8_t buffer[2];
  206. buffer[0] = (value >> 8) & 0xFF;
  207. buffer[1] = (value >> 0) & 0xFF;
  208. return i2c_write_buffer(address, buffer, 2);
  209. }
  210. uint16_t i2c_read_uint16_le(uint8_t address, uint8_t reg) {
  211. uint16_t temp = i2c_read_uint16(address, reg);
  212. return (temp / 256) | (temp * 256);
  213. };
  214. int16_t i2c_read_int16(uint8_t address, uint8_t reg) {
  215. return (int16_t) i2c_read_uint16(address, reg);
  216. };
  217. int16_t i2c_read_int16_le(uint8_t address, uint8_t reg) {
  218. return (int16_t) i2c_read_uint16_le(address, reg);
  219. };
  220. // -----------------------------------------------------------------------------
  221. // Utils
  222. // -----------------------------------------------------------------------------
  223. void i2cClearBus() {
  224. unsigned char sda = getSetting("i2cSDA", I2C_SDA_PIN).toInt();
  225. unsigned char scl = getSetting("i2cSCL", I2C_SCL_PIN).toInt();
  226. DEBUG_MSG_P(PSTR("[I2C] Clear bus (response: %d)\n"), _i2cClearbus(sda, scl));
  227. }
  228. bool i2cCheck(unsigned char address) {
  229. #if I2C_USE_BRZO
  230. brzo_i2c_start_transaction(address, _i2c_scl_frequency);
  231. brzo_i2c_ACK_polling(1000);
  232. return brzo_i2c_end_transaction();
  233. #else
  234. Wire.beginTransmission(address);
  235. return Wire.endTransmission();
  236. #endif
  237. }
  238. bool i2cGetLock(unsigned char address) {
  239. unsigned char index = address / 8;
  240. unsigned char mask = 1 << (address % 8);
  241. if (_i2c_locked[index] & mask) return false;
  242. _i2c_locked[index] = _i2c_locked[index] | mask;
  243. DEBUG_MSG_P(PSTR("[I2C] Address 0x%02X locked\n"), address);
  244. return true;
  245. }
  246. bool i2cReleaseLock(unsigned char address) {
  247. unsigned char index = address / 8;
  248. unsigned char mask = 1 << (address % 8);
  249. if (_i2c_locked[index] & mask) {
  250. _i2c_locked[index] = _i2c_locked[index] & ~mask;
  251. return true;
  252. }
  253. return false;
  254. }
  255. unsigned char i2cFind(size_t size, unsigned char * addresses, unsigned char &start) {
  256. for (unsigned char i=start; i<size; i++) {
  257. if (i2cCheck(addresses[i]) == 0) {
  258. start = i;
  259. return addresses[i];
  260. }
  261. }
  262. return 0;
  263. }
  264. unsigned char i2cFind(size_t size, unsigned char * addresses) {
  265. unsigned char start = 0;
  266. return i2cFind(size, addresses, start);
  267. }
  268. unsigned char i2cFindAndLock(size_t size, unsigned char * addresses) {
  269. unsigned char start = 0;
  270. unsigned char address = 0;
  271. while (address = i2cFind(size, addresses, start)) {
  272. if (i2cGetLock(address)) break;
  273. start++;
  274. }
  275. return address;
  276. }
  277. void i2cScan() {
  278. unsigned char nDevices = 0;
  279. for (unsigned char address = 1; address < 127; address++) {
  280. unsigned char error = i2cCheck(address);
  281. if (error == 0) {
  282. DEBUG_MSG_P(PSTR("[I2C] Device found at address 0x%02X\n"), address);
  283. nDevices++;
  284. }
  285. }
  286. if (nDevices == 0) DEBUG_MSG_P(PSTR("[I2C] No devices found\n"));
  287. }
  288. void i2cSetup() {
  289. unsigned char sda = getSetting("i2cSDA", I2C_SDA_PIN).toInt();
  290. unsigned char scl = getSetting("i2cSCL", I2C_SCL_PIN).toInt();
  291. #if I2C_USE_BRZO
  292. unsigned long cst = getSetting("i2cCST", I2C_CLOCK_STRETCH_TIME).toInt();
  293. _i2c_scl_frequency = getSetting("i2cFreq", I2C_SCL_FREQUENCY).toInt();
  294. brzo_i2c_setup(sda, scl, cst);
  295. #else
  296. Wire.begin(sda, scl);
  297. #endif
  298. DEBUG_MSG_P(PSTR("[I2C] Using GPIO%u for SDA and GPIO%u for SCL\n"), sda, scl);
  299. #if I2C_CLEAR_BUS
  300. i2cClearBus();
  301. #endif
  302. #if I2C_PERFORM_SCAN
  303. i2cScan();
  304. #endif
  305. }
  306. #endif