forked from nox771/i2c_t3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
i2c_t3.h
1158 lines (1060 loc) · 61.8 KB
/
i2c_t3.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
------------------------------------------------------------------------------------------------------
i2c_t3 - I2C library for Teensy 3.x & LC
Copyright (c) 2013-2017, Brian (nox771 at gmail.com)
- (v10.0) Modified 21Oct17 by Brian (nox771 at gmail.com)
Full changelog at end of file
------------------------------------------------------------------------------------------------------
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
------------------------------------------------------------------------------------------------------
*/
#if defined(__AVR__)
#error "Sorry, i2c_t3 only works on Teensy LC and 3.x boards. Use Wire for Teensy 2.0."
#endif
#if !defined(I2C_T3_H) && (defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__) || \
defined(__MK64FX512__) || defined(__MK66FX1M0__)) // 3.0/3.1-3.2/LC/3.5/3.6
#define I2C_T3_H
#include <inttypes.h>
#include <stdio.h> // for size_t
#include "Arduino.h"
#include <DMAChannel.h>
// TODO missing kinetis.h defs
#ifndef I2C_F_DIV52
#define I2C_F_DIV52 ((uint8_t)0x43)
#define I2C_F_DIV60 ((uint8_t)0x45)
#define I2C_F_DIV136 ((uint8_t)0x4F)
#define I2C_F_DIV176 ((uint8_t)0x55)
#define I2C_F_DIV352 ((uint8_t)0x95)
#define I2C_FLT_SSIE ((uint8_t)0x20) // Start/Stop Interrupt Enable
#define I2C_FLT_STARTF ((uint8_t)0x10) // Start Detect Flag
#endif
// ======================================================================================================
// == Start User Define Section =========================================================================
// ======================================================================================================
// ------------------------------------------------------------------------------------------------------
// I2C Bus Enable control - change to enable buses as follows. The number of buses will be limited to the
// lower of this setting or what is available on the device.
//
// Teensy Max #Buses
// ------ ----------
// LC 2
// 3.0 1
// 3.1 2
// 3.2 2
// 3.5 3
// 3.6 4
//
// I2C_BUS_ENABLE 1 (enable Wire only)
// I2C_BUS_ENABLE 2 (enable Wire & Wire1)
// I2C_BUS_ENABLE 3 (enable Wire & Wire1 & Wire2)
// I2C_BUS_ENABLE 4 (enable Wire & Wire1 & Wire2 & Wire3)
//
#define I2C_BUS_ENABLE 4
// ------------------------------------------------------------------------------------------------------
// Tx/Rx buffer sizes - modify these as needed. Buffers should be large enough to hold:
// Target Addr + Data payload. Default is: 1byte Addr + 258byte Data
// (this can be substantially reduced if working with sensors or small data packets)
//
#define I2C_TX_BUFFER_LENGTH 259
#define I2C_RX_BUFFER_LENGTH 259
// ------------------------------------------------------------------------------------------------------
// Interrupt flag - uncomment and set below to make the specified pin high whenever the
// I2C interrupt occurs (modify pin number as needed). This is useful as a
// trigger signal when using a logic analyzer.
//
//#define I2C0_INTR_FLAG_PIN 5
//#define I2C1_INTR_FLAG_PIN 6
//#define I2C2_INTR_FLAG_PIN 9
//#define I2C3_INTR_FLAG_PIN 10
// ------------------------------------------------------------------------------------------------------
// Auto retry - uncomment to make the library automatically call resetBus() if it has a timeout while
// trying to send a START (occurs at the beginning of any endTransmission() or requestFrom()
// call). This will toggle SCL to try and get a hung Slave device to release the SDA line.
// If successful then it will try again to send a START, if not then it will return a timeout
// error (same as if auto retry was not defined).
//
// Note: this is incompatible with multi-master buses, only use in single-master configurations
//
//#define I2C_AUTO_RETRY
// ------------------------------------------------------------------------------------------------------
// Error counters - uncomment to make the library track error counts. Error counts can be retrieved or
// zeroed using the getErrorCount() and zeroErrorCount() functions respectively.
// When included, errors will be tracked on the following (Master-mode only):
// Reset Bus (auto-retry only), Timeout, Addr NAK, Data NAK, Arb Lost, Bus Not Acquired,
// DMA Errors
//
#define I2C_ERROR_COUNTERS
// ------------------------------------------------------------------------------------------------------
// Disable priority check - uncomment this to entirely disable auto priority escalation. Normally
// priority escalation occurs to ensure I2C ISR operates at a higher priority
// than the calling function (to prevent ISR stall if the calling function
// blocks). Uncommenting this will disable the check and cause I2C ISR to
// remain at default priority. It is recommended to disable this check and
// manually set ISR priority levels when using complex configurations.
//
//#define I2C_DISABLE_PRIORITY_CHECK
// ======================================================================================================
// == End User Define Section ===========================================================================
// ======================================================================================================
// ------------------------------------------------------------------------------------------------------
// Set number of enabled buses
//
#if defined(__MK20DX128__) // 3.0
#define I2C_BUS_NUM 1
#elif (defined(__MK20DX256__) || defined(__MKL26Z64__)) && (I2C_BUS_ENABLE >= 2) // 3.1/3.2/LC
#define I2C_BUS_NUM 2
#elif defined(__MK64FX512__) && (I2C_BUS_ENABLE >= 3) // 3.5
#define I2C_BUS_NUM 3
#elif defined(__MK66FX1M0__) && (I2C_BUS_ENABLE >= 4) // 3.6
#define I2C_BUS_NUM 4
#else
#define I2C_BUS_NUM I2C_BUS_ENABLE
#endif
// ------------------------------------------------------------------------------------------------------
// Interrupt flag setup
//
#if defined(I2C0_INTR_FLAG_PIN)
#define I2C0_INTR_FLAG_INIT do \
{ \
pinMode(I2C0_INTR_FLAG_PIN, OUTPUT); \
digitalWrite(I2C0_INTR_FLAG_PIN, LOW); \
} while(0)
#define I2C0_INTR_FLAG_ON do {digitalWrite(I2C0_INTR_FLAG_PIN, HIGH);} while(0)
#define I2C0_INTR_FLAG_OFF do {digitalWrite(I2C0_INTR_FLAG_PIN, LOW);} while(0)
#else
#define I2C0_INTR_FLAG_INIT do{}while(0)
#define I2C0_INTR_FLAG_ON do{}while(0)
#define I2C0_INTR_FLAG_OFF do{}while(0)
#endif
#if defined(I2C1_INTR_FLAG_PIN)
#define I2C1_INTR_FLAG_INIT do \
{ \
pinMode(I2C1_INTR_FLAG_PIN, OUTPUT); \
digitalWrite(I2C1_INTR_FLAG_PIN, LOW); \
} while(0)
#define I2C1_INTR_FLAG_ON do {digitalWrite(I2C1_INTR_FLAG_PIN, HIGH);} while(0)
#define I2C1_INTR_FLAG_OFF do {digitalWrite(I2C1_INTR_FLAG_PIN, LOW);} while(0)
#else
#define I2C1_INTR_FLAG_INIT do{}while(0)
#define I2C1_INTR_FLAG_ON do{}while(0)
#define I2C1_INTR_FLAG_OFF do{}while(0)
#endif
#if defined(I2C2_INTR_FLAG_PIN)
#define I2C2_INTR_FLAG_INIT do \
{ \
pinMode(I2C2_INTR_FLAG_PIN, OUTPUT); \
digitalWrite(I2C2_INTR_FLAG_PIN, LOW); \
} while(0)
#define I2C2_INTR_FLAG_ON do {digitalWrite(I2C2_INTR_FLAG_PIN, HIGH);} while(0)
#define I2C2_INTR_FLAG_OFF do {digitalWrite(I2C2_INTR_FLAG_PIN, LOW);} while(0)
#else
#define I2C2_INTR_FLAG_INIT do{}while(0)
#define I2C2_INTR_FLAG_ON do{}while(0)
#define I2C2_INTR_FLAG_OFF do{}while(0)
#endif
#if defined(I2C3_INTR_FLAG_PIN)
#define I2C3_INTR_FLAG_INIT do \
{ \
pinMode(I2C3_INTR_FLAG_PIN, OUTPUT); \
digitalWrite(I2C3_INTR_FLAG_PIN, LOW); \
} while(0)
#define I2C3_INTR_FLAG_ON do {digitalWrite(I2C3_INTR_FLAG_PIN, HIGH);} while(0)
#define I2C3_INTR_FLAG_OFF do {digitalWrite(I2C3_INTR_FLAG_PIN, LOW);} while(0)
#else
#define I2C3_INTR_FLAG_INIT do{}while(0)
#define I2C3_INTR_FLAG_ON do{}while(0)
#define I2C3_INTR_FLAG_OFF do{}while(0)
#endif
// ------------------------------------------------------------------------------------------------------
// Error counters setup
//
#if defined(I2C_ERROR_COUNTERS)
#define I2C_ERR_INC(i2c_err_count) do {if(i2c->errCounts[i2c_err_count] < UINT32_MAX) i2c->errCounts[i2c_err_count]++;} while(0)
#else
#define I2C_ERR_INC(i2c_err_count) do{}while(0)
#endif
// ------------------------------------------------------------------------------------------------------
// Function argument enums
//
enum i2c_op_mode {I2C_OP_MODE_IMM, I2C_OP_MODE_ISR, I2C_OP_MODE_DMA};
enum i2c_mode {I2C_MASTER, I2C_SLAVE};
enum i2c_pullup {I2C_PULLUP_EXT, I2C_PULLUP_INT};
enum i2c_rate {I2C_RATE_100 = 100000,
I2C_RATE_200 = 200000,
I2C_RATE_300 = 300000,
I2C_RATE_400 = 400000,
I2C_RATE_600 = 600000,
I2C_RATE_800 = 800000,
I2C_RATE_1000 = 1000000,
I2C_RATE_1200 = 1200000,
I2C_RATE_1500 = 1500000,
I2C_RATE_1800 = 1800000,
I2C_RATE_2000 = 2000000,
I2C_RATE_2400 = 2400000,
I2C_RATE_2800 = 2800000,
I2C_RATE_3000 = 3000000};
enum i2c_stop {I2C_NOSTOP, I2C_STOP};
enum i2c_status {I2C_WAITING, // stopped states
I2C_TIMEOUT, // |
I2C_ADDR_NAK, // |
I2C_DATA_NAK, // |
I2C_ARB_LOST, // |
I2C_BUF_OVF, // |
I2C_NOT_ACQ, // |
I2C_DMA_ERR, // V
I2C_SENDING, // active states
I2C_SEND_ADDR, // |
I2C_RECEIVING, // |
I2C_SLAVE_TX, // |
I2C_SLAVE_RX}; // V
enum i2c_dma_state {I2C_DMA_OFF,
I2C_DMA_ADDR,
I2C_DMA_BULK,
I2C_DMA_LAST};
#if defined(__MKL26Z64__) // LC
enum i2c_pins {I2C_PINS_16_17 = 0, // 16 SCL0 17 SDA0
I2C_PINS_18_19, // 19 SCL0 18 SDA0
I2C_PINS_22_23, // 22 SCL1 23 SDA1
I2C_PINS_DEFAULT,
I2C_PINS_COUNT};
const uint8_t i2c_valid_pins[] = { 0, 16, 17, 2, // bus, scl, sda, alt
0, 19, 18, 2,
1, 22, 23, 2,
0, 0, 0, 0 };
#elif defined(__MK20DX128__) // 3.0
enum i2c_pins {I2C_PINS_16_17 = 0, // 16 SCL0 17 SDA0
I2C_PINS_18_19, // 19 SCL0 18 SDA0
I2C_PINS_DEFAULT,
I2C_PINS_COUNT};
const uint8_t i2c_valid_pins[] = { 0, 16, 17, 2, // bus, scl, sda, alt
0, 19, 18, 2,
0, 0, 0, 0 };
#elif defined(__MK20DX256__) // 3.1/3.2
enum i2c_pins {I2C_PINS_16_17 = 0, // 16 SCL0 17 SDA0
I2C_PINS_18_19, // 19 SCL0 18 SDA0
I2C_PINS_29_30, // 29 SCL1 30 SDA1
I2C_PINS_26_31, // 26 SCL1 31 SDA1
I2C_PINS_DEFAULT,
I2C_PINS_COUNT};
const uint8_t i2c_valid_pins[] = { 0, 16, 17, 2, // bus, scl, sda, alt
0, 19, 18, 2,
1, 29, 30, 2,
1, 26, 31, 6,
0, 0, 0, 0 };
#elif defined(__MK64FX512__) // 3.5
enum i2c_pins {I2C_PINS_3_4 = 0, // 3 SCL2 4 SDA2
I2C_PINS_7_8, // 7 SCL0 8 SDA0
I2C_PINS_16_17, // 16 SCL0 17 SDA0
I2C_PINS_18_19, // 19 SCL0 18 SDA0
I2C_PINS_33_34, // 33 SCL0 34 SDA0
I2C_PINS_37_38, // 37 SCL1 38 SDA1
I2C_PINS_47_48, // 47 SCL0 48 SDA0
I2C_PINS_DEFAULT,
I2C_PINS_COUNT};
const uint8_t i2c_valid_pins[] = { 2, 3, 4, 5, // bus, scl, sda, alt
0, 7, 8, 7,
0, 16, 17, 2,
0, 19, 18, 2,
0, 33, 34, 5,
1, 37, 38, 2,
0, 47, 48, 2,
0, 0, 0, 0 };
#elif defined(__MK66FX1M0__) // 3.6
enum i2c_pins {I2C_PINS_3_4 = 0, // 3 SCL2 4 SDA2
I2C_PINS_7_8, // 7 SCL0 8 SDA0
I2C_PINS_16_17, // 16 SCL0 17 SDA0
I2C_PINS_18_19, // 19 SCL0 18 SDA0
I2C_PINS_33_34, // 33 SCL0 34 SDA0
I2C_PINS_37_38, // 37 SCL1 38 SDA1
I2C_PINS_47_48, // 47 SCL0 48 SDA0
I2C_PINS_56_57, // 57 SCL3 56 SDA3
I2C_PINS_DEFAULT,
I2C_PINS_COUNT};
const uint8_t i2c_valid_pins[] = { 2, 3, 4, 5, // bus, scl, sda, alt
0, 7, 8, 7,
0, 16, 17, 2,
0, 19, 18, 2,
0, 33, 34, 5,
1, 37, 38, 2,
0, 47, 48, 2,
3, 57, 56, 2,
0, 0, 0, 0 };
#endif
enum i2c_err_count {I2C_ERRCNT_RESET_BUS=0,
I2C_ERRCNT_TIMEOUT,
I2C_ERRCNT_ADDR_NAK,
I2C_ERRCNT_DATA_NAK,
I2C_ERRCNT_ARBL,
I2C_ERRCNT_NOT_ACQ,
I2C_ERRCNT_DMA_ERR};
// ------------------------------------------------------------------------------------------------------
// Divide ratio tables
//
const int32_t i2c_div_num[] =
{20,22,24,26,28,30,32,34,36,40,44,48,52,56,60,64,68,72,
80,88,96,104,112,128,136,144,160,176,192,224,240,256,288,
320,352,384,448,480,512,576,640,768,896,960,1024,1152,
1280,1536,1920,1792,2048,2304,2560,3072,3840};
const uint8_t i2c_div_ratio[] =
{I2C_F_DIV20,I2C_F_DIV22,I2C_F_DIV24,I2C_F_DIV26,
I2C_F_DIV28,I2C_F_DIV30,I2C_F_DIV32,I2C_F_DIV34,
I2C_F_DIV36,I2C_F_DIV40,I2C_F_DIV44,I2C_F_DIV48,
I2C_F_DIV52,I2C_F_DIV56,I2C_F_DIV60,I2C_F_DIV64,
I2C_F_DIV68,I2C_F_DIV72,I2C_F_DIV80,I2C_F_DIV88,
I2C_F_DIV96,I2C_F_DIV104,I2C_F_DIV112,I2C_F_DIV128,
I2C_F_DIV136,I2C_F_DIV144,I2C_F_DIV160,I2C_F_DIV176,
I2C_F_DIV192,I2C_F_DIV224,I2C_F_DIV240,I2C_F_DIV256,
I2C_F_DIV288,I2C_F_DIV320,I2C_F_DIV352,I2C_F_DIV384,
I2C_F_DIV448,I2C_F_DIV480,I2C_F_DIV512,I2C_F_DIV576,
I2C_F_DIV640,I2C_F_DIV768,I2C_F_DIV896,I2C_F_DIV960,
I2C_F_DIV1024,I2C_F_DIV1152,I2C_F_DIV1280,I2C_F_DIV1536,
I2C_F_DIV1920,I2C_F_DIV1792,I2C_F_DIV2048,I2C_F_DIV2304,
I2C_F_DIV2560,I2C_F_DIV3072,I2C_F_DIV3840};
// ------------------------------------------------------------------------------------------------------
// Main I2C data structure
//
struct i2cStruct
{
volatile uint8_t* A1; // Address Register 1 (User&ISR)
volatile uint8_t* F; // Frequency Divider Register (User&ISR)
volatile uint8_t* C1; // Control Register 1 (User&ISR)
volatile uint8_t* S; // Status Register (User&ISR)
volatile uint8_t* D; // Data I/O Register (User&ISR)
volatile uint8_t* C2; // Control Register 2 (User&ISR)
volatile uint8_t* FLT; // Programmable Input Glitch Filter (User&ISR)
volatile uint8_t* RA; // Range Address Register (User&ISR)
volatile uint8_t* SMB; // SMBus Control and Status Register (User&ISR)
volatile uint8_t* A2; // Address Register 2 (User&ISR)
volatile uint8_t* SLTH; // SCL Low Timeout Register High (User&ISR)
volatile uint8_t* SLTL; // SCL Low Timeout Register Low (User&ISR)
uint8_t rxBuffer[I2C_RX_BUFFER_LENGTH]; // Rx Buffer (ISR)
volatile size_t rxBufferIndex; // Rx Index (User&ISR)
volatile size_t rxBufferLength; // Rx Length (ISR)
uint8_t txBuffer[I2C_TX_BUFFER_LENGTH]; // Tx Buffer (User)
volatile size_t txBufferIndex; // Tx Index (User&ISR)
volatile size_t txBufferLength; // Tx Length (User&ISR)
i2c_op_mode opMode; // Operating Mode (User)
i2c_mode currentMode; // Current Mode (User)
volatile uint8_t currentSCL; // Current SCL pin (User&ISR)
volatile uint8_t currentSDA; // Current SDA pin (User&ISR)
i2c_pullup currentPullup; // Current Pullup (User)
uint32_t currentRate; // Current Rate (User)
i2c_stop currentStop; // Current Stop (User)
volatile i2c_status currentStatus; // Current Status (User&ISR)
uint8_t rxAddr; // Rx Address (ISR)
size_t reqCount; // Byte Request Count (User)
uint8_t irqCount; // IRQ Count, used by SDA-rising ISR (ISR)
uint8_t timeoutRxNAK; // Rx Timeout NAK flag (ISR)
volatile i2c_dma_state activeDMA; // Active DMA flag (User&ISR)
void (*user_onTransmitDone)(void); // Master Tx Callback Function (User)
void (*user_onReqFromDone)(void); // Master Rx Callback Function (User)
void (*user_onReceive)(size_t len); // Slave Rx Callback Function (User)
void (*user_onRequest)(void); // Slave Tx Callback Function (User)
void (*user_onError)(void); // Error Callback Function (User)
DMAChannel* DMA; // DMA Channel object (User&ISR)
uint32_t defTimeout; // Default Timeout (User)
volatile uint32_t errCounts[7]; // Error Counts Array (User&ISR)
};
// ------------------------------------------------------------------------------------------------------
// I2C Class
//
extern "C" void i2c0_isr(void);
#if I2C_BUS_NUM >= 2
extern "C" void i2c1_isr(void);
#endif
#if I2C_BUS_NUM >= 3
extern "C" void i2c2_isr(void);
#endif
#if I2C_BUS_NUM >= 4
extern "C" void i2c3_isr(void);
#endif
extern "C" void i2c_isr_handler(struct i2cStruct* i2c, uint8_t bus);
class i2c_t3 : public Stream
{
private:
//
// I2C data structures - these need to be static so "C" ISRs can use them
//
static struct i2cStruct i2cData[I2C_BUS_NUM];
//
// Base handler - ISRs are non-class global functions, friend of class req'd for data access
//
friend void i2c_isr_handler(struct i2cStruct* i2c, uint8_t bus);
//
// Bus ISRs
//
friend void i2c0_isr(void); // I2C0 ISR
#if (defined(__MK20DX128__) || defined(__MK20DX256__))
static void sda_rising_isr_handler(struct i2cStruct* i2c, uint8_t bus); // Slave STOP base handler - 3.0/3.1/3.2 only
static void sda0_rising_isr(void); // Slave STOP detection (I2C0) - 3.0/3.1/3.2 only
#endif
#if I2C_BUS_NUM >= 2
friend void i2c1_isr(void); // I2C1 ISR
#if defined(__MK20DX256__)
static void sda1_rising_isr(void); // Slave STOP detection (I2C1) - 3.1/3.2 only
#endif
#endif
#if I2C_BUS_NUM >= 3
friend void i2c2_isr(void); // I2C2 ISR
#endif
#if I2C_BUS_NUM >= 4
friend void i2c3_isr(void); // I2C3 ISR
#endif
public:
//
// I2C bus number - this is a local, passed as an argument to base functions
// since static functions cannot see it.
uint8_t bus;
//
// I2C structure pointer - this is a local, passed as an argument to base functions
// since static functions cannot see it.
struct i2cStruct* i2c;
//
// I2C ISR Active flag - this is used to disable priority escalation. Increment to 1 to disable priority
// check. This is a global flag to prevent complex cross-bus issues. It is only
// incremented/decremented, not set.
//
static volatile uint8_t isrActive;
// ------------------------------------------------------------------------------------------------------
// Constructor
//
i2c_t3(uint8_t i2c_bus);
~i2c_t3();
// ------------------------------------------------------------------------------------------------------
// Pin Mapping - convert i2c_pins enum into pin values, intended for internal use only
//
inline uint8_t mapSCL(i2c_pins pins) { return i2c_valid_pins[pins*4+1]; }
inline uint8_t mapSDA(i2c_pins pins) { return i2c_valid_pins[pins*4+2]; }
// ------------------------------------------------------------------------------------------------------
// Valid pin checks - verify if SCL or SDA pin is valid, intended for internal use only
// return: alt setting, 0=not valid
// parameters:
// bus = bus number
// pin = pin number to check
// offset = array offset
//
static uint8_t validPin_(uint8_t bus, uint8_t pin, uint8_t offset);
// ------------------------------------------------------------------------------------------------------
// Initialize I2C (base routine)
//
static void begin_(struct i2cStruct* i2c, uint8_t bus, i2c_mode mode, uint8_t address1, uint8_t address2,
uint8_t pinSCL, uint8_t pinSDA, i2c_pullup pullup, uint32_t rate, i2c_op_mode opMode);
//
// Initialize I2C (Master) - initializes I2C as Master mode, external pullups, 100kHz rate,
// and default pin setting
// default pin setting SCL/SDA:
// Wire: 19/18
// Wire1: 29/30 (3.1/3.2), 22/23 (LC), 37/38 (3.5/3.6)
// Wire2: 3/4 (3.5/3.6)
// Wire3: 57/56 (3.6)
// return: none
//
inline void begin(void)
{ begin_(i2c, bus, I2C_MASTER, 0, 0, 0, 0, I2C_PULLUP_EXT, 100000, I2C_OP_MODE_ISR); }
//
// Initialize I2C (Slave) - initializes I2C as Slave mode using address, external pullups, 100kHz rate,
// and default pin setting
// default pin setting SCL/SDA:
// Wire: 19/18
// Wire1: 29/30 (3.1/3.2), 22/23 (LC), 37/38 (3.5/3.6)
// Wire2: 3/4 (3.5/3.6)
// Wire3: 57/56 (3.6)
// return: none
// parameters:
// address = 7bit slave address of device
//
inline void begin(int address)
{ begin_(i2c, bus, I2C_SLAVE, (uint8_t)address, 0, 0, 0, I2C_PULLUP_EXT, 100000, I2C_OP_MODE_ISR); }
inline void begin(uint8_t address)
{ begin_(i2c, bus, I2C_SLAVE, address, 0, 0, 0, I2C_PULLUP_EXT, 100000, I2C_OP_MODE_ISR); }
//
// Initialize I2C - initializes I2C as Master or single address Slave
// return: none
// parameters (optional parameters marked '^'):
// mode = I2C_MASTER, I2C_SLAVE
// address1 = 7bit slave address when configured as Slave (ignored for Master mode)
// ^address2 = 2nd 7bit address for specifying Slave address range (ignored for Master mode)
// ^pins = pins to use, can be specified as 'i2c_pins' enum,
// or as 'SCL,SDA' pair (using any valid SCL or SDA), options are:
// Interface Devices Pin Name SCL SDA Default
// --------- ------- -------------- ----- ----- -------
// Wire All I2C_PINS_16_17 16 17
// Wire All I2C_PINS_18_19 19* 18 +
// Wire 3.5/3.6 I2C_PINS_7_8 7 8
// Wire 3.5/3.6 I2C_PINS_33_34 33 34
// Wire 3.5/3.6 I2C_PINS_47_48 47 48
// Wire1 LC I2C_PINS_22_23 22 23 +
// Wire1 3.1/3.2 I2C_PINS_26_31 26 31
// Wire1 3.1/3.2 I2C_PINS_29_30 29 30 +
// Wire1 3.5/3.6 I2C_PINS_37_38 37 38 +
// Wire2 3.5/3.6 I2C_PINS_3_4 3 4 +
// Wire3 3.6 I2C_PINS_56_57 57* 56 +
// (note: in almost all cases SCL is the lower pin #, except cases marked *)
// ^pullup = I2C_PULLUP_EXT, I2C_PULLUP_INT (default I2C_PULLUP_EXT)
// ^rate = I2C frequency to use, can be specified directly in Hz, eg. 400000 for 400kHz, or using one of the
// following enum values (deprecated):
// I2C_RATE_100, I2C_RATE_200, I2C_RATE_300, I2C_RATE_400,
// I2C_RATE_600, I2C_RATE_800, I2C_RATE_1000, I2C_RATE_1200,
// I2C_RATE_1500, I2C_RATE_1800, I2C_RATE_2000, I2C_RATE_2400,
// I2C_RATE_2800, I2C_RATE_3000
// ^opMode = I2C_OP_MODE_IMM, I2C_OP_MODE_ISR, I2C_OP_MODE_DMA (ignored for Slave mode, defaults ISR mode)
//
inline void begin(i2c_mode mode, uint8_t address1, i2c_pins pins=I2C_PINS_DEFAULT,
i2c_pullup pullup=I2C_PULLUP_EXT, uint32_t rate=400000, i2c_op_mode opMode=I2C_OP_MODE_ISR)
{ begin_(i2c, bus, mode, address1, 0, mapSCL(pins), mapSDA(pins), pullup, rate, opMode); }
inline void begin(i2c_mode mode, uint8_t address1, uint8_t pinSCL, uint8_t pinSDA,
i2c_pullup pullup=I2C_PULLUP_EXT, uint32_t rate=400000, i2c_op_mode opMode=I2C_OP_MODE_ISR)
{ begin_(i2c, bus, mode, address1, 0, pinSCL, pinSDA, pullup, rate, opMode); }
inline void begin(i2c_mode mode, uint8_t address1, uint8_t address2, i2c_pins pins=I2C_PINS_DEFAULT,
i2c_pullup pullup=I2C_PULLUP_EXT, uint32_t rate=400000, i2c_op_mode opMode=I2C_OP_MODE_ISR)
{ begin_(i2c, bus, mode, address1, address2, mapSCL(pins), mapSDA(pins), pullup, rate, opMode); }
inline void begin(i2c_mode mode, uint8_t address1, uint8_t address2, uint8_t pinSCL, uint8_t pinSDA,
i2c_pullup pullup=I2C_PULLUP_EXT, uint32_t rate=400000, i2c_op_mode opMode=I2C_OP_MODE_ISR)
{ begin_(i2c, bus, mode, address1, address2, pinSCL, pinSDA, pullup, rate, opMode); }
// ------------------------------------------------------------------------------------------------------
// Set Operating Mode (base routine)
//
static uint8_t setOpMode_(struct i2cStruct* i2c, uint8_t bus, i2c_op_mode opMode);
//
// Set Operating Mode - this configures operating mode of the I2C as either Immediate, ISR, or DMA.
// By default Arduino-style begin() calls will initialize to ISR mode. This can
// only be called when the bus is idle (no changing mode in the middle of Tx/Rx).
// Note that Slave mode can only use ISR operation.
// return: 1=success, 0=fail (bus busy)
// parameters:
// opMode = I2C_OP_MODE_ISR, I2C_OP_MODE_DMA, I2C_OP_MODE_IMM
//
inline uint8_t setOpMode(i2c_op_mode opMode) { return setOpMode_(i2c, bus, opMode); }
// ------------------------------------------------------------------------------------------------------
// Set I2C rate (base routine)
//
static void setRate_(struct i2cStruct* i2c, uint32_t busFreq, uint32_t i2cFreq);
//
// Set I2C rate - reconfigures I2C frequency divider based on supplied bus freq and desired I2C freq.
// This will be done assuming an idealized I2C rate, even though at high I2C rates
// the actual throughput is much lower than theoretical value.
//
// Since the division ratios are quantized with non-uniform spacing, the selected rate
// will be the one using the nearest available divider.
// return: none
// parameters:
// busFreq = bus frequency, typically F_BUS unless reconfigured
// freq = desired I2C frequency (will be quantized to nearest rate), or can be I2C_RATE_XXX enum (deprecated),
// such as I2C_RATE_100, I2C_RATE_400, etc...
//
// Max I2C rate is 1/20th F_BUS. Some examples:
//
// F_CPU F_BUS Max I2C
// (MHz) (MHz) Rate
// ------------- ----- ----------
// 240/120 120 6.0M bus overclock
// 216 108 5.4M bus overclock
// 192/96 96 4.8M bus overclock
// 180 90 4.5M bus overclock
// 240 80 4.0M bus overclock
// 216/144/72 72 3.6M bus overclock
// 192 64 3.2M bus overclock
// 240/180/120 60 3.0M
// 168 56 2.8M
// 216 54 2.7M
// 192/144/96/48 48 2.4M
// 72 36 1.8M
// 24 24 1.2M
// 16 16 800k
// 8 8 400k
// 4 4 200k
// 2 2 100k
//
inline void setRate(uint32_t busFreq, uint32_t i2cFreq) { setRate_(i2c, busFreq, i2cFreq); }
// return value and i2c_rate enum no longer needed (deprecated form, always returns 1)
inline uint8_t setRate(uint32_t busFreq, i2c_rate rate) { setRate_(i2c, busFreq, (uint32_t)rate); return 1; }
// Wire compatibility
inline void setClock(uint32_t i2cFreq)
{
#if defined(__MKL26Z64__) // LC
if(i2c->currentSCL == 22)
setRate_(i2c, (uint32_t)F_CPU, i2cFreq); // LC Wire1 bus uses system clock (F_CPU) instead of bus clock (F_BUS)
else
setRate_(i2c, (uint32_t)F_BUS, i2cFreq);
#else
setRate_(i2c, (uint32_t)F_BUS, i2cFreq);
#endif
}
// i2c_t3 version of setClock (deprecated)
inline uint8_t setRate(i2c_rate rate) { setClock((uint32_t)rate); return 1; }
// ------------------------------------------------------------------------------------------------------
// Get I2C clock - return current clock setting
// return: uint32_t = bus frequency (Hz)
// parameters: none
inline uint32_t getClock(void) { return i2c->currentRate; }
// ------------------------------------------------------------------------------------------------------
// Configure I2C pins (base routine)
//
static uint8_t pinConfigure_(struct i2cStruct* i2c, uint8_t bus, uint8_t pinSCL, uint8_t pinSDA, i2c_pullup pullup, uint8_t reconfig=1);
//
// ------------------------------------------------------------------------------------------------------
// Configure I2C pins - reconfigures active I2C pins on-the-fly (only works when bus is idle). If reconfig
// set then inactive pins will switch to input mode using same pullup configuration.
// return: 1=success, 0=fail (bus busy or incompatible pins)
// parameters:
// pins = pins to use, can be specified as 'i2c_pins' enum,
// or as 'SCL,SDA' pair (using any valid SCL or SDA), options are:
// Interface Devices Pin Name SCL SDA Default
// --------- ------- -------------- ----- ----- -------
// Wire All I2C_PINS_16_17 16 17
// Wire All I2C_PINS_18_19 19* 18 +
// Wire 3.5/3.6 I2C_PINS_7_8 7 8
// Wire 3.5/3.6 I2C_PINS_33_34 33 34
// Wire 3.5/3.6 I2C_PINS_47_48 47 48
// Wire1 LC I2C_PINS_22_23 22 23 +
// Wire1 3.1/3.2 I2C_PINS_26_31 26 31
// Wire1 3.1/3.2 I2C_PINS_29_30 29 30 +
// Wire1 3.5/3.6 I2C_PINS_37_38 37 38 +
// Wire2 3.5/3.6 I2C_PINS_3_4 3 4 +
// Wire3 3.6 I2C_PINS_56_57 57* 56 +
// (note: in almost all cases SCL is the lower pin #, except cases marked *)
// ^pullup = I2C_PULLUP_EXT, I2C_PULLUP_INT (default I2C_PULLUP_EXT)
//
inline uint8_t pinConfigure(i2c_pins pins, i2c_pullup pullup=I2C_PULLUP_EXT)
{ return pinConfigure_(i2c, bus, mapSCL(pins), mapSDA(pins), pullup, 1); }
inline uint8_t pinConfigure(uint8_t pinSCL, uint8_t pinSDA, i2c_pullup pullup=I2C_PULLUP_EXT)
{ return pinConfigure_(i2c, bus, pinSCL, pinSDA, pullup, 1); }
//
// ------------------------------------------------------------------------------------------------------
// Set SCL/SDA - change the SCL or SDA pin
// return: none
// parameters:
// pin = pin to use, if invalid then no change will occur
inline void setSCL(uint8_t pin) { pinConfigure_(i2c, bus, pin, i2c->currentSDA, i2c->currentPullup, 1); }
inline void setSDA(uint8_t pin) { pinConfigure_(i2c, bus, i2c->currentSCL, pin, i2c->currentPullup, 1); }
//
// ------------------------------------------------------------------------------------------------------
// Get SCL/SDA - get the current SCL or SDA pin
// return: pin used
//
inline uint8_t getSCL(void) { return i2c->currentSCL; }
inline uint8_t getSDA(void) { return i2c->currentSDA; }
// ------------------------------------------------------------------------------------------------------
// Set Default Timeout - sets the default timeout to be applied to all functions called with a timeout of
// zero (the default in cases where timeout is not specified). The default is
// initially zero (infinite wait).
// return: none
// parameters:
// timeout = timeout in microseconds
inline void setDefaultTimeout(uint32_t timeout) { i2c->defTimeout = timeout; }
// ------------------------------------------------------------------------------------------------------
// Acquire Bus - acquires bus in Master mode and escalates priority as needed, intended
// for internal use only
// return: 1=success, 0=fail (cannot acquire bus)
// parameters:
// timeout = timeout in microseconds
// forceImm = flag to indicate if immediate mode is required
//
static uint8_t acquireBus_(struct i2cStruct* i2c, uint8_t bus, uint32_t timeout, uint8_t& forceImm);
// ------------------------------------------------------------------------------------------------------
// Reset Bus - toggles SCL until SDA line is released (9 clocks max). This is used to correct
// a hung bus in which a Slave device missed some clocks and remains stuck outputting
// a low signal on SDA (thereby preventing START/STOP signaling).
// return: none
//
static void resetBus_(struct i2cStruct* i2c, uint8_t bus);
inline void resetBus(void) { resetBus_(i2c, bus); }
// ------------------------------------------------------------------------------------------------------
// Setup Master Transmit - initialize Tx buffer for transmit to slave at address
// return: none
// parameters:
// address = target 7bit slave address
//
void beginTransmission(uint8_t address);
inline void beginTransmission(int address) { beginTransmission((uint8_t)address); } // Wire compatibility
// ------------------------------------------------------------------------------------------------------
// Master Transmit (base routine) - cannot be static due to call to getError() and in turn getWriteError()
//
uint8_t endTransmission(struct i2cStruct* i2c, uint8_t bus, i2c_stop sendStop, uint32_t timeout);
//
// Master Transmit - blocking routine, transmits Tx buffer to slave. i2c_stop parameter can be used
// to indicate if command should end with a STOP(I2C_STOP) or not (I2C_NOSTOP).
// Timeout parameter can be optionally specified.
// return: 0=success, 1=data too long, 2=recv addr NACK, 3=recv data NACK, 4=other error
// parameters:
// ^i2c_stop = I2C_NOSTOP, I2C_STOP (default STOP)
// ^timeout = timeout in microseconds (default 0 = infinite wait)
//
inline uint8_t endTransmission(i2c_stop sendStop=I2C_STOP, uint32_t timeout=0) { return endTransmission(i2c, bus, sendStop, timeout); }
inline uint8_t endTransmission(uint8_t sendStop) { return endTransmission(i2c, bus, (i2c_stop)sendStop, 0); } // Wire compatibility
// ------------------------------------------------------------------------------------------------------
// Send Master Transmit (base routine)
//
static void sendTransmission_(struct i2cStruct* i2c, uint8_t bus, i2c_stop sendStop, uint32_t timeout);
//
// Send Master Transmit - non-blocking routine, starts transmit of Tx buffer to slave. i2c_stop parameter can be
// used to indicate if command should end with a STOP (I2C_STOP) or not (I2C_NOSTOP). Use
// done(), finish(), or onTransmitDone() callback to determine completion and
// status() to determine success/fail. Note that sendTransmission() does not currently
// support timeouts (aside from initial bus acquisition which does support it).
// return: none
// parameters:
// ^i2c_stop = I2C_NOSTOP, I2C_STOP (default STOP)
//
inline void sendTransmission(i2c_stop sendStop=I2C_STOP) { sendTransmission_(i2c, bus, sendStop, 0); }
// ------------------------------------------------------------------------------------------------------
// Master Receive (base routine)
//
static size_t requestFrom_(struct i2cStruct* i2c, uint8_t bus, uint8_t addr, size_t len, i2c_stop sendStop, uint32_t timeout);
//
// Master Receive - Requests length bytes from slave at address. Receive data will be placed in the Rx buffer.
// i2c_stop parameter can be used to indicate if command should end with a STOP (I2C_STOP) or
// not (I2C_NOSTOP). Timeout parameter can be optionally specified.
// return: #bytes received = success, 0=fail (0 length request, NAK, timeout, or bus error)
// parameters:
// address = target 7bit slave address
// length = number of bytes requested
// ^i2c_stop = I2C_NOSTOP, I2C_STOP (default STOP)
// ^timeout = timeout in microseconds (default 0 = infinite wait)
//
inline size_t requestFrom(uint8_t addr, size_t len, i2c_stop sendStop=I2C_STOP, uint32_t timeout=0)
{ return requestFrom_(i2c, bus, addr, len, sendStop, timeout); }
inline size_t requestFrom(int addr, int len)
{ return requestFrom_(i2c, bus, (uint8_t)addr, (size_t)len, I2C_STOP, 0); } // Wire compatibility
inline uint8_t requestFrom(uint8_t addr, uint8_t len, uint8_t sendStop=1)
{ return (uint8_t)requestFrom_(i2c, bus, addr, (size_t)len, (i2c_stop)sendStop, 0); } // Wire compatibility
// ------------------------------------------------------------------------------------------------------
// Start Master Receive (base routine)
//
static void sendRequest_(struct i2cStruct* i2c, uint8_t bus, uint8_t addr, size_t len, i2c_stop sendStop, uint32_t timeout);
//
// Start Master Receive - non-blocking routine, starts request for length bytes from slave at address. Receive
// data will be placed in the Rx buffer. i2c_stop parameter can be used to indicate if
// command should end with a STOP (I2C_STOP) or not (I2C_NOSTOP). Use done(), finish()
// or onReqFromDone() callback to determine completion and status() to determine
// success/fail.
// return: none
// parameters:
// address = target 7bit slave address
// length = number of bytes requested
// ^i2c_stop = I2C_NOSTOP, I2C_STOP (default STOP)
//
inline void sendRequest(uint8_t addr, size_t len, i2c_stop sendStop=I2C_STOP) { sendRequest_(i2c, bus, addr, len, sendStop, 0); }
// ------------------------------------------------------------------------------------------------------
// Get Wire Error - returns "Wire" error code from a failed Tx/Rx command
// return: 0=success, 1=data too long, 2=recv addr NACK, 3=recv data NACK, 4=other error
//
uint8_t getError(void);
// ------------------------------------------------------------------------------------------------------
// Return Status - returns current status of I2C (enum return value)
// return: I2C_WAITING, I2C_TIMEOUT, I2C_ADDR_NAK, I2C_DATA_NAK, I2C_ARB_LOST, I2C_BUF_OVF,
// I2C_NOT_ACQ, I2C_DMA_ERR, I2C_SENDING, I2C_SEND_ADDR, I2C_RECEIVING, I2C_SLAVE_TX, I2C_SLAVE_RX
//
inline i2c_status status(void) { return i2c->currentStatus; }
// ------------------------------------------------------------------------------------------------------
// Return Status (base routine)
//
static uint8_t done_(struct i2cStruct* i2c);
//
// Done Check - returns simple complete/not-complete value to indicate I2C status
// return: 1=Tx/Rx complete (with or without errors), 0=still running
//
inline uint8_t done(void) { return done_(i2c); }
// ------------------------------------------------------------------------------------------------------
// Return Status (base routine)
//
static uint8_t finish_(struct i2cStruct* i2c, uint8_t bus, uint32_t timeout);
//
// Finish - blocking routine, loops until Tx/Rx is complete. Timeout parameter can be optionally specified.
// return: 1=success (Tx or Rx completed, no error), 0=fail (NAK, timeout or Arb Lost)
// parameters:
// ^timeout = timeout in microseconds (default 0 = infinite wait)
//
inline uint8_t finish(uint32_t timeout=0) { return finish_(i2c, bus, timeout); }
// ------------------------------------------------------------------------------------------------------
// Write - write data byte to Tx buffer
// return: #bytes written = success, 0=fail
// parameters:
// data = data byte
//
size_t write(uint8_t data);
inline size_t write(unsigned long n) { return write((uint8_t)n); }
inline size_t write(long n) { return write((uint8_t)n); }
inline size_t write(unsigned int n) { return write((uint8_t)n); }
inline size_t write(int n) { return write((uint8_t)n); }
// ------------------------------------------------------------------------------------------------------
// Write Array - write count number of bytes from data array to Tx buffer
// return: #bytes written = success, 0=fail
// parameters:
// data = pointer to uint8_t (or char) array of data
// count = number of bytes to write
//
// As a special case C-strings (null terminated) can be written without a count byte
//
size_t write(const uint8_t* data, size_t count);
inline size_t write(const char* str, size_t count) { return write((const uint8_t*)str, count); }
inline size_t write(const char* str) { return write((const uint8_t*)str, strlen(str)+1); } // write C-string
// ------------------------------------------------------------------------------------------------------
// Available - returns number of remaining available bytes in Rx buffer
// return: #bytes available
//
inline int available(void) { return i2c->rxBufferLength - i2c->rxBufferIndex; }
// ------------------------------------------------------------------------------------------------------
// Read (base routine)
//
static int read_(struct i2cStruct* i2c);
//
// Read - returns next data byte (signed int) from Rx buffer
// return: data, -1 if buffer empty
//
inline int read(void) { return read_(i2c); }
// ------------------------------------------------------------------------------------------------------
// Read Array - read count number of bytes from Rx buffer to data array
// return: #bytes read
// parameters:
// data = pointer to uint8_t (or char) array of data
// count = number of bytes to read
//
static size_t read_(struct i2cStruct* i2c, uint8_t* data, size_t count);
inline size_t read(uint8_t* data, size_t count) { return read_(i2c, data, count); }
inline size_t read(char* str, size_t count) { return read_(i2c, (uint8_t*)str, count); }
// ------------------------------------------------------------------------------------------------------
// Peek (base routine)
//
static int peek_(struct i2cStruct* i2c);
//
// Peek - returns next data byte (signed int) from Rx buffer without removing it from Rx buffer
// return: data, -1 if buffer empty
//
inline int peek(void) { return peek_(i2c); }
// ------------------------------------------------------------------------------------------------------
// Read Byte (base routine)
//
static uint8_t readByte_(struct i2cStruct* i2c);
//
// Read Byte - returns next data byte (uint8_t) from Rx buffer
// return: data, 0 if buffer empty
//
inline uint8_t readByte(void) { return readByte_(i2c); }
// ------------------------------------------------------------------------------------------------------
// Peek Byte (base routine)
//
static uint8_t peekByte_(struct i2cStruct* i2c);
//
// Peek Byte - returns next data byte (uint8_t) from Rx buffer without removing it from Rx buffer
// return: data, 0 if buffer empty
//
inline uint8_t peekByte(void) { return peekByte_(i2c); }
// ------------------------------------------------------------------------------------------------------
// Flush (not implemented)
//
inline void flush(void) {}
// ------------------------------------------------------------------------------------------------------
// Get Rx Address - returns target address of incoming I2C command. Used for Slaves operating over an address range.
// return: rxAddr of last received command
//
inline uint8_t getRxAddr(void) { return i2c->rxAddr; }
// ------------------------------------------------------------------------------------------------------
// Set callback function for Master Tx
//
inline void onTransmitDone(void (*function)(void)) { i2c->user_onTransmitDone = function; }
// ------------------------------------------------------------------------------------------------------
// Set callback function for Master Rx
//
inline void onReqFromDone(void (*function)(void)) { i2c->user_onReqFromDone = function; }
// ------------------------------------------------------------------------------------------------------
// Set callback function for Slave Rx
//
inline void onReceive(void (*function)(size_t len)) { i2c->user_onReceive = function; }
// ------------------------------------------------------------------------------------------------------
// Set callback function for Slave Tx
//
inline void onRequest(void (*function)(void)) { i2c->user_onRequest = function; }
// ------------------------------------------------------------------------------------------------------
// Set callback function for Errors
//
inline void onError(void (*function)(void)) { i2c->user_onError = function; }
// ------------------------------------------------------------------------------------------------------
// Get error count from specified counter
// return: error count
// parameters:
// counter = I2C_ERRCNT_RESET_BUS, I2C_ERRCNT_TIMEOUT, I2C_ERRCNT_ADDR_NAK, I2C_ERRCNT_DATA_NAK,
// I2C_ERRCNT_ARBL, I2C_ERRCNT_NOT_ACQ, I2C_ERRCNT_DMA_ERR
//
inline uint32_t getErrorCount(i2c_err_count counter) { return i2c->errCounts[counter]; }
// ------------------------------------------------------------------------------------------------------
// Zero error count of specified counter
// return: none
// parameters:
// counter = I2C_ERRCNT_RESET_BUS, I2C_ERRCNT_TIMEOUT, I2C_ERRCNT_ADDR_NAK, I2C_ERRCNT_DATA_NAK,
// I2C_ERRCNT_ARBL, I2C_ERRCNT_NOT_ACQ, I2C_ERRCNT_DMA_ERR
//
inline void zeroErrorCount(i2c_err_count counter) { i2c->errCounts[counter] = 0; }
// ------------------------------------------------------------------------------------------------------
// For compatibility with pre-1.0 sketches and libraries
inline void send(uint8_t b) { write(b); }
inline void send(uint8_t* s, uint8_t n) { write(s, n); }
inline void send(int n) { write((uint8_t)n); }
inline void send(char* s) { write(s); }
inline uint8_t receive(void) { int c = read(); return (c<0) ? 0 : c; }
};
extern i2c_t3 Wire;
#if I2C_BUS_NUM >= 2
extern i2c_t3 Wire1;
#endif
#if I2C_BUS_NUM >= 3
extern i2c_t3 Wire2;
#endif
#if I2C_BUS_NUM >= 4
extern i2c_t3 Wire3;
#endif
#endif // I2C_T3_H