29#include <avr/interrupt.h>
44#define I2C_FREQUENCY 100000
47#ifndef I2C_BUFFER_SIZE
53#define I2C_BUFFER_SIZE 32
54#elif I2C_BUFFER_SIZE > 256
55#error "I2C_BUFFER_SIZE is too big."
58#ifndef I2C_BUS_BUSY_CHECKS
69#define I2C_BUS_BUSY_CHECKS 16
79#define I2C_SCL_PIN PIND
88#define I2C_SCL_BIT PIND0
97#define I2C_SDA_PIN PIND
106#define I2C_SDA_BIT PIND1
116#define I2C_MAX_PLAYERS
121#define I2C_CUSTOM_HANDSHAKE
131#define TW_SUCCESS 0xFF
138#define I2C_HANDSHAKE_FAILED 0xFE
147#define I2C_MAX_ADDRESSES 112
154#define I2C_LIB_VER 20102
178 static void setAddress(uint8_t address,
bool generalCall =
false);
196 static void write(uint8_t address,
const void *buffer, uint8_t size,
bool wait);
214 static void write(uint8_t address,
const T *
object,
bool wait);
227 static void read(uint8_t address,
void *buffer, uint8_t size);
242 static void read(uint8_t address, T *
object);
258 static void transmit(
const void *buffer, uint8_t size);
274 template <
typename T>
362#ifdef I2C_IMPLEMENTATION
366namespace i2c_detail {
368 void (*onRequestFunction)();
369 void (*onReceiveFunction)();
371 volatile uint8_t *rxBuffer;
373 volatile uint8_t bufferIdx;
374 volatile uint8_t bufferSize;
376 volatile bool active;
377 volatile uint8_t slaRW;
378 volatile uint8_t error;
381#ifdef I2C_MAX_PLAYERS
383#if I2C_MAX_PLAYERS > I2C_MAX_ADDRESSES
384#error "Too many players. Max is I2C_MAX_ADDRESSES."
387#ifndef I2C_CUSTOM_HANDSHAKE
388volatile uint8_t handshakeState;
390void handshakeOnReceive() {
394void handshakeOnRequest() {
405 TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
411 TWAR = address << 1 | generalCall;
414void I2C::write(uint8_t address,
const void *buffer, uint8_t size,
bool wait) {
415 while (i2c_detail::data.active) {}
417 for (uint8_t i = 0; i < size; i++) {
418 i2c_detail::data.twiBuffer[i] = ((
const uint8_t *)buffer)[i];
420 i2c_detail::data.bufferIdx = 0;
421 i2c_detail::data.bufferSize = size;
425 i2c_detail::data.active =
true;
426 i2c_detail::data.slaRW = address << 1 | TW_WRITE;
433 i2c_detail::data.error = TW_MT_ARB_LOST;
438 TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);
440 while (i2c_detail::data.active) {}
445void I2C::write(uint8_t address,
const T *buffer,
bool wait) {
446 static_assert(
sizeof(T) <=
I2C_BUFFER_SIZE,
"Size of T must be less than or equal to I2C_BUFFER_SIZE.");
447 I2C::write(address, (
const void *)buffer,
sizeof(T), wait);
450void I2C::read(uint8_t address,
void *buffer, uint8_t size) {
451 while (i2c_detail::data.active) {}
453 i2c_detail::data.rxBuffer = (uint8_t *)buffer;
455 i2c_detail::data.bufferIdx = 0;
456 i2c_detail::data.bufferSize = size - 1;
460 i2c_detail::data.active =
true;
461 i2c_detail::data.slaRW = address << 1 | TW_READ;
468 i2c_detail::data.error = TW_MR_ARB_LOST;
473 TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);
474 while (i2c_detail::data.active) {}
478void I2C::read(uint8_t address, T *
object) {
479 static_assert(
sizeof(T) < 256,
"Size of T must be less than 256.");
480 I2C::read(address, (
void *)
object,
sizeof(T));
485 for (uint8_t i = 0; i < size; i++) {
486 i2c_detail::data.twiBuffer[i] = ((uint8_t *)buffer)[i];
488 i2c_detail::data.bufferIdx = 0;
489 i2c_detail::data.bufferSize = size;
494 static_assert(
sizeof(T) <=
I2C_BUFFER_SIZE,
"Size of T must be less than or equal to I2C_BUFFER_SIZE.");
499 i2c_detail::data.onRequestFunction = function;
502 i2c_detail::data.onReceiveFunction = function;
506 return i2c_detail::data.error;
510 return i2c_detail::data.twiBuffer;
517 return !(TWCR & _BV(TWWC));
520#ifdef I2C_MAX_PLAYERS
526#ifndef I2C_CUSTOM_LOBBY
542 while (i2c_detail::handshakeState < i) { }
556ISR(TWI_vect, ISR_NAKED) {
559; --------------------- defines ----------------------- ;
573.equ REPLY_ACK, (1 << TWINT) | (1 << TWEN) | (1 << TWIE) | (1 << TWEA)
574.equ REPLY_NACK, (1 << TWINT) | (1 << TWEN) | (1 << TWIE)
575.equ STOP, (1 << TWINT) | (1 << TWEN) | (1 << TWIE) | (1 << TWSTO) | (1 << TWEA)
577; -------------------- registers ---------------------- ;
578; r18 - TWSR (never used after function call)
580; r26 (X) - general use
581; r27 (X) - general use
582; r28 (Y) - data pointer
583; r29 (Y) - data pointer
584; r30 (Z) - TW register pointer
585; r31 (Z) - TW register pointer
586; --------------------- prologue ---------------------- ;
590; save and restore call-clobbered registers
591; target (slave) could call function pointer
605; save and restore tmp and zero registers (could be used in function calls)
609; ----------------------------------------------------- ;
610; set up Y pointer (data)
614; set up Z pointer (TW registers)
619ldd r18, Z + TWSR ; no mask needed because prescaler bits are cleared
630breq TW_MT_ARB_LOST ; same as TW_MR_ARB_LOST
638; 64 instruction limit on branches
642 ; TWDR = i2c_detail::data.slaRW;
643 ldd r26, Y + %[slaRW]
653 ; if (i2c_detail::data.bufferIdx >= i2c_detail::data.bufferSize) { stop(); return; }
654 ldd r26, Y + %[bufferIdx]
655 ldd r27, Y + %[bufferSize]
658 brlt 1f ; 64 instruction limit on branches
662 ; TWDR = i2c_detail::data.twiBuffer[i2c_detail::data.bufferIdx++];
664 std Y + %[bufferIdx], r26
666 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
667 ; bufferIdx is already incremented so decrement to compensate
670 subi r26, lo8(-(%[twiBuffer] - 1))
671 sbci r27, hi8(-(%[twiBuffer] - 1))
685 ; i2c_detail::data.error = TW_MT_ARB_LOST;
687 std Y + %[error], r26
690 rjmp active_false_reti
691; ----------------------------------------------------- ;
695 ; i2c_detail::data.rxBuffer[i2c_detail::data.bufferIdx++] = TWDR;
696 ldd r19, Y + %[bufferIdx]
698 std Y + %[bufferIdx], r19
701 ldd r26, Y + %[rxBuffer]
702 ldd r27, Y + %[rxBuffer] + 1
705 adc r27, __zero_reg__
710 ; if (TWSR == TW_MR_DATA_NACK) { stop(); return; }
713 brne 1f ; 64 instruction limit on branches
716; ------------------ fallthrough ---------------------- ;
718 ; if (i2c_detail::data.bufferIdx < i2c_detail::data.bufferSize) {
725 ldd r26, Y + %[bufferIdx]
726 ldd r27, Y + %[bufferSize]
734; ----------------------------------------------------- ;
739breq TW_SR_ARB_LOST_SLA_ACK
743breq TW_SR_ARB_LOST_GCALL_ACK
747breq TW_SR_GCALL_DATA_ACK
753breq TW_ST_ARB_LOST_SLA_ACK
764TW_SR_ARB_LOST_SLA_ACK:
766TW_SR_ARB_LOST_GCALL_ACK:
767 ; i2c_detail::data.active = TWSR; (true)
768 std Y + %[active], r18 ; r18 holds TWSR
769 ; i2c_detail::data.bufferIdx = 0;
770 std Y + %[bufferIdx], __zero_reg__
779 ; i2c_detail::data.twiBuffer[i2c_detail::data.bufferIdx++] = TWDR;
780 ldd r26, Y + %[bufferIdx]
782 std Y + %[bufferIdx], r26
784 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
785 ; bufferIdx is already incremented so decrement to compensate
788 subi r26, lo8(-(%[twiBuffer] - 1))
789 sbci r27, hi8(-(%[twiBuffer] - 1))
802 ; i2c_detail::data.onReceiveFunction();
803 ldd r30, Y + %[onReceiveFunction]
804 ldd r31, Y + %[onReceiveFunction] + 1
806 ; i2c_detail::data.active = false;
808 rjmp active_false_reti;
810; ----------------------------------------------------- ;
811TW_ST_ARB_LOST_SLA_ACK:
813 ; i2c_detail::data.active = TWSR; (true)
814 std Y + %[active], r18
815 ; i2c_detail::data.onRequestFunction();
816 ldd r30, Y + %[onRequestFunction]
817 ldd r31, Y + %[onRequestFunction] + 1
822; ------------------ fallthrough ---------------------- ;
824 ; TWDR = i2c_detail::data.twiBuffer[i2c_detail::data.bufferIdx++];
825 ldd r26, Y + %[bufferIdx]
827 std Y + %[bufferIdx], r26
829 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
830 ; bufferIdx is already incremented so decrement to compensate
833 subi r26, lo8(-(%[twiBuffer] - 1))
834 sbci r27, hi8(-(%[twiBuffer] - 1))
838 ; if (i2c_detail::data.bufferIdx < i2c_detail::data.bufferSize) {
851 ; i2c_detail::data.active = false;
853 rjmp active_false_reti
854; ----------------------------------------------------- ;
856 ; i2c_detail::data.error = TWSR;
857 std Y + %[error], r18
865 ; while (TWCR & _BV(TWSTO)) {}
868 sbrc r26, TWSTO ; skip if bit in register clear
872 ; i2c_detail::data.active = false;
873 std Y + %[active], __zero_reg__
875; --------------------- epilogue ---------------------- ;
898 [data]
"=m" (i2c_detail::data),
899 [twiBuffer]
"=m" (i2c_detail::data.twiBuffer)
901 [error]
"i" (offsetof(i2c_detail::i2c_data_t, error)),
902 [active]
"i" (offsetof(i2c_detail::i2c_data_t, active)),
903 [bufferIdx]
"i" (offsetof(i2c_detail::i2c_data_t, bufferIdx)),
904 [rxBuffer]
"i" (offsetof(i2c_detail::i2c_data_t, rxBuffer)),
905 [onRequestFunction]
"i" (offsetof(i2c_detail::i2c_data_t, onRequestFunction)),
906 [onReceiveFunction]
"i" (offsetof(i2c_detail::i2c_data_t, onReceiveFunction)),
907 [bufferSize]
"i" (offsetof(i2c_detail::i2c_data_t, bufferSize)),
908 [slaRW]
"i" (offsetof(i2c_detail::i2c_data_t, slaRW))
916 TWDR = i2c_detail::data.slaRW;
917 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
922 if (i2c_detail::data.bufferIdx < i2c_detail::data.bufferSize) {
923 TWDR = i2c_detail::data.twiBuffer[i2c_detail::data.bufferIdx++];
924 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
926 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTO) | _BV(TWEA);
927 while (TWCR & _BV(TWSTO)) { }
928 i2c_detail::data.active =
false;
932 i2c_detail::data.active =
false;
933 i2c_detail::data.error = TW_MT_ARB_LOST;
934 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
938 i2c_detail::data.rxBuffer[i2c_detail::data.bufferIdx++] = TWDR;
939 __attribute__((fallthrough));
941 if (i2c_detail::data.bufferIdx < i2c_detail::data.bufferSize) {
942 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
944 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
947 case TW_MR_DATA_NACK:
948 i2c_detail::data.rxBuffer[i2c_detail::data.bufferIdx++] = TWDR;
949 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTO) | _BV(TWEA);
950 while (TWCR & _BV(TWSTO)) { }
951 i2c_detail::data.active =
false;
955 case TW_ST_ARB_LOST_SLA_ACK:
956 i2c_detail::data.active =
true;
957 i2c_detail::data.onRequestFunction();
958 __attribute__((fallthrough));
960 TWDR = i2c_detail::data.twiBuffer[i2c_detail::data.bufferIdx++];
961 if (i2c_detail::data.bufferIdx < i2c_detail::data.bufferSize) {
962 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
964 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
967 case TW_ST_DATA_NACK:
968 case TW_ST_LAST_DATA:
969 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
970 i2c_detail::data.active =
false;
974 case TW_SR_GCALL_ACK:
975 case TW_SR_ARB_LOST_SLA_ACK:
976 case TW_SR_ARB_LOST_GCALL_ACK:
977 i2c_detail::data.bufferIdx = 0;
978 i2c_detail::data.active =
true;
979 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
981 case TW_SR_GCALL_DATA_ACK:
983 i2c_detail::data.twiBuffer[i2c_detail::data.bufferIdx++] = TWDR;
984 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
987 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
988 i2c_detail::data.onReceiveFunction(i2c_detail::data.twiBuffer);
989 i2c_detail::data.active =
false;
992 i2c_detail::data.error = TWSR;
993 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTO) | _BV(TWEA);
994 while (TWCR & _BV(TWSTO)) { }
995 i2c_detail::data.active =
false;
#define I2C_SCL_PIN
The pin on which the SCL line is connected.
Definition ArduboyI2C.h:79
#define I2C_SDA_PIN
The pin on which the SDA line is connected.
Definition ArduboyI2C.h:97
#define I2C_BUS_BUSY_CHECKS
The amount of times the bus is checked before continuing with a read/write operation.
Definition ArduboyI2C.h:69
#define I2C_HANDSHAKE_FAILED
Error code RETURNED by I2C::handshake, meaning the handshake has already been completed.
Definition ArduboyI2C.h:138
#define I2C_SCL_BIT
The bit of the pin on which the SCL line is connected.
Definition ArduboyI2C.h:88
#define I2C_BUFFER_SIZE
The size of the buffer used for writes/target (slave) operations.
Definition ArduboyI2C.h:53
#define I2C_MAX_PLAYERS
The maxmimum number of players in the handshake/lobby.
Definition ArduboyI2C.h:116
#define TW_SUCCESS
Error code used to mean success, returned by I2C::getTWError().
Definition ArduboyI2C.h:131
#define I2C_SDA_BIT
The bit of the pin on which the sda line is connected.
Definition ArduboyI2C.h:106
#define I2C_FREQUENCY
The initial I2C frequency.
Definition ArduboyI2C.h:44
Definition ArduboyI2C.h:159
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.