diff --git a/README.TXT b/README.TXT index 7b0e841..919ca67 100644 --- a/README.TXT +++ b/README.TXT @@ -3,6 +3,7 @@ SoftI2CMaster 2010-2012, Tod E. Kurt, http://todbot.com/blog/ 2014, by Testato: update library and examples for follow Wire’s API of Arduino IDE 1.x +2018, by Eli112358: update library to specification rev. 2.1 SoftI2CMaster is an Arduino library that implements diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..6ac9e4a --- /dev/null +++ b/keywords.txt @@ -0,0 +1,9 @@ +SoftI2CMaster KEYWORD1 +setPins KEYWORD2 +beginTransmission KEYWORD2 +endTransmission KEYWORD2 +write KEYWORD2 +begin KEYWORD2 +requestFrom KEYWORD2 +read KEYWORD2 +readLast KEYWORD2 diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..257cf8e --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=Soft I2C Master +version=1.0.0 +author=Tod E. Kurt +maintainer=Tod E. Kurt +sentence=Software I2C / TWI library for Arduino allows any two pins to be SDA & SCL +paragraph=SoftI2CMaster is an Arduino library that implements a simple "bit-bang" software-only I2C (aka "TWI") Master. This lets you use any two Arduino pins to be the SDA & SCL pins needed to communicate with I2C devices like BlinkMs. +category=Communication +url=https://github.com/todbot/SoftI2CMaster +architectures=* diff --git a/SoftI2CMaster.cpp b/src/SoftI2CMaster.cpp similarity index 95% rename from SoftI2CMaster.cpp rename to src/SoftI2CMaster.cpp index 8302ee4..cc59270 100644 --- a/SoftI2CMaster.cpp +++ b/src/SoftI2CMaster.cpp @@ -1,350 +1,350 @@ -/* - * SoftI2CMaster.cpp -- Multi-instance software I2C Master library - * - * - * 2010-12 Tod E. Kurt, http://todbot.com/blog/ - * - * This code takes some tricks from: - * http://codinglab.blogspot.com/2008/10/i2c-on-avr-using-bit-banging.html - * - * 2014, by Testato: update library and examples for follow Wire’s API of Arduino IDE 1.x - * - */ - -#if (ARDUINO >= 100) -#include -#else -#include -#endif - -#include "SoftI2CMaster.h" - -#include -#include - -#define i2cbitdelay 50 - -#define I2C_ACK 1 -#define I2C_NAK 0 - - -#define i2c_scl_release() \ - *_sclDirReg &=~ _sclBitMask -#define i2c_sda_release() \ - *_sdaDirReg &=~ _sdaBitMask - -// sets SCL low and drives output -#define i2c_scl_lo() \ - *_sclPortReg &=~ _sclBitMask; \ - *_sclDirReg |= _sclBitMask; - -// sets SDA low and drives output -#define i2c_sda_lo() \ - *_sdaPortReg &=~ _sdaBitMask; \ - *_sdaDirReg |= _sdaBitMask; - -// set SCL high and to input (releases pin) (i.e. change to input,turnon pullup) -#define i2c_scl_hi() \ - *_sclDirReg &=~ _sclBitMask; \ - if(usePullups) { *_sclPortReg |= _sclBitMask; } - -// set SDA high and to input (releases pin) (i.e. change to input,turnon pullup) -#define i2c_sda_hi() \ - *_sdaDirReg &=~ _sdaBitMask; \ - if(usePullups) { *_sdaPortReg |= _sdaBitMask; } - - -// -// Constructor -// -SoftI2CMaster::SoftI2CMaster() -{ - // do nothing, use setPins() later -} -// -SoftI2CMaster::SoftI2CMaster(uint8_t sclPin, uint8_t sdaPin) -{ - setPins(sclPin, sdaPin, true); - i2c_init(); -} - -// -SoftI2CMaster::SoftI2CMaster(uint8_t sclPin, uint8_t sdaPin, uint8_t pullups) -{ - setPins(sclPin, sdaPin, pullups); - i2c_init(); -} - -// -// Turn Arduino pin numbers into PORTx, DDRx, and PINx -// -void SoftI2CMaster::setPins(uint8_t sclPin, uint8_t sdaPin, uint8_t pullups) -{ - uint8_t port; - - usePullups = pullups; - - _sclPin = sclPin; - _sdaPin = sdaPin; - - _sclBitMask = digitalPinToBitMask(sclPin); - _sdaBitMask = digitalPinToBitMask(sdaPin); - - port = digitalPinToPort(sclPin); - _sclPortReg = portOutputRegister(port); - _sclDirReg = portModeRegister(port); - - port = digitalPinToPort(sdaPin); - _sdaPortReg = portOutputRegister(port); - _sdaDirReg = portModeRegister(port); - - initialized = 255; -} - -// -// -// -uint8_t SoftI2CMaster::beginTransmission(uint8_t address) -{ - i2c_start(); - uint8_t rc = i2c_write((address<<1) | 0); // clr read bit - // The standard Wire library returns a status in endTransmission(), not beginTransmission(). - // So we will return the status here but also remember the result so we can return it in endTransmission(). - // It also allows us to disable other I2C functions until beginTransmission has been called, if we want. - initialized = rc; - return rc; -} - -// -uint8_t SoftI2CMaster::requestFrom(uint8_t address) -{ - i2c_start(); - uint8_t rc = i2c_write((address<<1) | 1); // set read bit - return rc; -} -// -uint8_t SoftI2CMaster::requestFrom(int address) -{ - return requestFrom( (uint8_t) address); -} -// Added for compatibility with the standard Wire library. -uint8_t SoftI2CMaster::requestFrom(int address, int quantity) -{ - return requestFrom( (uint8_t) address); - - // Ignore 'quantity', since SoftI2CMaster::requestFrom() just sets the start of read adresses, - // so it's the same for any number of bytes. - (void)quantity; -} -// Added for compatibility with the standard Wire library. -uint8_t SoftI2CMaster::requestFrom(uint8_t address, uint8_t quantity) -{ - return requestFrom( (uint8_t) address); - - // Ignore 'quantity', since SoftI2CMaster::requestFrom() just sets the start of read adresses, - // so it's the same for any number of bytes. - (void)quantity; -} - -// -uint8_t SoftI2CMaster::beginTransmission(int address) -{ - return beginTransmission((uint8_t)address); -} - -// -// -// -uint8_t SoftI2CMaster::endTransmission(void) -{ - i2c_stop(); - return initialized; // Use the result of beginTransmission() -} - -// must be called in: -// slave tx event callback -// or after beginTransmission(address) -uint8_t SoftI2CMaster::write(uint8_t data) -{ - return i2c_write(data); -} - -// must be called in: -// slave tx event callback -// or after beginTransmission(address) -void SoftI2CMaster::write(uint8_t* data, uint8_t quantity) -{ - for(uint8_t i = 0; i < quantity; ++i){ - write(data[i]); - } -} - -// must be called in: -// slave tx event callback -// or after beginTransmission(address) -void SoftI2CMaster::write(char* data) -{ - write((uint8_t*)data, strlen(data)); -} - -// must be called in: -// slave tx event callback -// or after beginTransmission(address) -void SoftI2CMaster::write(int data) -{ - write((uint8_t)data); -} - -//-------------------------------------------------------------------- - - -void SoftI2CMaster::i2c_writebit( uint8_t c ) -{ - if ( c > 0 ) { - i2c_sda_hi(); - } else { - i2c_sda_lo(); - } - - i2c_scl_hi(); - _delay_us(i2cbitdelay); - - i2c_scl_lo(); - _delay_us(i2cbitdelay); - - if ( c > 0 ) { - i2c_sda_lo(); - } - _delay_us(i2cbitdelay); -} - -// -uint8_t SoftI2CMaster::i2c_readbit(void) -{ - i2c_sda_hi(); - i2c_scl_hi(); - _delay_us(i2cbitdelay); - - uint8_t port = digitalPinToPort(_sdaPin); - volatile uint8_t* pinReg = portInputRegister(port); - uint8_t c = *pinReg; // I2C_PIN; - - i2c_scl_lo(); - _delay_us(i2cbitdelay); - - return ( c & _sdaBitMask) ? 1 : 0; -} - -// Inits bitbanging port, must be called before using the functions below -// -void SoftI2CMaster::i2c_init(void) -{ - //I2C_PORT &=~ (_BV( I2C_SDA ) | _BV( I2C_SCL )); - //*_sclPortReg &=~ (_sdaBitMask | _sclBitMask); - i2c_sda_hi(); - i2c_scl_hi(); - - _delay_us(i2cbitdelay); -} - -// Send a START Condition -// -void SoftI2CMaster::i2c_start(void) -{ - // set both to high at the same time - //I2C_DDR &=~ (_BV( I2C_SDA ) | _BV( I2C_SCL )); - //*_sclDirReg &=~ (_sdaBitMask | _sclBitMask); - i2c_sda_hi(); - i2c_scl_hi(); - - _delay_us(i2cbitdelay); - - i2c_sda_lo(); - _delay_us(i2cbitdelay); - - i2c_scl_lo(); - _delay_us(i2cbitdelay); -} - -void SoftI2CMaster::i2c_repstart(void) -{ - // set both to high at the same time (releases drive on both lines) - //I2C_DDR &=~ (_BV( I2C_SDA ) | _BV( I2C_SCL )); - //*_sclDirReg &=~ (_sdaBitMask | _sclBitMask); - i2c_sda_hi(); - i2c_scl_hi(); - - i2c_scl_lo(); // force SCL low - _delay_us(i2cbitdelay); - - i2c_sda_release(); // release SDA - _delay_us(i2cbitdelay); - - i2c_scl_release(); // release SCL - _delay_us(i2cbitdelay); - - i2c_sda_lo(); // force SDA low - _delay_us(i2cbitdelay); -} - -// Send a STOP Condition -// -void SoftI2CMaster::i2c_stop(void) -{ - i2c_scl_hi(); - _delay_us(i2cbitdelay); - - i2c_sda_hi(); - _delay_us(i2cbitdelay); -} - -// write a byte to the I2C slave device -// -uint8_t SoftI2CMaster::i2c_write( uint8_t c ) -{ - for ( uint8_t i=0;i<8;i++) { - i2c_writebit( c & 128 ); - c<<=1; - } - - return i2c_readbit(); -} - -// read a byte from the I2C slave device -// -uint8_t SoftI2CMaster::i2c_read( uint8_t ack ) -{ - uint8_t res = 0; - - for ( uint8_t i=0;i<8;i++) { - res <<= 1; - res |= i2c_readbit(); - } - - if ( ack ) - i2c_writebit( 0 ); - else - i2c_writebit( 1 ); - - _delay_us(i2cbitdelay); - - return res; -} - -// FIXME: this isn't right, surely -uint8_t SoftI2CMaster::read( uint8_t ack ) -{ - return i2c_read( ack ); -} - -// -uint8_t SoftI2CMaster::read() -{ - return i2c_read( I2C_ACK ); -} - -// -uint8_t SoftI2CMaster::readLast() -{ - return i2c_read( I2C_NAK ); -} +/* + * SoftI2CMaster.cpp -- Multi-instance software I2C Master library + * + * + * 2010-12 Tod E. Kurt, http://todbot.com/blog/ + * + * This code takes some tricks from: + * http://codinglab.blogspot.com/2008/10/i2c-on-avr-using-bit-banging.html + * + * 2014, by Testato: update library and examples for follow Wire’s API of Arduino IDE 1.x + * + */ + +#if (ARDUINO >= 100) +#include +#else +#include +#endif + +#include "SoftI2CMaster.h" + +#include +#include + +#define i2cbitdelay 50 + +#define I2C_ACK 1 +#define I2C_NAK 0 + + +#define i2c_scl_release() \ + *_sclDirReg &=~ _sclBitMask +#define i2c_sda_release() \ + *_sdaDirReg &=~ _sdaBitMask + +// sets SCL low and drives output +#define i2c_scl_lo() \ + *_sclPortReg &=~ _sclBitMask; \ + *_sclDirReg |= _sclBitMask; + +// sets SDA low and drives output +#define i2c_sda_lo() \ + *_sdaPortReg &=~ _sdaBitMask; \ + *_sdaDirReg |= _sdaBitMask; + +// set SCL high and to input (releases pin) (i.e. change to input,turnon pullup) +#define i2c_scl_hi() \ + *_sclDirReg &=~ _sclBitMask; \ + if(usePullups) { *_sclPortReg |= _sclBitMask; } + +// set SDA high and to input (releases pin) (i.e. change to input,turnon pullup) +#define i2c_sda_hi() \ + *_sdaDirReg &=~ _sdaBitMask; \ + if(usePullups) { *_sdaPortReg |= _sdaBitMask; } + + +// +// Constructor +// +SoftI2CMaster::SoftI2CMaster() +{ + // do nothing, use setPins() later +} +// +SoftI2CMaster::SoftI2CMaster(uint8_t sclPin, uint8_t sdaPin) +{ + setPins(sclPin, sdaPin, true); + i2c_init(); +} + +// +SoftI2CMaster::SoftI2CMaster(uint8_t sclPin, uint8_t sdaPin, uint8_t pullups) +{ + setPins(sclPin, sdaPin, pullups); + i2c_init(); +} + +// +// Turn Arduino pin numbers into PORTx, DDRx, and PINx +// +void SoftI2CMaster::setPins(uint8_t sclPin, uint8_t sdaPin, uint8_t pullups) +{ + uint8_t port; + + usePullups = pullups; + + _sclPin = sclPin; + _sdaPin = sdaPin; + + _sclBitMask = digitalPinToBitMask(sclPin); + _sdaBitMask = digitalPinToBitMask(sdaPin); + + port = digitalPinToPort(sclPin); + _sclPortReg = portOutputRegister(port); + _sclDirReg = portModeRegister(port); + + port = digitalPinToPort(sdaPin); + _sdaPortReg = portOutputRegister(port); + _sdaDirReg = portModeRegister(port); + + initialized = 255; +} + +// +// +// +uint8_t SoftI2CMaster::beginTransmission(uint8_t address) +{ + i2c_start(); + uint8_t rc = i2c_write((address<<1) | 0); // clr read bit + // The standard Wire library returns a status in endTransmission(), not beginTransmission(). + // So we will return the status here but also remember the result so we can return it in endTransmission(). + // It also allows us to disable other I2C functions until beginTransmission has been called, if we want. + initialized = rc; + return rc; +} + +// +uint8_t SoftI2CMaster::requestFrom(uint8_t address) +{ + i2c_start(); + uint8_t rc = i2c_write((address<<1) | 1); // set read bit + return rc; +} +// +uint8_t SoftI2CMaster::requestFrom(int address) +{ + return requestFrom( (uint8_t) address); +} +// Added for compatibility with the standard Wire library. +uint8_t SoftI2CMaster::requestFrom(int address, int quantity) +{ + return requestFrom( (uint8_t) address); + + // Ignore 'quantity', since SoftI2CMaster::requestFrom() just sets the start of read adresses, + // so it's the same for any number of bytes. + (void)quantity; +} +// Added for compatibility with the standard Wire library. +uint8_t SoftI2CMaster::requestFrom(uint8_t address, uint8_t quantity) +{ + return requestFrom( (uint8_t) address); + + // Ignore 'quantity', since SoftI2CMaster::requestFrom() just sets the start of read adresses, + // so it's the same for any number of bytes. + (void)quantity; +} + +// +uint8_t SoftI2CMaster::beginTransmission(int address) +{ + return beginTransmission((uint8_t)address); +} + +// +// +// +uint8_t SoftI2CMaster::endTransmission(void) +{ + i2c_stop(); + return initialized; // Use the result of beginTransmission() +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +uint8_t SoftI2CMaster::write(uint8_t data) +{ + return i2c_write(data); +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +void SoftI2CMaster::write(uint8_t* data, uint8_t quantity) +{ + for(uint8_t i = 0; i < quantity; ++i){ + write(data[i]); + } +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +void SoftI2CMaster::write(char* data) +{ + write((uint8_t*)data, strlen(data)); +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +void SoftI2CMaster::write(int data) +{ + write((uint8_t)data); +} + +//-------------------------------------------------------------------- + + +void SoftI2CMaster::i2c_writebit( uint8_t c ) +{ + if ( c > 0 ) { + i2c_sda_hi(); + } else { + i2c_sda_lo(); + } + + i2c_scl_hi(); + _delay_us(i2cbitdelay); + + i2c_scl_lo(); + _delay_us(i2cbitdelay); + + if ( c > 0 ) { + i2c_sda_lo(); + } + _delay_us(i2cbitdelay); +} + +// +uint8_t SoftI2CMaster::i2c_readbit(void) +{ + i2c_sda_hi(); + i2c_scl_hi(); + _delay_us(i2cbitdelay); + + uint8_t port = digitalPinToPort(_sdaPin); + volatile uint8_t* pinReg = portInputRegister(port); + uint8_t c = *pinReg; // I2C_PIN; + + i2c_scl_lo(); + _delay_us(i2cbitdelay); + + return ( c & _sdaBitMask) ? 1 : 0; +} + +// Inits bitbanging port, must be called before using the functions below +// +void SoftI2CMaster::i2c_init(void) +{ + //I2C_PORT &=~ (_BV( I2C_SDA ) | _BV( I2C_SCL )); + //*_sclPortReg &=~ (_sdaBitMask | _sclBitMask); + i2c_sda_hi(); + i2c_scl_hi(); + + _delay_us(i2cbitdelay); +} + +// Send a START Condition +// +void SoftI2CMaster::i2c_start(void) +{ + // set both to high at the same time + //I2C_DDR &=~ (_BV( I2C_SDA ) | _BV( I2C_SCL )); + //*_sclDirReg &=~ (_sdaBitMask | _sclBitMask); + i2c_sda_hi(); + i2c_scl_hi(); + + _delay_us(i2cbitdelay); + + i2c_sda_lo(); + _delay_us(i2cbitdelay); + + i2c_scl_lo(); + _delay_us(i2cbitdelay); +} + +void SoftI2CMaster::i2c_repstart(void) +{ + // set both to high at the same time (releases drive on both lines) + //I2C_DDR &=~ (_BV( I2C_SDA ) | _BV( I2C_SCL )); + //*_sclDirReg &=~ (_sdaBitMask | _sclBitMask); + i2c_sda_hi(); + i2c_scl_hi(); + + i2c_scl_lo(); // force SCL low + _delay_us(i2cbitdelay); + + i2c_sda_release(); // release SDA + _delay_us(i2cbitdelay); + + i2c_scl_release(); // release SCL + _delay_us(i2cbitdelay); + + i2c_sda_lo(); // force SDA low + _delay_us(i2cbitdelay); +} + +// Send a STOP Condition +// +void SoftI2CMaster::i2c_stop(void) +{ + i2c_scl_hi(); + _delay_us(i2cbitdelay); + + i2c_sda_hi(); + _delay_us(i2cbitdelay); +} + +// write a byte to the I2C slave device +// +uint8_t SoftI2CMaster::i2c_write( uint8_t c ) +{ + for ( uint8_t i=0;i<8;i++) { + i2c_writebit( c & 128 ); + c<<=1; + } + + return i2c_readbit(); +} + +// read a byte from the I2C slave device +// +uint8_t SoftI2CMaster::i2c_read( uint8_t ack ) +{ + uint8_t res = 0; + + for ( uint8_t i=0;i<8;i++) { + res <<= 1; + res |= i2c_readbit(); + } + + if ( ack ) + i2c_writebit( 0 ); + else + i2c_writebit( 1 ); + + _delay_us(i2cbitdelay); + + return res; +} + +// FIXME: this isn't right, surely +uint8_t SoftI2CMaster::read( uint8_t ack ) +{ + return i2c_read( ack ); +} + +// +uint8_t SoftI2CMaster::read() +{ + return i2c_read( I2C_ACK ); +} + +// +uint8_t SoftI2CMaster::readLast() +{ + return i2c_read( I2C_NAK ); +} diff --git a/SoftI2CMaster.h b/src/SoftI2CMaster.h similarity index 96% rename from SoftI2CMaster.h rename to src/SoftI2CMaster.h index 5f11fc3..da6bc1f 100644 --- a/SoftI2CMaster.h +++ b/src/SoftI2CMaster.h @@ -1,76 +1,76 @@ -/* - * SoftI2CMaster.h -- Multi-instance software I2C Master library - * - * 2010-2012 Tod E. Kurt, http://todbot.com/blog/ - * 2014, by Testato: update library and examples for follow Wire’s API of Arduino IDE 1.x - * - */ - -#ifndef SoftI2CMaster_h -#define SoftI2CMaster_h - -#include - -#define _SOFTI2CMASTER_VERSION 13 // software version of this library - - -class SoftI2CMaster -{ - -private: - // per object data - uint8_t _sclPin; - uint8_t _sdaPin; - uint8_t _sclBitMask; - uint8_t _sdaBitMask; - volatile uint8_t *_sclPortReg; - volatile uint8_t *_sdaPortReg; - volatile uint8_t *_sclDirReg; - volatile uint8_t *_sdaDirReg; - - uint8_t usePullups; - - // 'initialized' will be: - // 255 on startup, - // 0 if beginTransmission() was called and successful, - // any other value if there was an error during beginTransmission(). - uint8_t initialized; - - // private methods - - void i2c_writebit( uint8_t c ); - uint8_t i2c_readbit(void); - void i2c_init(void); - void i2c_start(void); - void i2c_repstart(void); - void i2c_stop(void); - uint8_t i2c_write( uint8_t c ); - uint8_t i2c_read( uint8_t ack ); - -public: - // public methods - SoftI2CMaster(); - SoftI2CMaster(uint8_t sclPin, uint8_t sdaPin); - SoftI2CMaster(uint8_t sclPin, uint8_t sdaPin, uint8_t usePullups); - - void setPins(uint8_t sclPin, uint8_t sdaPin, uint8_t usePullups); - - uint8_t beginTransmission(uint8_t address); - uint8_t beginTransmission(int address); - uint8_t endTransmission(void); - uint8_t write(uint8_t); - void write(uint8_t*, uint8_t); - void write(int); - void write(char*); - void begin(void) {return;}; - uint8_t requestFrom(int address); - uint8_t requestFrom(uint8_t address); - uint8_t requestFrom(int address, int quantity); - uint8_t requestFrom(uint8_t address, uint8_t quantity); - uint8_t read( uint8_t ack ); - uint8_t read(); - uint8_t readLast(); - -}; - -#endif +/* + * SoftI2CMaster.h -- Multi-instance software I2C Master library + * + * 2010-2012 Tod E. Kurt, http://todbot.com/blog/ + * 2014, by Testato: update library and examples for follow Wire’s API of Arduino IDE 1.x + * + */ + +#ifndef SoftI2CMaster_h +#define SoftI2CMaster_h + +#include + +#define _SOFTI2CMASTER_VERSION 13 // software version of this library + + +class SoftI2CMaster +{ + +private: + // per object data + uint8_t _sclPin; + uint8_t _sdaPin; + uint8_t _sclBitMask; + uint8_t _sdaBitMask; + volatile uint8_t *_sclPortReg; + volatile uint8_t *_sdaPortReg; + volatile uint8_t *_sclDirReg; + volatile uint8_t *_sdaDirReg; + + uint8_t usePullups; + + // 'initialized' will be: + // 255 on startup, + // 0 if beginTransmission() was called and successful, + // any other value if there was an error during beginTransmission(). + uint8_t initialized; + + // private methods + + void i2c_writebit( uint8_t c ); + uint8_t i2c_readbit(void); + void i2c_init(void); + void i2c_start(void); + void i2c_repstart(void); + void i2c_stop(void); + uint8_t i2c_write( uint8_t c ); + uint8_t i2c_read( uint8_t ack ); + +public: + // public methods + SoftI2CMaster(); + SoftI2CMaster(uint8_t sclPin, uint8_t sdaPin); + SoftI2CMaster(uint8_t sclPin, uint8_t sdaPin, uint8_t usePullups); + + void setPins(uint8_t sclPin, uint8_t sdaPin, uint8_t usePullups); + + uint8_t beginTransmission(uint8_t address); + uint8_t beginTransmission(int address); + uint8_t endTransmission(void); + uint8_t write(uint8_t); + void write(uint8_t*, uint8_t); + void write(int); + void write(char*); + void begin(void) {return;}; + uint8_t requestFrom(int address); + uint8_t requestFrom(uint8_t address); + uint8_t requestFrom(int address, int quantity); + uint8_t requestFrom(uint8_t address, uint8_t quantity); + uint8_t read( uint8_t ack ); + uint8_t read(); + uint8_t readLast(); + +}; + +#endif