29#include <avr/interrupt.h>
43#define I2C_FREQUENCY 100000
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."
57#ifndef I2C_BUS_BUSY_CHECKS
68#define I2C_BUS_BUSY_CHECKS 16
78#define I2C_SCL_PIN PIND
87#define I2C_SCL_BIT PIND0
96#define I2C_SDA_PIN PIND
105#define I2C_SDA_BIT PIND1
115#define I2C_MAX_PLAYERS
125#define TW_SUCCESS 0xFF
132#define I2C_HANDSHAKE_FAILED 0xFE
141#define I2C_MAX_ADDRESSES 112
148#define I2C_LIB_VER 20100
172 static void setAddress(uint8_t address,
bool generalCall =
false);
190 static void write(uint8_t address,
const void *buffer, uint8_t size,
bool wait);
208 static void write(uint8_t address,
const T *
object,
bool wait);
221 static void read(uint8_t address,
void *buffer, uint8_t size);
236 static void read(uint8_t address, T *
object);
252 static void transmit(
const void *buffer, uint8_t size);
268 template <
typename T>
356#ifdef I2C_IMPLEMENTATION
360namespace i2c_detail {
363volatile uint8_t *rxBuffer;
364volatile uint8_t bufferIdx;
365volatile uint8_t bufferSize;
368volatile uint8_t slaRW;
369volatile uint8_t error;
371void (*onRequestFunction)();
372void (*onReceiveFunction)();
374#ifdef I2C_MAX_PLAYERS
376#if I2C_MAX_PLAYERS > I2C_MAX_ADDRESSES
377#error "Too many players. Max is I2C_MAX_ADDRESSES."
380volatile uint8_t handshakeState;
382void handshakeOnReceive() {
386void handshakeOnRequest() {
396 TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
402 TWAR = address << 1 | generalCall;
405void I2C::write(uint8_t address,
const void *buffer, uint8_t size,
bool wait) {
406 while (i2c_detail::active) {}
408 for (uint8_t i = 0; i < size; i++) {
409 i2c_detail::twiBuffer[i] = ((
const uint8_t *)buffer)[i];
411 i2c_detail::bufferIdx = 0;
412 i2c_detail::bufferSize = size;
416 i2c_detail::active =
true;
417 i2c_detail::slaRW = address << 1 | TW_WRITE;
424 i2c_detail::error = TW_MT_ARB_LOST;
429 TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);
431 while (i2c_detail::active) {}
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);
441void I2C::read(uint8_t address,
void *buffer, uint8_t size) {
442 while (i2c_detail::active) {}
444 i2c_detail::rxBuffer = (uint8_t *)buffer;
446 i2c_detail::bufferIdx = 0;
447 i2c_detail::bufferSize = size - 1;
451 i2c_detail::active =
true;
452 i2c_detail::slaRW = address << 1 | TW_READ;
459 i2c_detail::error = TW_MR_ARB_LOST;
464 TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);
465 while (i2c_detail::active) {}
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));
476 for (uint8_t i = 0; i < size; i++) {
477 i2c_detail::twiBuffer[i] = ((uint8_t *)buffer)[i];
479 i2c_detail::bufferIdx = 0;
480 i2c_detail::bufferSize = size;
485 static_assert(
sizeof(T) <=
I2C_BUFFER_SIZE,
"Size of T must be less than or equal to I2C_BUFFER_SIZE.");
490 i2c_detail::onRequestFunction = function;
493 i2c_detail::onReceiveFunction = function;
497 return i2c_detail::error;
501 return i2c_detail::twiBuffer;
508 return !(TWCR & _BV(TWWC));
511#ifdef I2C_MAX_PLAYERS
531 while (i2c_detail::handshakeState < i) { }
544ISR(TWI_vect, ISR_NAKED) {
547; --------------------- defines ----------------------- ;
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)
565; -------------------- registers ---------------------- ;
566; r18 - TWSR (never used after function call)
570; --------------------- prologue ---------------------- ;
576; save and restore call-clobbered registers
577; target (slave) could call function pointer
587; save and restore tmp and zero registers (could be used in function calls)
591; ----------------------------------------------------- ;
594lds r18, TWSR ; no mask needed because prescaler bits are cleared
605breq TW_MT_ARB_LOST ; same as TW_MR_ARB_LOST
613; 64 instruction limit on branches
617 ; TWDR = i2c_detail::slaRW;
628 ; if (i2c_detail::bufferIdx >= bufferSize) { stop(); return; }
629 lds r30, %[bufferIdx]
630 lds r31, %[bufferSize]
633 brlt 1f ; 64 instruction limit on branches
637 ; TWDR = i2c_detail::twiBuffer[i2c_detail::bufferIdx++];
639 sts %[bufferIdx], r30
641 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
642 ; bufferIdx is already incremented so decrement to compensate
645 subi r30, lo8(-(%[twiBuffer] - 1))
646 sbci r31, hi8(-(%[twiBuffer] - 1))
660 ; i2c_detail::error = TW_MT_ARB_LOST;
665 rjmp active_false_reti
666; ----------------------------------------------------- ;
670 ; i2c_detail::rxBuffer[i2c_detail::bufferIdx++] = TWDR;
671 lds r19, %[bufferIdx]
673 sts %[bufferIdx], r19
677 lds r31, %[rxBuffer] + 1
680 adc r31, __zero_reg__
685 ; if (TWSR == TW_MR_DATA_NACK) { stop(); return; }
688 brne 1f ; 64 instruction limit on branches
691; ------------------ fallthrough ---------------------- ;
693 ; if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
700 lds r30, %[bufferIdx]
701 lds r31, %[bufferSize]
709; ----------------------------------------------------- ;
714breq TW_SR_ARB_LOST_SLA_ACK
718breq TW_SR_ARB_LOST_GCALL_ACK
722breq TW_SR_GCALL_DATA_ACK
728breq TW_ST_ARB_LOST_SLA_ACK
739TW_SR_ARB_LOST_SLA_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__
754 ; i2c_detail::twiBuffer[i2c_detail::bufferIdx++] = TWDR;
755 lds r30, %[bufferIdx]
757 sts %[bufferIdx], r30
759 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
760 ; bufferIdx is already incremented so decrement to compensate
763 subi r30, lo8(-(%[twiBuffer] - 1))
764 sbci r31, hi8(-(%[twiBuffer] - 1))
777 ; i2c_detail::onReceiveFunction();
778 lds r30, %[onReceiveFunction]
779 lds r31, %[onReceiveFunction] + 1
781 ; i2c_detail::active = false;
783 rjmp active_false_reti;
785; ----------------------------------------------------- ;
786TW_ST_ARB_LOST_SLA_ACK:
788 ; i2c_detail::active = TWSR; (true)
790 ; i2c_detail::onRequestFunction();
791 lds 30, %[onRequestFunction]
792 lds 31, %[onRequestFunction] + 1
794; ------------------ fallthrough ---------------------- ;
796 ; TWDR = i2c_detail::twiBuffer[i2c_detail::bufferIdx++];
797 lds r30, %[bufferIdx]
799 sts %[bufferIdx], r30
801 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
802 ; bufferIdx is already incremented so decrement to compensate
805 subi r30, lo8(-(%[twiBuffer] - 1))
806 sbci r31, hi8(-(%[twiBuffer] - 1))
810 ; if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
823 ; i2c_detail::active = false;
825 rjmp active_false_reti
826; ----------------------------------------------------- ;
828 ; i2c_detail::error = TWSR;
837 ; while (TWCR & _BV(TWSTO)) {}
840 sbrc r30, TWSTO ; skip if bit in register clear
844 ; i2c_detail::active = false;
845 sts %[active], __zero_reg__
847; --------------------- epilogue ---------------------- ;
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)
874 [onRequestFunction]
"m" (i2c_detail::onRequestFunction),
875 [onReceiveFunction]
"m" (i2c_detail::onReceiveFunction),
876 [bufferSize]
"m" (i2c_detail::bufferSize),
877 [slaRW]
"m" (i2c_detail::slaRW)
885 TWDR = i2c_detail::slaRW;
886 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
891 if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
892 TWDR = i2c_detail::twiBuffer[i2c_detail::bufferIdx++];
893 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
895 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTO) | _BV(TWEA);
896 while (TWCR & _BV(TWSTO)) { }
897 i2c_detail::active =
false;
901 i2c_detail::active =
false;
902 i2c_detail::error = TW_MT_ARB_LOST;
903 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
907 i2c_detail::rxBuffer[i2c_detail::bufferIdx++] = TWDR;
908 __attribute__((fallthrough));
910 if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
911 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
913 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
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;
924 case TW_ST_ARB_LOST_SLA_ACK:
925 i2c_detail::active =
true;
926 i2c_detail::onRequestFunction();
927 __attribute__((fallthrough));
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);
933 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
936 case TW_ST_DATA_NACK:
937 case TW_ST_LAST_DATA:
938 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
939 i2c_detail::active =
false;
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);
950 case TW_SR_GCALL_DATA_ACK:
952 i2c_detail::twiBuffer[i2c_detail::bufferIdx++] = TWDR;
953 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
956 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
957 i2c_detail::onReceiveFunction(i2c_detail::twiBuffer);
958 i2c_detail::active =
false;
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;
#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.