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.

384 lines
12KB

  1. #include "Wire.h"
  2. #if defined(__IMXRT1052__) || defined(__IMXRT1062__)
  3. #include "debug/printf.h"
  4. void TwoWire::begin(void)
  5. {
  6. // use 24 MHz clock
  7. CCM_CSCDR2 = (CCM_CSCDR2 & ~CCM_CSCDR2_LPI2C_CLK_PODF(63)) | CCM_CSCDR2_LPI2C_CLK_SEL;
  8. hardware.clock_gate_register |= hardware.clock_gate_mask;
  9. port->MCR = LPI2C_MCR_RST;
  10. setClock(100000);
  11. // Setup SDA register
  12. *(portControlRegister(hardware.sda_pins[sda_pin_index_].pin)) |= IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3);
  13. *(portConfigRegister(hardware.sda_pins[sda_pin_index_].pin)) = hardware.sda_pins[sda_pin_index_].mux_val;
  14. if (hardware.sda_pins[sda_pin_index_].select_input_register) {
  15. *(hardware.sda_pins[sda_pin_index_].select_input_register) = hardware.sda_pins[sda_pin_index_].select_val;
  16. }
  17. // setup SCL register
  18. *(portControlRegister(hardware.scl_pins[scl_pin_index_].pin)) |= IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3);
  19. *(portConfigRegister(hardware.scl_pins[scl_pin_index_].pin)) = hardware.scl_pins[scl_pin_index_].mux_val;
  20. if (hardware.scl_pins[scl_pin_index_].select_input_register) {
  21. *(hardware.scl_pins[scl_pin_index_].select_input_register) = hardware.scl_pins[scl_pin_index_].select_val;
  22. }
  23. }
  24. void TwoWire::begin(uint8_t address)
  25. {
  26. // TODO: slave mode
  27. }
  28. void TwoWire::end()
  29. {
  30. }
  31. void TwoWire::setSDA(uint8_t pin) {
  32. if (pin == hardware.sda_pins[sda_pin_index_].pin) return;
  33. uint32_t newindex=0;
  34. while (1) {
  35. uint32_t sda_pin = hardware.sda_pins[newindex].pin;
  36. if (sda_pin == 255) return;
  37. if (sda_pin == pin) break;
  38. if (++newindex >= sizeof(hardware.sda_pins)) return;
  39. }
  40. if ((hardware.clock_gate_register & hardware.clock_gate_mask)) {
  41. *(portConfigRegister(hardware.sda_pins[sda_pin_index_].pin)) = 5; // hard to know what to go back to?
  42. // setup new one...
  43. *(portControlRegister(hardware.sda_pins[newindex].pin)) |= IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3);
  44. *(portConfigRegister(hardware.sda_pins[newindex].pin)) = hardware.sda_pins[newindex].mux_val;
  45. if (hardware.sda_pins[newindex].select_input_register) {
  46. *(hardware.sda_pins[newindex].select_input_register) = hardware.sda_pins[newindex].select_val;
  47. }
  48. }
  49. sda_pin_index_ = newindex;
  50. }
  51. void TwoWire::setSCL(uint8_t pin) {
  52. if (pin == hardware.scl_pins[scl_pin_index_].pin) return;
  53. uint32_t newindex=0;
  54. while (1) {
  55. uint32_t scl_pin = hardware.scl_pins[newindex].pin;
  56. if (scl_pin == 255) return;
  57. if (scl_pin == pin) break;
  58. if (++newindex >= sizeof(hardware.scl_pins)) return;
  59. }
  60. if ((hardware.clock_gate_register & hardware.clock_gate_mask)) {
  61. *(portConfigRegister(hardware.scl_pins[scl_pin_index_].pin)) = 5; // hard to know what to go back to?
  62. // setup new one...
  63. *(portControlRegister(hardware.scl_pins[newindex].pin)) |= IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3);
  64. *(portConfigRegister(hardware.scl_pins[newindex].pin)) = hardware.scl_pins[newindex].mux_val;
  65. if (hardware.scl_pins[newindex].select_input_register) {
  66. *(hardware.scl_pins[newindex].select_input_register) = hardware.scl_pins[newindex].select_val;
  67. }
  68. }
  69. scl_pin_index_ = newindex;
  70. }
  71. size_t TwoWire::write(uint8_t data)
  72. {
  73. if (transmitting || slave_mode) {
  74. if (txBufferLength >= BUFFER_LENGTH+1) {
  75. setWriteError();
  76. return 0;
  77. }
  78. txBuffer[txBufferLength++] = data;
  79. return 1;
  80. }
  81. return 0;
  82. }
  83. size_t TwoWire::write(const uint8_t *data, size_t quantity)
  84. {
  85. if (transmitting || slave_mode) {
  86. size_t avail = BUFFER_LENGTH+1 - txBufferLength;
  87. if (quantity > avail) {
  88. quantity = avail;
  89. setWriteError();
  90. }
  91. memcpy(txBuffer + txBufferLength, data, quantity);
  92. txBufferLength += quantity;
  93. return quantity;
  94. }
  95. return 0;
  96. }
  97. uint8_t TwoWire::endTransmission(uint8_t sendStop)
  98. {
  99. //printf("\nendTransmission %d (%x %x %x) %x\n", txBufferLength,txBuffer[0], txBuffer[1], txBuffer[2], sendStop);
  100. uint32_t i=0, len, status;
  101. len = txBufferLength;
  102. if (!len) return 4; // no data to transmit
  103. // wait while bus is busy
  104. while (1) {
  105. status = port->MSR; // pg 2899 & 2892
  106. if (!(status & LPI2C_MSR_BBF)) break; // bus is available
  107. if (status & LPI2C_MSR_MBF) break; // we already have bus control
  108. // TODO: timeout...
  109. }
  110. //printf("m=%x\n", status);
  111. // Wonder if MFSR we should maybe clear it?
  112. if ( port->MFSR & 0x7) {
  113. port->MCR = LPI2C_MCR_MEN | LPI2C_MCR_RTF; // clear the FIFO
  114. port->MSR = LPI2C_MSR_PLTF | LPI2C_MSR_ALF | LPI2C_MSR_NDF | LPI2C_MSR_SDF | LPI2C_MSR_FEF; // clear flags
  115. //printf("Clear TX Fifo %lx %lx\n", port->MSR, port->MFSR);
  116. }
  117. // TODO: is this correct if the prior use didn't send stop?
  118. //port->MSR = LPI2C_MSR_PLTF | LPI2C_MSR_ALF | LPI2C_MSR_NDF | LPI2C_MSR_SDF; // clear flags
  119. port->MSR = status;
  120. //printf("MSR=%lX, MFSR=%lX\n", status, port->MFSR);
  121. //elapsedMillis timeout=0;
  122. while (1) {
  123. // transmit stuff, if we haven't already
  124. if (i <= len) {
  125. uint32_t fifo_used = port->MFSR & 0x07; // pg 2914
  126. //if (fifo_used < 4) printf("t=%ld\n", fifo_used);
  127. while (fifo_used < 4) {
  128. if (i == 0) {
  129. //printf("start %x\n", txBuffer[0]);
  130. port->MTDR = LPI2C_MTDR_CMD_START | txBuffer[0];
  131. i = 1;
  132. } else if (i < len) {
  133. port->MTDR = LPI2C_MTDR_CMD_TRANSMIT | txBuffer[i++];
  134. } else {
  135. if (sendStop) port->MTDR = LPI2C_MTDR_CMD_STOP;
  136. i++;
  137. break;
  138. }
  139. fifo_used = fifo_used + 1;
  140. }
  141. }
  142. // monitor status
  143. status = port->MSR; // pg 2899 & 2892
  144. if (status & LPI2C_MSR_ALF) {
  145. //printf("arbitration lost\n");
  146. return 4; // we lost bus arbitration to another master
  147. }
  148. if (status & LPI2C_MSR_NDF) {
  149. //printf("NACK, f=%d, i=%d\n", port->MFSR & 0x07, i);
  150. // TODO: check that hardware really sends stop automatically
  151. port->MCR = LPI2C_MCR_MEN | LPI2C_MCR_RTF; // clear the FIFO
  152. // TODO: is always sending a stop the right way to recover?
  153. port->MTDR = LPI2C_MTDR_CMD_STOP;
  154. return 2; // NACK for address
  155. //return 3; // NACK for data TODO: how to discern addr from data?
  156. }
  157. //if (status & LPI2C_MSR_PLTF) {
  158. //printf("bus stuck - what to do?\n");
  159. //return 4;
  160. //}
  161. //if (timeout > 100) {
  162. //printf("status = %x\n", status);
  163. //timeout = 0;
  164. //}
  165. if (sendStop) {
  166. if (status & LPI2C_MSR_SDF) {
  167. // master automatically sends stop condition on some
  168. // types of errors, so this flag only means success
  169. // when all comments in fifo have been fully used
  170. uint32_t fifo = port->MFSR & 0x07;
  171. if (fifo == 0) return 0;
  172. }
  173. } else {
  174. uint32_t fifo_used = port->MFSR & 0x07; // pg 2914
  175. if (fifo_used == 0) {
  176. //digitalWriteFast(15, HIGH);
  177. //delayMicroseconds(2);
  178. //digitalWriteFast(15, LOW);
  179. // TODO: this returns before the last data transmits!
  180. // Should verify every byte ACKs, arbitration not lost
  181. //printf("fifo empty, msr=%x\n", status);
  182. return 0;
  183. }
  184. }
  185. }
  186. }
  187. uint8_t TwoWire::requestFrom(uint8_t address, uint8_t length, uint8_t sendStop)
  188. {
  189. uint32_t cmd=0, status, fifo;
  190. // wait while bus is busy
  191. //printf("\nrequestFrom %x %x %x\n", address, length, sendStop);
  192. while (1) {
  193. status = port->MSR; // pg 2899 & 2892
  194. if (!(status & LPI2C_MSR_BBF)) break; // bus is available
  195. if (status & LPI2C_MSR_MBF) break; // we already have bus control
  196. // TODO: timeout...
  197. }
  198. //printf("idle2, msr=%x\n", status);
  199. // TODO: is this correct if the prior use didn't send stop?
  200. port->MSR = LPI2C_MSR_PLTF | LPI2C_MSR_ALF | LPI2C_MSR_NDF | LPI2C_MSR_SDF | LPI2C_MSR_FEF; // clear flags
  201. //printf("MSR=%lX, MCR:%lx, MFSR=%lX\n", status, port->MCR, port->MFSR);
  202. // Wonder if MFSR we should maybe clear it?
  203. if ( port->MFSR & 0x7) {
  204. port->MCR = LPI2C_MCR_MEN | LPI2C_MCR_RTF; // clear the FIFO
  205. port->MSR = LPI2C_MSR_PLTF | LPI2C_MSR_ALF | LPI2C_MSR_NDF | LPI2C_MSR_SDF | LPI2C_MSR_FEF; // clear flags
  206. //printf("Clear TX Fifo %lx %lx\n", port->MSR, port->MFSR);
  207. }
  208. address = (address & 0x7F) << 1;
  209. if (length < 1) length = 1;
  210. if (length > 255) length = 255;
  211. rxBufferIndex = 0;
  212. rxBufferLength = 0;
  213. //elapsedMillis timeout=0;
  214. while (1) {
  215. // transmit stuff, if we haven't already
  216. if (cmd < 3) {
  217. fifo = port->MFSR & 0x07; // pg 2914
  218. //if (fifo < 4) printf("t=%ld\n", fifo);
  219. while (fifo < 4 && cmd < 3) {
  220. if (cmd == 0) {
  221. port->MTDR = LPI2C_MTDR_CMD_START | 1 | address;
  222. } else if (cmd == 1) {
  223. // causes bus stuck... need way to recover
  224. //port->MTDR = LPI2C_MTDR_CMD_START | (length - 1);
  225. port->MTDR = LPI2C_MTDR_CMD_RECEIVE | (length - 1);
  226. } else {
  227. if (sendStop) port->MTDR = LPI2C_MTDR_CMD_STOP;
  228. }
  229. cmd++;
  230. fifo = fifo + 1;
  231. }
  232. }
  233. // receive stuff
  234. if (rxBufferLength < sizeof(rxBuffer)) {
  235. fifo = (port->MFSR >> 16) & 0x07;
  236. //if (fifo > 0) printf("r=%ld\n", fifo);
  237. while (fifo > 0 && rxBufferLength < sizeof(rxBuffer)) {
  238. rxBuffer[rxBufferLength++] = port->MRDR;
  239. fifo = fifo - 1;
  240. }
  241. }
  242. // monitor status
  243. status = port->MSR; // pg 2899 & 2892
  244. if (status & LPI2C_MSR_ALF) {
  245. //printf("arbitration lost\n");
  246. break;
  247. }
  248. if (status & LPI2C_MSR_NDF) {
  249. //printf("got NACK\n");
  250. // TODO: how to make sure stop is sent?
  251. break;
  252. }
  253. //if (timeout > 250) {
  254. //printf("Status = %x\n", status);
  255. //timeout = 0;
  256. //}
  257. if (rxBufferLength >= length && cmd >= 3) break;
  258. }
  259. //digitalWriteFast(15, HIGH);
  260. //delayMicroseconds(2);
  261. //digitalWriteFast(15, LOW);
  262. return rxBufferLength;
  263. }
  264. uint8_t TwoWire::requestFrom(uint8_t addr, uint8_t qty, uint32_t iaddr, uint8_t n, uint8_t stop)
  265. {
  266. if (n > 0) {
  267. union { uint32_t ul; uint8_t b[4]; } iaddress;
  268. iaddress.ul = iaddr;
  269. beginTransmission(addr);
  270. if (n > 3) n = 3;
  271. do {
  272. n = n - 1;
  273. write(iaddress.b[n]);
  274. } while (n > 0);
  275. endTransmission(false);
  276. }
  277. if (qty > BUFFER_LENGTH) qty = BUFFER_LENGTH;
  278. return requestFrom(addr, qty, stop);
  279. }
  280. PROGMEM
  281. constexpr TwoWire::I2C_Hardware_t TwoWire::i2c1_hardware = {
  282. CCM_CCGR2, CCM_CCGR2_LPI2C1(CCM_CCGR_ON),
  283. {{18, 3 | 0x10, &IOMUXC_LPI2C1_SDA_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}},
  284. {{19, 3 | 0x10, &IOMUXC_LPI2C1_SCL_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}},
  285. IRQ_LPI2C1
  286. };
  287. TwoWire Wire(&IMXRT_LPI2C1, TwoWire::i2c1_hardware);
  288. PROGMEM
  289. constexpr TwoWire::I2C_Hardware_t TwoWire::i2c3_hardware = {
  290. CCM_CCGR2, CCM_CCGR2_LPI2C3(CCM_CCGR_ON),
  291. {{17, 1 | 0x10, &IOMUXC_LPI2C3_SDA_SELECT_INPUT, 2}, {36, 2 | 0x10, &IOMUXC_LPI2C3_SDA_SELECT_INPUT, 1}},
  292. {{16, 1 | 0x10, &IOMUXC_LPI2C3_SCL_SELECT_INPUT, 2}, {37, 2 | 0x10, &IOMUXC_LPI2C3_SCL_SELECT_INPUT, 1}},
  293. IRQ_LPI2C3
  294. };
  295. TwoWire Wire1(&IMXRT_LPI2C3, TwoWire::i2c3_hardware);
  296. PROGMEM
  297. constexpr TwoWire::I2C_Hardware_t TwoWire::i2c4_hardware = {
  298. CCM_CCGR6, CCM_CCGR6_LPI2C4_SERIAL(CCM_CCGR_ON),
  299. {{25, 0 | 0x10, &IOMUXC_LPI2C4_SDA_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}},
  300. {{24, 0 | 0x10, &IOMUXC_LPI2C4_SCL_SELECT_INPUT, 1}, {0xff, 0xff, nullptr, 0}},
  301. IRQ_LPI2C4
  302. };
  303. TwoWire Wire2(&IMXRT_LPI2C4, TwoWire::i2c4_hardware);
  304. void TwoWire::setClock(uint32_t frequency)
  305. {
  306. port->MCR = 0;
  307. if (frequency < 400000) {
  308. // 100 kHz
  309. port->MCCR0 = LPI2C_MCCR0_CLKHI(55) | LPI2C_MCCR0_CLKLO(59) |
  310. LPI2C_MCCR0_DATAVD(25) | LPI2C_MCCR0_SETHOLD(40);
  311. port->MCFGR1 = LPI2C_MCFGR1_PRESCALE(1);
  312. port->MCFGR2 = LPI2C_MCFGR2_FILTSDA(5) | LPI2C_MCFGR2_FILTSCL(5) |
  313. LPI2C_MCFGR2_BUSIDLE(3900);
  314. } else if (frequency < 1000000) {
  315. // 400 kHz
  316. port->MCCR0 = LPI2C_MCCR0_CLKHI(26) | LPI2C_MCCR0_CLKLO(28) |
  317. LPI2C_MCCR0_DATAVD(12) | LPI2C_MCCR0_SETHOLD(18);
  318. port->MCFGR1 = LPI2C_MCFGR1_PRESCALE(0);
  319. port->MCFGR2 = LPI2C_MCFGR2_FILTSDA(2) | LPI2C_MCFGR2_FILTSCL(2) |
  320. LPI2C_MCFGR2_BUSIDLE(3900);
  321. } else {
  322. // 1 MHz
  323. port->MCCR0 = LPI2C_MCCR0_CLKHI(9) | LPI2C_MCCR0_CLKLO(10) |
  324. LPI2C_MCCR0_DATAVD(4) | LPI2C_MCCR0_SETHOLD(7);
  325. port->MCFGR1 = LPI2C_MCFGR1_PRESCALE(0);
  326. port->MCFGR2 = LPI2C_MCFGR2_FILTSDA(1) | LPI2C_MCFGR2_FILTSCL(1) |
  327. LPI2C_MCFGR2_BUSIDLE(3900);
  328. }
  329. port->MCCR1 = port->MCCR0;
  330. port->MCFGR0 = 0;
  331. port->MCFGR3 = LPI2C_MCFGR3_PINLOW(3900);
  332. port->MFCR = LPI2C_MFCR_RXWATER(1) | LPI2C_MFCR_TXWATER(1);
  333. port->MCR = LPI2C_MCR_MEN;
  334. }
  335. #endif