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 20000
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>
349#ifdef I2C_IMPLEMENTATION
353namespace i2c_detail {
356volatile uint8_t *rxBuffer;
357volatile uint8_t bufferIdx;
358volatile uint8_t bufferSize;
361volatile uint8_t slaRW;
362volatile uint8_t error;
364void (*onRequestFunction)();
365void (*onReceiveFunction)();
368 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTO) | _BV(TWEA);
369 while (TWCR & _BV(TWSTO)) { }
370 i2c_detail::active =
false;
373#ifdef I2C_MAX_PLAYERS
375#if I2C_MAX_PLAYERS > I2C_MAX_ADDRESSES
376#error "Too many players. Max is I2C_MAX_ADDRESSES."
379volatile uint8_t handshakeState;
381void handshakeOnReceive() {
385void handshakeOnRequest() {
395 TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
401 TWAR = address << 1 | generalCall;
404void I2C::write(uint8_t address,
const void *buffer, uint8_t size,
bool wait) {
405 while (i2c_detail::active) {}
407 for (uint8_t i = 0; i < size; i++) {
408 i2c_detail::twiBuffer[i] = ((
const uint8_t *)buffer)[i];
410 i2c_detail::bufferIdx = 0;
411 i2c_detail::bufferSize = size;
415 i2c_detail::active =
true;
416 i2c_detail::slaRW = address << 1 | TW_WRITE;
427 TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);
429 while (i2c_detail::active) {}
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);
439void I2C::read(uint8_t address,
void *buffer, uint8_t size) {
440 while (i2c_detail::active) {}
442 i2c_detail::rxBuffer = (uint8_t *)buffer;
444 i2c_detail::bufferIdx = 0;
445 i2c_detail::bufferSize = size - 1;
449 i2c_detail::active =
true;
450 i2c_detail::slaRW = address << 1 | TW_READ;
461 TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);
462 while (i2c_detail::active) {}
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));
473 for (uint8_t i = 0; i < size; i++) {
474 i2c_detail::twiBuffer[i] = ((uint8_t *)buffer)[i];
476 i2c_detail::bufferIdx = 0;
477 i2c_detail::bufferSize = size;
482 static_assert(
sizeof(T) <=
I2C_BUFFER_SIZE,
"Size of T must be less than or equal to I2C_BUFFER_SIZE.");
487 i2c_detail::onRequestFunction = function;
490 i2c_detail::onReceiveFunction = function;
494 return i2c_detail::error;
498 return i2c_detail::twiBuffer;
501#ifdef I2C_MAX_PLAYERS
521 while (i2c_detail::handshakeState < i) { }
534ISR(TWI_vect, ISR_NAKED) {
537; --------------------- defines ----------------------- ;
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)
555; -------------------- registers ---------------------- ;
556; r18 - TWSR (never used after function call)
560; --------------------- prologue ---------------------- ;
566; save and restore call-clobbered registers
567; target (slave) could call function pointer
577; save and restore tmp and zero registers (could be used in function calls)
581; ----------------------------------------------------- ;
584lds r18, TWSR ; no mask needed because prescaler bits are cleared
595breq TW_MT_ARB_LOST ; same as TW_MR_ARB_LOST
603; 64 instruction limit on branches
607 ; TWDR = i2c_detail::slaRW;
618 ; if (i2c_detail::bufferIdx >= bufferSize) { stop(); return; }
619 lds r30, %[bufferIdx]
620 lds r31, %[bufferSize]
623 brlt 1f ; 64 instruction limit on branches
627 ; TWDR = i2c_detail::twiBuffer[i2c_detail::bufferIdx++];
628 ; Increment bufferIdx but preserve r30
630 sts %[bufferIdx], r30
633 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
635 subi r30, lo8(-(%[twiBuffer]))
636 sbci r31, hi8(-(%[twiBuffer]))
640 ; https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48APA88APA168APA328P-SiliConErrataClarif-DS80000855A.pdf
654 ; i2c_detail::error = TW_MT_ARB_LOST;
659 rjmp active_false_reti
660; ----------------------------------------------------- ;
664 ; i2c_detail::rxBuffer[i2c_detail::bufferIdx++] = TWDR;
665 lds r30, %[bufferIdx]
667 sts %[bufferIdx], r30
670 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
672 subi r30, lo8(-(%[rxBuffer]))
673 sbci r31, hi8(-(%[rxBuffer]))
677 ; if (TWSR == TW_MR_DATA_NACK) { stop(); return; }
680 brne 1f ; 64 instruction limit on branches
683; ------------------ fallthrough ---------------------- ;
685 ; if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
692 lds r30, %[bufferIdx]
693 lds r31, %[bufferSize]
701; ----------------------------------------------------- ;
706breq TW_SR_ARB_LOST_SLA_ACK
710breq TW_SR_ARB_LOST_GCALL_ACK
714breq TW_SR_GCALL_DATA_ACK
720breq TW_ST_ARB_LOST_SLA_ACK
731TW_SR_ARB_LOST_SLA_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__
746 ; i2c_detail::twiBuffer[i2c_detail::bufferIdx++] = TWDR;
747 lds r30, %[bufferIdx]
749 sts %[bufferIdx], r30
752 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
754 subi r30, lo8(-(%[twiBuffer]))
755 sbci r31, hi8(-(%[twiBuffer]))
768 ; i2c_detail::onReceiveFunction();
769 lds r30, %[onReceiveFunction]
770 lds r31, %[onReceiveFunction] + 1
772 ; i2c_detail::active = false;
774 rjmp active_false_reti;
776; ----------------------------------------------------- ;
777TW_ST_ARB_LOST_SLA_ACK:
779 ; i2c_detail::active = TWSR; (true)
781 ; i2c_detail::onRequestFunction();
782 lds 30, %[onRequestFunction]
783 lds 31, %[onRequestFunction] + 1
785; ------------------ fallthrough ---------------------- ;
787 ; TWDR = i2c_detail::twiBuffer[i2c_detail::bufferIdx++];
788 lds r30, %[bufferIdx]
790 sts %[bufferIdx], r30
792 ; Use SUBI and SBCI as (non-existant) ADDI and (non-existant) ADCI
794 subi r30, lo8(-(%[twiBuffer]))
795 sbci r31, hi8(-(%[twiBuffer]))
799 ; if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
812 ; i2c_detail::active = false;
814 rjmp active_false_reti
815; ----------------------------------------------------- ;
817 ; i2c_detail::error = TWSR;
826 ; while (TWCR & _BV(TWSTO)) {}
829 sbrc r30, TWSTO ; skip if bit in register clear
833 ; i2c_detail::active = false;
834 sts %[active], __zero_reg__
836; --------------------- epilogue ---------------------- ;
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)
863 [onRequestFunction]
"m" (i2c_detail::onRequestFunction),
864 [onReceiveFunction]
"m" (i2c_detail::onReceiveFunction),
865 [bufferSize]
"m" (i2c_detail::bufferSize),
866 [slaRW]
"m" (i2c_detail::slaRW)
874 TWDR = i2c_detail::slaRW;
875 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
880 if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
881 TWDR = i2c_detail::twiBuffer[i2c_detail::bufferIdx++];
882 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
888 i2c_detail::active =
false;
889 i2c_detail::error = TW_MT_ARB_LOST;
890 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
894 i2c_detail::rxBuffer[i2c_detail::bufferIdx++] = TWDR;
895 __attribute__((fallthrough));
897 if (i2c_detail::bufferIdx < i2c_detail::bufferSize) {
898 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
900 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
903 case TW_MR_DATA_NACK:
904 i2c_detail::rxBuffer[i2c_detail::bufferIdx++] = TWDR;
909 case TW_ST_ARB_LOST_SLA_ACK:
910 i2c_detail::active =
true;
911 i2c_detail::onRequestFunction();
912 __attribute__((fallthrough));
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);
918 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE);
921 case TW_ST_DATA_NACK:
922 case TW_ST_LAST_DATA:
923 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
924 i2c_detail::active =
false;
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);
935 case TW_SR_GCALL_DATA_ACK:
937 i2c_detail::twiBuffer[i2c_detail::bufferIdx++] = TWDR;
938 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
941 TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
942 i2c_detail::onReceiveFunction(i2c_detail::twiBuffer);
943 i2c_detail::active =
false;
946 i2c_detail::error = TWSR;
#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.