diff --git a/avr/cores/tiny/WInterrupts.c b/avr/cores/tiny/WInterrupts.c index eea5d8a..d15d724 100644 --- a/avr/cores/tiny/WInterrupts.c +++ b/avr/cores/tiny/WInterrupts.c @@ -34,7 +34,7 @@ static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS]; -void attachInterrupt(uint8_t pin, void (*userFunc)(void), PinStatus mode) { +void attachInterrupt(uint8_t pin, void (*userFunc)(void), uint8_t mode) { /* Get bit position and check pin validity */ uint8_t bit_pos = digitalPinToBitPosition(pin); diff --git a/avr/cores/tiny/api/Common.h b/avr/cores/tiny/api/Common.h index 302be4c..473dfc2 100644 --- a/avr/cores/tiny/api/Common.h +++ b/avr/cores/tiny/api/Common.h @@ -6,25 +6,37 @@ extern "C"{ void yield(void); -typedef enum { - LOW = 0, - HIGH = 1, - CHANGE = 2, - FALLING = 3, - RISING = 4, -} PinStatus; - -typedef enum { - INPUT = 0x0, - OUTPUT = 0x1, - INPUT_PULLUP = 0x2, - INPUT_PULLDOWN = 0x3, -} PinMode; - -typedef enum { - LSBFIRST = 0, - MSBFIRST = 1, -} BitOrder; +#define LOW 0x00 +#define HIGH 0x01 +#define CHANGE 0x04 +#define FALLING 0x02 +#define RISING 0x03 +#define INPUT 0x00 +#define OUTPUT 0x01 +#define INPUT_PULLUP 0x02 +#define LSBFIRST 0x00 +#define MSBFIRST 0x01 +#define FLOAT HIGH + +// typedef enum { +// LOW = 0, +// HIGH = 1, +// CHANGE = 2, +// FALLING = 3, +// RISING = 4, +// } PinStatus; + +// typedef enum { +// INPUT = 0x0, +// OUTPUT = 0x1, +// INPUT_PULLUP = 0x2, +// INPUT_PULLDOWN = 0x3, +// } PinMode; + +// typedef enum { +// LSBFIRST = 0, +// MSBFIRST = 1, +// } BitOrder; #define PI 3.1415926535897932384626433832795 #define HALF_PI 1.5707963267948966192313216916398 @@ -100,9 +112,9 @@ typedef uint32_t pin_size_t; typedef uint8_t pin_size_t; #endif -void pinMode(pin_size_t pinNumber, PinMode pinMode); -void digitalWrite(pin_size_t pinNumber, PinStatus status); -PinStatus digitalRead(pin_size_t pinNumber); +void pinMode(pin_size_t pinNumber, uint8_t mode); +void digitalWrite(pin_size_t pinNumber, uint8_t val); +int8_t digitalRead(pin_size_t pinNumber); int analogRead(pin_size_t pinNumber); void analogReference(uint8_t mode); void analogWrite(pin_size_t pinNumber, int value); @@ -114,10 +126,10 @@ void delayMicroseconds(unsigned int us); unsigned long pulseIn(pin_size_t pin, uint8_t state, unsigned long timeout); unsigned long pulseInLong(pin_size_t pin, uint8_t state, unsigned long timeout); -void shiftOut(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOrder, uint8_t val); -pin_size_t shiftIn(pin_size_t dataPin, pin_size_t clockPin, BitOrder bitOrder); +void shiftOut(pin_size_t dataPin, pin_size_t clockPin, uint8_t bitOrder, uint8_t val); +pin_size_t shiftIn(pin_size_t dataPin, pin_size_t clockPin, uint8_t bitOrder); -void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, PinStatus mode); +void attachInterrupt(pin_size_t interruptNumber, voidFuncPtr callback, uint8_t mode); void detachInterrupt(pin_size_t interruptNumber); void setup(void); diff --git a/avr/cores/tiny/wiring_digital.c b/avr/cores/tiny/wiring_digital.c index 04de889..15a8cf8 100644 --- a/avr/cores/tiny/wiring_digital.c +++ b/avr/cores/tiny/wiring_digital.c @@ -30,7 +30,7 @@ __attribute__((weak)) bool isDoubleBondedActive(uint8_t pin __attribute__((unus return false; }; -void pinMode(uint8_t pin, PinMode mode) +void pinMode(uint8_t pin, uint8_t mode) { uint8_t bit_mask = digitalPinToBitMask(pin); @@ -141,7 +141,7 @@ static void turnOffPWM(uint8_t pin) } } -void digitalWrite(uint8_t pin, PinStatus val) +void digitalWrite(uint8_t pin, uint8_t val) { /* Get bit mask for pin */ uint8_t bit_mask = digitalPinToBitMask(pin); @@ -204,7 +204,7 @@ void digitalWrite(uint8_t pin, PinStatus val) } -PinStatus digitalRead(uint8_t pin) +int8_t digitalRead(uint8_t pin) { /* Get bit mask and check valid pin */ uint8_t bit_mask = digitalPinToBitMask(pin); diff --git a/avr/cores/tiny/wiring_shift.c b/avr/cores/tiny/wiring_shift.c index 0848df9..441fcd3 100644 --- a/avr/cores/tiny/wiring_shift.c +++ b/avr/cores/tiny/wiring_shift.c @@ -22,7 +22,7 @@ #include -uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, BitOrder bitOrder) { +uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) { uint8_t value = 0; uint8_t i; @@ -37,7 +37,7 @@ uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, BitOrder bitOrder) { return value; } -void shiftOut(uint8_t dataPin, uint8_t clockPin, BitOrder bitOrder, uint8_t val) +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) { uint8_t i; diff --git a/avr/libraries/SPI/src/SPI.cpp b/avr/libraries/SPI/src/SPI.cpp index 5888c8f..ebae00e 100644 --- a/avr/libraries/SPI/src/SPI.cpp +++ b/avr/libraries/SPI/src/SPI.cpp @@ -204,7 +204,7 @@ void SPIClass::endTransaction(void) } } -void SPIClass::setBitOrder(BitOrder order) +void SPIClass::setBitOrder(uint8_t order) { if (order == LSBFIRST) SPI0.CTRLA |= (SPI_DORD_bm); diff --git a/avr/libraries/SPI/src/SPI.h b/avr/libraries/SPI/src/SPI.h index 18262c9..1094646 100644 --- a/avr/libraries/SPI/src/SPI.h +++ b/avr/libraries/SPI/src/SPI.h @@ -54,7 +54,7 @@ class SPISettings { public: - SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) { + SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { if (__builtin_constant_p(clock)) { init_AlwaysInline(clock, bitOrder, dataMode); } else { @@ -66,11 +66,11 @@ class SPISettings { SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); } private: - void init_MightInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) { + void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { init_AlwaysInline(clock, bitOrder, dataMode); } - void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) __attribute__((__always_inline__)) { + void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) __attribute__((__always_inline__)) { // Clock settings are defined as follows. Note that this shows SPI2X // inverted, so the bits form increasing numbers. Also note that // fosc/64 appears twice. If FOSC is 16 Mhz @@ -162,7 +162,7 @@ class SPIClass { void begin(); void end(); - void setBitOrder(BitOrder order); + void setBitOrder(uint8_t order); void setDataMode(uint8_t uc_mode); void setClockDivider(uint8_t uc_div); diff --git a/avr/libraries/Wire/src/Wire.cpp b/avr/libraries/Wire/src/Wire.cpp index b535683..3d5f209 100644 --- a/avr/libraries/Wire/src/Wire.cpp +++ b/avr/libraries/Wire/src/Wire.cpp @@ -15,32 +15,34 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - + Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts Modified 2017 by Chuck Todd (ctodd@cableone.net) to correct Unconfigured Slave Mode reboot */ extern "C" { - #include - #include - #include - #include "utility/twi.h" +#include +#include +#include +#include "utility/twi.h" } #include "Wire.h" -#define DEFAULT_FREQUENCY 100000 +#ifndef DEFAULT_FREQUENCY + #define DEFAULT_FREQUENCY 100000 +#endif // Initialize Class Variables ////////////////////////////////////////////////// uint8_t TwoWire::rxBuffer[BUFFER_LENGTH]; -uint8_t TwoWire::rxBufferIndex = 0; //head -uint8_t TwoWire::rxBufferLength = 0; //tail +uint8_t TwoWire::rxBufferIndex = 0; //head +uint8_t TwoWire::rxBufferLength = 0; //tail uint8_t TwoWire::txAddress = 0; uint8_t TwoWire::txBuffer[BUFFER_LENGTH]; -uint8_t TwoWire::txBufferIndex = 0; //head -uint8_t TwoWire::txBufferLength = 0; //tail +uint8_t TwoWire::txBufferIndex = 0; //head +uint8_t TwoWire::txBufferLength = 0; //tail uint8_t TwoWire::transmitting = 0; void (*TwoWire::user_onRequest)(void); @@ -48,88 +50,205 @@ void (*TwoWire::user_onReceive)(int); // Constructors //////////////////////////////////////////////////////////////// -TwoWire::TwoWire() -{ +TwoWire::TwoWire() { } // Public Methods ////////////////////////////////////////////////////////////// -void TwoWire::useAlternatePins(){ - PORTMUX.CTRLB |= PORTMUX_TWI0_ALTERNATE_gc; +// Special for megaAVR 0-series: Select which pins to use for I2C interface +// True if pin specification actually exists +// Note that we do not currently support the dual TWI mode +bool TwoWire::pins(uint8_t sda_pin, uint8_t scl_pin) { + #if defined(PORTMUX_CTRLB) + #if defined(PIN_WIRE_SDA_PINSWAP_1) && defined(PIN_WIRE_SCL_PINSWAP_1) + if (sda_pin == PIN_WIRE_SDA_PINSWAP_1 && scl_pin == PIN_WIRE_SCL_PINSWAP_1) { + // Use pin swap + PORTMUX.CTRLB |= PORTMUX_TWI0_bm; + return true; + } else if (sda_pin == PIN_WIRE_SDA && scl_pin == PIN_WIRE_SCL) { + // Use default configuration + PORTMUX.CTRLB &= ~PORTMUX_TWI0_bm; + return true; + } else { + // Assume default configuration + PORTMUX.CTRLB &= ~PORTMUX_TWI0_bm; + return false; + } + #else //keep compiler happy + return (sda_pin == PIN_WIRE_SDA && scl_pin == PIN_WIRE_SCL); + #endif + #elif defined(PORTMUX_TWIROUTEA) + if (sda_pin == PIN_WIRE_SDA_PINSWAP_2 && scl_pin == PIN_WIRE_SCL_PINSWAP_2) { + // Use pin swap + PORTMUX.TWIROUTEA = (PORTMUX.TWIROUTEA & 0xFC) | 0x02; + return true; + } else if (sda_pin == PIN_WIRE_SDA && scl_pin == PIN_WIRE_SCL) { + // Use default configuration + PORTMUX.TWIROUTEA = (PORTMUX.TWIROUTEA & 0xFC); + return true; + } else { + // Assume default configuration + PORTMUX.TWIROUTEA = (PORTMUX.TWIROUTEA & 0xFC); + return false; + } + #endif + return false; +} + +bool TwoWire::swap(uint8_t state) { + #if defined(PORTMUX_CTRLB) + #if defined(PIN_WIRE_SDA_PINSWAP_1) && defined(PIN_WIRE_SCL_PINSWAP_1) + if (state == 1) { + // Use pin swap + PORTMUX.CTRLB |= PORTMUX_TWI0_bm; + return true; + } else if (state == 0) { + // Use default configuration + PORTMUX.CTRLB &= ~PORTMUX_TWI0_bm; + return true; + } else { + // Assume default configuration + PORTMUX.CTRLB &= ~PORTMUX_TWI0_bm; + return false; + } + #else //keep compiler happy + return (state == 0); + #endif + #elif defined(PORTMUX_TWIROUTEA) + if (state == 2) { + // Use pin swap + PORTMUX.TWIROUTEA = (PORTMUX.TWIROUTEA & 0xFC) | 0x02; + return true; + } else if (state == 1) { + // Use pin swap + PORTMUX.TWIROUTEA = (PORTMUX.TWIROUTEA & 0xFC) | 0x01; + return true; + } else if (state == 0) { + // Use default configuration + PORTMUX.TWIROUTEA = (PORTMUX.TWIROUTEA & 0xFC); + return true; + } else { + // Assume default configuration + PORTMUX.TWIROUTEA = (PORTMUX.TWIROUTEA & 0xFC); + return false; + } + #endif + return false; } -void TwoWire::begin(void) -{ - rxBufferIndex = 0; - rxBufferLength = 0; +void TwoWire::usePullups() { + #ifdef PORTMUX_TWIROUTEA + if ((PORTMUX.TWIROUTEA & PORTMUX_TWI0_gm) == 0x02) { + // make sure we don't get errata'ed - make sure their bits in the + // PORTx.OUT registers are 0. + PORTC.OUTCLR = 0x0C; //bits 2 and 3 + } else { + PORTA.OUTCLR = 0x0C; //bits 2 and 3 + } + #else // megaTinyCore + #if defined(PORTMUX_TWI0_bm) + if ((PORTMUX.CTRLB & PORTMUX_TWI0_bm)) { + PORTA.PIN2CTRL |= PORT_PULLUPEN_bm; + PORTA.PIN1CTRL |= PORT_PULLUPEN_bm; + } else { + PORTB.PIN1CTRL |= PORT_PULLUPEN_bm; + PORTB.PIN0CTRL |= PORT_PULLUPEN_bm; + } + #elif defined(__AVR_ATtinyxy2__) + PORTA.PIN2CTRL |= PORT_PULLUPEN_bm; + PORTA.PIN1CTRL |= PORT_PULLUPEN_bm; + #else + PORTB.PIN1CTRL |= PORT_PULLUPEN_bm; + PORTB.PIN0CTRL |= PORT_PULLUPEN_bm; + #endif + #endif +} - txBufferIndex = 0; - txBufferLength = 0; +void TwoWire::begin(void) { + rxBufferIndex = 0; + rxBufferLength = 0; - TWI_MasterInit(DEFAULT_FREQUENCY); + txBufferIndex = 0; + txBufferLength = 0; + + TWI_MasterInit(DEFAULT_FREQUENCY); } -void TwoWire::begin(uint8_t address) -{ - rxBufferIndex = 0; - rxBufferLength = 0; +void TwoWire::begin(uint8_t address, bool receive_broadcast, uint8_t second_address) { + rxBufferIndex = 0; + rxBufferLength = 0; + + txBufferIndex = 0; + txBufferLength = 0; + + TWI_SlaveInit(address, receive_broadcast, second_address); - txBufferIndex = 0; - txBufferLength = 0; - - TWI_SlaveInit(address); - - TWI_attachSlaveTxEvent(onRequestService, txBuffer); // default callback must exist - TWI_attachSlaveRxEvent(onReceiveService, rxBuffer, BUFFER_LENGTH); // default callback must exist - + TWI_attachSlaveTxEvent(onRequestService, txBuffer); // default callback must exist + TWI_attachSlaveRxEvent(onReceiveService, rxBuffer, BUFFER_LENGTH); // default callback must exist + +} + +void TwoWire::begin(int address, bool receive_broadcast, uint8_t second_address) { + begin((uint8_t)address, receive_broadcast, second_address); } -void TwoWire::begin(int address) -{ - begin((uint8_t)address); +void TwoWire::begin(uint8_t address, bool receive_broadcast) { + begin(address, receive_broadcast, 0); } -void TwoWire::end(void) -{ - TWI_Disable(); +void TwoWire::begin(int address, bool receive_broadcast) { + begin((uint8_t)address, receive_broadcast, 0); } -void TwoWire::setClock(uint32_t clock) -{ - TWI_MasterSetBaud(clock); +void TwoWire::begin(uint8_t address) { + begin(address, 0, 0); } -uint8_t TwoWire::requestFrom(uint8_t address, size_t quantity, bool sendStop) { - if(quantity > BUFFER_LENGTH){ - quantity = BUFFER_LENGTH; - } - - uint8_t bytes_read = TWI_MasterRead(address, rxBuffer, quantity, sendStop); - - /* Initialize read variables */ - rxBufferIndex = 0; - rxBufferLength = bytes_read; +void TwoWire::begin(int address) { + begin((uint8_t)address, 0, 0); +} +void TwoWire::end(void) { + TWI_Disable(); +} - return bytes_read; +void TwoWire::setClock(uint32_t clock) { + TWI_MasterSetBaud(clock); } -uint8_t TwoWire::requestFrom(uint8_t address, size_t quantity) -{ - return requestFrom(address, quantity, true); +uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) { + if (quantity > BUFFER_LENGTH) { + quantity = BUFFER_LENGTH; + } + + uint8_t bytes_read = TWI_MasterRead(address, rxBuffer, quantity, sendStop); + + /* Initialize read variables */ + rxBufferIndex = 0; + rxBufferLength = bytes_read; + + return bytes_read; +} +uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) { + return requestFrom(address, quantity, (uint8_t)1); +} +// Translate "new" style of call to requestFrom() +uint8_t TwoWire::requestFrom(uint8_t address, size_t quantity) { + return requestFrom(address, (uint8_t)quantity, (uint8_t)1); +} +// Translate "new" style of call with three args to traditional requestFrom() +uint8_t TwoWire::requestFrom(uint8_t address, size_t quantity, bool sendStop) { + return requestFrom(address, (uint8_t)quantity, (uint8_t)sendStop); } -uint8_t TwoWire::requestFrom(int address, int quantity) -{ - return requestFrom((uint8_t)address, (size_t)quantity, true); +uint8_t TwoWire::requestFrom(int address, int quantity) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)1); } -uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) -{ - return requestFrom((uint8_t)address, (size_t)quantity, (bool)sendStop); +uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) { + return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); } -void TwoWire::beginTransmission(uint8_t address) -{ +void TwoWire::beginTransmission(uint8_t address) { // indicate that we are transmitting transmitting = 1; // set address of targeted slave @@ -139,192 +258,179 @@ void TwoWire::beginTransmission(uint8_t address) txBufferLength = 0; } -void TwoWire::beginTransmission(int address) -{ - beginTransmission((uint8_t)address); +void TwoWire::beginTransmission(int address) { + beginTransmission((uint8_t)address); } // -// Originally, 'endTransmission' was an f(void) function. -// It has been modified to take one parameter indicating -// whether or not a STOP should be performed on the bus. -// Calling endTransmission(false) allows a sketch to -// perform a repeated start. +// Originally, 'endTransmission' was an f(void) function. +// It has been modified to take one parameter indicating +// whether or not a STOP should be performed on the bus. +// Calling endTransmission(false) allows a sketch to +// perform a repeated start. // -// WARNING: Nothing in the library keeps track of whether -// the bus tenure has been properly ended with a STOP. It -// is very possible to leave the bus in a hung state if -// no call to endTransmission(true) is made. Some I2C -// devices will behave oddly if they do not see a STOP. +// WARNING: Nothing in the library keeps track of whether +// the bus tenure has been properly ended with a STOP. It +// is very possible to leave the bus in a hung state if +// no call to endTransmission(true) is made. Some I2C +// devices will behave oddly if they do not see a STOP. // -uint8_t TwoWire::endTransmission(bool sendStop) -{ - // transmit buffer (blocking) - uint8_t status = TWI_MasterWrite(txAddress, txBuffer, txBufferLength, sendStop); - - // reset tx buffer iterator vars - txBufferIndex = 0; - txBufferLength = 0; - - // indicate that we are done transmitting - transmitting = 0; - - return status; -} - -// This provides backwards compatibility with the original -// definition, and expected behaviour, of endTransmission +uint8_t TwoWire::endTransmission(bool sendStop) { + // transmit buffer (blocking) + uint8_t status = TWI_MasterWrite(txAddress, txBuffer, txBufferLength, sendStop); + + // reset tx buffer iterator vars + txBufferIndex = 0; + txBufferLength = 0; + + // indicate that we are done transmitting + transmitting = 0; + + return status; +} + +// This provides backwards compatibility with the original +// definition, and expected behaviour, of endTransmission // -uint8_t TwoWire::endTransmission(void) -{ +uint8_t TwoWire::endTransmission(void) { return endTransmission(true); } // must be called in: // slave tx event callback // or after beginTransmission(address) -size_t TwoWire::write(uint8_t data) -{ - /* Check if buffer is full */ - if(txBufferLength >= BUFFER_LENGTH){ - setWriteError(); - return 0; - } +size_t TwoWire::write(uint8_t data) { + /* Check if buffer is full */ + if (txBufferLength >= BUFFER_LENGTH) { + setWriteError(); + return 0; + } + + /* Put byte in txBuffer */ + txBuffer[txBufferIndex] = data; + txBufferIndex++; - /* Put byte in txBuffer */ - txBuffer[txBufferIndex] = data; - txBufferIndex++; + /* Update buffer length */ + txBufferLength = txBufferIndex; - /* Update buffer length */ - txBufferLength = txBufferIndex; - - return 1; + return 1; } // must be called in: // slave tx event callback // or after beginTransmission(address) -size_t TwoWire::write(const uint8_t *data, size_t quantity) -{ +size_t TwoWire::write(const uint8_t *data, size_t quantity) { - for(size_t i = 0; i < quantity; i++){ - write(*(data + i)); - } + for (size_t i = 0; i < quantity; i++) { + write(*(data + i)); + } - return quantity; + return quantity; } + // must be called in: // slave rx event callback // or after requestFrom(address, numBytes) -int TwoWire::available(void) -{ - return rxBufferLength - rxBufferIndex; +int TwoWire::available(void) { + return rxBufferLength - rxBufferIndex; } // must be called in: // slave rx event callback // or after requestFrom(address, numBytes) -int TwoWire::read(void) -{ - int value = -1; - - // get each successive byte on each call - if(rxBufferIndex < rxBufferLength){ - value = rxBuffer[rxBufferIndex]; - rxBufferIndex++; - } +int TwoWire::read(void) { + int value = -1; + + // get each successive byte on each call + if (rxBufferIndex < rxBufferLength) { + value = rxBuffer[rxBufferIndex]; + rxBufferIndex++; + } - return value; + return value; } // must be called in: // slave rx event callback // or after requestFrom(address, numBytes) -int TwoWire::peek(void) -{ - int value = -1; - - if(rxBufferIndex < rxBufferLength){ - value = rxBuffer[rxBufferIndex]; - } - - return value; -} - -// can be used to get out of an error state in TWI module -// e.g. when MDATA regsiter is written before MADDR -void TwoWire::flush(void) -{ -// /* Clear buffers */ -// for(uint8_t i = 0; i < BUFFER_LENGTH; i++){ -// txBuffer[i] = 0; -// rxBuffer[i] = 0; -// } -// -// /* Clear buffer variables */ -// txBufferIndex = 0; -// txBufferLength = 0; -// rxBufferIndex = 0; -// rxBufferLength = 0; -// -// /* Turn off and on TWI module */ -// TWI_Flush(); +int TwoWire::peek(void) { + int value = -1; + + if (rxBufferIndex < rxBufferLength) { + value = rxBuffer[rxBufferIndex]; + } + + return value; +} + +// can be used to get out of an error state in TWI module +// e.g. when MDATA register is written before MADDR +void TwoWire::flush(void) { + // /* Clear buffers */ + // for(uint8_t i = 0; i < BUFFER_LENGTH; i++){ + // txBuffer[i] = 0; + // rxBuffer[i] = 0; + // } + // + // /* Clear buffer variables */ + // txBufferIndex = 0; + // txBufferLength = 0; + // rxBufferIndex = 0; + // rxBufferLength = 0; + // + // /* Turn off and on TWI module */ + // TWI_Flush(); } // behind the scenes function that is called when data is received -void TwoWire::onReceiveService(int numBytes) -{ - // don't bother if user hasn't registered a callback - if(!user_onReceive){ - return; - } - // don't bother if rx buffer is in use by a master requestFrom() op - // i know this drops data, but it allows for slight stupidity - // meaning, they may not have read all the master requestFrom() data yet - if(rxBufferIndex < rxBufferLength){ - return; - } - - // set rx iterator vars - rxBufferIndex = 0; - rxBufferLength = numBytes; - - // alert user program - user_onReceive(numBytes); +void TwoWire::onReceiveService(int numBytes) { + // don't bother if user hasn't registered a callback + if (!user_onReceive) { + return; + } + // don't bother if rx buffer is in use by a master requestFrom() op + // i know this drops data, but it allows for slight stupidity + // meaning, they may not have read all the master requestFrom() data yet + if (rxBufferIndex < rxBufferLength) { + return; + } + + // set rx iterator vars + rxBufferIndex = 0; + rxBufferLength = numBytes; + + // alert user program + user_onReceive(numBytes); } // behind the scenes function that is called when data is requested -uint8_t TwoWire::onRequestService(void) -{ - // don't bother if user hasn't registered a callback - if(!user_onRequest){ - return 0; - } - - // reset slave write buffer iterator var - txBufferIndex = 0; - txBufferLength = 0; - - // alert user program - user_onRequest(); - - return txBufferLength; +uint8_t TwoWire::onRequestService(void) { + // don't bother if user hasn't registered a callback + if (!user_onRequest) { + return 0; + } + + // reset slave write buffer iterator var + txBufferIndex = 0; + txBufferLength = 0; + + // alert user program + user_onRequest(); + + return txBufferLength; } // sets function called on slave write -void TwoWire::onReceive( void (*function)(int) ) -{ - user_onReceive = function; +void TwoWire::onReceive(void (*function)(int)) { + user_onReceive = function; } // sets function called on slave read -void TwoWire::onRequest( void (*function)(void) ) -{ - user_onRequest = function; +void TwoWire::onRequest(void (*function)(void)) { + user_onRequest = function; } // Preinstantiate Objects ////////////////////////////////////////////////////// TwoWire Wire = TwoWire(); - diff --git a/avr/libraries/Wire/src/Wire.h b/avr/libraries/Wire/src/Wire.h index 94d5b73..18019f1 100644 --- a/avr/libraries/Wire/src/Wire.h +++ b/avr/libraries/Wire/src/Wire.h @@ -24,16 +24,23 @@ #include -#if ((RAMEND - RAMSTART) < 1023) -#define BUFFER_LENGTH 16 -#else -#define BUFFER_LENGTH 32 +#ifndef BUFFER_LENGTH + #if ((RAMEND - RAMSTART) < 1023) + #define BUFFER_LENGTH 16 + #elif ((RAMEND - RAMSTART) < 4095) + #define BUFFER_LENGTH 32 + #elif ((RAMEND - RAMSTART) < 8191) + #define BUFFER_LENGTH 64 + #else + #define BUFFER_LENGTH 128 + #endif #endif -// WIRE_HAS_END means Wire has end() -#define WIRE_HAS_END 1 -class TwoWire : public HardwareI2C -{ +// WIRE_HAS_END means Wire has end() +#ifndef WIRE_HAS_END + #define WIRE_HAS_END 1 +#endif +class TwoWire : public Stream { private: static uint8_t rxBuffer[]; static uint8_t rxBufferIndex; @@ -51,16 +58,24 @@ class TwoWire : public HardwareI2C static void onReceiveService(int); public: TwoWire(); + bool pins(uint8_t sda_pin, uint8_t scl_pin); + bool swap(uint8_t state = 1); + void usePullups(); void begin(); void begin(uint8_t); void begin(int); + void begin(uint8_t, bool, uint8_t); + void begin(int, bool, uint8_t); + void begin(uint8_t, bool); + void begin(int, bool); void end(); void setClock(uint32_t); void beginTransmission(uint8_t); void beginTransmission(int); - void useAlternatePins(); uint8_t endTransmission(void); uint8_t endTransmission(bool); + uint8_t requestFrom(uint8_t, uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint8_t); uint8_t requestFrom(uint8_t, size_t); uint8_t requestFrom(uint8_t, size_t, bool); uint8_t requestFrom(int, int); @@ -71,17 +86,24 @@ class TwoWire : public HardwareI2C virtual int read(void); virtual int peek(void); virtual void flush(void); - void onReceive( void (*)(int) ); - void onRequest( void (*)(void) ); + void onReceive(void (*)(int)); + void onRequest(void (*)(void)); - inline size_t write(unsigned long n) { return write((uint8_t)n); } - inline size_t write(long n) { return write((uint8_t)n); } - inline size_t write(unsigned int n) { return write((uint8_t)n); } - inline size_t write(int n) { return write((uint8_t)n); } + inline size_t write(unsigned long n) { + return write((uint8_t)n); + } + inline size_t write(long n) { + return write((uint8_t)n); + } + inline size_t write(unsigned int n) { + return write((uint8_t)n); + } + inline size_t write(int n) { + return write((uint8_t)n); + } using Print::write; }; extern TwoWire Wire; #endif - diff --git a/avr/libraries/Wire/src/utility/twi.c b/avr/libraries/Wire/src/utility/twi.c index 4b87a29..14171be 100644 --- a/avr/libraries/Wire/src/utility/twi.c +++ b/avr/libraries/Wire/src/utility/twi.c @@ -1,23 +1,23 @@ /****************************************************************************** -* © 2018 Microchip Technology Inc. and its subsidiaries. -* -* Subject to your compliance with these terms, you may use Microchip software -* and any derivatives exclusively with Microchip products. It is your -* responsibility to comply with third party license terms applicable to your -* use of third party software (including open source software) that may -* accompany Microchip software. -* -* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER -* EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED -* WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A PARTICULAR -* PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, -* PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY -* KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP -* HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE -* FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN -* ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, -* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. -* + © 2018 Microchip Technology Inc. and its subsidiaries. + + Subject to your compliance with these terms, you may use Microchip software + and any derivatives exclusively with Microchip products. It is your + responsibility to comply with third party license terms applicable to your + use of third party software (including open source software) that may + accompany Microchip software. + + THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A PARTICULAR + PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, + PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY + KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP + HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE + FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN + ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + *****************************************************************************/ #include "twi.h" @@ -25,8 +25,8 @@ /* Master variables */ static register8_t master_slaveAddress; /*!< Slave address */ -static register8_t* master_writeData; /*!< Data to write */ -static register8_t* master_readData; /*!< Read data */ +static register8_t *master_writeData; /*!< Data to write */ +static register8_t *master_readData; /*!< Read data */ static register8_t master_bytesToWrite; /*!< Number of bytes to write */ static register8_t master_bytesToRead; /*!< Number of bytes to read */ static register8_t master_bytesWritten; /*!< Number of bytes written */ @@ -38,8 +38,8 @@ static register8_t master_result; /*!< Result of tr /* Slave variables */ static uint8_t (*TWI_onSlaveTransmit)(void) __attribute__((unused)); static void (*TWI_onSlaveReceive)(int) __attribute__((unused)); -static register8_t* slave_writeData; -static register8_t* slave_readData; +static register8_t *slave_writeData; +static register8_t *slave_readData; static register8_t slave_bytesToWrite; static register8_t slave_bytesWritten; static register8_t slave_bytesToRead; @@ -53,717 +53,768 @@ static register8_t slave_callUserRequest; static volatile TWI_MODE_t twi_mode; /*! \brief Initialize the TWI module as a master. - * - * TWI master initialization function. - * Enables master read and write interrupts. - * Remember to enable interrupts globally from the main application. - * - * \param frequency The required baud. - */ -void TWI_MasterInit(uint32_t frequency) -{ - if(twi_mode != TWI_MODE_UNKNOWN) return; - - // Enable pullups just in case, should have external ones though -#ifdef NO_EXTERNAL_I2C_PULLUP - pinMode(PIN_WIRE_SDA, INPUT_PULLUP); - pinMode(PIN_WIRE_SCL, INPUT_PULLUP); -#endif -#if defined(TWISPIROUTEA) - PORTMUX.TWISPIROUTEA |= TWI_MUX; -#endif - twi_mode = TWI_MODE_MASTER; - - master_bytesRead = 0; - master_bytesWritten = 0; - master_trans_status = TWIM_STATUS_READY; - master_result = TWIM_RESULT_UNKNOWN; - - TWI0.MCTRLA = TWI_RIEN_bm | TWI_WIEN_bm | TWI_ENABLE_bm; - TWI_MasterSetBaud(frequency); - TWI0.MSTATUS = TWI_BUSSTATE_IDLE_gc; + + TWI master initialization function. + Enables master read and write interrupts. + Remember to enable interrupts globally from the main application. + + \param frequency The required baud. +*/ +void TWI_MasterInit(uint32_t frequency) { + if (twi_mode != TWI_MODE_UNKNOWN) { + return; + } + #ifdef PORTMUX_TWIROUTEA + if ((PORTMUX.TWIROUTEA & PORTMUX_TWI0_gm) == PORTMUX_TWI0_ALT2_gc) { + // make sure we don't get errata'ed - make sure their bits in the + // PORTx.OUT registers are 0. + PORTC.OUTCLR = 0x0C; // bits 2 and 3 + } else { + PORTA.OUTCLR = 0x0C; // bits 2 and 3 + } + #else // megaTinyCore + #if defined(PORTMUX_TWI0_bm) + if ((PORTMUX.CTRLB & PORTMUX_TWI0_bm)) { + // make sure we don't get errata'ed - make sure their bits in the + // PORTx.OUT registers are 0. + PORTA.OUTCLR = 0x06; // if swapped it's on PA1, PA2 + } else { + PORTB.OUTCLR = 0x03; // else PB0, PB1 + } + #elif defined(__AVR_ATtinyxy2__) + PORTA.OUTCLR = 0x06; // 8-pin parts always have it on PA1/2 + #else + PORTB.OUTCLR = 0x03; // else, zero series, no remapping, it's on PB0, PB1 + #endif + #endif + + twi_mode = TWI_MODE_MASTER; + + master_bytesRead = 0; + master_bytesWritten = 0; + master_trans_status = TWIM_STATUS_READY; + master_result = TWIM_RESULT_UNKNOWN; + + TWI0.MCTRLA = TWI_RIEN_bm | TWI_WIEN_bm | TWI_ENABLE_bm; + TWI_MasterSetBaud(frequency); + TWI0.MSTATUS = TWI_BUSSTATE_IDLE_gc; } /*! \brief Initialize the TWI module as a slave. - * - * TWI slave initialization function. - * Enables slave address/stop and data interrupts. - * Assigns slave's own address. - * Remember to enable interrupts globally from the main application. - * - * \param address The TWI Slave's own address. - */ -void TWI_SlaveInit(uint8_t address) -{ - if(twi_mode != TWI_MODE_UNKNOWN) return; - - twi_mode = TWI_MODE_SLAVE; - - slave_bytesRead = 0; - slave_bytesWritten = 0; - slave_trans_status = TWIS_STATUS_READY; - slave_result = TWIS_RESULT_UNKNOWN; - slave_callUserRequest = 0; - slave_callUserReceive = 0; - - TWI0.SADDR = address << 1; - TWI0.SCTRLA = TWI_DIEN_bm | TWI_APIEN_bm | TWI_PIEN_bm | TWI_ENABLE_bm; - - /* Bus Error Detection circuitry needs Master enabled to work */ - TWI0.MCTRLA = TWI_ENABLE_bm; + + TWI slave initialization function. + Enables slave address/stop and data interrupts. + Assigns slave's own address. + Remember to enable interrupts globally from the main application. + + \param address The TWI Slave's own address. +*/ + +void TWI_SlaveInit(uint8_t address, uint8_t receive_broadcast, uint8_t second_address) { + if (twi_mode != TWI_MODE_UNKNOWN) { + return; + } + + #ifdef PORTMUX_TWIROUTEA + if ((PORTMUX.TWIROUTEA & PORTMUX_TWI0_gm) == PORTMUX_TWI0_ALT2_gc) { + // make sure we don't get errata'ed - make sure their bits in the + // PORTx.OUT registers are 0. + PORTC.OUTCLR = 0x0C; // bits 2 and 3 + } else { + PORTA.OUTCLR = 0x0C; // bits 2 and 3 + } + #else // megaTinyCore + #if defined(PORTMUX_TWI0_bm) + if ((PORTMUX.CTRLB & PORTMUX_TWI0_bm)) { + // make sure we don't get errata'ed - make sure their bits in the + // PORTx.OUT registers are 0. + PORTA.OUTCLR = 0x06; // if swapped it's on PA1, PA2 + } else { + PORTB.OUTCLR = 0x03; // else PB0, PB1 + } + #elif defined(__AVR_ATtinyxy2__) + PORTA.OUTCLR = 0x06; // 8-pin parts always have it on PA1/2 + #else + PORTB.OUTCLR = 0x03; // else, zero series, no remapping, it's on PB0, PB1 + #endif + #endif + + twi_mode = TWI_MODE_SLAVE; + + slave_bytesRead = 0; + slave_bytesWritten = 0; + slave_trans_status = TWIS_STATUS_READY; + slave_result = TWIS_RESULT_UNKNOWN; + slave_callUserRequest = 0; + slave_callUserReceive = 0; + + TWI0.SADDR = address << 1 | receive_broadcast; + TWI0.SADDRMASK = second_address; + TWI0.SCTRLA = TWI_DIEN_bm | TWI_APIEN_bm | TWI_PIEN_bm | TWI_ENABLE_bm; + + /* Bus Error Detection circuitry needs Master enabled to work */ + TWI0.MCTRLA = TWI_ENABLE_bm; } -void TWI_Flush(void){ - TWI0.MCTRLB |= TWI_FLUSH_bm; +void TWI_Flush(void) { + TWI0.MCTRLB |= TWI_FLUSH_bm; } /*! \brief Disable the TWI module. - * - * TWI module disable function. - * Disables both master and slave modes - * - * \param frequency The required baud. - */ -void TWI_Disable(void) -{ - TWI0.MCTRLA = 0x00; - TWI0.MBAUD = 0x00; - TWI0.MSTATUS = TWI_BUSSTATE_IDLE_gc; - TWI0.SADDR = 0x00; - TWI0.SCTRLA = 0x00; - - twi_mode = TWI_MODE_UNKNOWN; + + TWI module disable function. + Disables both master and slave modes + + \param frequency The required baud. +*/ +void TWI_Disable(void) { + TWI0.MCTRLA = 0x00; + TWI0.MBAUD = 0x00; + TWI0.MSTATUS = TWI_BUSSTATE_IDLE_gc; + TWI0.SADDR = 0x00; + TWI0.SCTRLA = 0x00; + TWI0.SADDRMASK = 0; + twi_mode = TWI_MODE_UNKNOWN; } /*! \brief Returns the TWI bus state. - * - * Returns the TWI bus state (type defined in device headerfile), - * unknown, idle, owner or busy. - * - * \param twi The TWI_Master_t struct instance. - * - * \retval TWI_MASTER_BUSSTATE_UNKNOWN_gc Bus state is unknown. - * \retval TWI_MASTER_BUSSTATE_IDLE_gc Bus state is idle. - * \retval TWI_MASTER_BUSSTATE_OWNER_gc Bus state is owned by the master. - * \retval TWI_MASTER_BUSSTATE_BUSY_gc Bus state is busy. - */ -TWI_BUSSTATE_t TWI_MasterState(void) -{ - TWI_BUSSTATE_t twi_status; - twi_status = (TWI_BUSSTATE_t) (TWI0.MSTATUS & TWI_BUSSTATE_gm); - return twi_status; + + Returns the TWI bus state (type defined in device headerfile), + unknown, idle, owner or busy. + + \param twi The TWI_Master_t struct instance. + + \retval TWI_MASTER_BUSSTATE_UNKNOWN_gc Bus state is unknown. + \retval TWI_MASTER_BUSSTATE_IDLE_gc Bus state is idle. + \retval TWI_MASTER_BUSSTATE_OWNER_gc Bus state is owned by the master. + \retval TWI_MASTER_BUSSTATE_BUSY_gc Bus state is busy. +*/ +TWI_BUSSTATE_t TWI_MasterState(void) { + TWI_BUSSTATE_t twi_status; + twi_status = (TWI_BUSSTATE_t)(TWI0.MSTATUS & TWI_BUSSTATE_gm); + return twi_status; } /*! \brief Returns true if transaction is ready. - * - * This function returns a boolean whether the TWI Master is ready - * for a new transaction. - * - * \param twi The TWI_Master_t struct instance. - * - * \retval true If transaction could be started. - * \retval false If transaction could not be started. - */ -uint8_t TWI_MasterReady(void) -{ - uint8_t twi_status = (master_trans_status & TWIM_STATUS_READY); - return twi_status; + + This function returns a boolean whether the TWI Master is ready + for a new transaction. + + \param twi The TWI_Master_t struct instance. + + \retval true If transaction could be started. + \retval false If transaction could not be started. +*/ +uint8_t TWI_MasterReady(void) { + uint8_t twi_status = (master_trans_status & TWIM_STATUS_READY); + return twi_status; } /*! \brief Set the TWI baud rate. - * - * Sets the baud rate used by TWI Master. - * - * \param frequency The required baud. - */ -void TWI_MasterSetBaud(uint32_t frequency){ - -// Formula is: BAUD = ((F_CLKPER/frequency) - F_CLKPER*T_RISE - 10)/2; -// Where T_RISE varies depending on operating frequency... -// From 1617 DS: 1000ns @ 100kHz / 300ns @ 400kHz / 120ns @ 1MHz - - uint16_t t_rise; - - if(frequency < 200000){ - frequency = 100000; - t_rise = 1000; - - } else if (frequency < 800000){ - frequency = 400000; - t_rise = 300; - - } else if (frequency < 1200000){ - frequency = 1000000; - t_rise = 120; - - } else { - frequency = 100000; - t_rise = 1000; - } - - uint32_t baud = ((F_CPU_CORRECTED/frequency) - (((F_CPU_CORRECTED*t_rise)/1000)/1000)/1000 - 10)/2; - TWI0.MBAUD = (uint8_t)baud; + Sets the baud rate used by TWI Master. + + \param frequency The required baud. +*/ +void TWI_MasterSetBaud(uint32_t frequency) { + + // Formula is: BAUD = ((F_CLKPER/frequency) - F_CLKPER*T_RISE - 10)/2; + // Where T_RISE varies depending on operating frequency... + // From 1617 DS: 1000ns @ 100kHz / 300ns @ 400kHz / 120ns @ 1MHz + + uint16_t t_rise; + + if (frequency < 200000) { + frequency = 100000; + t_rise = 1000; + + } else if (frequency < 800000) { + frequency = 400000; + t_rise = 300; + + } else if (frequency < 1200000) { + frequency = 1000000; + t_rise = 120; + + } else { + frequency = 100000; + t_rise = 1000; + } + + uint32_t baud = (F_CPU / frequency - F_CPU / 1000 / 1000 * t_rise / 1000 - 10) / 2; + TWI0.MBAUD = (uint8_t)baud; + + // 1/16/2021: + // Prevent an integer overflow that can result in incorrect baud rates. + // Arduino megaAVR #90. + // 1/23/2021: + // Grab the rest of the fix and add it in here. } /*! \brief TWI write transaction. - * - * This function is TWI Master wrapper for a write-only transaction. - * - * \param twi The TWI_Master_t struct instance. - * \param address Slave address. - * \param writeData Pointer to data to write. - * \param bytesToWrite Number of data bytes to write. - * - * \retval true If transaction could be started. - * \retval false If transaction could not be started. - */ + + This function is TWI Master wrapper for a write-only transaction. + + \param twi The TWI_Master_t struct instance. + \param address Slave address. + \param writeData Pointer to data to write. + \param bytesToWrite Number of data bytes to write. + + \retval true If transaction could be started. + \retval false If transaction could not be started. +*/ uint8_t TWI_MasterWrite(uint8_t slave_address, - uint8_t *write_data, - uint8_t bytes_to_write, - uint8_t send_stop) -{ - return TWI_MasterWriteRead(slave_address, - write_data, - bytes_to_write, - 0, - send_stop); + uint8_t *write_data, + uint8_t bytes_to_write, + uint8_t send_stop) { + return TWI_MasterWriteRead(slave_address, + write_data, + bytes_to_write, + 0, + send_stop); } /*! \brief TWI read transaction. - * - * This function is a TWI Master wrapper for read-only transaction. - * - * \param twi The TWI_Master_t struct instance. - * \param address The slave address. - * \param bytesToRead The number of bytes to read. - * - * \retval true If transaction could be started. - * \retval false If transaction could not be started. - */ + + This function is a TWI Master wrapper for read-only transaction. + + \param twi The TWI_Master_t struct instance. + \param address The slave address. + \param bytesToRead The number of bytes to read. + + \retval true If transaction could be started. + \retval false If transaction could not be started. +*/ uint8_t TWI_MasterRead(uint8_t slave_address, - uint8_t* read_data, - uint8_t bytes_to_read, - uint8_t send_stop) -{ - master_readData = read_data; - - uint8_t bytes_read = TWI_MasterWriteRead(slave_address, - 0, - 0, - bytes_to_read, - send_stop); - return bytes_read; + uint8_t *read_data, + uint8_t bytes_to_read, + uint8_t send_stop) { + master_readData = read_data; + + uint8_t bytes_read = TWI_MasterWriteRead(slave_address, + 0, + 0, + bytes_to_read, + send_stop); + return bytes_read; } /*! \brief TWI write and/or read transaction. - * - * This function is a TWI Master write and/or read transaction. The function - * can be used to both write and/or read bytes to/from the TWI Slave in one - * transaction. - * - * \param twi The TWI_Master_t struct instance. - * \param address The slave address. - * \param writeData Pointer to data to write. - * \param bytesToWrite Number of bytes to write. - * \param bytesToRead Number of bytes to read. - * - * \retval true If transaction could be started. - * \retval false If transaction could not be started. - */ + + This function is a TWI Master write and/or read transaction. The function + can be used to both write and/or read bytes to/from the TWI Slave in one + transaction. + + \param twi The TWI_Master_t struct instance. + \param address The slave address. + \param writeData Pointer to data to write. + \param bytesToWrite Number of bytes to write. + \param bytesToRead Number of bytes to read. + + \retval true If transaction could be started. + \retval false If transaction could not be started. +*/ uint8_t TWI_MasterWriteRead(uint8_t slave_address, - uint8_t *write_data, - uint8_t bytes_to_write, - uint8_t bytes_to_read, - uint8_t send_stop) -{ - if(twi_mode != TWI_MODE_MASTER) return false; - - /*Initiate transaction if bus is ready. */ - if (master_trans_status == TWIM_STATUS_READY) { - - master_trans_status = TWIM_STATUS_BUSY; - master_result = TWIM_RESULT_UNKNOWN; - - master_writeData = write_data; - - master_bytesToWrite = bytes_to_write; - master_bytesToRead = bytes_to_read; - master_bytesWritten = 0; - master_bytesRead = 0; - master_sendStop = send_stop; - master_slaveAddress = slave_address<<1; - -trigger_action: - - /* If write command, send the START condition + Address + - * 'R/_W = 0' - */ - if (master_bytesToWrite > 0) { - twi_mode = TWI_MODE_MASTER_TRANSMIT; - uint8_t writeAddress = ADD_WRITE_BIT(master_slaveAddress); - TWI0.MADDR = writeAddress; - } - - /* If read command, send the START condition + Address + - * 'R/_W = 1' - */ - else if (master_bytesToRead > 0) { - twi_mode = TWI_MODE_MASTER_RECEIVE; - uint8_t readAddress = ADD_READ_BIT(master_slaveAddress); - TWI0.MADDR = readAddress; - } - - else if (master_bytesToWrite == 0 && master_bytesToRead == 0) { - twi_mode = TWI_MODE_MASTER_TRANSMIT; - uint8_t writeAddress = ADD_WRITE_BIT(master_slaveAddress); - TWI0.MADDR = writeAddress; - } - - /* Arduino requires blocking function */ - while(master_result == TWIM_RESULT_UNKNOWN) {} - - // in case of arbitration lost, retry sending - if (master_result == TWIM_RESULT_ARBITRATION_LOST) { - goto trigger_action; - } - - uint8_t ret = 0; - if (master_bytesToRead > 0) { - // return bytes really read - ret = master_bytesRead; - } else { - // return 0 if success, >0 otherwise - ret = (master_result == TWIM_RESULT_OK ? 0 : 1); - } - - return ret; - } else { - return 1; - } + uint8_t *write_data, + uint8_t bytes_to_write, + uint8_t bytes_to_read, + uint8_t send_stop) { + if (twi_mode != TWI_MODE_MASTER) { + return false; + } + + /*Initiate transaction if bus is ready. */ + if (master_trans_status == TWIM_STATUS_READY) { + + master_trans_status = TWIM_STATUS_BUSY; + master_result = TWIM_RESULT_UNKNOWN; + + master_writeData = write_data; + + master_bytesToWrite = bytes_to_write; + master_bytesToRead = bytes_to_read; + master_bytesWritten = 0; + master_bytesRead = 0; + master_sendStop = send_stop; + master_slaveAddress = slave_address << 1; + + trigger_action: + + /* If write command, send the START condition + Address + + 'R/_W = 0' + */ + if (master_bytesToWrite > 0) { + twi_mode = TWI_MODE_MASTER_TRANSMIT; + uint8_t writeAddress = ADD_WRITE_BIT(master_slaveAddress); + TWI0.MADDR = writeAddress; + } + + /* If read command, send the START condition + Address + + 'R/_W = 1' + */ + else if (master_bytesToRead > 0) { + twi_mode = TWI_MODE_MASTER_RECEIVE; + uint8_t readAddress = ADD_READ_BIT(master_slaveAddress); + TWI0.MADDR = readAddress; + } + + else if (master_bytesToWrite == 0 && master_bytesToRead == 0) { + twi_mode = TWI_MODE_MASTER_TRANSMIT; + uint8_t writeAddress = ADD_WRITE_BIT(master_slaveAddress); + TWI0.MADDR = writeAddress; + } + + /* Arduino requires blocking function */ + while (master_result == TWIM_RESULT_UNKNOWN) {} + + // in case of arbitration lost, retry sending + if (master_result == TWIM_RESULT_ARBITRATION_LOST) { + goto trigger_action; + } + + uint8_t ret = 0; + if (master_bytesToRead > 0) { + // return bytes really read + ret = master_bytesRead; + } else { + // return 0 if success, >0 otherwise (follow classic AVR conventions) + switch (master_result) { + case TWIM_RESULT_OK: + ret = 0; + break; + case TWIM_RESULT_BUFFER_OVERFLOW: + ret = 1; + break; + case TWIM_RESULT_NACK_RECEIVED: + ret = 3; + break; + default: + ret = 4; + break; + } + } + + return ret; + } else { + return 1; + } } /*! \brief Common TWI master interrupt service routine. - * - * Check current status and calls the appropriate handler. - * - */ -void TWI_MasterInterruptHandler() -{ - uint8_t currentStatus = TWI0.MSTATUS; - - /* If arbitration lost or bus error. */ - if ((currentStatus & TWI_ARBLOST_bm) || - (currentStatus & TWI_BUSERR_bm)) { - - TWI_MasterArbitrationLostBusErrorHandler(); - } - - /* If master write interrupt. */ - else if (currentStatus & TWI_WIF_bm) { - TWI_MasterWriteHandler(); - } - - /* If master read interrupt. */ - else if (currentStatus & TWI_RIF_bm) { - TWI_MasterReadHandler(); - } - - /* If unexpected state. */ - else { - TWI_MasterTransactionFinished(TWIM_RESULT_FAIL); - } + + Check current status and calls the appropriate handler. + +*/ +void TWI_MasterInterruptHandler() { + uint8_t currentStatus = TWI0.MSTATUS; + + /* If arbitration lost or bus error. */ + if ((currentStatus & TWI_ARBLOST_bm) || + (currentStatus & TWI_BUSERR_bm)) { + + TWI_MasterArbitrationLostBusErrorHandler(); + } + + /* If master write interrupt. */ + else if (currentStatus & TWI_WIF_bm) { + TWI_MasterWriteHandler(); + } + + /* If master read interrupt. */ + else if (currentStatus & TWI_RIF_bm) { + TWI_MasterReadHandler(); + } + + /* If unexpected state. */ + else { + TWI_MasterTransactionFinished(TWIM_RESULT_FAIL); + } } /*! \brief TWI master arbitration lost and bus error interrupt handler. - * - * Handles TWI responses to lost arbitration and bus error. - * - */ -void TWI_MasterArbitrationLostBusErrorHandler() -{ - uint8_t currentStatus = TWI0.MSTATUS; - - /* If bus error. */ - if (currentStatus & TWI_BUSERR_bm) { - master_result = TWIM_RESULT_BUS_ERROR; - } - /* If arbitration lost. */ - else { - master_result = TWIM_RESULT_ARBITRATION_LOST; - } - - /* Clear all flags, abort operation */ - TWI0.MSTATUS = currentStatus; - - /* Wait for a new operation */ - twi_mode = TWI_MODE_MASTER; - master_trans_status = TWIM_STATUS_READY; + + Handles TWI responses to lost arbitration and bus error. + +*/ +void TWI_MasterArbitrationLostBusErrorHandler() { + uint8_t currentStatus = TWI0.MSTATUS; + + /* If bus error. */ + if (currentStatus & TWI_BUSERR_bm) { + master_result = TWIM_RESULT_BUS_ERROR; + } + /* If arbitration lost. */ + else { + master_result = TWIM_RESULT_ARBITRATION_LOST; + } + + /* Clear all flags, abort operation */ + TWI0.MSTATUS = currentStatus; + + /* Wait for a new operation */ + twi_mode = TWI_MODE_MASTER; + master_trans_status = TWIM_STATUS_READY; } /*! \brief TWI master write interrupt handler. - * - * Handles TWI transactions (master write) and responses to (N)ACK. - * - */ -void TWI_MasterWriteHandler() -{ - /* Local variables used in if tests to avoid compiler warning. */ - uint8_t bytesToWrite = master_bytesToWrite; - uint8_t bytesToRead = master_bytesToRead; - - /* If NOT acknowledged (NACK) by slave cancel the transaction. */ - if (TWI0.MSTATUS & TWI_RXACK_bm) { - if(master_sendStop){ - TWI0.MCTRLB = TWI_MCMD_STOP_gc; - } else { - TWI0.MCTRLB = TWI_MCMD_REPSTART_gc; - - } - TWI_MasterTransactionFinished(TWIM_RESULT_NACK_RECEIVED); - } - - /* If more bytes to write, send data. */ - else if (master_bytesWritten < bytesToWrite) { - uint8_t data = master_writeData[master_bytesWritten]; - TWI0.MDATA = data; - master_bytesWritten++; - } - - /* If bytes to read, send START condition + Address + - * 'R/_W = 1' - */ - else if (master_bytesRead < bytesToRead) { - twi_mode = TWI_MODE_MASTER_RECEIVE; - uint8_t readAddress = ADD_READ_BIT(master_slaveAddress); - TWI0.MADDR = readAddress; - } - - /* If transaction finished, send ACK/STOP condition if instructed and set RESULT OK. */ - else { - if(master_sendStop){ - TWI0.MCTRLB = TWI_MCMD_STOP_gc; - } else { - TWI0.MCTRLB = TWI_MCMD_REPSTART_gc; - } - TWI_MasterTransactionFinished(TWIM_RESULT_OK); - } + + Handles TWI transactions (master write) and responses to (N)ACK. + +*/ +void TWI_MasterWriteHandler() { + /* Local variables used in if tests to avoid compiler warning. */ + uint8_t bytesToWrite = master_bytesToWrite; + uint8_t bytesToRead = master_bytesToRead; + + /* If NOT acknowledged (NACK) by slave cancel the transaction. */ + if (TWI0.MSTATUS & TWI_RXACK_bm) { + if (master_sendStop) { + TWI0.MCTRLB = TWI_MCMD_STOP_gc; + } else { + TWI0.MCTRLB = TWI_MCMD_REPSTART_gc; + + } + TWI_MasterTransactionFinished(TWIM_RESULT_NACK_RECEIVED); + } + + /* If more bytes to write, send data. */ + else if (master_bytesWritten < bytesToWrite) { + uint8_t data = master_writeData[master_bytesWritten]; + TWI0.MDATA = data; + master_bytesWritten++; + } + + /* If bytes to read, send START condition + Address + + 'R/_W = 1' + */ + else if (master_bytesRead < bytesToRead) { + twi_mode = TWI_MODE_MASTER_RECEIVE; + uint8_t readAddress = ADD_READ_BIT(master_slaveAddress); + TWI0.MADDR = readAddress; + } + + /* If transaction finished, send ACK/STOP condition if instructed and set RESULT OK. */ + else { + if (master_sendStop) { + TWI0.MCTRLB = TWI_MCMD_STOP_gc; + } else { + TWI0.MCTRLB = TWI_MCMD_REPSTART_gc; + } + TWI_MasterTransactionFinished(TWIM_RESULT_OK); + } } /*! \brief TWI master read interrupt handler. - * - * This is the master read interrupt handler that takes care of - * reading bytes from the TWI slave. - * - * \param twi The TWI_Master_t struct instance. - */ -void TWI_MasterReadHandler() -{ - /* Fetch data if bytes to be read. */ - if (master_bytesRead < master_bytesToRead) { - uint8_t data = TWI0.MDATA; - master_readData[master_bytesRead] = data; - master_bytesRead++; - } - - /* If buffer overflow, issue NACK/STOP and BUFFER_OVERFLOW condition. */ - else { - if(master_sendStop){ - TWI0.MCTRLB = TWI_ACKACT_bm | TWI_MCMD_STOP_gc; - } else { - TWI0.MCTRLB = TWI_ACKACT_bm | TWI_MCMD_REPSTART_gc; - } - - TWI_MasterTransactionFinished(TWIM_RESULT_BUFFER_OVERFLOW); - master_bytesToRead = 0; - return; - } - - /* Local variable used in if test to avoid compiler warning. */ - uint8_t bytesToRead = master_bytesToRead; - - /* If more bytes to read, issue ACK and start a byte read. */ - if (master_bytesRead < bytesToRead) { - TWI0.MCTRLB = TWI_MCMD_RECVTRANS_gc; - } - - /* If transaction finished, issue NACK and STOP condition if instructed. */ - else { - if(master_sendStop){ - TWI0.MCTRLB = TWI_ACKACT_bm | TWI_MCMD_STOP_gc; - } else { - TWI0.MCTRLB = TWI_ACKACT_bm | TWI_MCMD_REPSTART_gc; - } - - TWI_MasterTransactionFinished(TWIM_RESULT_OK); - } + + This is the master read interrupt handler that takes care of + reading bytes from the TWI slave. + + \param twi The TWI_Master_t struct instance. +*/ +void TWI_MasterReadHandler() { + /* Fetch data if bytes to be read. */ + if (master_bytesRead < master_bytesToRead) { + uint8_t data = TWI0.MDATA; + master_readData[master_bytesRead] = data; + master_bytesRead++; + } + + /* If buffer overflow, issue NACK/STOP and BUFFER_OVERFLOW condition. */ + else { + if (master_sendStop) { + TWI0.MCTRLB = TWI_ACKACT_bm | TWI_MCMD_STOP_gc; + } else { + TWI0.MCTRLB = TWI_ACKACT_bm | TWI_MCMD_REPSTART_gc; + } + + TWI_MasterTransactionFinished(TWIM_RESULT_BUFFER_OVERFLOW); + master_bytesToRead = 0; + return; + } + + /* Local variable used in if test to avoid compiler warning. */ + uint8_t bytesToRead = master_bytesToRead; + + /* If more bytes to read, issue ACK and start a byte read. */ + if (master_bytesRead < bytesToRead) { + TWI0.MCTRLB = TWI_MCMD_RECVTRANS_gc; + } + + /* If transaction finished, issue NACK and STOP condition if instructed. */ + else { + if (master_sendStop) { + TWI0.MCTRLB = TWI_ACKACT_bm | TWI_MCMD_STOP_gc; + } else { + TWI0.MCTRLB = TWI_ACKACT_bm | TWI_MCMD_REPSTART_gc; + } + + TWI_MasterTransactionFinished(TWIM_RESULT_OK); + } } /*! \brief TWI transaction finished handler. - * - * Prepares module for new transaction. - * - * \param result The result of the operation. - */ -void TWI_MasterTransactionFinished(uint8_t result) -{ - master_result = result; - master_trans_status = TWIM_STATUS_READY; - twi_mode = TWI_MODE_MASTER; + + Prepares module for new transaction. + + \param result The result of the operation. +*/ +void TWI_MasterTransactionFinished(uint8_t result) { + master_result = result; + master_trans_status = TWIM_STATUS_READY; + twi_mode = TWI_MODE_MASTER; } /*! \brief Common TWI slave interrupt service routine. - * - * Check current status and calls the appropriate handler. - * - */ -void TWI_SlaveInterruptHandler(){ - uint8_t currentStatus = TWI0.SSTATUS; - - /* If bus error */ - if(currentStatus & TWI_BUSERR_bm){ - slave_bytesRead = 0; - slave_bytesWritten = 0; - slave_bytesToWrite = 0; - TWI_SlaveTransactionFinished(TWIS_RESULT_BUS_ERROR); - } - - /* If Address or Stop */ - else if(currentStatus & TWI_APIF_bm){ - - /* Call user onReceive function if end of Master Write/Slave Read. - * This should be hit when there is a STOP or REPSTART - */ - if(slave_callUserReceive == 1){ - TWI_onSlaveReceive(slave_bytesRead); - slave_callUserReceive = 0; - } - - /* If address match */ - if(currentStatus & TWI_AP_bm){ - TWI_SlaveAddressMatchHandler(); - } - - /* If stop */ - else { - TWI_SlaveStopHandler(); - - /* If CLKHOLD is high, we have missed an address match - from a fast start after stop. - Because the flag is shared we need to handle this here. - */ - if(TWI0.SSTATUS & TWI_CLKHOLD_bm){ - - /* CLKHOLD will be cleared by servicing the address match */ - TWI_SlaveAddressMatchHandler(); - } - } - } - - /* If Data Interrupt */ - else if (currentStatus & TWI_DIF_bm){ - - /* If collision flag is raised, slave transmit unsuccessful */ - if (currentStatus & TWI_COLL_bm){ - slave_bytesRead = 0; - slave_bytesWritten = 0; - slave_bytesToWrite = 0; - TWI_SlaveTransactionFinished(TWIS_RESULT_TRANSMIT_COLLISION); - } - - /* Otherwise, normal data interrupt */ - else { - TWI_SlaveDataHandler(); - } - } - - /* If unexpected state */ - else { - TWI_SlaveTransactionFinished(TWIS_RESULT_FAIL); - } + + Check current status and calls the appropriate handler. + +*/ +void TWI_SlaveInterruptHandler() { + uint8_t currentStatus = TWI0.SSTATUS; + + /* If bus error */ + if (currentStatus & TWI_BUSERR_bm) { + slave_bytesRead = 0; + slave_bytesWritten = 0; + slave_bytesToWrite = 0; + TWI_SlaveTransactionFinished(TWIS_RESULT_BUS_ERROR); + } + + /* If Address or Stop */ + else if (currentStatus & TWI_APIF_bm) { + + /* Call user onReceive function if end of Master Write/Slave Read. + This should be hit when there is a STOP or REPSTART + */ + if (slave_callUserReceive == 1) { + TWI_onSlaveReceive(slave_bytesRead); + slave_callUserReceive = 0; + } + + /* If address match */ + if (currentStatus & TWI_AP_bm) { + TWI_SlaveAddressMatchHandler(); + } + + /* If stop */ + else { + TWI_SlaveStopHandler(); + + /* If CLKHOLD is high, we have missed an address match + from a fast start after stop. + Because the flag is shared we need to handle this here. + */ + if (TWI0.SSTATUS & TWI_CLKHOLD_bm) { + + /* CLKHOLD will be cleared by servicing the address match */ + TWI_SlaveAddressMatchHandler(); + } + } + } + + /* If Data Interrupt */ + else if (currentStatus & TWI_DIF_bm) { + + /* If collision flag is raised, slave transmit unsuccessful */ + if (currentStatus & TWI_COLL_bm) { + slave_bytesRead = 0; + slave_bytesWritten = 0; + slave_bytesToWrite = 0; + TWI_SlaveTransactionFinished(TWIS_RESULT_TRANSMIT_COLLISION); + } + + /* Otherwise, normal data interrupt */ + else { + TWI_SlaveDataHandler(); + } + } + + /* If unexpected state */ + else { + TWI_SlaveTransactionFinished(TWIS_RESULT_FAIL); + } } /*! \brief TWI slave address interrupt handler. - * - * This is the slave address match handler that takes care of responding to - * being addressed by a master - * - */ -void TWI_SlaveAddressMatchHandler(){ - slave_trans_status = TWIS_STATUS_BUSY; - slave_result = TWIS_RESULT_UNKNOWN; - - /* Send ACK, wait for data interrupt */ - TWI0.SCTRLB = TWI_SCMD_RESPONSE_gc; - - /* If Master Read/Slave Write */ - if(TWI0.SSTATUS & TWI_DIR_bm){ - slave_bytesWritten = 0; - /* Call user function */ - slave_bytesToWrite = TWI_onSlaveTransmit(); - twi_mode = TWI_MODE_SLAVE_TRANSMIT; - } - /* If Master Write/Slave Read */ - else { - slave_bytesRead = 0; - slave_callUserReceive = 1; - twi_mode = TWI_MODE_SLAVE_RECEIVE; - } - - /* Data interrupt to follow... */ + + This is the slave address match handler that takes care of responding to + being addressed by a master + +*/ +void TWI_SlaveAddressMatchHandler() { + slave_trans_status = TWIS_STATUS_BUSY; + slave_result = TWIS_RESULT_UNKNOWN; + + /* If Master Read/Slave Write */ + if (TWI0.SSTATUS & TWI_DIR_bm) { + slave_bytesWritten = 0; + /* Call user function */ + slave_bytesToWrite = TWI_onSlaveTransmit(); + twi_mode = TWI_MODE_SLAVE_TRANSMIT; + } + /* If Master Write/Slave Read */ + else { + slave_bytesRead = 0; + slave_callUserReceive = 1; + twi_mode = TWI_MODE_SLAVE_RECEIVE; + } + + /* Send ACK, wait for data interrupt */ + TWI0.SCTRLB = TWI_SCMD_RESPONSE_gc; + + /* Data interrupt to follow... */ } /*! \brief TWI slave stop interrupt handler. - * - */ -void TWI_SlaveStopHandler(){ - - /* Clear APIF, don't ACK or NACK */ - TWI0.SSTATUS = TWI_APIF_bm; - - TWI_SlaveTransactionFinished(TWIS_RESULT_OK); - + +*/ +void TWI_SlaveStopHandler() { + + /* Clear APIF, don't ACK or NACK */ + TWI0.SSTATUS = TWI_APIF_bm; + + TWI_SlaveTransactionFinished(TWIS_RESULT_OK); + } /*! \brief TWI slave data interrupt handler. - * - * This is the slave data handler that takes care of sending data to or - * receiving data from a master - * - */ -void TWI_SlaveDataHandler(){ - - /* Enable stop interrupt */ - TWI0.SCTRLA |= (TWI_APIEN_bm | TWI_PIEN_bm); - - /* If Master Read/Slave Write */ - if(TWI0.SSTATUS & TWI_DIR_bm){ - - TWI_SlaveWriteHandler(); - } - - /* If Master Write/Slave Read */ - else { - TWI_SlaveReadHandler(); - } - + + This is the slave data handler that takes care of sending data to or + receiving data from a master + +*/ +void TWI_SlaveDataHandler() { + + /* Enable stop interrupt */ + TWI0.SCTRLA |= (TWI_APIEN_bm | TWI_PIEN_bm); + + /* If Master Read/Slave Write */ + if (TWI0.SSTATUS & TWI_DIR_bm) { + + TWI_SlaveWriteHandler(); + } + + /* If Master Write/Slave Read */ + else { + TWI_SlaveReadHandler(); + } + } /*! \brief TWI slave data write interrupt handler. - * - * This is the slave data handler that takes care of sending data to a master - * - */ -void TWI_SlaveWriteHandler(){ - - /* If NACK, slave write transaction finished */ - if((slave_bytesWritten > 0) && (TWI0.SSTATUS & TWI_RXACK_bm)){ - - TWI0.SCTRLB = TWI_SCMD_COMPTRANS_gc; - TWI_SlaveTransactionFinished(TWIS_RESULT_OK); - } - - /* If ACK, master expects more data */ - else { - - if(slave_bytesWritten < slave_bytesToWrite){ - uint8_t data = slave_writeData[slave_bytesWritten]; - TWI0.SDATA = data; - slave_bytesWritten++; - - /* Send data, wait for data interrupt */ - TWI0.SCTRLB = TWI_SCMD_RESPONSE_gc; - - } - - /* If buffer overflow */ - else { - TWI0.SCTRLB = TWI_SCMD_COMPTRANS_gc; - TWI_SlaveTransactionFinished(TWIS_RESULT_BUFFER_OVERFLOW); - - } - - - } + + This is the slave data handler that takes care of sending data to a master + +*/ +void TWI_SlaveWriteHandler() { + + /* If NACK, slave write transaction finished */ + if ((slave_bytesWritten > 0) && (TWI0.SSTATUS & TWI_RXACK_bm)) { + + TWI0.SCTRLB = TWI_SCMD_COMPTRANS_gc; + TWI_SlaveTransactionFinished(TWIS_RESULT_OK); + } + + /* If ACK, master expects more data */ + else { + + if (slave_bytesWritten < slave_bytesToWrite) { + uint8_t data = slave_writeData[slave_bytesWritten]; + TWI0.SDATA = data; + slave_bytesWritten++; + + /* Send data, wait for data interrupt */ + TWI0.SCTRLB = TWI_SCMD_RESPONSE_gc; + + } + + /* If buffer overflow */ + else { + TWI0.SCTRLB = TWI_SCMD_COMPTRANS_gc; + TWI_SlaveTransactionFinished(TWIS_RESULT_BUFFER_OVERFLOW); + + } + + + } } /*! \brief TWI slave data read interrupt handler. - * - * This is the slave data handler that takes care of receiving data from a master - * - */ -void TWI_SlaveReadHandler(){ - - /* If free space in buffer */ - if(slave_bytesRead < slave_bytesToRead){ - - /* Fetch data */ - uint8_t data = TWI0.SDATA; - slave_readData[slave_bytesRead] = data; - slave_bytesRead++; - - /* Send ACK and wait for data interrupt */ - TWI0.SCTRLB = TWI_SCMD_RESPONSE_gc; - } - /* If buffer overflow, send NACK and wait for next START. - Set result buffer overflow */ - else { - TWI0.SCTRLB = TWI_ACKACT_bm | TWI_SCMD_COMPTRANS_gc; - TWI_SlaveTransactionFinished(TWIS_RESULT_BUFFER_OVERFLOW); - } + + This is the slave data handler that takes care of receiving data from a master + +*/ +void TWI_SlaveReadHandler() { + + /* If free space in buffer */ + if (slave_bytesRead < slave_bytesToRead) { + + /* Fetch data */ + uint8_t data = TWI0.SDATA; + slave_readData[slave_bytesRead] = data; + slave_bytesRead++; + + /* Send ACK and wait for data interrupt */ + TWI0.SCTRLB = TWI_SCMD_RESPONSE_gc; + } + /* If buffer overflow, send NACK and wait for next START. + Set result buffer overflow */ + else { + TWI0.SCTRLB = TWI_ACKACT_bm | TWI_SCMD_COMPTRANS_gc; + TWI_SlaveTransactionFinished(TWIS_RESULT_BUFFER_OVERFLOW); + } } -/* - * Function twi_attachSlaveRxEvent - * Desc sets function called before a slave read operation - * Input function: callback function to use - * Output none - */ -void TWI_attachSlaveRxEvent( void (*function)(int), uint8_t *read_data, uint8_t bytes_to_read ){ +/* + Function twi_attachSlaveRxEvent + Desc sets function called before a slave read operation + Input function: callback function to use + Output none +*/ +void TWI_attachSlaveRxEvent(void (*function)(int), uint8_t *read_data, uint8_t bytes_to_read) { TWI_onSlaveReceive = function; slave_readData = read_data; slave_bytesToRead = bytes_to_read; } -/* - * Function twi_attachSlaveTxEvent - * Desc sets function called before a slave write operation - * Input function: callback function to use - * Output none - */ -void TWI_attachSlaveTxEvent( uint8_t (*function)(void), uint8_t* write_data ){ +/* + Function twi_attachSlaveTxEvent + Desc sets function called before a slave write operation + Input function: callback function to use + Output none +*/ +void TWI_attachSlaveTxEvent(uint8_t (*function)(void), uint8_t *write_data) { TWI_onSlaveTransmit = function; slave_writeData = write_data; } /*! \brief TWI slave transaction finished handler. - * - * Prepares module for new transaction. - * - * \param result The result of the operation. - */ -void TWI_SlaveTransactionFinished(uint8_t result) -{ - TWI0.SCTRLA |= (TWI_APIEN_bm | TWI_PIEN_bm); - twi_mode = TWI_MODE_SLAVE; - slave_result = result; - slave_trans_status = TWIM_STATUS_READY; + + Prepares module for new transaction. + + \param result The result of the operation. +*/ +void TWI_SlaveTransactionFinished(uint8_t result) { + TWI0.SCTRLA |= (TWI_APIEN_bm | TWI_PIEN_bm); + twi_mode = TWI_MODE_SLAVE; + slave_result = result; + slave_trans_status = TWIM_STATUS_READY; } -ISR(TWI0_TWIM_vect){ - TWI_MasterInterruptHandler(); +ISR(TWI0_TWIM_vect) { + TWI_MasterInterruptHandler(); } -ISR(TWI0_TWIS_vect){ - TWI_SlaveInterruptHandler(); -} \ No newline at end of file +ISR(TWI0_TWIS_vect) { + TWI_SlaveInterruptHandler(); +} diff --git a/avr/libraries/Wire/src/utility/twi.h b/avr/libraries/Wire/src/utility/twi.h index 8e76e54..d818faa 100644 --- a/avr/libraries/Wire/src/utility/twi.h +++ b/avr/libraries/Wire/src/utility/twi.h @@ -1,23 +1,23 @@ /****************************************************************************** -* © 2018 Microchip Technology Inc. and its subsidiaries. -* -* Subject to your compliance with these terms, you may use Microchip software -* and any derivatives exclusively with Microchip products. It is your -* responsibility to comply with third party license terms applicable to your -* use of third party software (including open source software) that may -* accompany Microchip software. -* -* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER -* EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED -* WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A PARTICULAR -* PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, -* PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY -* KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP -* HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE -* FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN -* ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, -* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. -* + � 2018 Microchip Technology Inc. and its subsidiaries. + + Subject to your compliance with these terms, you may use Microchip software + and any derivatives exclusively with Microchip products. It is your + responsibility to comply with third party license terms applicable to your + use of third party software (including open source software) that may + accompany Microchip software. + + THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER + EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED + WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A PARTICULAR + PURPOSE. IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, + PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY + KIND WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP + HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE + FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN + ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + *****************************************************************************/ #ifndef TWI_DRIVER_H #define TWI_DRIVER_H @@ -25,70 +25,82 @@ #include "avr/io.h" /*! Transaction status defines. */ -#define TWIM_STATUS_READY 0 -#define TWIM_STATUS_BUSY 1 +#ifndef TWIM_STATUS_READY + #define TWIM_STATUS_READY 0 +#endif +#ifndef TWIM_STATUS_BUSY + #define TWIM_STATUS_BUSY 1 +#endif /* Transaction status defines.*/ -#define TWIS_STATUS_READY 0 -#define TWIS_STATUS_BUSY 1 +#ifndef TWIS_STATUS_READY + #define TWIS_STATUS_READY 0 +#endif +#ifndef TWIS_STATUS_BUSY + #define TWIS_STATUS_BUSY 1 +#endif /*! Transaction result enumeration. */ -typedef enum TWIM_RESULT_enum { - TWIM_RESULT_UNKNOWN = (0x00<<0), - TWIM_RESULT_OK = (0x01<<0), - TWIM_RESULT_BUFFER_OVERFLOW = (0x02<<0), - TWIM_RESULT_ARBITRATION_LOST = (0x03<<0), - TWIM_RESULT_BUS_ERROR = (0x04<<0), - TWIM_RESULT_NACK_RECEIVED = (0x05<<0), - TWIM_RESULT_FAIL = (0x06<<0), +typedef enum __attribute__((packed)) TWIM_RESULT_enum { + TWIM_RESULT_UNKNOWN = (0x00 << 0), + TWIM_RESULT_OK = (0x01 << 0), + TWIM_RESULT_BUFFER_OVERFLOW = (0x02 << 0), + TWIM_RESULT_ARBITRATION_LOST = (0x03 << 0), + TWIM_RESULT_BUS_ERROR = (0x04 << 0), + TWIM_RESULT_NACK_RECEIVED = (0x05 << 0), + TWIM_RESULT_FAIL = (0x06 << 0), } TWIM_RESULT_t; /* Transaction result enumeration */ -typedef enum TWIS_RESULT_enum { - TWIS_RESULT_UNKNOWN = (0x00<<0), - TWIS_RESULT_OK = (0x01<<0), - TWIS_RESULT_BUFFER_OVERFLOW = (0x02<<0), - TWIS_RESULT_TRANSMIT_COLLISION = (0x03<<0), - TWIS_RESULT_BUS_ERROR = (0x04<<0), - TWIS_RESULT_FAIL = (0x05<<0), - TWIS_RESULT_ABORTED = (0x06<<0), +typedef enum __attribute__((packed)) TWIS_RESULT_enum { + TWIS_RESULT_UNKNOWN = (0x00 << 0), + TWIS_RESULT_OK = (0x01 << 0), + TWIS_RESULT_BUFFER_OVERFLOW = (0x02 << 0), + TWIS_RESULT_TRANSMIT_COLLISION = (0x03 << 0), + TWIS_RESULT_BUS_ERROR = (0x04 << 0), + TWIS_RESULT_FAIL = (0x05 << 0), + TWIS_RESULT_ABORTED = (0x06 << 0), } TWIS_RESULT_t; /*! TWI Modes */ -typedef enum TWI_MODE_enum { - TWI_MODE_UNKNOWN = 0, - TWI_MODE_MASTER = 1, - TWI_MODE_SLAVE = 2, - TWI_MODE_MASTER_TRANSMIT = 3, - TWI_MODE_MASTER_RECEIVE = 4, - TWI_MODE_SLAVE_TRANSMIT = 5, - TWI_MODE_SLAVE_RECEIVE = 6 +typedef enum __attribute__((packed)) TWI_MODE_enum { + TWI_MODE_UNKNOWN = 0, + TWI_MODE_MASTER = 1, + TWI_MODE_SLAVE = 2, + TWI_MODE_MASTER_TRANSMIT = 3, + TWI_MODE_MASTER_RECEIVE = 4, + TWI_MODE_SLAVE_TRANSMIT = 5, + TWI_MODE_SLAVE_RECEIVE = 6 } TWI_MODE_t; /*! For adding R/_W bit to address */ -#define ADD_READ_BIT(address) (address | 0x01) -#define ADD_WRITE_BIT(address) (address & ~0x01) +#ifndef ADD_READ_BIT + #define ADD_READ_BIT(address) (address | 0x01) +#endif +#ifndef ADD_WRITE_BIT + #define ADD_WRITE_BIT(address) (address & ~0x01) +#endif void TWI_MasterInit(uint32_t frequency); -void TWI_SlaveInit(uint8_t address); +void TWI_SlaveInit(uint8_t address, uint8_t receive_broadcast, uint8_t second_address); void TWI_Flush(void); void TWI_Disable(void); TWI_BUSSTATE_t TWI_MasterState(void); uint8_t TWI_MasterReady(void); void TWI_MasterSetBaud(uint32_t frequency); uint8_t TWI_MasterWrite(uint8_t slave_address, - uint8_t *write_data, - uint8_t bytes_to_write, - uint8_t send_stop); + uint8_t *write_data, + uint8_t bytes_to_write, + uint8_t send_stop); uint8_t TWI_MasterRead(uint8_t slave_address, - uint8_t* read_data, - uint8_t bytes_to_read, - uint8_t send_stop); + uint8_t *read_data, + uint8_t bytes_to_read, + uint8_t send_stop); uint8_t TWI_MasterWriteRead(uint8_t slave_address, - uint8_t *write_data, - uint8_t bytes_to_write, - uint8_t bytes_to_read, - uint8_t send_stop); + uint8_t *write_data, + uint8_t bytes_to_write, + uint8_t bytes_to_read, + uint8_t send_stop); void TWI_MasterInterruptHandler(void); void TWI_MasterArbitrationLostBusErrorHandler(void); void TWI_MasterWriteHandler(void); @@ -101,26 +113,9 @@ void TWI_SlaveStopHandler(void); void TWI_SlaveDataHandler(void); void TWI_SlaveWriteHandler(void); void TWI_SlaveReadHandler(void); -void TWI_attachSlaveRxEvent( void (*function)(int), uint8_t *read_data, uint8_t bytes_to_read ); -void TWI_attachSlaveTxEvent( uint8_t (*function)(void), uint8_t *write_data ); +void TWI_attachSlaveRxEvent(void (*function)(int), uint8_t *read_data, uint8_t bytes_to_read); +void TWI_attachSlaveTxEvent(uint8_t (*function)(void), uint8_t *write_data); void TWI_SlaveTransactionFinished(uint8_t result); -/*! TWI master interrupt service routine. - * - * Interrupt service routine for the TWI master. Copy the needed vectors - * into your code. - * - - - ISR(TWI0_TWIM_vect){ - TWI_MasterInterruptHandler(); - } - - ISR(TWI0_TWIS_vect){ - TWI_SlaveInterruptHandler(); - } - - * - */ #endif /* TWI_DRIVER_H */ diff --git a/avr/package/package_tinycore_index.json b/avr/package/package_tinycore_index.json index 43f3a80..4a07949 100644 --- a/avr/package/package_tinycore_index.json +++ b/avr/package/package_tinycore_index.json @@ -9,6 +9,39 @@ "online":"http://tinycore.dev" }, "platforms":[ + { + "name":"TinyCore Boards", + "architecture":"avr", + "version":"0.0.7", + "category":"TinyCore", + "url":"https://github.com/xukangmin/TinyCore/releases/download/0.0.7/TinyCore-0.0.7.zip", + "archiveFileName":"TinyCore-0.0.7.zip", + "checksum":"SHA-256:82c0a53833edfd81a513f06c030ac7d200d58c6cc2753edd2a03d316d25bcae8", + "size":"761296", + "help":{ + "online":"https://docs.tinycore.dev" + }, + "boards":[ + { + "name":"TinyCore 16" + }, + { + "name":"TinyCore 32" + } + ], + "toolsDependencies":[ + { + "packager":"arduino", + "name":"avr-gcc", + "version":"7.3.0-atmel3.6.1-arduino5" + }, + { + "packager":"arduino", + "name":"avrdude", + "version":"6.3.0-arduino16" + } + ] + }, { "name":"TinyCore Boards", "architecture":"avr",