ngc 1.5.0
 
Loading...
Searching...
No Matches
ngcbI2C.hpp
Go to the documentation of this file.
1
8#ifndef ngcbI2C_H
9#define ngcbI2C_H
10
11
12#ifndef __cplusplus
13#error This is a C++ include file and cannot be used from plain C
14#endif
15
16#include <stdio.h>
17#include <stdlib.h>
18
20#define ngcbI2C_TX_SIZE7(n) ((((n + 1) * 8) + 2) * 3)
21
23#define ngcbI2C_TX_SIZE10(n) ((((n + 2) * 8) + 2) * 3)
24
25/*
26 * Error codes
27 */
28
30#define ngcbI2C_ERR_CLK 0x0000000A
31
33#define ngcbI2C_ERR_ACK 0x0000000B
34
38class ngcbI2C {
39public:
44 ngcbI2C() {Init_(0, 1, 0);}
45
51 explicit ngcbI2C(int cnt) {Init_(0, 1, cnt);}
52
57 ngcbI2C(int scl, int sda) {Init_(scl, sda, 0);}
58
68 ngcbI2C(int scl, int sda, int cnt) {Init_(scl, sda, cnt);}
69
74 ngcbI2C(int scl, int sda, int sclIn, int sdaIn, int ackIn, int cnt) {
75 Init_(scl, sda, cnt);
76 sclIn_ = sclIn;
77 sdaIn_ = sdaIn;
78 ackIn_ = ackIn;
79 }
80
82 virtual ~ngcbI2C() {}
83
85 char *ErrMsg() {return (erms_);}
86
88 void AckOn() {ignoreAck_ = 0;}
89
91 void AckOff() {ignoreAck_ = 1;}
92
94 void SCL_IN(int bit) {sclIn_ = bit;}
95
97 void SDA_IN(int bit) {sdaIn_ = bit; ackIn_ = sdaIn_;}
98
100 void ACK_IN(int bit) {ackIn_ = bit;}
101
103 void SDA_DIR_SWITCH(int bit) {sdaDirSwitch_ = bit;}
104
106 void SCL_DIR_SWITCH(int bit) {sclDirSwitch_ = bit;}
107
109 void ClkStretching(int rx, int tx) {
110 /*
111 * Clock-stretching capability on RX-operations
112 */
113 if (rx < 0) rxStretching_ = 0;
114 else rxStretching_ = rx;
115
116 /*
117 * Clock-stretching capability on TX-operations
118 */
119 if (tx < 0) txStretching_ = 0;
120 else txStretching_ = tx;
121 }
122
124 void ClkStretchCnt(int cnt) {
125 if (cnt < 0) clkStretchCnt_ = 0;
126 else clkStretchCnt_ = cnt;
127 }
128
130 int ClkStretchCnt() {return (clkStretchCnt_);}
131
133 int Write(int addr, const char *byte, int n) {
134 int byteBuf[8 * 3];
135 int *b;
136 int i = 0;
137 int res;
138
139 erms_[0] = '\0';
140
141 /*
142 * Start
143 */
144 res = Start_();
145 if (res != 0)
146 {
147 return (res);
148 }
149
150 b = byteBuf;
151
152 /*
153 * 7-Bit address
154 */
155 for (i=6;i>=0;i--)
156 {
157 *b++ = ((addr >> i) & 0x1) << sda_;
158 *b++ = (((addr >> i) & 0x1) << sda_) | (1 << scl_);
159 *b++ = ((addr >> i) & 0x1) << sda_;
160 }
161
162 /*
163 * R/W bit (0 for write-operation)
164 */
165 *b++ = 0x0;
166 *b++ = 1 << scl_;
167 *b++ = 0x0;
168
169 /*
170 * Send the address byte
171 */
172 res = SendByte_(byteBuf);
173 if (res != 0)
174 {
175 return (res);
176 }
177
178 /*
179 * Now send the n data bytes
180 */
181 for (i=0;i<n;i++)
182 {
183 int j;
184
185 b = byteBuf;
186 for (j=7;j>=0;j--)
187 {
188 *b++ = ((byte[i] >> j) & 0x1) << sda_;
189 *b++ = (((byte[i] >> j) & 0x1) << sda_) | (1 << scl_);
190 *b++ = ((byte[i] >> j) & 0x1) << sda_;
191 }
192
193 res = SendByte_(byteBuf);
194 if (res != 0)
195 {
196 return (res);
197 }
198 }
199
200 /*
201 * Stop
202 */
203 res = Stop_();
204 if (res != 0)
205 {
206 return (res);
207 }
208
209 return (0);
210 }
211
213 int Write10(int addr, const char *byte, int n) {
214 int byteBuf[8 * 3];
215 int *b;
216 int i = 0;
217 int res;
218 int a0 = addr & 0xff;
219 int a1 = 0xf0 | ((addr >> 7) & 0x6);
220
221 erms_[0] = '\0';
222
223 /*
224 * Start
225 */
226 res = Start_();
227 if (res != 0)
228 {
229 return (res);
230 }
231
232 /*
233 * 10-Bit marker + 2 MSB bits of address + R/W
234 */
235 b = byteBuf;
236 for (i=7;i>=0;i--)
237 {
238 *b++ = ((a1 >> i) & 0x1) << sda_;
239 *b++ = (((a1 >> i) & 0x1) << sda_) | (1 << scl_);
240 *b++ = ((a1 >> i) & 0x1) << sda_;
241 }
242 res = SendByte_(byteBuf);
243 if (res != 0)
244 {
245 return (res);
246 }
247
248 /*
249 * 8 LSB bits of address
250 */
251 b = byteBuf;
252 for (i=7;i>=0;i--)
253 {
254 *b++ = ((a0 >> i) & 0x1) << sda_;
255 *b++ = (((a0 >> i) & 0x1) << sda_) | (1 << scl_);
256 *b++ = ((a0 >> i) & 0x1) << sda_;
257 }
258 res = SendByte_(byteBuf);
259 if (res != 0)
260 {
261 return (res);
262 }
263
264 /*
265 * Now send the n bytes
266 */
267 for (i=0;i<n;i++)
268 {
269 int j;
270
271 b = byteBuf;
272 for (j=7;j>=0;j--)
273 {
274 *b++ = ((byte[i] >> j) & 0x1) << sda_;
275 *b++ = (((byte[i] >> j) & 0x1) << sda_) | (1 << scl_);
276 *b++ = ((byte[i] >> j) & 0x1) << sda_;
277 }
278
279 res = SendByte_(byteBuf);
280 if (res != 0)
281 {
282 return (res);
283 }
284 }
285
286 /*
287 * Stop
288 */
289 res = Stop_();
290 if (res != 0)
291 {
292 return (res);
293 }
294
295 return (0);
296 }
297
299 int Read(int addr, char *byte, int n) {
300 int byteBuf[8 * 3];
301 int *b;
302 int i = 0;
303 int res;
304
305 erms_[0] = '\0';
306
307 /*
308 * Start
309 */
310 res = Start_();
311 if (res != 0)
312 {
313 return (res);
314 }
315
316 b = byteBuf;
317
318 /*
319 * 7-Bit address
320 */
321 for (i=6;i>=0;i--)
322 {
323 *b++ = ((addr >> i) & 0x1) << sda_;
324 *b++ = (((addr >> i) & 0x1) << sda_) | (1 << scl_);
325 *b++ = ((addr >> i) & 0x1) << sda_;
326 }
327
328 /*
329 * R/W bit (1 for read-operation)
330 */
331 *b++ = (0x1 << sda_) | (0x0 << scl_);
332 *b++ = (0x1 << sda_) | (0x1 << scl_);
333 *b++ = (0x1 << sda_) | (0x0 << scl_);
334
335 /*
336 * Send the address byte
337 */
338 res = SendByte_(byteBuf);
339 if (res != 0)
340 {
341 return (res);
342 }
343
344 /*
345 * Now read the n bytes
346 */
347 for (i=0;i<n;i++)
348 {
349 res = RecvByte_(&byte[i], (i == (n-1)));
350 if (res != 0)
351 {
352 return (res);
353 }
354 }
355
356 /*
357 * Stop
358 */
359 res = Stop_();
360 if (res != 0)
361 {
362 return (res);
363 }
364
365 return (0);
366 }
367
369 int Read10(int addr, char *byte, int n) {
370 int byteBuf[8 * 3];
371 int *b;
372 int i = 0;
373 int res;
374 int a0 = addr & 0xff;
375 int a1 = 0xf1 | ((addr >> 7) & 0x6);
376
377 erms_[0] = '\0';
378
379 /*
380 * Start
381 */
382 res = Start_();
383 if (res != 0)
384 {
385 return (res);
386 }
387
388 /*
389 * 10-Bit marker + 2 MSB bits of address + R/W
390 */
391 b = byteBuf;
392 for (i=7;i>=0;i--)
393 {
394 *b++ = ((a1 >> i) & 0x1) << sda_;
395 *b++ = (((a1 >> i) & 0x1) << sda_) | (1 << scl_);
396 *b++ = ((a1 >> i) & 0x1) << sda_;
397 }
398 res = SendByte_(byteBuf);
399 if (res != 0)
400 {
401 return (res);
402 }
403
404 /*
405 * 8 LSB bits of address
406 */
407 b = byteBuf;
408 for (i=7;i>=0;i--)
409 {
410 *b++ = ((a0 >> i) & 0x1) << sda_;
411 *b++ = (((a0 >> i) & 0x1) << sda_) | (1 << scl_);
412 *b++ = ((a0 >> i) & 0x1) << sda_;
413 }
414 res = SendByte_(byteBuf);
415 if (res != 0)
416 {
417 return (res);
418 }
419
420 /*
421 * Now read the n bytes
422 */
423 for (i=0;i<n;i++)
424 {
425 res = RecvByte_(&byte[i]);
426 if (res != 0)
427 {
428 return (res);
429 }
430 }
431
432 /*
433 * Stop
434 */
435 res = Stop_();
436 if (res != 0)
437 {
438 return (res);
439 }
440
441 return (0);
442 }
443
445 int LastState() {
446 int s = lastState_ & (1 << sda_) & (1 << scl_);
447 return (s);
448 }
449
450protected:
452 virtual int OutCB(int d, int *resultCode, char *erms) {
453 char s[33];
454 *resultCode = 0;
455 erms[0] = '\0';
456 Int2Bin_(s, d);
457 fprintf(stdout, "<%s>\n", s);
458 return (0);
459 }
460
462 virtual int InCB(int *d, int *resultCode, char *erms) {
463 *resultCode = 0;
464 erms[0] = '\0';
465 *d = 0;
466 return (0);
467 }
468
469private:
471 char erms_[256];
472
474 int scl_;
475
477 int sda_;
478
480 int sclIn_;
481
483 int sdaIn_;
484
486 int ackIn_;
487
489 int sdaDirSwitch_;
490
492 int sclDirSwitch_;
493
495 int lastClkState_;
496
498 int clkStretchCnt_;
499
501 int ignoreAck_;
502
504 int txStretching_;
505
507 int rxStretching_;
508
510 int lastState_;
511
513 void Init_(int scl, int sda, int cnt) {
514 scl_ = scl;
515 sda_ = sda;
516 clkStretchCnt_ = cnt;
517
518 sclIn_ = scl_; // same as SCL output
519 sdaIn_ = sda_; // same as SDA output
520 ackIn_ = sdaIn_; // same as SDA input
521 sdaDirSwitch_ = -1; // SDA direction switch disabled
522 sclDirSwitch_ = -1; // SCL direction disabled
523
524 erms_[0] = '\0';
525
526 lastClkState_ = -1; // unknown
527 lastState_ = 0x0; // all lines zero
528 ignoreAck_ = 0; // consider acknowledge signal
529 txStretching_ = 0; // no clock stretching for write operations
530 rxStretching_ = 1; // clock stretching for read operations
531 }
532
534 int Start_() {
535 int buf[2];
536 buf[0] = (0x1 << sda_) | (0x1 << scl_);
537 buf[1] = (0x0 << sda_) | (0x1 << scl_);
538 return (Out_(buf, 2));
539 }
540
542 int Stop_() {
543 int buf[2];
544 buf[0] = (0x0 << sda_) | (0x1 << scl_);
545 buf[1] = (0x1 << sda_) | (0x1 << scl_);
546 return (Out_(buf, 2));
547 }
548
550 int SendByte_(const int *buf) {
551 int a;
552 int res;
553
554 /*
555 * Send the 8 bits
556 */
557 res = Out_(buf, 8 * 3, txStretching_);
558 if (res != 0)
559 {
560 return (res);
561 }
562
563 /*
564 * Read the acknowledge bit
565 */
566 res = GetAck_(&a);
567 if (res != 0)
568 {
569 return (res);
570 }
571
572 if (a)
573 {
574 /*
575 * Ack is high - we have to stop
576 */
577 res = Stop_();
578 if (res != 0)
579 {
580 return (res);
581 }
582 else
583 {
584 sprintf(ErrMsg(), "no acknowledge from slave-device");
585 return (ngcbI2C_ERR_ACK);
586 }
587 }
588
589 return (0);
590 }
591
593 int RecvByte_(char *byte, int last=0) {
594 int d;
595 int buf[3];
596 int res;
597 int i;
598 int ds = 0;
599
600 if (sdaDirSwitch_ >= 0)
601 {
602 /*
603 * Switch SDA direction
604 */
605 ds = 1 << sdaDirSwitch_;
606 buf[0] = (0x1 << sda_) | (0x0 << scl_) | ds;
607 res = Out_(buf, 1);
608 if (res != 0)
609 {
610 return (res);
611 }
612 }
613
614 *byte = 0;
615 for (i=7;i>=0;i--)
616 {
617 /*
618 * Issue clock pulse
619 */
620 buf[0] = (0x1 << sda_) | (0x0 << scl_) | ds;
621 buf[1] = (0x1 << sda_) | (0x1 << scl_) | ds;
622 res = Out_(buf, 2, rxStretching_);
623 if (res != 0)
624 {
625 return (res);
626 }
627
628 /*
629 * Read data
630 */
631 res = In_(&d);
632 if (res != 0)
633 {
634 return (res);
635 }
636
637 /*
638 * Last edge on clock-line
639 */
640 buf[0] = (0x1 << sda_) | (0x0 << scl_) | ds;
641 res = Out_(buf, 1);
642 if (res != 0)
643 {
644 return (res);
645 }
646
647 /*
648 * Shift data bit to correct position
649 */
650 *byte |= (char)(((d >> sdaIn_) & 0x1) << i);
651 }
652
653 if (sdaDirSwitch_ >= 0)
654 {
655 /*
656 * Switch back SDA direction
657 */
658 buf[0] = (0x1 << sda_) | (0x0 << scl_);
659 res = Out_(buf, 1);
660 if (res != 0)
661 {
662 return (res);
663 }
664 }
665
666 if (!last)
667 {
668 /*
669 * Issue acknowledge (hold data-line low)
670 */
671 buf[0] = (0x0 << sda_) | (0x0 << scl_);
672 buf[1] = (0x0 << sda_) | (0x1 << scl_);
673 buf[2] = (0x0 << sda_) | (0x0 << scl_);
674 }
675 else
676 {
677 /*
678 * Deny acknowledge (release data-line)
679 */
680 buf[0] = (0x1 << sda_) | (0x0 << scl_);
681 buf[1] = (0x1 << sda_) | (0x1 << scl_);
682 buf[2] = (0x1 << sda_) | (0x0 << scl_);
683 }
684 res = Out_(buf, 3, txStretching_);
685 if (res != 0)
686 {
687 return (res);
688 }
689
690 return (0);
691 }
692
694 int GetAck_(int *a) {
695 int buf[2];
696 int res;
697
698 /*
699 * Release data-line and issue clock pulse. Unless the
700 * acknowledge signal is ignored we have to consider
701 * clock-stretching (if enabled)
702 */
703 buf[0] = (0x1 << sda_) | (0x0 << scl_);
704 buf[1] = (0x1 << sda_) | (0x1 << scl_);
705 res = Out_(buf, 2, (!ignoreAck_ && rxStretching_) || txStretching_);
706 if (res != 0)
707 {
708 return (res);
709 }
710
711 if (!ignoreAck_)
712 {
713 if ((sdaDirSwitch_ >= 0) && ((ackIn_ == sdaIn_) || (ackIn_ == sda_)))
714 {
715 /*
716 * Switch SDA direction to read the acknowledge signal
717 */
718 buf[0] = (0x1 << sda_) | (0x1 << scl_) | (1 << sdaDirSwitch_);
719 res = Out_(buf, 1);
720 if (res != 0)
721 {
722 return (res);
723 }
724 }
725
726 /*
727 * Read actual state
728 */
729 res = In_(a, ackIn_);
730 if (res != 0)
731 {
732 return (res);
733 }
734 }
735 else
736 {
737 /*
738 * We assume the acknowledge signal was there
739 */
740 *a = 0;
741 }
742
743 /*
744 * Last edge on clock-line
745 */
746 buf[0] = (0x1 << sda_) | (0x0 << scl_);
747 res = Out_(buf, 1);
748 if (res != 0)
749 {
750 return (res);
751 }
752
753 return (0);
754 }
755
757 int Out_(const int *buf, int size, int doStretching=0) {
758 int i, r;
759
760 for (i=0;i<size;i++)
761 {
762 /*
763 * Send new state
764 */
765 if (OutCB(buf[i], &r, erms_) != 0)
766 {
767 lastClkState_ = -1;
768 return (r);
769 }
770
771 /*
772 * Always save last state (here we use the full word to
773 * have it for whatever purpose)
774 */
775 lastState_ = buf[i];
776
777 if (doStretching && (clkStretchCnt_ > 0))
778 {
779 int thisClkState = (buf[i] >> scl_) & 0x1;
780
781 if ((lastClkState_ == 0) && (thisClkState == 1))
782 {
783 int b = 0;
784 int cnt = 0;
785
786 if (sclDirSwitch_ >= 0)
787 {
788 /*
789 * Switch SCL direction to read the clock-line signal
790 */
791 if (OutCB(lastState_ | (1 << sclDirSwitch_), &r, erms_) != 0)
792 {
793 lastClkState_ = -1;
794 return (r);
795 }
796 }
797
798 /*
799 * Poll for clock high
800 */
801 while (!((b >> sclIn_) & 0x1) && (cnt < clkStretchCnt_))
802 {
803 if (InCB(&b, &r, erms_) != 0)
804 {
805 return (r);
806 }
807
808 cnt++;
809 if (cnt >= clkStretchCnt_)
810 {
811 sprintf(ErrMsg(), "clock line is forced low");
812 return (ngcbI2C_ERR_CLK);
813 }
814
815 // delay (TBD)
816 }
817
818 if (sclDirSwitch_ >= 0)
819 {
820 /*
821 * Switch back SCL direction
822 */
823 if (OutCB(lastState_, &r, erms_) != 0)
824 {
825 lastClkState_ = -1;
826 return (r);
827 }
828 }
829 }
830 }
831
832 /*
833 * Save last clock state
834 */
835 lastClkState_ = (buf[i] >> scl_) & 0x1;
836 }
837
838 return (0);
839 }
840
842 int In_(int *d) {return (In_(d, sdaIn_));}
843
845 int In_(int *d, int line) {
846 int b, r;
847
848 /*
849 * Read actual state
850 */
851 if (InCB(&b, &r, erms_) != 0)
852 {
853 *d = 0;
854 return (r);
855 }
856
857 /*
858 * Get data bit
859 */
860 *d = (b >> line) & 0x1;
861
862 return (0);
863 }
864
866 void Int2Bin_(char *str, int in) {
867 int x = in;
868 int i;
869
870 for (i=0;i<32;i++)
871 {
872 if ((x & 0x00000001) == 1) str[31 - i]='1';
873 else str[31 - i]='0';
874 x = x >> 1;
875 }
876 str[32] = '\0';
877 }
878
879};
880
881
882#endif
ngcbI2C()
Definition ngcbI2C.hpp:44
void AckOff()
Disable acknowledge handling.
Definition ngcbI2C.hpp:91
void AckOn()
Enable acknowledge handling.
Definition ngcbI2C.hpp:88
virtual int OutCB(int d, int *resultCode, char *erms)
Output call-back (1 word)
Definition ngcbI2C.hpp:452
void ClkStretching(int rx, int tx)
Set clock-stretching capabilities.
Definition ngcbI2C.hpp:109
void ClkStretchCnt(int cnt)
Set counter for clock-stretching.
Definition ngcbI2C.hpp:124
char * ErrMsg()
Return error-message buffer.
Definition ngcbI2C.hpp:85
int LastState()
Return last state of SDA and SCL.
Definition ngcbI2C.hpp:445
int Write10(int addr, const char *byte, int n)
10-bit write operation
Definition ngcbI2C.hpp:213
virtual ~ngcbI2C()
Destructor.
Definition ngcbI2C.hpp:82
int Read(int addr, char *byte, int n)
Standard 7-bit read operation.
Definition ngcbI2C.hpp:299
ngcbI2C(int cnt)
Definition ngcbI2C.hpp:51
void SDA_IN(int bit)
Define data-line bit for read (by default ack-line is the same)
Definition ngcbI2C.hpp:97
int Read10(int addr, char *byte, int n)
10-bit read operation
Definition ngcbI2C.hpp:369
void SCL_IN(int bit)
Define clock-line bit fot read (clock-stretching)
Definition ngcbI2C.hpp:94
void ACK_IN(int bit)
Define ack-line bit.
Definition ngcbI2C.hpp:100
ngcbI2C(int scl, int sda, int cnt)
Definition ngcbI2C.hpp:68
void SCL_DIR_SWITCH(int bit)
Define SCL direction switch bit.
Definition ngcbI2C.hpp:106
int ClkStretchCnt()
Return clock-stretching counter.
Definition ngcbI2C.hpp:130
ngcbI2C(int scl, int sda, int sclIn, int sdaIn, int ackIn, int cnt)
Definition ngcbI2C.hpp:74
virtual int InCB(int *d, int *resultCode, char *erms)
Input call-back (1 word)
Definition ngcbI2C.hpp:462
int Write(int addr, const char *byte, int n)
Standard 7-bit write operation.
Definition ngcbI2C.hpp:133
void SDA_DIR_SWITCH(int bit)
Define SDA direction switch bit.
Definition ngcbI2C.hpp:103
ngcbI2C(int scl, int sda)
Definition ngcbI2C.hpp:57
#define ngcbI2C_ERR_CLK
I2C-bus clock line forced low.
Definition ngcbI2C.hpp:30
#define ngcbI2C_ERR_ACK
I2C-bus no acknowledge.
Definition ngcbI2C.hpp:33