PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
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.

534 lines
23KB

  1. // -------------------------------------------------------------------------------------------
  2. // I2C Advanced Master
  3. // -------------------------------------------------------------------------------------------
  4. //
  5. // This creates an I2C master device with simple read/write commands and a small
  6. // addressable memory. Note that this communication adds a protocol layer on top of
  7. // normal I2C read/write procedures. As such, it is meant to pair with the advanced_slave
  8. // sketch. The read/write commands are described below.
  9. //
  10. // This code assumes the slave config has 256 byte memory and I2C addr is 0x44.
  11. //
  12. // Tests are as follows:
  13. // Pull pin12 input low to send/receive 256 bytes to/from slave in 32 byte blocks.
  14. // Pull pin11 input low to send/receive 256 bytes to/from slave in single block.
  15. // Pull pin10 input low to send/receive 256 bytes to/from slave in single block, using
  16. // non-blocking commands.
  17. // Pull pin9 input low to send/receive 256 bytes to/from slave in single block, using
  18. // non-blocking commands in DMA mode.
  19. // Pull pin8 input low to run I2C rate sweep test. This sweeps the I2C rates on both master
  20. // and slave and times the duration of a 256 byte transfer at each rate.
  21. //
  22. // For basic I2C communication only, refer to basic_master and basic_slave example sketches.
  23. //
  24. // This example code is in the public domain.
  25. //
  26. // -------------------------------------------------------------------------------------------
  27. // Slave protocol is as follows:
  28. // -------------------------------------------------------------------------------------------
  29. // WRITE - The I2C Master can write to the device by transmitting the WRITE command,
  30. // a memory address to store to, and a sequence of data to store.
  31. // The command sequence is:
  32. //
  33. // START|I2CADDR+W|WRITE|MEMADDR|DATA0|DATA1|DATA2|...|STOP
  34. //
  35. // where START = I2C START sequence
  36. // I2CADDR+W = I2C Slave address + I2C write flag
  37. // WRITE = WRITE command
  38. // MEMADDR = memory address to store data to
  39. // DATAx = data byte to store, multiple bytes are stored to increasing address
  40. // STOP = I2C STOP sequence
  41. // -------------------------------------------------------------------------------------------
  42. // READ - The I2C Master can read data from the device by transmitting the READ command,
  43. // a memory address to read from, and then issuing a STOP/START or Repeated-START,
  44. // followed by reading the data. The command sequence is:
  45. //
  46. // START|I2CADDR+W|READ|MEMADDR|REPSTART|I2CADDR+R|DATA0|DATA1|DATA2|...|STOP
  47. //
  48. // where START = I2C START sequence
  49. // I2CADDR+W = I2C Slave address + I2C write flag
  50. // READ = READ command
  51. // MEMADDR = memory address to read data from
  52. // REPSTART = I2C Repeated-START sequence (or STOP/START if single Master)
  53. // I2CADDR+R = I2C Slave address + I2C read flag
  54. // DATAx = data byte read by Master, multiple bytes are read from increasing address
  55. // STOP = I2C STOP sequence
  56. // -------------------------------------------------------------------------------------------
  57. // SETRATE - The I2C Master can adjust the Slave configured I2C rate with this command
  58. // The command sequence is:
  59. //
  60. // START|I2CADDR+W|SETRATE|RATE0|RATE1|RATE2|RATE3|STOP
  61. //
  62. // where START = I2C START sequence
  63. // I2CADDR+W = I2C Slave address + I2C write flag
  64. // SETRATE = SETRATE command
  65. // RATE0-3 = I2C frequency (uint32_t) LSB-to-MSB format
  66. // -------------------------------------------------------------------------------------------
  67. #include <i2c_t3.h>
  68. // Command definitions
  69. #define WRITE 0x10
  70. #define READ 0x20
  71. #define SETRATE 0x30
  72. // Function prototypes
  73. void print_i2c_setup(void);
  74. void print_i2c_status(void);
  75. void test_rate(uint8_t target, uint32_t rate);
  76. // Memory
  77. #define MEM_LEN 256
  78. uint8_t databuf[MEM_LEN];
  79. void setup()
  80. {
  81. pinMode(LED_BUILTIN,OUTPUT); // LED
  82. digitalWrite(LED_BUILTIN,LOW); // LED off
  83. pinMode(12,INPUT_PULLUP); // Control for Test1
  84. pinMode(11,INPUT_PULLUP); // Control for Test2
  85. pinMode(10,INPUT_PULLUP); // Control for Test3
  86. pinMode(9,INPUT_PULLUP); // Control for Test4
  87. pinMode(8,INPUT_PULLUP); // Control for Test5
  88. Serial.begin(115200);
  89. // Setup for Master mode, pins 18/19, external pullups, 400kHz
  90. Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);
  91. Wire.setDefaultTimeout(250000); // 250ms default timeout
  92. }
  93. void loop()
  94. {
  95. size_t addr, len;
  96. uint8_t target = 0x44; // slave addr
  97. uint32_t count;
  98. //
  99. // A sequence of different read/write techniques.
  100. // Pull respective control pin low to initiate sequence.
  101. //
  102. // All tests will first write values to the slave, then read back the values.
  103. // The readback values should match.
  104. //
  105. // The LED is turned on during I2C operations. If it gets stuck on then the
  106. // ISR likely had a problem. This can happen with excessive baud rate.
  107. //
  108. // Various forms of the Wire calls (blocking/non-blocking/STOP/NOSTOP) are
  109. // used in the different tests.
  110. //
  111. if(digitalRead(12) == LOW)
  112. {
  113. digitalWrite(LED_BUILTIN,HIGH); // LED on
  114. Serial.print("---------------------------------------------------------\n");
  115. Serial.print("Test1 : Using blocking commands:\n");
  116. Serial.print(" 1) WRITE memory in 32 byte blocks\n");
  117. Serial.print(" 2) READ back memory in 32 byte blocks\n");
  118. Serial.print("---------------------------------------------------------\n");
  119. // Writing to Slave --------------------------------------------------------
  120. for(addr = 0; addr < 256; addr += 32) // sweep addr in 32byte blocks
  121. {
  122. for(len = 0; len < 32; len++) // prepare data to send
  123. databuf[len] = (addr+len)^0xFF; // set data (equal to bit inverse of memory address)
  124. Serial.printf("I2C WRITE 32 bytes to Slave 0x%0X at MemAddr %d\n", target, addr);
  125. Serial.print("Writing: ");
  126. for(len = 0; len < 32; len++) { Serial.printf("%d ",databuf[len]); }
  127. Serial.print("\n");
  128. Wire.beginTransmission(target); // slave addr
  129. Wire.write(WRITE); // WRITE command
  130. Wire.write(addr); // memory address
  131. Wire.write(databuf, 32); // write 32 byte block
  132. Wire.endTransmission(); // blocking write (when not specified I2C_STOP is implicit)
  133. print_i2c_status(); // print I2C final status
  134. }
  135. // Reading from Slave ------------------------------------------------------
  136. for(addr = 0; addr < 256; addr += 32) // sweep addr in 32byte blocks
  137. {
  138. Wire.beginTransmission(target); // slave addr
  139. Wire.write(READ); // READ command
  140. Wire.write(addr); // memory address
  141. Wire.endTransmission(I2C_NOSTOP); // blocking write (NOSTOP triggers RepSTART on next I2C command)
  142. Wire.requestFrom(target,32,I2C_STOP);// blocking read (request 32 bytes)
  143. Serial.printf("I2C READ 32 bytes from Slave 0x%0X at MemAddr %d\n", target, addr);
  144. Serial.print("Received: "); // print received bytes
  145. while(Wire.available()) { Serial.printf("%d ", Wire.readByte()); }
  146. Serial.print("\n");
  147. print_i2c_status(); // print I2C final status
  148. }
  149. digitalWrite(LED_BUILTIN,LOW); // LED off
  150. delay(500); // delay to space out tests
  151. }
  152. if(digitalRead(11) == LOW)
  153. {
  154. digitalWrite(LED_BUILTIN,HIGH); // LED on
  155. Serial.print("---------------------------------------------------------\n");
  156. Serial.print("Test2 : Using blocking commands:\n");
  157. Serial.print(" 1) WRITE entire memory in a single 256 byte block\n");
  158. Serial.print(" 2) READ back entire memory in a single 256 byte block\n");
  159. Serial.print("---------------------------------------------------------\n");
  160. // Writing to Slave --------------------------------------------------------
  161. addr = 0;
  162. for(len = 0; len < 256; len++) // prepare data to send
  163. databuf[len] = (addr+len)^0xFF; // set data (equal to bit inverse of memory address)
  164. Serial.printf("I2C WRITE 256 bytes to Slave 0x%0X at MemAddr %d\n", target, addr);
  165. Serial.print("Writing: ");
  166. for(len = 0; len < 256; len++) { Serial.printf("%d ",databuf[len]); }
  167. Serial.print("\n");
  168. Wire.beginTransmission(target); // slave addr
  169. Wire.write(WRITE); // WRITE command
  170. Wire.write(addr); // memory address
  171. Wire.write(databuf, 256); // write 256 byte block
  172. Wire.endTransmission(I2C_STOP); // blocking write (using explicit I2C_STOP)
  173. print_i2c_status(); // print I2C final status
  174. // Reading from Slave ------------------------------------------------------
  175. Wire.beginTransmission(target); // slave addr
  176. Wire.write(READ); // READ command
  177. Wire.write(addr); // memory address
  178. Wire.endTransmission(I2C_NOSTOP); // blocking write (NOSTOP triggers RepSTART on next I2C command)
  179. Wire.requestFrom(target,256,I2C_STOP); // blocking read (request 256 bytes)
  180. Serial.printf("I2C READ %d bytes from Slave 0x%0X at MemAddr %d\n", Wire.available(), target, addr);
  181. Serial.print("Received: "); // print received bytes
  182. while(Wire.available()) { Serial.printf("%d ", Wire.readByte()); }
  183. Serial.print("\n");
  184. print_i2c_status(); // print I2C final status
  185. Serial.printf("Rate (Hz): %d\n", Wire.i2c->currentRate);
  186. digitalWrite(LED_BUILTIN,LOW); // LED off
  187. delay(500); // delay to space out tests
  188. }
  189. if(digitalRead(10) == LOW)
  190. {
  191. digitalWrite(LED_BUILTIN,HIGH); // LED on
  192. Serial.print("---------------------------------------------------------\n");
  193. Serial.print("Test3 : Using ISR NON-blocking commands:\n");
  194. Serial.print(" 1) WRITE a 256 byte block to Slave. While block is\n");
  195. Serial.print(" transferring, perform other commands.\n");
  196. Serial.print(" 2) READ back the 256 byte block from Slave. While\n");
  197. Serial.print(" block is transferring, perform other commands.\n");
  198. Serial.print("---------------------------------------------------------\n");
  199. // Set operating mode to ISR
  200. Wire.setOpMode(I2C_OP_MODE_ISR);
  201. // Writing to Slave --------------------------------------------------------
  202. addr = 0;
  203. for(len = 0; len < 256; len++) // prepare data to send
  204. databuf[len] = (addr+len)^0xFF; // set data (equal to bit inverse of memory address)
  205. Serial.printf("I2C WRITE 256 bytes to Slave 0x%0X at MemAddr %d\n", target, addr);
  206. Serial.print("Writing: ");
  207. for(len = 0; len < 256; len++) { Serial.printf("%d ",databuf[len]); }
  208. Serial.print("\n");
  209. Wire.beginTransmission(target); // slave addr
  210. Wire.write(WRITE); // WRITE command
  211. Wire.write(addr); // memory address
  212. Wire.write(databuf, 256); // write 256 byte block
  213. Wire.sendTransmission(); // NON-blocking write (when not specified I2C_STOP is implicit)
  214. Serial.print("...write sent, counting while waiting for Wire.done()...\n");
  215. count = 1;
  216. while(!Wire.done()) count++; // Since write is non-blocking, do some counting while waiting
  217. Serial.printf("Counted to: %d\n", count++);
  218. print_i2c_status(); // print I2C final status
  219. // Reading from Slave ------------------------------------------------------
  220. Wire.beginTransmission(target); // slave addr
  221. Wire.write(READ); // READ command
  222. Wire.write(addr); // memory address
  223. Wire.endTransmission(I2C_NOSTOP); // blocking write (NOSTOP triggers RepSTART on next I2C command)
  224. Wire.sendRequest(target,256,I2C_STOP); // NON-blocking read (request 256 bytes)
  225. // Since request is non-blocking, do some other things.
  226. Serial.print("...request sent, doing one thing then waiting for Wire.finish()...\n");
  227. // After doing something, use finish() to wait until I2C done
  228. Wire.finish();
  229. Serial.printf("I2C READ %d bytes from Slave 0x%0X at MemAddr %d\n", Wire.available(), target, addr);
  230. Serial.print("Received: "); // print received bytes
  231. while(Wire.available()) { Serial.printf("%d ", Wire.readByte()); }
  232. Serial.print("\n");
  233. print_i2c_status(); // print I2C final status
  234. digitalWrite(LED_BUILTIN,LOW); // LED off
  235. delay(500); // delay to space out tests
  236. }
  237. if(digitalRead(9) == LOW)
  238. {
  239. digitalWrite(LED_BUILTIN,HIGH); // LED on
  240. Serial.print("---------------------------------------------------------\n");
  241. Serial.print("Test4 : Using DMA NON-blocking commands:\n");
  242. Serial.print(" 1) WRITE a 256 byte block to Slave. While block is\n");
  243. Serial.print(" transferring, perform other commands.\n");
  244. Serial.print(" 2) READ back the 256 byte block from Slave. While\n");
  245. Serial.print(" block is transferring, perform other commands.\n");
  246. Serial.print("---------------------------------------------------------\n");
  247. // Set operating mode to DMA
  248. Serial.print("Trying to set DMA mode : ");
  249. Wire.setOpMode(I2C_OP_MODE_DMA);
  250. if(Wire.i2c->opMode == I2C_OP_MODE_DMA)
  251. Serial.printf("OK (Channel %d)\n",Wire.i2c->DMA->channel);
  252. else
  253. Serial.print("Failed, using ISR\n");
  254. // Writing to Slave --------------------------------------------------------
  255. addr = 0;
  256. for(len = 0; len < 256; len++) // prepare data to send
  257. databuf[len] = (addr+len)^0xFF; // set data (equal to bit inverse of memory address)
  258. Serial.printf("I2C WRITE 256 bytes to Slave 0x%0X at MemAddr %d\n", target, addr);
  259. Serial.print("Writing: ");
  260. for(len = 0; len < 256; len++) { Serial.printf("%d ",databuf[len]); }
  261. Serial.print("\n");
  262. Wire.beginTransmission(target); // slave addr
  263. Wire.write(WRITE); // WRITE command
  264. Wire.write(addr); // memory address
  265. Wire.write(databuf, 256); // write 256 byte block
  266. Wire.sendTransmission(); // NON-blocking write (when not specified I2C_STOP is implicit)
  267. Serial.print("...write sent, counting while waiting for Wire.done()...\n");
  268. count = 1;
  269. while(!Wire.done()) count++; // Since write is non-blocking, do some counting while waiting
  270. Serial.printf("Counted to: %d\n", count++);
  271. print_i2c_status(); // print I2C final status
  272. // Reading from Slave ------------------------------------------------------
  273. Wire.beginTransmission(target); // slave addr
  274. Wire.write(READ); // READ command
  275. Wire.write(addr); // memory address
  276. Wire.endTransmission(I2C_NOSTOP); // blocking write (NOSTOP triggers RepSTART on next I2C command)
  277. Wire.sendRequest(target,256,I2C_STOP); // NON-blocking read (request 256 bytes)
  278. // Since request is non-blocking, do some other things.
  279. Serial.print("...request sent, doing one thing then waiting for Wire.finish()...\n");
  280. // After doing something, use finish() to wait until I2C done
  281. Wire.finish();
  282. Serial.printf("I2C READ %d bytes from Slave 0x%0X at MemAddr %d\n", Wire.available(), target, addr);
  283. Serial.print("Received: "); // print received bytes
  284. while(Wire.available()) { Serial.printf("%d ", Wire.readByte()); }
  285. Serial.print("\n");
  286. print_i2c_status(); // print I2C final status
  287. digitalWrite(LED_BUILTIN,LOW); // LED off
  288. delay(500); // delay to space out tests
  289. }
  290. if(digitalRead(8) == LOW)
  291. {
  292. uint8_t fail=0;
  293. digitalWrite(LED_BUILTIN,HIGH); // LED on
  294. Serial.print("---------------------------------------------------------\n");
  295. Serial.print("Test5 : Rate adjustment tests. This sweeps the I2C rates\n");
  296. Serial.print(" on both Master and Slave and times the duration \n");
  297. Serial.print(" of a 256 byte transfer at each rate.\n");
  298. Serial.print("---------------------------------------------------------\n");
  299. for(uint8_t opMode = I2C_OP_MODE_IMM; opMode <= I2C_OP_MODE_DMA; opMode++)
  300. {
  301. Wire.setOpMode((i2c_op_mode)opMode); // set op mode
  302. test_rate(target, 10000, fail);
  303. test_rate(target, 100000, fail);
  304. test_rate(target, 200000, fail);
  305. test_rate(target, 300000, fail);
  306. test_rate(target, 400000, fail);
  307. test_rate(target, 600000, fail);
  308. test_rate(target, 800000, fail);
  309. test_rate(target, 1000000, fail);
  310. test_rate(target, 1200000, fail);
  311. test_rate(target, 1500000, fail);
  312. test_rate(target, 1800000, fail);
  313. test_rate(target, 2000000, fail);
  314. test_rate(target, 2400000, fail);
  315. test_rate(target, 2800000, fail);
  316. test_rate(target, 3000000, fail);
  317. test_rate(target, 4000000, fail);
  318. test_rate(target, 5000000, fail);
  319. test_rate(target, 6000000, fail);
  320. // Restore normal settings
  321. // Change Slave rate
  322. Wire.beginTransmission(target); // slave addr
  323. Wire.write(SETRATE); // SETRATE command
  324. Wire.write((uint8_t)400000&0xFF); // rate LSB
  325. Wire.write((uint8_t)(400000>>8)&0xFF);
  326. Wire.write((uint8_t)(400000>>16)&0xFF);
  327. Wire.write((uint8_t)(400000>>24)&0xFF); // rate MSB
  328. Wire.endTransmission(); // blocking write
  329. // Change Master rate
  330. Wire.setClock(400000);
  331. fail = 0; // reset flag
  332. }
  333. Wire.setOpMode(I2C_OP_MODE_ISR); // restore default ISR mode
  334. print_i2c_status(); // print I2C final status
  335. // Restore normal settings (400kHz)
  336. // Change Slave rate
  337. Wire.beginTransmission(target); // slave addr
  338. Wire.write(SETRATE); // SETRATE command
  339. Wire.write((uint8_t)400000&0xFF); // rate LSB
  340. Wire.write((uint8_t)(400000>>8)&0xFF);
  341. Wire.write((uint8_t)(400000>>16)&0xFF);
  342. Wire.write((uint8_t)(400000>>24)&0xFF); // rate MSB
  343. Wire.endTransmission(); // blocking write
  344. // Change Master rate
  345. Wire.setClock(400000);
  346. digitalWrite(LED_BUILTIN,LOW); // LED off
  347. delay(500); // delay to space out tests
  348. }
  349. }
  350. //
  351. // print current setup
  352. //
  353. void print_i2c_setup()
  354. {
  355. Serial.print("Mode:");
  356. switch(Wire.i2c->opMode)
  357. {
  358. case I2C_OP_MODE_IMM: Serial.print("IMM "); break;
  359. case I2C_OP_MODE_ISR: Serial.print("ISR "); break;
  360. case I2C_OP_MODE_DMA: Serial.printf("DMA[%d] ",Wire.i2c->DMA->channel); break;
  361. }
  362. Serial.printf("Pins: %d/%d ", Wire.i2c->currentSCL, Wire.i2c->currentSDA);
  363. }
  364. //
  365. // print I2C status
  366. //
  367. void print_i2c_status(void)
  368. {
  369. switch(Wire.status())
  370. {
  371. case I2C_WAITING: Serial.print("I2C waiting, no errors\n"); break;
  372. case I2C_ADDR_NAK: Serial.print("Slave addr not acknowledged\n"); break;
  373. case I2C_DATA_NAK: Serial.print("Slave data not acknowledged\n"); break;
  374. case I2C_ARB_LOST: Serial.print("Bus Error: Arbitration Lost\n"); break;
  375. case I2C_TIMEOUT: Serial.print("I2C timeout\n"); break;
  376. case I2C_BUF_OVF: Serial.print("I2C buffer overflow\n"); break;
  377. default: Serial.print("I2C busy\n"); break;
  378. }
  379. }
  380. //
  381. // print I2C rate
  382. //
  383. void print_rate(uint32_t rate)
  384. {
  385. Serial.printf("%d Hz ", rate);
  386. }
  387. //
  388. // test rate
  389. //
  390. void test_rate(uint8_t target, uint32_t rate, uint8_t& fail)
  391. {
  392. uint32_t deltatime=0;
  393. size_t len;
  394. if(!fail)
  395. {
  396. for(len = 0; len < 256; len++) // prepare data to send
  397. databuf[len] = len; // set data (equal to addr)
  398. // Change Slave rate
  399. Wire.beginTransmission(target); // slave addr
  400. Wire.write(SETRATE); // SETRATE command
  401. Wire.write((uint8_t)rate&0xFF); // rate LSB
  402. Wire.write((uint8_t)(rate>>8)&0xFF);
  403. Wire.write((uint8_t)(rate>>16)&0xFF);
  404. Wire.write((uint8_t)(rate>>24)&0xFF); // rate MSB
  405. Wire.endTransmission(); // blocking write
  406. fail = Wire.getError();
  407. if(!fail)
  408. {
  409. // Change Master rate
  410. Wire.setClock(rate);
  411. // Setup write buffer
  412. Wire.beginTransmission(target); // slave addr
  413. Wire.write(WRITE); // WRITE command
  414. Wire.write(0); // memory address
  415. Wire.write(databuf, 256); // write 256 byte block
  416. // Write to Slave
  417. elapsedMicros deltaT;
  418. Wire.endTransmission(); // blocking write
  419. deltatime = deltaT;
  420. fail = Wire.getError();
  421. if(!fail)
  422. {
  423. Wire.beginTransmission(target); // slave addr
  424. Wire.write(READ); // READ command
  425. Wire.write(0); // memory address
  426. Wire.endTransmission(I2C_NOSTOP); // blocking write (NOSTOP triggers RepSTART on next I2C command)
  427. Wire.requestFrom(target,256,I2C_STOP);// blocking read
  428. fail = Wire.getError();
  429. if(!fail)
  430. {
  431. for(len = 0; len < 256; len++) // verify block
  432. if(databuf[len] != Wire.readByte()) { fail=1; break; }
  433. }
  434. }
  435. }
  436. print_i2c_setup();
  437. if(!fail)
  438. {
  439. // Print result
  440. Serial.print("256 byte transfer at ");
  441. print_rate(rate);
  442. Serial.printf(" (Actual Rate (Hz): %d) : %d us : ", Wire.getClock(), deltatime);
  443. print_i2c_status();
  444. }
  445. else
  446. {
  447. Serial.printf("Transfer fail : %d us : ",deltatime);
  448. print_i2c_status();
  449. }
  450. }
  451. }