Mirror of espurna firmware for wireless switches and more
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.

605 lines
15 KiB

  1. /*
  2. I2C MODULE
  3. Copyright (C) 2017-2019 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #include "espurna.h"
  6. #if I2C_SUPPORT
  7. #if I2C_USE_BRZO
  8. #include <brzo_i2c.h>
  9. #else
  10. #include <Wire.h>
  11. #endif
  12. #include "i2c.h"
  13. #include <cstring>
  14. #include <bitset>
  15. // -----------------------------------------------------------------------------
  16. // Private
  17. // -----------------------------------------------------------------------------
  18. namespace espurna {
  19. namespace i2c {
  20. namespace {
  21. struct Bus {
  22. unsigned char sda { GPIO_NONE };
  23. unsigned char scl { GPIO_NONE };
  24. #if I2C_USE_BRZO
  25. unsigned long frequency { 0 };
  26. #endif
  27. };
  28. namespace internal {
  29. Bus bus;
  30. } // namespace internal
  31. namespace lock {
  32. std::bitset<128> storage{};
  33. void reset(uint8_t address) {
  34. storage.reset(address);
  35. }
  36. bool get(uint8_t address) {
  37. return storage.test(address);
  38. }
  39. bool set(uint8_t address) {
  40. if (!get(address)) {
  41. storage.set(address);
  42. return true;
  43. }
  44. return false;
  45. }
  46. } // namespace lock
  47. #if I2C_USE_BRZO
  48. void brzo_i2c_start_transaction(uint8_t address) {
  49. ::brzo_i2c_start_transaction(address, internal::bus.frequency);
  50. }
  51. #endif
  52. namespace build {
  53. constexpr unsigned char sda() {
  54. return I2C_SDA_PIN;
  55. }
  56. constexpr unsigned char scl() {
  57. return I2C_SCL_PIN;
  58. }
  59. constexpr bool performScanOnBoot() {
  60. return I2C_PERFORM_SCAN == 1;
  61. }
  62. #if I2C_USE_BRZO
  63. constexpr unsigned long cst() {
  64. return I2C_CLOCK_STRETCH_TIME;
  65. }
  66. constexpr unsigned long sclFrequency() {
  67. return I2C_SCL_FREQUENCY;
  68. }
  69. #endif
  70. } // namespace build
  71. namespace settings {
  72. unsigned char sda() {
  73. return getSetting("i2cSDA", build::sda());
  74. }
  75. unsigned char scl() {
  76. return getSetting("i2cSCL", build::scl());
  77. }
  78. #if I2C_USE_BRZO
  79. unsigned long cst() {
  80. return getSetting("i2cCST", build::cst());
  81. }
  82. unsigned long sclFrequency() {
  83. return getSetting("i2cFreq", build::sclFrequency());
  84. }
  85. #endif
  86. } // namespace settings
  87. // make note that both APIs return integer status codes
  88. // success is 0, everything else depends on the implementation
  89. // for example, for our Wire it is:
  90. // - 4 if line is busy
  91. // - 2 if NACK happened when writing address
  92. // - 3 if NACK happened when writing data
  93. bool find(uint8_t address) {
  94. #if I2C_USE_BRZO
  95. i2c::start_brzo_transaction(address);
  96. brzo_i2c_ACK_polling(1000);
  97. return 0 == brzo_i2c_end_transaction();
  98. #else
  99. Wire.beginTransmission(address);
  100. return 0 == Wire.endTransmission();
  101. #endif
  102. }
  103. template <typename T>
  104. uint8_t find(const uint8_t* begin, const uint8_t* end, T&& filter) {
  105. for (const auto* it = begin; it != end; ++it) {
  106. if (filter(*it) && find(*it)) {
  107. return *it;
  108. }
  109. }
  110. return 0;
  111. }
  112. uint8_t find(const uint8_t* begin, const uint8_t* end) {
  113. return find(begin, end, [](uint8_t) {
  114. return true;
  115. });
  116. }
  117. uint8_t findAndLock(const uint8_t* begin, const uint8_t* end) {
  118. const auto address = find(begin, end, [](uint8_t address) {
  119. return !lock::get(address);
  120. });
  121. if (address != 0) {
  122. lock::set(address);
  123. }
  124. return address;
  125. }
  126. template <typename T>
  127. void scan(T&& callback) {
  128. static constexpr uint8_t Min { 0x8 };
  129. static constexpr uint8_t Max { 0x78 };
  130. for (auto address = Min; address < Max; ++address) {
  131. if (find(address)) {
  132. callback(address);
  133. }
  134. }
  135. }
  136. void bootScan() {
  137. String addresses;
  138. scan([&](uint8_t address) {
  139. if (addresses.length()) {
  140. addresses += F(", ");
  141. }
  142. addresses += F("0x");
  143. addresses += hexEncode(address);
  144. });
  145. if (addresses.length()) {
  146. DEBUG_MSG_P(PSTR("[I2C] Found device(s): %s\n"), addresses.c_str());
  147. } else {
  148. DEBUG_MSG_P(PSTR("[I2C] No devices found\n"));
  149. }
  150. }
  151. int clear(unsigned char sda, unsigned char scl) {
  152. #if defined(TWCR) && defined(TWEN)
  153. // Disable the Atmel 2-Wire interface so we can control the SDA and SCL pins directly
  154. TWCR &= ~(_BV(TWEN));
  155. #endif
  156. // Make SDA (data) and SCL (clock) pins inputs with pullup
  157. pinMode(sda, INPUT_PULLUP);
  158. pinMode(scl, INPUT_PULLUP);
  159. // Wait 2.5 secs. This is strictly only necessary on the first power
  160. // up of the DS3231 module to allow it to initialize properly,
  161. // but is also assists in reliable programming of FioV3 boards as it gives the
  162. // IDE a chance to start uploaded the program
  163. // before existing sketch confuses the IDE by sending Serial data.
  164. espurna::time::blockingDelay(
  165. espurna::duration::Milliseconds(2500));
  166. // If it is held low the device cannot become the I2C master
  167. // I2C bus error. Could not clear SCL clock line held low
  168. bool scl_low = (digitalRead(scl) == LOW);
  169. if (scl_low) {
  170. return 1;
  171. }
  172. bool sda_low = (digitalRead(sda) == LOW);
  173. int clockCount = 20; // > 2x9 clock
  174. // While SDA is low for at most 20 cycles
  175. while (sda_low && (clockCount > 0)) {
  176. clockCount--;
  177. // Note: I2C bus is open collector so do NOT drive SCL or SDA high
  178. pinMode(scl, INPUT); // release SCL pullup so that when made output it will be LOW
  179. pinMode(scl, OUTPUT); // then clock SCL Low
  180. delayMicroseconds(10); // for >5uS
  181. pinMode(scl, INPUT); // release SCL LOW
  182. pinMode(scl, INPUT_PULLUP); // turn on pullup resistors again
  183. // do not force high as slave may be holding it low for clock stretching
  184. delayMicroseconds(10); // The >5uS is so that even the slowest I2C devices are handled
  185. // loop waiting for SCL to become high only wait 2sec
  186. scl_low = (digitalRead(scl) == LOW);
  187. int counter = 20;
  188. while (scl_low && (counter > 0)) {
  189. counter--;
  190. espurna::time::blockingDelay(
  191. espurna::duration::Milliseconds(100));
  192. scl_low = (digitalRead(scl) == LOW);
  193. }
  194. // If still low after 2 sec error
  195. // I2C bus error. Could not clear. SCL clock line held low by slave clock stretch for >2sec
  196. if (scl_low) {
  197. return 2;
  198. }
  199. sda_low = (digitalRead(sda) == LOW); // and check SDA input again and loop
  200. }
  201. // If still low
  202. // I2C bus error. Could not clear. SDA data line held low
  203. if (sda_low) {
  204. return 3;
  205. }
  206. // Pull SDA line low for "start" or "repeated start"
  207. pinMode(sda, INPUT); // remove pullup
  208. pinMode(sda, OUTPUT); // and then make it LOW i.e. send an I2C Start or Repeated start control
  209. // When there is only one I2C master a "start" or "repeat start" has the same function as a "stop" and clears the bus
  210. // A Repeat Start is a Start occurring after a Start with no intervening Stop.
  211. delayMicroseconds(10); // wait >5uS
  212. pinMode(sda, INPUT); // remove output low
  213. pinMode(sda, INPUT_PULLUP); // and make SDA high i.e. send I2C STOP control.
  214. delayMicroseconds(10); // wait >5uS
  215. pinMode(sda, INPUT); // and reset pins as tri-state inputs which is the default state on reset
  216. pinMode(scl, INPUT);
  217. // Everything OK
  218. return 0;
  219. }
  220. int clear(const Bus& bus) {
  221. return clear(bus.sda, bus.scl);
  222. }
  223. int clear() {
  224. return clear(internal::bus);
  225. }
  226. void init() {
  227. internal::bus.sda = settings::sda();
  228. internal::bus.scl = settings::scl();
  229. #if I2C_USE_BRZO
  230. internal::bus.frequency = settings::sclFrequency();
  231. brzo_i2c_setup(internal::bus.sda, internal::bus.scl, settings::cst());
  232. #else
  233. Wire.begin(internal::bus.sda, internal::bus.scl);
  234. #endif
  235. DEBUG_MSG_P(PSTR("[I2C] Initialized SDA @ GPIO%hhu and SCL @ GPIO%hhu\n"),
  236. internal::bus.sda, internal::bus.scl);
  237. #if I2C_CLEAR_BUS
  238. clear(internal::bus);
  239. #endif
  240. }
  241. #if TERMINAL_SUPPORT
  242. namespace terminal {
  243. PROGMEM_STRING(Locked, "I2C.LOCKED");
  244. void locked(::terminal::CommandContext&& ctx) {
  245. for (size_t address = 0; address < lock::storage.size(); ++address) {
  246. if (lock::storage.test(address)) {
  247. ctx.output.printf_P(PSTR("0x%02X\n"), address);
  248. }
  249. }
  250. terminalOK(ctx);
  251. }
  252. PROGMEM_STRING(Scan, "I2C.SCAN");
  253. void scan(::terminal::CommandContext&& ctx) {
  254. size_t devices { 0 };
  255. i2c::scan([&](uint8_t address) {
  256. ++devices;
  257. ctx.output.printf_P(PSTR("0x%02X\n"), address);
  258. });
  259. if (devices) {
  260. ctx.output.printf_P(PSTR("found %zu device(s)\n"), devices);
  261. terminalOK(ctx);
  262. return;
  263. }
  264. terminalError(ctx, F("no devices found"));
  265. }
  266. PROGMEM_STRING(Clear, "I2C.CLEAR");
  267. void clear(::terminal::CommandContext&& ctx) {
  268. ctx.output.printf_P(PSTR("result %d\n"), i2c::clear());
  269. terminalOK(ctx);
  270. }
  271. static constexpr ::terminal::Command Commands[] PROGMEM {
  272. {Locked, locked},
  273. {Scan, scan},
  274. {Clear, clear},
  275. };
  276. void setup() {
  277. espurna::terminal::add(Commands);
  278. }
  279. } // namespace terminal
  280. #endif // TERMINAL_SUPPORT
  281. } // namespace
  282. } // namespace i2c
  283. } // namespace espurna
  284. // ---------------------------------------------------------------------
  285. // I2C API
  286. // ---------------------------------------------------------------------
  287. #if I2C_USE_BRZO
  288. void i2c_wakeup(uint8_t address) {
  289. i2c::brzo_i2c_start_transaction(address);
  290. brzo_i2c_end_transaction();
  291. }
  292. uint8_t i2c_write_buffer(uint8_t address, uint8_t * buffer, size_t len) {
  293. i2c::brzo_i2c_start_transaction(address);
  294. brzo_i2c_write(buffer, len, false);
  295. return brzo_i2c_end_transaction();
  296. }
  297. uint8_t i2c_write_uint8(uint8_t address, uint8_t value) {
  298. uint8_t buffer[1] = {value};
  299. return i2c_write_buffer(address, buffer, sizeof(buffer));
  300. }
  301. uint8_t i2c_read_uint8(uint8_t address) {
  302. uint8_t buffer[1] = {0};
  303. i2c::brzo_i2c_start_transaction(address);
  304. brzo_i2c_read(buffer, 1, false);
  305. brzo_i2c_end_transaction();
  306. return buffer[0];
  307. }
  308. uint8_t i2c_read_uint8(uint8_t address, uint8_t reg) {
  309. uint8_t buffer[1] = {reg};
  310. i2c::brzo_i2c_start_transaction(address);
  311. brzo_i2c_write(buffer, 1, true);
  312. brzo_i2c_read(buffer, 1, false);
  313. brzo_i2c_end_transaction();
  314. return buffer[0];
  315. }
  316. uint16_t i2c_read_uint16(uint8_t address) {
  317. uint8_t buffer[2] = {0, 0};
  318. i2c::brzo_i2c_start_transaction(address);
  319. brzo_i2c_read(buffer, 2, false);
  320. brzo_i2c_end_transaction();
  321. return (buffer[0] * 256) | buffer[1];
  322. }
  323. uint16_t i2c_read_uint16(uint8_t address, uint8_t reg) {
  324. uint8_t buffer[2] = {reg, 0};
  325. i2c::brzo_i2c_start_transaction(address);
  326. brzo_i2c_write(buffer, 1, true);
  327. brzo_i2c_read(buffer, 2, false);
  328. brzo_i2c_end_transaction();
  329. return (buffer[0] * 256) | buffer[1];
  330. }
  331. void i2c_read_buffer(uint8_t address, uint8_t * buffer, size_t len) {
  332. i2c::start_brzo_transaction(address);
  333. brzo_i2c_read(buffer, len, false);
  334. brzo_i2c_end_transaction();
  335. }
  336. #else // not I2C_USE_BRZO
  337. void i2c_wakeup(uint8_t address) {
  338. Wire.beginTransmission((uint8_t) address);
  339. Wire.endTransmission();
  340. }
  341. uint8_t i2c_write_uint8(uint8_t address, uint8_t value) {
  342. Wire.beginTransmission((uint8_t) address);
  343. Wire.write((uint8_t) value);
  344. return Wire.endTransmission();
  345. }
  346. uint8_t i2c_write_buffer(uint8_t address, uint8_t * buffer, size_t len) {
  347. Wire.beginTransmission((uint8_t) address);
  348. Wire.write(buffer, len);
  349. return Wire.endTransmission();
  350. }
  351. uint8_t i2c_read_uint8(uint8_t address) {
  352. uint8_t value;
  353. Wire.requestFrom((uint8_t) address, (uint8_t) 1);
  354. value = Wire.read();
  355. return value;
  356. }
  357. uint8_t i2c_read_uint8(uint8_t address, uint8_t reg) {
  358. uint8_t value;
  359. Wire.beginTransmission((uint8_t) address);
  360. Wire.write((uint8_t) reg);
  361. Wire.endTransmission();
  362. Wire.requestFrom((uint8_t) address, (uint8_t) 1);
  363. value = Wire.read();
  364. return value;
  365. }
  366. uint16_t i2c_read_uint16(uint8_t address) {
  367. uint16_t value;
  368. Wire.requestFrom((uint8_t) address, (uint8_t) 2);
  369. value = (Wire.read() * 256) | Wire.read();
  370. return value;
  371. }
  372. uint16_t i2c_read_uint16(uint8_t address, uint8_t reg) {
  373. uint16_t value;
  374. Wire.beginTransmission((uint8_t) address);
  375. Wire.write((uint8_t) reg);
  376. Wire.endTransmission();
  377. Wire.requestFrom((uint8_t) address, (uint8_t) 2);
  378. value = (Wire.read() * 256) | Wire.read();
  379. return value;
  380. }
  381. void i2c_read_buffer(uint8_t address, uint8_t* buffer, size_t len) {
  382. Wire.requestFrom(address, (uint8_t) len);
  383. for (size_t i=0; i<len; ++i) {
  384. buffer[i] = Wire.read();
  385. }
  386. }
  387. void i2c_write_uint(uint8_t address, uint16_t reg, uint32_t input, size_t size) {
  388. if (size && (size <= sizeof(input))) {
  389. Wire.beginTransmission(address);
  390. Wire.write((reg >> 8) & 0xff);
  391. Wire.write(reg & 0xff);
  392. uint8_t buf[sizeof(input)];
  393. std::memcpy(&buf[0], &input, sizeof(buf));
  394. Wire.write(&buf[sizeof(buf) - size], size);
  395. Wire.endTransmission();
  396. }
  397. }
  398. uint32_t i2c_read_uint(uint8_t address, uint16_t reg, size_t size, bool stop) {
  399. uint32_t out { 0 };
  400. if (size <= sizeof(out)) {
  401. Wire.beginTransmission(address);
  402. Wire.write((reg >> 8) & 0xff);
  403. Wire.write(reg & 0xff);
  404. Wire.endTransmission(stop);
  405. if (size == Wire.requestFrom(address, size)) {
  406. for (size_t byte = 0; byte < size; --byte) {
  407. out = (out << 8ul) | static_cast<uint8_t>(Wire.read());
  408. }
  409. }
  410. }
  411. return out;
  412. }
  413. #endif // I2C_USE_BRZO
  414. uint8_t i2c_write_uint8(uint8_t address, uint8_t reg, uint8_t value) {
  415. uint8_t buffer[2] = {reg, value};
  416. return i2c_write_buffer(address, buffer, 2);
  417. }
  418. uint8_t i2c_write_uint8(uint8_t address, uint8_t reg, uint8_t value1, uint8_t value2) {
  419. uint8_t buffer[3] = {reg, value1, value2};
  420. return i2c_write_buffer(address, buffer, 3);
  421. }
  422. uint8_t i2c_write_uint16(uint8_t address, uint8_t reg, uint16_t value) {
  423. uint8_t buffer[3];
  424. buffer[0] = reg;
  425. buffer[1] = (value >> 8) & 0xFF;
  426. buffer[2] = (value >> 0) & 0xFF;
  427. return i2c_write_buffer(address, buffer, 3);
  428. }
  429. uint8_t i2c_write_uint16(uint8_t address, uint16_t value) {
  430. uint8_t buffer[2];
  431. buffer[0] = (value >> 8) & 0xFF;
  432. buffer[1] = (value >> 0) & 0xFF;
  433. return i2c_write_buffer(address, buffer, 2);
  434. }
  435. uint16_t i2c_read_uint16_le(uint8_t address, uint8_t reg) {
  436. uint16_t temp = i2c_read_uint16(address, reg);
  437. return (temp / 256) | (temp * 256);
  438. }
  439. int16_t i2c_read_int16(uint8_t address, uint8_t reg) {
  440. return (int16_t) i2c_read_uint16(address, reg);
  441. }
  442. int16_t i2c_read_int16_le(uint8_t address, uint8_t reg) {
  443. return (int16_t) i2c_read_uint16_le(address, reg);
  444. }
  445. // -----------------------------------------------------------------------------
  446. // Utils
  447. // -----------------------------------------------------------------------------
  448. int i2cClearBus() {
  449. return espurna::i2c::clear();
  450. }
  451. bool i2cLock(uint8_t address) {
  452. return espurna::i2c::lock::set(address);
  453. }
  454. void i2cUnlock(uint8_t address) {
  455. espurna::i2c::lock::reset(address);
  456. }
  457. uint8_t i2cFind(uint8_t address) {
  458. return espurna::i2c::find(address);
  459. }
  460. uint8_t i2cFind(const uint8_t* begin, const uint8_t* end) {
  461. return espurna::i2c::find(begin, end);
  462. }
  463. uint8_t i2cFindAndLock(const uint8_t* begin, const uint8_t* end) {
  464. return espurna::i2c::findAndLock(begin, end);
  465. }
  466. void i2cSetup() {
  467. espurna::i2c::init();
  468. #if TERMINAL_SUPPORT
  469. espurna::i2c::terminal::setup();
  470. #endif
  471. if (espurna::i2c::build::performScanOnBoot()) {
  472. espurna::i2c::bootScan();
  473. }
  474. }
  475. #endif