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 20000
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
336 static uint8_t getAddressFromId(uint8_t id);
345 static uint8_t handshake();
346
347};
348
349#ifdef I2C_IMPLEMENTATION
353namespace i2c_detail {
354
355uint8_t twiBuffer[I2C_BUFFER_SIZE];
356volatile uint8_t *rxBuffer;
357volatile uint8_t bufferIdx;
358volatile uint8_t bufferSize;
359
360volatile bool active;
361volatile uint8_t slaRW;
362volatile uint8_t error;
363
364void (*onRequestFunction)();
365void (*onReceiveFunction)();
366
367void stop() {
368 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTO) | _BV(TWEA);
369 while (TWCR & _BV(TWSTO)) { }
370 i2c_detail::active = false;
371}
372
373#ifdef I2C_MAX_PLAYERS
374
375#if I2C_MAX_PLAYERS > I2C_MAX_ADDRESSES
376#error "Too many players. Max is I2C_MAX_ADDRESSES."
377#endif // #if I2C_MAX_PLAYERS > I2C_MAX_ADDRESSES
378
379volatile uint8_t handshakeState;
380
381void handshakeOnReceive() {
382 return;
383}
384
385void handshakeOnRequest() {
386 handshakeState++;
387 I2C::transmit(&handshakeState);
388}
389#endif // #ifdef I2C_MAX_PLAYERS
390
391}
392
393void I2C::init() {
394 power_twi_enable();
395 TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
396 TWSR = 0; // clear prescaler bits
397 TWBR = (F_CPU / I2C_FREQUENCY - 16) / 2;
398}
399
400void I2C::setAddress(uint8_t address, bool generalCall) {
401 TWAR = address << 1 | generalCall;
402}
403
404void I2C::write(uint8_t address, const void *buffer, uint8_t size, bool wait) {
405 while (i2c_detail::active) {}
406
407 for (uint8_t i = 0; i < size; i++) {
408 i2c_detail::twiBuffer[i] = ((const uint8_t *)buffer)[i];
409 }
410 i2c_detail::bufferIdx = 0;
411 i2c_detail::bufferSize = size;
412
413 i2c_detail::error = TW_SUCCESS;
414
415 i2c_detail::active = true;
416 i2c_detail::slaRW = address << 1 | TW_WRITE;
417
418 uint8_t busyChecks = I2C_BUS_BUSY_CHECKS;
419 while (busyChecks) {
420 if ((I2C_SCL_PIN & _BV(I2C_SCL_BIT)) && (I2C_SDA_PIN & _BV(I2C_SDA_BIT))) {
421 busyChecks--;
422 } else {
423 busyChecks = I2C_BUS_BUSY_CHECKS;
424 }
425 }
426
427 TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);
428 if (wait) {
429 while (i2c_detail::active) {}
430 }
431}
432
433template<typename T>
434void I2C::write(uint8_t address, const T *buffer, bool wait) {
435 static_assert(sizeof(T) <= I2C_BUFFER_SIZE, "Size of T must be less than or equal to I2C_BUFFER_SIZE.");
436 I2C::write(address, (const void *)buffer, sizeof(T), wait);
437}
438
439void I2C::read(uint8_t address, void *buffer, uint8_t size) {
440 while (i2c_detail::active) {}
441
442 i2c_detail::rxBuffer = (uint8_t *)buffer;
443
444 i2c_detail::bufferIdx = 0;
445 i2c_detail::bufferSize = size - 1;
446
447 i2c_detail::error = TW_SUCCESS;
448
449 i2c_detail::active = true;
450 i2c_detail::slaRW = address << 1 | TW_READ;
451
452 uint8_t busyChecks = I2C_BUS_BUSY_CHECKS;
453 while (busyChecks) {
454 if ((I2C_SCL_PIN & _BV(I2C_SCL_BIT)) && (I2C_SDA_PIN & _BV(I2C_SDA_BIT))) {
455 busyChecks--;
456 } else {
457 busyChecks = I2C_BUS_BUSY_CHECKS;
458 }
459 }
460
461 TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);
462 while (i2c_detail::active) {}
463}
464
465template<typename T>
466void I2C::read(uint8_t address, T *object) {
467 static_assert(sizeof(T) < 256, "Size of T must be less than 256.");
468 I2C::read(address, (void *)object, sizeof(T));
469}
470
471
472void I2C::transmit(const void *buffer, uint8_t size) {
473 for (uint8_t i = 0; i < size; i++) {
474 i2c_detail::twiBuffer[i] = ((uint8_t *)buffer)[i];
475 }
476 i2c_detail::bufferIdx = 0;
477 i2c_detail::bufferSize = size;
478}
479
480template <typename T>
481void I2C::transmit(const T *object) {
482 static_assert(sizeof(T) <= I2C_BUFFER_SIZE, "Size of T must be less than or equal to I2C_BUFFER_SIZE.");
483 I2C::transmit((const void *)object, sizeof(T));
484}
485
486void I2C::onRequest(void (*function)()) {
487 i2c_detail::onRequestFunction = function;
488}
489void I2C::onReceive(void (*function)()) {
490 i2c_detail::onReceiveFunction = function;
491}
492
493inline uint8_t I2C::getTWError() {
494 return i2c_detail::error;
495}
496
497inline uint8_t *I2C::getBuffer() {
498 return i2c_detail::twiBuffer;
499}
500
501#ifdef I2C_MAX_PLAYERS
502
503inline uint8_t I2C::getAddressFromId(uint8_t id) {
504 return 0x8 + id;
505}
506
507uint8_t I2C::handshake() {
508 for (int8_t i = I2C_MAX_PLAYERS - 1; i >= 0; ) {
509 uint8_t dummy;
510
511 I2C::read(I2C::getAddressFromId(i), &dummy, 1);
512
513 switch (I2C::getTWError()) {
514 case TW_MR_SLA_NACK:
516 I2C::onReceive(i2c_detail::handshakeOnReceive);
517 I2C::onRequest(i2c_detail::handshakeOnRequest);
518
519 // handshakeState is the number of times the callback has been called.
520 // When the callback has been called i times, the final Arduboy has joined.
521 while (i2c_detail::handshakeState < i) { }
522
523 return i;
524 case TW_SUCCESS:
525 i--;
526 break;
527 }
528 }
530}
531
532#endif
533
534ISR(TWI_vect, ISR_NAKED) {
535 asm volatile (
536R"(
537; --------------------- defines ----------------------- ;
538
539.equ TWCR, 0xBC
540.equ TWSR, 0xB9
541.equ TWDR, 0xBB
542
543.equ TWIE, 0
544.equ TWEN, 2
545.equ TWWC, 3
546.equ TWSTO, 4
547.equ TWSTA, 5
548.equ TWEA, 6
549.equ TWINT, 7
550
551.equ REPLY_ACK, (1 << TWINT) | (1 << TWEN) | (1 << TWIE) | (1 << TWEA)
552.equ REPLY_NACK, (1 << TWINT) | (1 << TWEN) | (1 << TWIE)
553.equ STOP, (1 << TWINT) | (1 << TWEN) | (1 << TWIE) | (1 << TWSTO) | (1 << TWEA)
554
555; -------------------- registers ---------------------- ;
556; r18 - TWSR (never used after function call)
557; r19 - general use
558; r30 - general use
559; r31 - general use
560; --------------------- prologue ---------------------- ;
561push r18
562in r18, __SREG__
563push r18
564push r30
565push r31
566; save and restore call-clobbered registers
567; target (slave) could call function pointer
568push r19
569push r20
570push r21
571push r22
572push r23
573push r24
574push r25
575push r26
576push r27
577; save and restore tmp and zero registers (could be used in function calls)
578push __tmp_reg__
579push __zero_reg__
580clr __zero_reg__
581; ----------------------------------------------------- ;
582
583; switch (TWSR)
584lds r18, TWSR ; no mask needed because prescaler bits are cleared
585
586cpi r18, 0x08
587breq TW_START
588
589; MT_MR
590cpi r18, 0x18
591breq TW_MT_SLA_ACK
592cpi r18, 0x28
593breq TW_MT_DATA_ACK
594cpi r18, 0x38
595breq TW_MT_ARB_LOST ; same as TW_MR_ARB_LOST
596cpi r18, 0x40
597breq TW_MR_SLA_ACK
598cpi r18, 0x50
599breq TW_MR_DATA_ACK
600cpi r18, 0x58
601breq TW_MR_DATA_NACK
602
603; 64 instruction limit on branches
604rjmp SR_ST
605
606TW_START:
607 ; TWDR = i2c_detail::slaRW;
608 lds r30, %[slaRW]
609 sts TWDR, r30
610 ; TWCR = REPLY_NACK;
611 ldi r30, REPLY_NACK
612 sts TWCR, r30
613 ; return;
614 rjmp pop_reti
615
616TW_MT_SLA_ACK:
617TW_MT_DATA_ACK:
618 ; if (i2c_detail::bufferIdx >= bufferSize) { stop(); return; }
619 lds r30, %[bufferIdx]
620 lds r31, %[bufferSize]
621 cp r30, r31
622
623 brlt 1f ; 64 instruction limit on branches
624 rjmp stop_reti
625 1:
626
627 ; TWDR = i2c_detail::twiBuffer[i2c_detail::bufferIdx++];
628 ; Increment bufferIdx but preserve r30
629 inc r30
630 sts %[bufferIdx], r30
631 dec r30
632
633 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
634 clr r31
635 subi r30, lo8(-(%[twiBuffer]))
636 sbci r31, hi8(-(%[twiBuffer]))
637 ld r30, Z
638 sts TWDR, r30
639
640 ; https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48APA88APA168APA328P-SiliConErrataClarif-DS80000855A.pdf
641 ; Section 2.3.1
642 lpm ; 3 cycle delay
643
644 ; TWCR = REPLY_NACK;
645 ldi r30, REPLY_NACK
646 sts TWCR, r30
647 ; return;
648 rjmp pop_reti
649
650TW_MT_ARB_LOST:
651 ; TWCR = REPLY_ACK;
652 ldi r30, REPLY_ACK
653 sts TWCR, r30
654 ; i2c_detail::error = TW_MT_ARB_LOST;
655 ldi r30, 0x38
656 sts %[error], r30
657 ; active = false;
658 ; return;
659 rjmp active_false_reti
660; ----------------------------------------------------- ;
661
662TW_MR_DATA_NACK:
663TW_MR_DATA_ACK:
664 ; i2c_detail::rxBuffer[i2c_detail::bufferIdx++] = TWDR;
665 lds r30, %[bufferIdx]
666 inc r30
667 sts %[bufferIdx], r30
668 dec r30
669
670 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
671 clr r31
672 subi r30, lo8(-(%[rxBuffer]))
673 sbci r31, hi8(-(%[rxBuffer]))
674 lds r19, TWDR
675 st Z, r19
676
677 ; if (TWSR == TW_MR_DATA_NACK) { stop(); return; }
678 ; r18 holds TWSR
679 cpi r18, 0x58
680 brne 1f ; 64 instruction limit on branches
681 rjmp stop_reti
682 1:
683; ------------------ fallthrough ---------------------- ;
684TW_MR_SLA_ACK:
685 ; if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
686 ; TWCR = REPLY_ACK;
687 ; } else {
688 ; TWCR = REPLY_nACK;
689 ; }
690 ; return;
691
692 lds r30, %[bufferIdx]
693 lds r31, %[bufferSize]
694 cp r30, r31
695 ldi r30, REPLY_ACK
696 brlt 1f
697 ldi r30, REPLY_NACK
698 1:
699 sts TWCR, r30
700 rjmp pop_reti
701; ----------------------------------------------------- ;
702SR_ST:
703cpi r18, 0x60
704breq TW_SR_SLA_ACK
705cpi r18, 0x68
706breq TW_SR_ARB_LOST_SLA_ACK
707cpi r18, 0x70
708breq TW_SR_GCALL_ACK
709cpi r18, 0x78
710breq TW_SR_ARB_LOST_GCALL_ACK
711cpi r18, 0x80
712breq TW_SR_DATA_ACK
713cpi r18, 0x90
714breq TW_SR_GCALL_DATA_ACK
715cpi r18, 0xA0
716breq TW_SR_STOP
717cpi r18, 0xA8
718breq TW_ST_SLA_ACK
719cpi r18, 0xB0
720breq TW_ST_ARB_LOST_SLA_ACK
721cpi r18, 0xB8
722breq TW_ST_DATA_ACK
723cpi r18, 0xC0
724breq TW_ST_DATA_NACK
725cpi r18, 0xC8
726breq TW_ST_LAST_DATA
727
728rjmp default
729
730TW_SR_SLA_ACK:
731TW_SR_ARB_LOST_SLA_ACK:
732TW_SR_GCALL_ACK:
733TW_SR_ARB_LOST_GCALL_ACK:
734 ; i2c_detail::active = TWSR; (true)
735 sts %[active], r18 ; r18 holds TWSR
736 ; i2c_detail::bufferIdx = 0;
737 sts %[bufferIdx], __zero_reg__
738 ; TWCR = REPLY_ACK;
739 ldi r30, REPLY_ACK
740 sts TWCR, r30
741 ; return;
742 rjmp pop_reti
743
744TW_SR_DATA_ACK:
745TW_SR_GCALL_DATA_ACK:
746 ; i2c_detail::twiBuffer[i2c_detail::bufferIdx++] = TWDR;
747 lds r30, %[bufferIdx]
748 inc r30
749 sts %[bufferIdx], r30
750 dec r30
751
752 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
753 clr r31
754 subi r30, lo8(-(%[twiBuffer]))
755 sbci r31, hi8(-(%[twiBuffer]))
756 lds r19, TWDR
757 st Z, r19
758
759 ; TWCR = REPLY_ACK;
760 ldi r30, REPLY_ACK
761 sts TWCR, r30
762 ; return;
763 rjmp pop_reti
764TW_SR_STOP:
765 ; TWCR = REPLY_ACK;
766 ldi r30, REPLY_ACK
767 sts TWCR, r30
768 ; i2c_detail::onReceiveFunction();
769 lds r30, %[onReceiveFunction]
770 lds r31, %[onReceiveFunction] + 1
771 icall
772 ; i2c_detail::active = false;
773 ; return;
774 rjmp active_false_reti;
775
776; ----------------------------------------------------- ;
777TW_ST_ARB_LOST_SLA_ACK:
778TW_ST_SLA_ACK:
779 ; i2c_detail::active = TWSR; (true)
780 sts %[active], r18
781 ; i2c_detail::onRequestFunction();
782 lds 30, %[onRequestFunction]
783 lds 31, %[onRequestFunction] + 1
784 icall
785; ------------------ fallthrough ---------------------- ;
786TW_ST_DATA_ACK:
787 ; TWDR = i2c_detail::twiBuffer[i2c_detail::bufferIdx++];
788 lds r30, %[bufferIdx]
789 inc r30
790 sts %[bufferIdx], r30
791 dec r30
792 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
793 clr r31
794 subi r30, lo8(-(%[twiBuffer]))
795 sbci r31, hi8(-(%[twiBuffer]))
796 ld r30, Z
797 sts TWDR, r30
798
799 ; if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
800 ; TWCR = REPLY_ACK;
801 ; } else {
802 ; TWCR = REPLY_NACK;
803 ; }
804 ; return;
805 ; (reuse code in MR)
806 rjmp TW_MR_SLA_ACK
807TW_ST_DATA_NACK:
808TW_ST_LAST_DATA:
809 ; TWCR = REPLY_ACK;
810 ldi r30, REPLY_ACK
811 sts TWCR, r30
812 ; i2c_detail::active = false;
813 ; return;
814 rjmp active_false_reti
815; ----------------------------------------------------- ;
816default:
817 ; i2c_detail::error = TWSR;
818 sts %[error], r18
819
820 stop_reti:
821
822 ; TWCR = STOP;
823 ldi r30, STOP
824 sts TWCR, r30
825
826 ; while (TWCR & _BV(TWSTO)) {}
827 1:
828 lds r30, TWCR
829 sbrc r30, TWSTO ; skip if bit in register clear
830 rjmp 1b
831
832 active_false_reti:
833 ; i2c_detail::active = false;
834 sts %[active], __zero_reg__
835
836; --------------------- epilogue ---------------------- ;
837 pop_reti:
838 pop __zero_reg__
839 pop __tmp_reg__
840 pop r27
841 pop r26
842 pop r25
843 pop r24
844 pop r23
845 pop r22
846 pop r21
847 pop r20
848 pop r19
849 pop r31
850 pop r30
851 pop r18
852 out __SREG__, r18
853 pop r18
854 reti
855)"
856 : // Output Operands
857 [error] "=m" (i2c_detail::error),
858 [active] "=m" (i2c_detail::active),
859 [bufferIdx] "=m" (i2c_detail::bufferIdx),
860 [rxBuffer] "=m" (i2c_detail::rxBuffer),
861 [twiBuffer] "=m" (i2c_detail::twiBuffer)
862 : // Input Operands
863 [onRequestFunction] "m" (i2c_detail::onRequestFunction),
864 [onReceiveFunction] "m" (i2c_detail::onReceiveFunction),
865 [bufferSize] "m" (i2c_detail::bufferSize),
866 [slaRW] "m" (i2c_detail::slaRW)
867 );
868}
869
870#if 0
871ISR(TWI_vect) {
872 switch (TWSR) { // prescaler bits are cleared, no mask needed
873 case TW_START:
874 TWDR = i2c_detail::slaRW;
875 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
876 break;
877 // MT
878 case TW_MT_SLA_ACK:
879 case TW_MT_DATA_ACK:
880 if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
881 TWDR = i2c_detail::twiBuffer[i2c_detail::bufferIdx++];
882 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
883 } else {
884 i2c_detail::stop();
885 }
886 break;
887 case TW_MT_ARB_LOST: // same as TW_MR_ARB_LOST
888 i2c_detail::active = false;
889 i2c_detail::error = TW_MT_ARB_LOST;
890 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
891 break;
892 // MR
893 case TW_MR_DATA_ACK:
894 i2c_detail::rxBuffer[i2c_detail::bufferIdx++] = TWDR;
895 __attribute__((fallthrough));
896 case TW_MR_SLA_ACK:
897 if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
898 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
899 } else {
900 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
901 }
902 break;
903 case TW_MR_DATA_NACK:
904 i2c_detail::rxBuffer[i2c_detail::bufferIdx++] = TWDR;
905 i2c_detail::stop();
906 break;
907 // ST
908 case TW_ST_SLA_ACK:
909 case TW_ST_ARB_LOST_SLA_ACK:
910 i2c_detail::active = true;
911 i2c_detail::onRequestFunction();
912 __attribute__((fallthrough));
913 case TW_ST_DATA_ACK:
914 TWDR = i2c_detail::twiBuffer[i2c_detail::bufferIdx++];
915 if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
916 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
917 } else {
918 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
919 }
920 break;
921 case TW_ST_DATA_NACK:
922 case TW_ST_LAST_DATA: // last interrupt cleared TWEA
923 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
924 i2c_detail::active = false;
925 break;
926 // SR
927 case TW_SR_SLA_ACK:
928 case TW_SR_GCALL_ACK:
929 case TW_SR_ARB_LOST_SLA_ACK:
930 case TW_SR_ARB_LOST_GCALL_ACK:
931 i2c_detail::bufferIdx = 0;
932 i2c_detail::active = true;
933 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
934 break;
935 case TW_SR_GCALL_DATA_ACK:
936 case TW_SR_DATA_ACK:
937 i2c_detail::twiBuffer[i2c_detail::bufferIdx++] = TWDR;
938 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
939 break;
940 case TW_SR_STOP:
941 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
942 i2c_detail::onReceiveFunction(i2c_detail::twiBuffer);
943 i2c_detail::active = false;
944 break;
945 default:
946 i2c_detail::error = TWSR;
947 i2c_detail::stop();
948 break;
949 }
950}
951#endif // #if 0
952
953#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 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.