ArduboyI2C Library
Loading...
Searching...
No Matches
ArduboyI2C.h
Go to the documentation of this file.
1/*
2MIT License
3
4Copyright (c) 2024 sub1inear
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
28#pragma once
29#include <avr/interrupt.h>
30#include <avr/power.h>
31#include <util/twi.h>
32#include <stdint.h>
33
34#ifndef I2C_FREQUENCY
43#define I2C_FREQUENCY 100000
44#endif
45
46#ifndef I2C_BUFFER_SIZE
52#define I2C_BUFFER_SIZE 32
53#elif I2C_BUFFER_SIZE > 256
54#error "I2C_BUFFER_SIZE is too big."
55#endif
56
57#ifndef I2C_BUS_BUSY_CHECKS
68#define I2C_BUS_BUSY_CHECKS 16
69#endif
70
71
72#ifndef I2C_SCL_PIN
78#define I2C_SCL_PIN PIND
79#endif
80
81#ifndef I2C_SCL_BIT
87#define I2C_SCL_BIT PIND0
88#endif
89
90#ifndef I2C_SDA_PIN
96#define I2C_SDA_PIN PIND
97#endif
98
99#ifndef I2C_SDA_BIT
105#define I2C_SDA_BIT PIND1
106#endif
107
108#ifdef __DOXYGEN__
109
115#define I2C_MAX_PLAYERS
116
117#endif
118
119
125#define TW_SUCCESS 0xFF
126
132#define I2C_HANDSHAKE_FAILED 0xFE
133
141#define I2C_MAX_ADDRESSES 112
142
148#define I2C_LIB_VER 20100
149
153class I2C {
154public:
161 static void init();
162
172 static void setAddress(uint8_t address, bool generalCall = false);
173
190 static void write(uint8_t address, const void *buffer, uint8_t size, bool wait);
191
207 template<typename T>
208 static void write(uint8_t address, const T *object, bool wait);
209
221 static void read(uint8_t address, void *buffer, uint8_t size);
222
235 template<typename T>
236 static void read(uint8_t address, T *object);
237
252 static void transmit(const void *buffer, uint8_t size);
253
268 template <typename T>
269 static void transmit(const T *object);
270
292 static void onRequest(void (*function)());
293
312 static void onReceive(void (*function)());
313
319 static uint8_t getTWError();
320
327 static uint8_t *getBuffer();
328
333 static bool detectEmulator();
334
342 static uint8_t getAddressFromId(uint8_t id);
343
352 static uint8_t handshake();
353
354};
355
356#ifdef I2C_IMPLEMENTATION
360namespace i2c_detail {
361
362uint8_t twiBuffer[I2C_BUFFER_SIZE];
363volatile uint8_t *rxBuffer;
364volatile uint8_t bufferIdx;
365volatile uint8_t bufferSize;
366
367volatile bool active;
368volatile uint8_t slaRW;
369volatile uint8_t error;
370
371void (*onRequestFunction)();
372void (*onReceiveFunction)();
373
374#ifdef I2C_MAX_PLAYERS
375
376#if I2C_MAX_PLAYERS > I2C_MAX_ADDRESSES
377#error "Too many players. Max is I2C_MAX_ADDRESSES."
378#endif // #if I2C_MAX_PLAYERS > I2C_MAX_ADDRESSES
379
380volatile uint8_t handshakeState;
381
382void handshakeOnReceive() {
383 return;
384}
385
386void handshakeOnRequest() {
387 handshakeState++;
388 I2C::transmit(&handshakeState);
389}
390#endif // #ifdef I2C_MAX_PLAYERS
391
392}
393
394void I2C::init() {
395 power_twi_enable();
396 TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
397 TWSR = 0; // clear prescaler bits
398 TWBR = (F_CPU / I2C_FREQUENCY - 16) / 2;
399}
400
401void I2C::setAddress(uint8_t address, bool generalCall) {
402 TWAR = address << 1 | generalCall;
403}
404
405void I2C::write(uint8_t address, const void *buffer, uint8_t size, bool wait) {
406 while (i2c_detail::active) {}
407
408 for (uint8_t i = 0; i < size; i++) {
409 i2c_detail::twiBuffer[i] = ((const uint8_t *)buffer)[i];
410 }
411 i2c_detail::bufferIdx = 0;
412 i2c_detail::bufferSize = size;
413
414 i2c_detail::error = TW_SUCCESS;
415
416 i2c_detail::active = true;
417 i2c_detail::slaRW = address << 1 | TW_WRITE;
418
419 uint8_t busyChecks = I2C_BUS_BUSY_CHECKS;
420 while (busyChecks) {
421 if ((I2C_SCL_PIN & _BV(I2C_SCL_BIT)) && (I2C_SDA_PIN & _BV(I2C_SDA_BIT))) {
422 busyChecks--;
423 } else {
424 i2c_detail::error = TW_MT_ARB_LOST;
425 return;
426 }
427 }
428
429 TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);
430 if (wait) {
431 while (i2c_detail::active) {}
432 }
433}
434
435template<typename T>
436void I2C::write(uint8_t address, const T *buffer, bool wait) {
437 static_assert(sizeof(T) <= I2C_BUFFER_SIZE, "Size of T must be less than or equal to I2C_BUFFER_SIZE.");
438 I2C::write(address, (const void *)buffer, sizeof(T), wait);
439}
440
441void I2C::read(uint8_t address, void *buffer, uint8_t size) {
442 while (i2c_detail::active) {}
443
444 i2c_detail::rxBuffer = (uint8_t *)buffer;
445
446 i2c_detail::bufferIdx = 0;
447 i2c_detail::bufferSize = size - 1;
448
449 i2c_detail::error = TW_SUCCESS;
450
451 i2c_detail::active = true;
452 i2c_detail::slaRW = address << 1 | TW_READ;
453
454 uint8_t busyChecks = I2C_BUS_BUSY_CHECKS;
455 while (busyChecks) {
456 if ((I2C_SCL_PIN & _BV(I2C_SCL_BIT)) && (I2C_SDA_PIN & _BV(I2C_SDA_BIT))) {
457 busyChecks--;
458 } else {
459 i2c_detail::error = TW_MR_ARB_LOST;
460 return;
461 }
462 }
463
464 TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);
465 while (i2c_detail::active) {}
466}
467
468template<typename T>
469void I2C::read(uint8_t address, T *object) {
470 static_assert(sizeof(T) < 256, "Size of T must be less than 256.");
471 I2C::read(address, (void *)object, sizeof(T));
472}
473
474
475void I2C::transmit(const void *buffer, uint8_t size) {
476 for (uint8_t i = 0; i < size; i++) {
477 i2c_detail::twiBuffer[i] = ((uint8_t *)buffer)[i];
478 }
479 i2c_detail::bufferIdx = 0;
480 i2c_detail::bufferSize = size;
481}
482
483template <typename T>
484void I2C::transmit(const T *object) {
485 static_assert(sizeof(T) <= I2C_BUFFER_SIZE, "Size of T must be less than or equal to I2C_BUFFER_SIZE.");
486 I2C::transmit((const void *)object, sizeof(T));
487}
488
489void I2C::onRequest(void (*function)()) {
490 i2c_detail::onRequestFunction = function;
491}
492void I2C::onReceive(void (*function)()) {
493 i2c_detail::onReceiveFunction = function;
494}
495
496inline uint8_t I2C::getTWError() {
497 return i2c_detail::error;
498}
499
500inline uint8_t *I2C::getBuffer() {
501 return i2c_detail::twiBuffer;
502}
503
504inline bool I2C::detectEmulator() {
505 // TWWC is set when TWDR is written to without TWINT being set
506 // Not done in emulator
507 TWDR = 0;
508 return !(TWCR & _BV(TWWC));
509}
510
511#ifdef I2C_MAX_PLAYERS
512
513inline uint8_t I2C::getAddressFromId(uint8_t id) {
514 return 0x8 + id;
515}
516
517uint8_t I2C::handshake() {
518 for (int8_t i = I2C_MAX_PLAYERS - 1; i >= 0; ) {
519 uint8_t dummy;
520
521 I2C::read(I2C::getAddressFromId(i), &dummy, 1);
522
523 switch (I2C::getTWError()) {
524 case TW_MR_SLA_NACK:
526 I2C::onReceive(i2c_detail::handshakeOnReceive);
527 I2C::onRequest(i2c_detail::handshakeOnRequest);
528
529 // handshakeState is the number of times the callback has been called.
530 // When the callback has been called i times, the final Arduboy has joined.
531 while (i2c_detail::handshakeState < i) { }
532
533 return i;
534 case TW_SUCCESS:
535 i--;
536 break;
537 }
538 }
540}
541
542#endif
543
544ISR(TWI_vect, ISR_NAKED) {
545 asm volatile (
546R"(
547; --------------------- defines ----------------------- ;
548
549.equ TWCR, 0xBC
550.equ TWSR, 0xB9
551.equ TWDR, 0xBB
552
553.equ TWIE, 0
554.equ TWEN, 2
555.equ TWWC, 3
556.equ TWSTO, 4
557.equ TWSTA, 5
558.equ TWEA, 6
559.equ TWINT, 7
560
561.equ REPLY_ACK, (1 << TWINT) | (1 << TWEN) | (1 << TWIE) | (1 << TWEA)
562.equ REPLY_NACK, (1 << TWINT) | (1 << TWEN) | (1 << TWIE)
563.equ STOP, (1 << TWINT) | (1 << TWEN) | (1 << TWIE) | (1 << TWSTO) | (1 << TWEA)
564
565; -------------------- registers ---------------------- ;
566; r18 - TWSR (never used after function call)
567; r19 - general use
568; r30 - general use
569; r31 - general use
570; --------------------- prologue ---------------------- ;
571push r18
572in r18, __SREG__
573push r18
574push r30
575push r31
576; save and restore call-clobbered registers
577; target (slave) could call function pointer
578push r19
579push r20
580push r21
581push r22
582push r23
583push r24
584push r25
585push r26
586push r27
587; save and restore tmp and zero registers (could be used in function calls)
588push __tmp_reg__
589push __zero_reg__
590clr __zero_reg__
591; ----------------------------------------------------- ;
592
593; switch (TWSR)
594lds r18, TWSR ; no mask needed because prescaler bits are cleared
595
596cpi r18, 0x08
597breq TW_START
598
599; MT_MR
600cpi r18, 0x18
601breq TW_MT_SLA_ACK
602cpi r18, 0x28
603breq TW_MT_DATA_ACK
604cpi r18, 0x38
605breq TW_MT_ARB_LOST ; same as TW_MR_ARB_LOST
606cpi r18, 0x40
607breq TW_MR_SLA_ACK
608cpi r18, 0x50
609breq TW_MR_DATA_ACK
610cpi r18, 0x58
611breq TW_MR_DATA_NACK
612
613; 64 instruction limit on branches
614rjmp SR_ST
615
616TW_START:
617 ; TWDR = i2c_detail::slaRW;
618 lds r30, %[slaRW]
619 sts TWDR, r30
620 ; TWCR = REPLY_NACK;
621 ldi r30, REPLY_NACK
622 sts TWCR, r30
623 ; return;
624 rjmp pop_reti
625
626TW_MT_SLA_ACK:
627TW_MT_DATA_ACK:
628 ; if (i2c_detail::bufferIdx >= bufferSize) { stop(); return; }
629 lds r30, %[bufferIdx]
630 lds r31, %[bufferSize]
631 cp r30, r31
632
633 brlt 1f ; 64 instruction limit on branches
634 rjmp stop_reti
635 1:
636
637 ; TWDR = i2c_detail::twiBuffer[i2c_detail::bufferIdx++];
638 inc r30
639 sts %[bufferIdx], r30
640
641 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
642 ; bufferIdx is already incremented so decrement to compensate
643
644 clr r31
645 subi r30, lo8(-(%[twiBuffer] - 1))
646 sbci r31, hi8(-(%[twiBuffer] - 1))
647 ld r30, Z
648 sts TWDR, r30
649
650 ; TWCR = REPLY_NACK;
651 ldi r30, REPLY_NACK
652 sts TWCR, r30
653 ; return;
654 rjmp pop_reti
655
656TW_MT_ARB_LOST:
657 ; TWCR = REPLY_ACK;
658 ldi r30, REPLY_ACK
659 sts TWCR, r30
660 ; i2c_detail::error = TW_MT_ARB_LOST;
661 ldi r30, 0x38
662 sts %[error], r30
663 ; active = false;
664 ; return;
665 rjmp active_false_reti
666; ----------------------------------------------------- ;
667
668TW_MR_DATA_NACK:
669TW_MR_DATA_ACK:
670 ; i2c_detail::rxBuffer[i2c_detail::bufferIdx++] = TWDR;
671 lds r19, %[bufferIdx]
672 inc r19
673 sts %[bufferIdx], r19
674 dec r19
675
676 lds r30, %[rxBuffer]
677 lds r31, %[rxBuffer] + 1
678
679 add r30, r19
680 adc r31, __zero_reg__
681
682 lds r19, TWDR
683 st Z, r19
684
685 ; if (TWSR == TW_MR_DATA_NACK) { stop(); return; }
686 ; r18 holds TWSR
687 cpi r18, 0x58
688 brne 1f ; 64 instruction limit on branches
689 rjmp stop_reti
690 1:
691; ------------------ fallthrough ---------------------- ;
692TW_MR_SLA_ACK:
693 ; if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
694 ; TWCR = REPLY_ACK;
695 ; } else {
696 ; TWCR = REPLY_nACK;
697 ; }
698 ; return;
699
700 lds r30, %[bufferIdx]
701 lds r31, %[bufferSize]
702 cp r30, r31
703 ldi r30, REPLY_ACK
704 brlt 1f
705 ldi r30, REPLY_NACK
706 1:
707 sts TWCR, r30
708 rjmp pop_reti
709; ----------------------------------------------------- ;
710SR_ST:
711cpi r18, 0x60
712breq TW_SR_SLA_ACK
713cpi r18, 0x68
714breq TW_SR_ARB_LOST_SLA_ACK
715cpi r18, 0x70
716breq TW_SR_GCALL_ACK
717cpi r18, 0x78
718breq TW_SR_ARB_LOST_GCALL_ACK
719cpi r18, 0x80
720breq TW_SR_DATA_ACK
721cpi r18, 0x90
722breq TW_SR_GCALL_DATA_ACK
723cpi r18, 0xA0
724breq TW_SR_STOP
725cpi r18, 0xA8
726breq TW_ST_SLA_ACK
727cpi r18, 0xB0
728breq TW_ST_ARB_LOST_SLA_ACK
729cpi r18, 0xB8
730breq TW_ST_DATA_ACK
731cpi r18, 0xC0
732breq TW_ST_DATA_NACK
733cpi r18, 0xC8
734breq TW_ST_LAST_DATA
735
736rjmp default
737
738TW_SR_SLA_ACK:
739TW_SR_ARB_LOST_SLA_ACK:
740TW_SR_GCALL_ACK:
741TW_SR_ARB_LOST_GCALL_ACK:
742 ; i2c_detail::active = TWSR; (true)
743 sts %[active], r18 ; r18 holds TWSR
744 ; i2c_detail::bufferIdx = 0;
745 sts %[bufferIdx], __zero_reg__
746 ; TWCR = REPLY_ACK;
747 ldi r30, REPLY_ACK
748 sts TWCR, r30
749 ; return;
750 rjmp pop_reti
751
752TW_SR_DATA_ACK:
753TW_SR_GCALL_DATA_ACK:
754 ; i2c_detail::twiBuffer[i2c_detail::bufferIdx++] = TWDR;
755 lds r30, %[bufferIdx]
756 inc r30
757 sts %[bufferIdx], r30
758
759 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
760 ; bufferIdx is already incremented so decrement to compensate
761
762 clr r31
763 subi r30, lo8(-(%[twiBuffer] - 1))
764 sbci r31, hi8(-(%[twiBuffer] - 1))
765 lds r19, TWDR
766 st Z, r19
767
768 ; TWCR = REPLY_ACK;
769 ldi r30, REPLY_ACK
770 sts TWCR, r30
771 ; return;
772 rjmp pop_reti
773TW_SR_STOP:
774 ; TWCR = REPLY_ACK;
775 ldi r30, REPLY_ACK
776 sts TWCR, r30
777 ; i2c_detail::onReceiveFunction();
778 lds r30, %[onReceiveFunction]
779 lds r31, %[onReceiveFunction] + 1
780 icall
781 ; i2c_detail::active = false;
782 ; return;
783 rjmp active_false_reti;
784
785; ----------------------------------------------------- ;
786TW_ST_ARB_LOST_SLA_ACK:
787TW_ST_SLA_ACK:
788 ; i2c_detail::active = TWSR; (true)
789 sts %[active], r18
790 ; i2c_detail::onRequestFunction();
791 lds 30, %[onRequestFunction]
792 lds 31, %[onRequestFunction] + 1
793 icall
794; ------------------ fallthrough ---------------------- ;
795TW_ST_DATA_ACK:
796 ; TWDR = i2c_detail::twiBuffer[i2c_detail::bufferIdx++];
797 lds r30, %[bufferIdx]
798 inc r30
799 sts %[bufferIdx], r30
800
801 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
802 ; bufferIdx is already incremented so decrement to compensate
803
804 clr r31
805 subi r30, lo8(-(%[twiBuffer] - 1))
806 sbci r31, hi8(-(%[twiBuffer] - 1))
807 ld r30, Z
808 sts TWDR, r30
809
810 ; if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
811 ; TWCR = REPLY_ACK;
812 ; } else {
813 ; TWCR = REPLY_NACK;
814 ; }
815 ; return;
816 ; (reuse code in MR)
817 rjmp TW_MR_SLA_ACK
818TW_ST_DATA_NACK:
819TW_ST_LAST_DATA:
820 ; TWCR = REPLY_ACK;
821 ldi r30, REPLY_ACK
822 sts TWCR, r30
823 ; i2c_detail::active = false;
824 ; return;
825 rjmp active_false_reti
826; ----------------------------------------------------- ;
827default:
828 ; i2c_detail::error = TWSR;
829 sts %[error], r18
830
831 stop_reti:
832
833 ; TWCR = STOP;
834 ldi r30, STOP
835 sts TWCR, r30
836
837 ; while (TWCR & _BV(TWSTO)) {}
838 1:
839 lds r30, TWCR
840 sbrc r30, TWSTO ; skip if bit in register clear
841 rjmp 1b
842
843 active_false_reti:
844 ; i2c_detail::active = false;
845 sts %[active], __zero_reg__
846
847; --------------------- epilogue ---------------------- ;
848 pop_reti:
849 pop __zero_reg__
850 pop __tmp_reg__
851 pop r27
852 pop r26
853 pop r25
854 pop r24
855 pop r23
856 pop r22
857 pop r21
858 pop r20
859 pop r19
860 pop r31
861 pop r30
862 pop r18
863 out __SREG__, r18
864 pop r18
865 reti
866)"
867 : // Output Operands
868 [error] "=m" (i2c_detail::error),
869 [active] "=m" (i2c_detail::active),
870 [bufferIdx] "=m" (i2c_detail::bufferIdx),
871 [rxBuffer] "=m" (i2c_detail::rxBuffer),
872 [twiBuffer] "=m" (i2c_detail::twiBuffer)
873 : // Input Operands
874 [onRequestFunction] "m" (i2c_detail::onRequestFunction),
875 [onReceiveFunction] "m" (i2c_detail::onReceiveFunction),
876 [bufferSize] "m" (i2c_detail::bufferSize),
877 [slaRW] "m" (i2c_detail::slaRW)
878 );
879}
880
881#if 0
882ISR(TWI_vect) {
883 switch (TWSR) { // prescaler bits are cleared, no mask needed
884 case TW_START:
885 TWDR = i2c_detail::slaRW;
886 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
887 break;
888 // MT
889 case TW_MT_SLA_ACK:
890 case TW_MT_DATA_ACK:
891 if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
892 TWDR = i2c_detail::twiBuffer[i2c_detail::bufferIdx++];
893 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
894 } else {
895 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTO) | _BV(TWEA);
896 while (TWCR & _BV(TWSTO)) { }
897 i2c_detail::active = false;
898 }
899 break;
900 case TW_MT_ARB_LOST: // same as TW_MR_ARB_LOST
901 i2c_detail::active = false;
902 i2c_detail::error = TW_MT_ARB_LOST;
903 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
904 break;
905 // MR
906 case TW_MR_DATA_ACK:
907 i2c_detail::rxBuffer[i2c_detail::bufferIdx++] = TWDR;
908 __attribute__((fallthrough));
909 case TW_MR_SLA_ACK:
910 if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
911 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
912 } else {
913 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
914 }
915 break;
916 case TW_MR_DATA_NACK:
917 i2c_detail::rxBuffer[i2c_detail::bufferIdx++] = TWDR;
918 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTO) | _BV(TWEA);
919 while (TWCR & _BV(TWSTO)) { }
920 i2c_detail::active = false;
921 break;
922 // ST
923 case TW_ST_SLA_ACK:
924 case TW_ST_ARB_LOST_SLA_ACK:
925 i2c_detail::active = true;
926 i2c_detail::onRequestFunction();
927 __attribute__((fallthrough));
928 case TW_ST_DATA_ACK:
929 TWDR = i2c_detail::twiBuffer[i2c_detail::bufferIdx++];
930 if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
931 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
932 } else {
933 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
934 }
935 break;
936 case TW_ST_DATA_NACK:
937 case TW_ST_LAST_DATA: // last interrupt cleared TWEA
938 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
939 i2c_detail::active = false;
940 break;
941 // SR
942 case TW_SR_SLA_ACK:
943 case TW_SR_GCALL_ACK:
944 case TW_SR_ARB_LOST_SLA_ACK:
945 case TW_SR_ARB_LOST_GCALL_ACK:
946 i2c_detail::bufferIdx = 0;
947 i2c_detail::active = true;
948 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
949 break;
950 case TW_SR_GCALL_DATA_ACK:
951 case TW_SR_DATA_ACK:
952 i2c_detail::twiBuffer[i2c_detail::bufferIdx++] = TWDR;
953 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
954 break;
955 case TW_SR_STOP:
956 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
957 i2c_detail::onReceiveFunction(i2c_detail::twiBuffer);
958 i2c_detail::active = false;
959 break;
960 default:
961 i2c_detail::error = TWSR;
962 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTO) | _BV(TWEA);
963 while (TWCR & _BV(TWSTO)) { }
964 i2c_detail::active = false;
965 break;
966 }
967}
968#endif // #if 0
969
970#endif // #ifdef I2C_IMPLEMENTATION
#define I2C_SCL_PIN
The pin on which the SCL line is connected.
Definition ArduboyI2C.h:78
#define I2C_SDA_PIN
The pin on which the SDA line is connected.
Definition ArduboyI2C.h:96
#define I2C_BUS_BUSY_CHECKS
The amount of times the bus is checked before continuing with a read/write operation.
Definition ArduboyI2C.h:68
#define I2C_HANDSHAKE_FAILED
Error code RETURNED by I2C::handshake, meaning the handshake has already been completed.
Definition ArduboyI2C.h:132
#define I2C_SCL_BIT
The bit of the pin on which the SCL line is connected.
Definition ArduboyI2C.h:87
#define I2C_BUFFER_SIZE
The size of the buffer used for writes/target (slave) operations.
Definition ArduboyI2C.h:52
#define I2C_MAX_PLAYERS
The maxmimum number of players in the handshake/lobby.
Definition ArduboyI2C.h:115
#define TW_SUCCESS
Error code used to mean success, returned by I2C::getTWError().
Definition ArduboyI2C.h:125
#define I2C_SDA_BIT
The bit of the pin on which the sda line is connected.
Definition ArduboyI2C.h:105
#define I2C_FREQUENCY
The initial I2C frequency.
Definition ArduboyI2C.h:43
Definition ArduboyI2C.h:153
static void onRequest(void(*function)())
Sets up the callback to be called when data is requested from the device's address (a read).
static uint8_t getTWError()
Gets the hardware error which happened in a previous read or write.
static void init()
Initalizes I2C hardware.
static bool detectEmulator()
Checks if an emulator without I2C support is being used to run the code.
static void transmit(const T *object)
Transmits data back to the controller (master).
static uint8_t * getBuffer()
Gets a pointer to the I2C buffer holding received data.
static void transmit(const void *buffer, uint8_t size)
Transmits data back to the controller (master).
static void read(uint8_t address, void *buffer, uint8_t size)
Attempts to become the bus controller (master) and reads data over I2C from the specified address.
static uint8_t handshake()
Handshakes with other devices and returns a unique id once complete.
static void setAddress(uint8_t address, bool generalCall=false)
Set the address of the device and enable/disable general calls on the I2C bus.
static void onReceive(void(*function)())
Sets up the callback to be called when data is sent to the device's address (a write)
static void write(uint8_t address, const T *object, bool wait)
Attempts to become the bus controller (master) and sends data over I2C to the specified address.
static uint8_t getAddressFromId(uint8_t id)
Gets the address from a provided id.
static void read(uint8_t address, T *object)
Attempts to become the bus controller (master) and reads data over I2C from the specified address.
static void write(uint8_t address, const void *buffer, uint8_t size, bool wait)
Attempts to become the bus controller (master) and sends data over I2C to the specified address.