diff --git a/lib/lib_i2c/Adafruit_BusIO/Adafruit_BusIO_Register.cpp b/lib/lib_i2c/Adafruit_BusIO/Adafruit_BusIO_Register.cpp index 2c2b22e00..f8025257d 100644 --- a/lib/lib_i2c/Adafruit_BusIO/Adafruit_BusIO_Register.cpp +++ b/lib/lib_i2c/Adafruit_BusIO/Adafruit_BusIO_Register.cpp @@ -1,86 +1,133 @@ #include +#if !defined(SPI_INTERFACES_COUNT) || \ + (defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0)) + /*! - * @brief Create a register we access over an I2C Device (which defines the bus and address) + * @brief Create a register we access over an I2C Device (which defines the + * bus and address) * @param i2cdevice The I2CDevice to use for underlying I2C access - * @param reg_addr The address pointer value for the I2C/SMBus register, can be 8 or 16 bits + * @param reg_addr The address pointer value for the I2C/SMBus register, can + * be 8 or 16 bits * @param width The width of the register data itself, defaults to 1 byte - * @param bitorder The bit order of the register (used when width is > 1), defaults to LSBFIRST - * @param address_width The width of the register address itself, defaults to 1 byte + * @param byteorder The byte order of the register (used when width is > 1), + * defaults to LSBFIRST + * @param address_width The width of the register address itself, defaults + * to 1 byte */ -Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice, uint16_t reg_addr, - uint8_t width, uint8_t bitorder, uint8_t address_width) { +Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice, + uint16_t reg_addr, + uint8_t width, + uint8_t byteorder, + uint8_t address_width) { _i2cdevice = i2cdevice; _spidevice = NULL; _addrwidth = address_width; _address = reg_addr; - _bitorder = bitorder; + _byteorder = byteorder; _width = width; } /*! - * @brief Create a register we access over an SPI Device (which defines the bus and CS pin) - * @param spidevice The SPIDevice to use for underlying I2C access - * @param reg_addr The address pointer value for the I2C/SMBus register, can be 8 or 16 bits - * @param type The method we use to read/write data to SPI (which is not as well defined as I2C) + * @brief Create a register we access over an SPI Device (which defines the + * bus and CS pin) + * @param spidevice The SPIDevice to use for underlying SPI access + * @param reg_addr The address pointer value for the SPI register, can + * be 8 or 16 bits + * @param type The method we use to read/write data to SPI (which is not + * as well defined as I2C) * @param width The width of the register data itself, defaults to 1 byte - * @param bitorder The bit order of the register (used when width is > 1), defaults to LSBFIRST - * @param address_width The width of the register address itself, defaults to 1 byte + * @param byteorder The byte order of the register (used when width is > 1), + * defaults to LSBFIRST + * @param address_width The width of the register address itself, defaults + * to 1 byte */ -Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_SPIDevice *spidevice, uint16_t reg_addr, - Adafruit_BusIO_SPIRegType type, - uint8_t width, uint8_t bitorder, uint8_t address_width) { +Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_SPIDevice *spidevice, + uint16_t reg_addr, + Adafruit_BusIO_SPIRegType type, + uint8_t width, + uint8_t byteorder, + uint8_t address_width) { _spidevice = spidevice; _spiregtype = type; _i2cdevice = NULL; _addrwidth = address_width; _address = reg_addr; - _bitorder = bitorder; + _byteorder = byteorder; _width = width; } /*! - * @brief Create a register we access over an I2C or SPI Device. This is a handy function because we - * can pass in NULL for the unused interface, allowing libraries to mass-define all the registers - * @param i2cdevice The I2CDevice to use for underlying I2C access, if NULL we use SPI - * @param spidevice The SPIDevice to use for underlying I2C access, if NULL we use I2C - * @param reg_addr The address pointer value for the I2C/SMBus register, can be 8 or 16 bits - * @param type The method we use to read/write data to SPI (which is not as well defined as I2C) + * @brief Create a register we access over an I2C or SPI Device. This is a + * handy function because we can pass in NULL for the unused interface, allowing + * libraries to mass-define all the registers + * @param i2cdevice The I2CDevice to use for underlying I2C access, if NULL + * we use SPI + * @param spidevice The SPIDevice to use for underlying SPI access, if NULL + * we use I2C + * @param reg_addr The address pointer value for the I2C/SMBus/SPI register, + * can be 8 or 16 bits + * @param type The method we use to read/write data to SPI (which is not + * as well defined as I2C) * @param width The width of the register data itself, defaults to 1 byte - * @param bitorder The bit order of the register (used when width is > 1), defaults to LSBFIRST - * @param address_width The width of the register address itself, defaults to 1 byte + * @param byteorder The byte order of the register (used when width is > 1), + * defaults to LSBFIRST + * @param address_width The width of the register address itself, defaults + * to 1 byte */ -Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice, Adafruit_SPIDevice *spidevice, - Adafruit_BusIO_SPIRegType type, uint16_t reg_addr, - uint8_t width, uint8_t bitorder, uint8_t address_width) { +Adafruit_BusIO_Register::Adafruit_BusIO_Register( + Adafruit_I2CDevice *i2cdevice, Adafruit_SPIDevice *spidevice, + Adafruit_BusIO_SPIRegType type, uint16_t reg_addr, uint8_t width, + uint8_t byteorder, uint8_t address_width) { _spidevice = spidevice; _i2cdevice = i2cdevice; _spiregtype = type; _addrwidth = address_width; _address = reg_addr; - _bitorder = bitorder; + _byteorder = byteorder; _width = width; } - /*! * @brief Write a buffer of data to the register location * @param buffer Pointer to data to write * @param len Number of bytes to write - * @return True on successful write (only really useful for I2C as SPI is uncheckable) + * @return True on successful write (only really useful for I2C as SPI is + * uncheckable) */ bool Adafruit_BusIO_Register::write(uint8_t *buffer, uint8_t len) { - uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF), (uint8_t)(_address>>8)}; + uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF), + (uint8_t)(_address >> 8)}; if (_i2cdevice) { return _i2cdevice->write(buffer, len, true, addrbuffer, _addrwidth); } if (_spidevice) { + if (_spiregtype == ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE) { + // very special case! + + // pass the special opcode address which we set as the high byte of the + // regaddr + addrbuffer[0] = + (uint8_t)(_address >> 8) & ~0x01; // set bottom bit low to write + // the 'actual' reg addr is the second byte then + addrbuffer[1] = (uint8_t)(_address & 0xFF); + // the address appears to be a byte longer + return _spidevice->write(buffer, len, addrbuffer, _addrwidth + 1); + } + if (_spiregtype == ADDRBIT8_HIGH_TOREAD) { addrbuffer[0] &= ~0x80; } - return _spidevice->write( buffer, len, addrbuffer, _addrwidth); + if (_spiregtype == ADDRBIT8_HIGH_TOWRITE) { + addrbuffer[0] |= 0x80; + } + if (_spiregtype == AD8_HIGH_TOREAD_AD7_HIGH_TOINC) { + addrbuffer[0] &= ~0x80; + addrbuffer[0] |= 0x40; + } + return _spidevice->write(buffer, len, addrbuffer, _addrwidth); } return false; } @@ -89,7 +136,8 @@ bool Adafruit_BusIO_Register::write(uint8_t *buffer, uint8_t len) { * @brief Write up to 4 bytes of data to the register location * @param value Data to write * @param numbytes How many bytes from 'value' to write - * @return True on successful write (only really useful for I2C as SPI is uncheckable) + * @return True on successful write (only really useful for I2C as SPI is + * uncheckable) */ bool Adafruit_BusIO_Register::write(uint32_t value, uint8_t numbytes) { if (numbytes == 0) { @@ -99,11 +147,14 @@ bool Adafruit_BusIO_Register::write(uint32_t value, uint8_t numbytes) { return false; } - for (int i=0; i>= 8; } @@ -111,45 +162,72 @@ bool Adafruit_BusIO_Register::write(uint32_t value, uint8_t numbytes) { } /*! - * @brief Read data from the register location. This does not do any error checking! + * @brief Read data from the register location. This does not do any error + * checking! * @return Returns 0xFFFFFFFF on failure, value otherwise */ uint32_t Adafruit_BusIO_Register::read(void) { - if (! read(_buffer, _width)) { + if (!read(_buffer, _width)) { return -1; } uint32_t value = 0; - for (int i=0; i < _width; i++) { - value <<= 8; - if (_bitorder == LSBFIRST) { - value |= _buffer[_width-i-1]; - } else { - value |= _buffer[i]; - } - } + for (int i = 0; i < _width; i++) { + value <<= 8; + if (_byteorder == LSBFIRST) { + value |= _buffer[_width - i - 1]; + } else { + value |= _buffer[i]; + } + } - return value; + return value; } +/*! + * @brief Read cached data from last time we wrote to this register + * @return Returns 0xFFFFFFFF on failure, value otherwise + */ +uint32_t Adafruit_BusIO_Register::readCached(void) { return _cached; } /*! * @brief Read a buffer of data from the register location * @param buffer Pointer to data to read into * @param len Number of bytes to read - * @return True on successful write (only really useful for I2C as SPI is uncheckable) + * @return True on successful write (only really useful for I2C as SPI is + * uncheckable) */ bool Adafruit_BusIO_Register::read(uint8_t *buffer, uint8_t len) { - uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF), (uint8_t)(_address>>8)}; + uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF), + (uint8_t)(_address >> 8)}; if (_i2cdevice) { return _i2cdevice->write_then_read(addrbuffer, _addrwidth, buffer, len); } if (_spidevice) { + if (_spiregtype == ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE) { + // very special case! + + // pass the special opcode address which we set as the high byte of the + // regaddr + addrbuffer[0] = + (uint8_t)(_address >> 8) | 0x01; // set bottom bit high to read + // the 'actual' reg addr is the second byte then + addrbuffer[1] = (uint8_t)(_address & 0xFF); + // the address appears to be a byte longer + return _spidevice->write_then_read(addrbuffer, _addrwidth + 1, buffer, + len); + } if (_spiregtype == ADDRBIT8_HIGH_TOREAD) { addrbuffer[0] |= 0x80; } + if (_spiregtype == ADDRBIT8_HIGH_TOWRITE) { + addrbuffer[0] &= ~0x80; + } + if (_spiregtype == AD8_HIGH_TOREAD_AD7_HIGH_TOINC) { + addrbuffer[0] |= 0x80 | 0x40; + } return _spidevice->write_then_read(addrbuffer, _addrwidth, buffer, len); } return false; @@ -158,14 +236,15 @@ bool Adafruit_BusIO_Register::read(uint8_t *buffer, uint8_t len) { /*! * @brief Read 2 bytes of data from the register location * @param value Pointer to uint16_t variable to read into - * @return True on successful write (only really useful for I2C as SPI is uncheckable) + * @return True on successful write (only really useful for I2C as SPI is + * uncheckable) */ bool Adafruit_BusIO_Register::read(uint16_t *value) { - if (! read(_buffer, 2)) { + if (!read(_buffer, 2)) { return false; } - if (_bitorder == LSBFIRST) { + if (_byteorder == LSBFIRST) { *value = _buffer[1]; *value <<= 8; *value |= _buffer[0]; @@ -180,10 +259,11 @@ bool Adafruit_BusIO_Register::read(uint16_t *value) { /*! * @brief Read 1 byte of data from the register location * @param value Pointer to uint8_t variable to read into - * @return True on successful write (only really useful for I2C as SPI is uncheckable) + * @return True on successful write (only really useful for I2C as SPI is + * uncheckable) */ bool Adafruit_BusIO_Register::read(uint8_t *value) { - if (! read(_buffer, 1)) { + if (!read(_buffer, 1)) { return false; } @@ -197,7 +277,8 @@ bool Adafruit_BusIO_Register::read(uint8_t *value) { */ void Adafruit_BusIO_Register::print(Stream *s) { uint32_t val = read(); - s->print("0x"); s->print(val, HEX); + s->print("0x"); + s->print(val, HEX); } /*! @@ -209,14 +290,15 @@ void Adafruit_BusIO_Register::println(Stream *s) { s->println(); } - /*! - * @brief Create a slice of the register that we can address without touching other bits + * @brief Create a slice of the register that we can address without + * touching other bits * @param reg The Adafruit_BusIO_Register which defines the bus/register * @param bits The number of bits wide we are slicing * @param shift The number of bits that our bit-slice is shifted from LSB */ -Adafruit_BusIO_RegisterBits::Adafruit_BusIO_RegisterBits(Adafruit_BusIO_Register *reg, uint8_t bits, uint8_t shift) { +Adafruit_BusIO_RegisterBits::Adafruit_BusIO_RegisterBits( + Adafruit_BusIO_Register *reg, uint8_t bits, uint8_t shift) { _register = reg; _bits = bits; _shift = shift; @@ -232,12 +314,13 @@ uint32_t Adafruit_BusIO_RegisterBits::read(void) { return val & ((1 << (_bits)) - 1); } - /*! * @brief Write 4 bytes of data to the register * @param data The 4 bytes to write + * @return True on successful write (only really useful for I2C as SPI is + * uncheckable) */ -void Adafruit_BusIO_RegisterBits::write(uint32_t data) { +bool Adafruit_BusIO_RegisterBits::write(uint32_t data) { uint32_t val = _register->read(); // mask off the data before writing @@ -245,10 +328,10 @@ void Adafruit_BusIO_RegisterBits::write(uint32_t data) { data &= mask; mask <<= _shift; - val &= ~mask; // remove the current data at that spot + val &= ~mask; // remove the current data at that spot val |= data << _shift; // and add in the new data - - _register->write(val, _register->width()); + + return _register->write(val, _register->width()); } /*! @@ -256,3 +339,27 @@ void Adafruit_BusIO_RegisterBits::write(uint32_t data) { * @returns The data width used when initializing the register */ uint8_t Adafruit_BusIO_Register::width(void) { return _width; } + +/*! + * @brief Set the default width of data + * @param width the default width of data read from register + */ +void Adafruit_BusIO_Register::setWidth(uint8_t width) { _width = width; } + +/*! + * @brief Set register address + * @param address the address from register + */ +void Adafruit_BusIO_Register::setAddress(uint16_t address) { + _address = address; +} + +/*! + * @brief Set the width of register address + * @param address_width the width for register address + */ +void Adafruit_BusIO_Register::setAddressWidth(uint16_t address_width) { + _addrwidth = address_width; +} + +#endif // SPI exists diff --git a/lib/lib_i2c/Adafruit_BusIO/Adafruit_BusIO_Register.h b/lib/lib_i2c/Adafruit_BusIO/Adafruit_BusIO_Register.h index 45ae1e146..c6d58de60 100644 --- a/lib/lib_i2c/Adafruit_BusIO/Adafruit_BusIO_Register.h +++ b/lib/lib_i2c/Adafruit_BusIO/Adafruit_BusIO_Register.h @@ -1,69 +1,105 @@ -#include -#include -#include - - #ifndef Adafruit_BusIO_Register_h #define Adafruit_BusIO_Register_h +#include + +#if !defined(SPI_INTERFACES_COUNT) || \ + (defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0)) + +#include +#include + typedef enum _Adafruit_BusIO_SPIRegType { ADDRBIT8_HIGH_TOREAD = 0, + /*!< + * ADDRBIT8_HIGH_TOREAD + * When reading a register you must actually send the value 0x80 + register + * address to the device. e.g. To read the register 0x0B the register value + * 0x8B is sent and to write 0x0B is sent. + */ + AD8_HIGH_TOREAD_AD7_HIGH_TOINC = 1, + + /*!< + * ADDRBIT8_HIGH_TOWRITE + * When writing to a register you must actually send the value 0x80 + + * the register address to the device. e.g. To write to the register 0x19 the + * register value 0x99 is sent and to read 0x19 is sent. + */ + ADDRBIT8_HIGH_TOWRITE = 2, + + /*!< + * ADDRESSED_OPCODE_LOWBIT_TO_WRITE + * Used by the MCP23S series, we send 0x40 |'rd with the opcode + * Then set the lowest bit to write + */ + ADDRESSED_OPCODE_BIT0_LOW_TO_WRITE = 3, + } Adafruit_BusIO_SPIRegType; /*! - * @brief The class which defines a device register (a location to read/write data from) + * @brief The class which defines a device register (a location to read/write + * data from) */ class Adafruit_BusIO_Register { - public: - Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice, uint16_t reg_addr, - uint8_t width=1, uint8_t bitorder=LSBFIRST, - uint8_t address_width=1); - Adafruit_BusIO_Register(Adafruit_SPIDevice *spidevice, uint16_t reg_addr, - Adafruit_BusIO_SPIRegType type, - uint8_t width=1, uint8_t bitorder=LSBFIRST, - uint8_t address_width=1); +public: + Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice, uint16_t reg_addr, + uint8_t width = 1, uint8_t byteorder = LSBFIRST, + uint8_t address_width = 1); + + Adafruit_BusIO_Register(Adafruit_SPIDevice *spidevice, uint16_t reg_addr, + Adafruit_BusIO_SPIRegType type, uint8_t width = 1, + uint8_t byteorder = LSBFIRST, + uint8_t address_width = 1); Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice, - Adafruit_SPIDevice *spidevice, - Adafruit_BusIO_SPIRegType type, - uint16_t reg_addr, - uint8_t width=1, uint8_t bitorder=LSBFIRST, - uint8_t address_width=1); + Adafruit_SPIDevice *spidevice, + Adafruit_BusIO_SPIRegType type, uint16_t reg_addr, + uint8_t width = 1, uint8_t byteorder = LSBFIRST, + uint8_t address_width = 1); bool read(uint8_t *buffer, uint8_t len); bool read(uint8_t *value); bool read(uint16_t *value); uint32_t read(void); + uint32_t readCached(void); bool write(uint8_t *buffer, uint8_t len); - bool write(uint32_t value, uint8_t numbytes=0); + bool write(uint32_t value, uint8_t numbytes = 0); uint8_t width(void); - void print(Stream *s=&Serial); - void println(Stream *s=&Serial); + void setWidth(uint8_t width); + void setAddress(uint16_t address); + void setAddressWidth(uint16_t address_width); - private: + void print(Stream *s = &Serial); + void println(Stream *s = &Serial); + +private: Adafruit_I2CDevice *_i2cdevice; Adafruit_SPIDevice *_spidevice; Adafruit_BusIO_SPIRegType _spiregtype; uint16_t _address; - uint8_t _width, _addrwidth, _bitorder; - uint8_t _buffer[4]; // we wont support anything larger than uint32 for non-buffered read + uint8_t _width, _addrwidth, _byteorder; + uint8_t _buffer[4]; // we won't support anything larger than uint32 for + // non-buffered read + uint32_t _cached = 0; }; - /*! - * @brief The class which defines a slice of bits from within a device register (a location to read/write data from) + * @brief The class which defines a slice of bits from within a device register + * (a location to read/write data from) */ class Adafruit_BusIO_RegisterBits { - public: - Adafruit_BusIO_RegisterBits(Adafruit_BusIO_Register *reg, uint8_t bits, uint8_t shift); - void write(uint32_t value); +public: + Adafruit_BusIO_RegisterBits(Adafruit_BusIO_Register *reg, uint8_t bits, + uint8_t shift); + bool write(uint32_t value); uint32_t read(void); - private: + +private: Adafruit_BusIO_Register *_register; uint8_t _bits, _shift; }; - -#endif //BusIO_Register_h +#endif // SPI exists +#endif // BusIO_Register_h diff --git a/lib/lib_i2c/Adafruit_BusIO/Adafruit_I2CDevice.cpp b/lib/lib_i2c/Adafruit_BusIO/Adafruit_I2CDevice.cpp index 7813a6df7..716fe1eaf 100644 --- a/lib/lib_i2c/Adafruit_BusIO/Adafruit_I2CDevice.cpp +++ b/lib/lib_i2c/Adafruit_BusIO/Adafruit_I2CDevice.cpp @@ -1,5 +1,4 @@ -#include -#include +#include "Adafruit_I2CDevice.h" //#define DEBUG_SERIAL Serial @@ -21,20 +20,37 @@ Adafruit_I2CDevice::Adafruit_I2CDevice(uint8_t addr, TwoWire *theWire) { /*! * @brief Initializes and does basic address detection - * @param addr_detect Whether we should attempt to detect the I2C address with a scan. - * 99% of sensors/devices don't mind but once in a while, they spaz on a scan! + * @param addr_detect Whether we should attempt to detect the I2C address + * with a scan. 99% of sensors/devices don't mind but once in a while, they spaz + * on a scan! * @return True if I2C initialized and a device with the addr found */ bool Adafruit_I2CDevice::begin(bool addr_detect) { _wire->begin(); _begun = true; - + if (addr_detect) { return detected(); } return true; } +/*! + * @brief De-initialize device, turn off the Wire interface + */ +void Adafruit_I2CDevice::end(void) { + // Not all port implement Wire::end(), such as + // - ESP8266 + // - AVR core without WIRE_HAS_END + // - ESP32: end() is implemented since 2.0.1 which is latest at the moment. + // Temporarily disable for now to give time for user to update. +#if !(defined(ESP8266) || \ + (defined(ARDUINO_ARCH_AVR) && !defined(WIRE_HAS_END)) || \ + defined(ARDUINO_ARCH_ESP32)) + _wire->end(); + _begun = false; +#endif +} /*! * @brief Scans I2C for the address - note will give a false-positive @@ -49,24 +65,35 @@ bool Adafruit_I2CDevice::detected(void) { // A basic scanner, see if it ACK's _wire->beginTransmission(_addr); - if (_wire->endTransmission () == 0) { + if (_wire->endTransmission() == 0) { +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println(F("Detected")); +#endif return true; } +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println(F("Not detected")); +#endif return false; } /*! - * @brief Write a buffer or two to the I2C device. Cannot be more than maxBufferSize() bytes. - * @param buffer Pointer to buffer of data to write + * @brief Write a buffer or two to the I2C device. Cannot be more than + * maxBufferSize() bytes. + * @param buffer Pointer to buffer of data to write. This is const to + * ensure the content of this buffer doesn't change. * @param len Number of bytes from buffer to write - * @param prefix_buffer Pointer to optional array of data to write before buffer. - * Cannot be more than maxBufferSize() bytes. + * @param prefix_buffer Pointer to optional array of data to write before + * buffer. Cannot be more than maxBufferSize() bytes. This is const to + * ensure the content of this buffer doesn't change. * @param prefix_len Number of bytes from prefix buffer to write * @param stop Whether to send an I2C STOP signal on write * @return True if write was successful, otherwise false. */ -bool Adafruit_I2CDevice::write(uint8_t *buffer, size_t len, bool stop, uint8_t *prefix_buffer, size_t prefix_len) { - if ((len+prefix_len) > maxBufferSize()) { +bool Adafruit_I2CDevice::write(const uint8_t *buffer, size_t len, bool stop, + const uint8_t *prefix_buffer, + size_t prefix_len) { + if ((len + prefix_len) > maxBufferSize()) { // currently not guaranteed to work if more than 32 bytes! // we will need to find out if some platforms have larger // I2C buffer sizes :/ @@ -97,45 +124,47 @@ bool Adafruit_I2CDevice::write(uint8_t *buffer, size_t len, bool stop, uint8_t * } #ifdef DEBUG_SERIAL - DEBUG_SERIAL.print(F("\tI2CDevice Wrote: ")); + + DEBUG_SERIAL.print(F("\tI2CWRITE @ 0x")); + DEBUG_SERIAL.print(_addr, HEX); + DEBUG_SERIAL.print(F(" :: ")); if ((prefix_len != 0) && (prefix_buffer != NULL)) { - for (uint16_t i=0; iendTransmission(stop) == 0) { #ifdef DEBUG_SERIAL - DEBUG_SERIAL.println("Sent!"); + DEBUG_SERIAL.println(); + // DEBUG_SERIAL.println("Sent!"); #endif return true; } else { #ifdef DEBUG_SERIAL - DEBUG_SERIAL.println("Failed to send!"); + DEBUG_SERIAL.println("\tFailed to send!"); #endif return false; } } - /*! - * @brief Read from I2C into a buffer from the I2C device. + * @brief Read from I2C into a buffer from the I2C device. * Cannot be more than maxBufferSize() bytes. * @param buffer Pointer to buffer of data to read into * @param len Number of bytes from buffer to read. @@ -143,17 +172,25 @@ bool Adafruit_I2CDevice::write(uint8_t *buffer, size_t len, bool stop, uint8_t * * @return True if read was successful, otherwise false. */ bool Adafruit_I2CDevice::read(uint8_t *buffer, size_t len, bool stop) { - if (len > maxBufferSize()) { - // currently not guaranteed to work if more than 32 bytes! - // we will need to find out if some platforms have larger - // I2C buffer sizes :/ -#ifdef DEBUG_SERIAL - DEBUG_SERIAL.println(F("\tI2CDevice could not read such a large buffer")); -#endif - return false; + size_t pos = 0; + while (pos < len) { + size_t read_len = + ((len - pos) > maxBufferSize()) ? maxBufferSize() : (len - pos); + bool read_stop = (pos < (len - read_len)) ? false : stop; + if (!_read(buffer + pos, read_len, read_stop)) + return false; + pos += read_len; } + return true; +} +bool Adafruit_I2CDevice::_read(uint8_t *buffer, size_t len, bool stop) { +#if defined(TinyWireM_h) + size_t recv = _wire->requestFrom((uint8_t)_addr, (uint8_t)len); +#else size_t recv = _wire->requestFrom((uint8_t)_addr, (uint8_t)len, (uint8_t)stop); +#endif + if (recv != len) { // Not enough data available to fulfill our obligation! #ifdef DEBUG_SERIAL @@ -163,15 +200,17 @@ bool Adafruit_I2CDevice::read(uint8_t *buffer, size_t len, bool stop) { return false; } - for (uint16_t i=0; iread(); } #ifdef DEBUG_SERIAL - DEBUG_SERIAL.print(F("\tI2CDevice Read: ")); - for (uint16_t i=0; i= 157) && !defined(ARDUINO_STM32_FEATHER) && !defined(TinyWireM_h) + _wire->setClock(desiredclk); + return true; +#else + (void)desiredclk; + return false; +#endif } diff --git a/lib/lib_i2c/Adafruit_BusIO/Adafruit_I2CDevice.h b/lib/lib_i2c/Adafruit_BusIO/Adafruit_I2CDevice.h index be0a6c962..5baa6fda8 100644 --- a/lib/lib_i2c/Adafruit_BusIO/Adafruit_I2CDevice.h +++ b/lib/lib_i2c/Adafruit_BusIO/Adafruit_I2CDevice.h @@ -1,29 +1,36 @@ -#include - #ifndef Adafruit_I2CDevice_h #define Adafruit_I2CDevice_h +#include +#include + ///< The class which defines how we will talk to this device over I2C class Adafruit_I2CDevice { - public: - Adafruit_I2CDevice(uint8_t addr, TwoWire *theWire=&Wire); +public: + Adafruit_I2CDevice(uint8_t addr, TwoWire *theWire = &Wire); uint8_t address(void); - bool begin(bool addr_detect=true); + bool begin(bool addr_detect = true); + void end(void); bool detected(void); - bool read(uint8_t *buffer, size_t len, bool stop=true); - bool write(uint8_t *buffer, size_t len, bool stop=true, uint8_t *prefix_buffer=NULL, size_t prefix_len=0); - bool write_then_read(uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len, bool stop=false); + bool read(uint8_t *buffer, size_t len, bool stop = true); + bool write(const uint8_t *buffer, size_t len, bool stop = true, + const uint8_t *prefix_buffer = NULL, size_t prefix_len = 0); + bool write_then_read(const uint8_t *write_buffer, size_t write_len, + uint8_t *read_buffer, size_t read_len, + bool stop = false); + bool setSpeed(uint32_t desiredclk); /*! @brief How many bytes we can read in a transaction - * @return The size of the Wire receive/transmit buffer */ - uint16_t maxBufferSize() { return _maxBufferSize; } + * @return The size of the Wire receive/transmit buffer */ + size_t maxBufferSize() { return _maxBufferSize; } - private: +private: uint8_t _addr; TwoWire *_wire; bool _begun; - uint16_t _maxBufferSize; + size_t _maxBufferSize; + bool _read(uint8_t *buffer, size_t len, bool stop); }; #endif // Adafruit_I2CDevice_h diff --git a/lib/lib_i2c/Adafruit_BusIO/Adafruit_I2CRegister.h b/lib/lib_i2c/Adafruit_BusIO/Adafruit_I2CRegister.h index 703e93b76..186850fa6 100644 --- a/lib/lib_i2c/Adafruit_BusIO/Adafruit_I2CRegister.h +++ b/lib/lib_i2c/Adafruit_BusIO/Adafruit_I2CRegister.h @@ -1,7 +1,9 @@ -#include "Adafruit_BusIO_Register.h" #ifndef _ADAFRUIT_I2C_REGISTER_H_ #define _ADAFRUIT_I2C_REGISTER_H_ +#include +#include + typedef Adafruit_BusIO_Register Adafruit_I2CRegister; typedef Adafruit_BusIO_RegisterBits Adafruit_I2CRegisterBits; diff --git a/lib/lib_i2c/Adafruit_BusIO/Adafruit_SPIDevice.cpp b/lib/lib_i2c/Adafruit_BusIO/Adafruit_SPIDevice.cpp index 1d599bb11..fdd50c0e8 100644 --- a/lib/lib_i2c/Adafruit_BusIO/Adafruit_SPIDevice.cpp +++ b/lib/lib_i2c/Adafruit_BusIO/Adafruit_SPIDevice.cpp @@ -1,17 +1,22 @@ -#include -#include +#include "Adafruit_SPIDevice.h" + +#if !defined(SPI_INTERFACES_COUNT) || \ + (defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0)) //#define DEBUG_SERIAL Serial /*! - * @brief Create an SPI device with the given CS pin and settins + * @brief Create an SPI device with the given CS pin and settings * @param cspin The arduino pin number to use for chip select * @param freq The SPI clock frequency to use, defaults to 1MHz - * @param dataOrder The SPI data order to use for bits within each byte, defaults to SPI_BITORDER_MSBFIRST + * @param dataOrder The SPI data order to use for bits within each byte, + * defaults to SPI_BITORDER_MSBFIRST * @param dataMode The SPI mode to use, defaults to SPI_MODE0 * @param theSPI The SPI bus to use, defaults to &theSPI */ -Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, uint32_t freq, BitOrder dataOrder, uint8_t dataMode, SPIClass *theSPI) { +Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, uint32_t freq, + BusIOBitOrder dataOrder, + uint8_t dataMode, SPIClass *theSPI) { _cs = cspin; _sck = _mosi = _miso = -1; _spi = theSPI; @@ -23,21 +28,42 @@ Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, uint32_t freq, BitOrder dat } /*! - * @brief Create an SPI device with the given CS pin and settins + * @brief Create an SPI device with the given CS pin and settings * @param cspin The arduino pin number to use for chip select * @param sckpin The arduino pin number to use for SCK - * @param misopin The arduino pin number to use for MISO, set to -1 if not used - * @param mosipin The arduino pin number to use for MOSI, set to -1 if not used + * @param misopin The arduino pin number to use for MISO, set to -1 if not + * used + * @param mosipin The arduino pin number to use for MOSI, set to -1 if not + * used * @param freq The SPI clock frequency to use, defaults to 1MHz - * @param dataOrder The SPI data order to use for bits within each byte, defaults to SPI_BITORDER_MSBFIRST + * @param dataOrder The SPI data order to use for bits within each byte, + * defaults to SPI_BITORDER_MSBFIRST * @param dataMode The SPI mode to use, defaults to SPI_MODE0 */ -Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, int8_t sckpin, int8_t misopin, int8_t mosipin, - uint32_t freq, BitOrder dataOrder, uint8_t dataMode) { +Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, int8_t sckpin, + int8_t misopin, int8_t mosipin, + uint32_t freq, BusIOBitOrder dataOrder, + uint8_t dataMode) { _cs = cspin; _sck = sckpin; _miso = misopin; _mosi = mosipin; + +#ifdef BUSIO_USE_FAST_PINIO + csPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(cspin)); + csPinMask = digitalPinToBitMask(cspin); + if (mosipin != -1) { + mosiPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(mosipin)); + mosiPinMask = digitalPinToBitMask(mosipin); + } + if (misopin != -1) { + misoPort = (BusIO_PortReg *)portInputRegister(digitalPinToPort(misopin)); + misoPinMask = digitalPinToBitMask(misopin); + } + clkPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(sckpin)); + clkPinMask = digitalPinToBitMask(sckpin); +#endif + _freq = freq; _dataOrder = dataOrder; _dataMode = dataMode; @@ -46,24 +72,38 @@ Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, int8_t sckpin, int8_t misop _spi = NULL; } +/*! + * @brief Release memory allocated in constructors + */ +Adafruit_SPIDevice::~Adafruit_SPIDevice() { + if (_spiSetting) { + delete _spiSetting; + _spiSetting = nullptr; + } +} /*! * @brief Initializes SPI bus and sets CS pin high - * @return Always returns true because there's no way to test success of SPI init + * @return Always returns true because there's no way to test success of SPI + * init */ bool Adafruit_SPIDevice::begin(void) { - pinMode(_cs, OUTPUT); - digitalWrite(_cs, HIGH); + if (_cs != -1) { + pinMode(_cs, OUTPUT); + digitalWrite(_cs, HIGH); + } if (_spi) { // hardware SPI _spi->begin(); } else { pinMode(_sck, OUTPUT); - if (_dataMode==SPI_MODE0) { - digitalWrite(_sck, HIGH); - } else { + if ((_dataMode == SPI_MODE0) || (_dataMode == SPI_MODE1)) { + // idle low on mode 0 and 1 digitalWrite(_sck, LOW); + } else { + // idle high on mode 2 or 3 + digitalWrite(_sck, HIGH); } if (_mosi != -1) { pinMode(_mosi, OUTPUT); @@ -73,12 +113,11 @@ bool Adafruit_SPIDevice::begin(void) { pinMode(_miso, INPUT); } } - + _begun = true; return true; } - /*! * @brief Transfer (send/receive) one byte over hard/soft SPI * @param buffer The buffer to send and receive at the same time @@ -87,60 +126,135 @@ bool Adafruit_SPIDevice::begin(void) { void Adafruit_SPIDevice::transfer(uint8_t *buffer, size_t len) { if (_spi) { // hardware SPI is easy + +#if defined(SPARK) + _spi->transfer(buffer, buffer, len, NULL); +#elif defined(STM32) + for (size_t i = 0; i < len; i++) { + _spi->transfer(buffer[i]); + } +#else _spi->transfer(buffer, len); +#endif return; } + uint8_t startbit; + if (_dataOrder == SPI_BITORDER_LSBFIRST) { + startbit = 0x1; + } else { + startbit = 0x80; + } + + bool towrite, lastmosi = !(buffer[0] & startbit); + uint8_t bitdelay_us = (1000000 / _freq) / 2; + // for softSPI we'll do it by hand - for (size_t i=0; i> b) & 0x1) << (7-b); - } - send = temp; - } - for (int b=7; b>=0; b--) { - reply <<= 1; - if (_dataMode == SPI_MODE0) { - digitalWrite(_sck, LOW); - digitalWrite(_mosi, send & (1< 0x"); + */ - if (_dataOrder == SPI_BITORDER_LSBFIRST) { - // LSB is rare, if it happens we'll just flip the bits around for them - uint8_t temp = 0; - for (uint8_t b=0; b<8; b++) { - temp |= ((reply >> b) & 0x1) << (7-b); - } - reply = temp; - } + // Serial.print(send, HEX); + for (uint8_t b = startbit; b != 0; + b = (_dataOrder == SPI_BITORDER_LSBFIRST) ? b << 1 : b >> 1) { - buffer[i] = reply; + if (bitdelay_us) { + delayMicroseconds(bitdelay_us); + } + + if (_dataMode == SPI_MODE0 || _dataMode == SPI_MODE2) { + towrite = send & b; + if ((_mosi != -1) && (lastmosi != towrite)) { +#ifdef BUSIO_USE_FAST_PINIO + if (towrite) + *mosiPort |= mosiPinMask; + else + *mosiPort &= ~mosiPinMask; +#else + digitalWrite(_mosi, towrite); +#endif + lastmosi = towrite; + } + +#ifdef BUSIO_USE_FAST_PINIO + *clkPort |= clkPinMask; // Clock high +#else + digitalWrite(_sck, HIGH); +#endif + + if (bitdelay_us) { + delayMicroseconds(bitdelay_us); + } + + if (_miso != -1) { +#ifdef BUSIO_USE_FAST_PINIO + if (*misoPort & misoPinMask) { +#else + if (digitalRead(_miso)) { +#endif + reply |= b; + } + } + +#ifdef BUSIO_USE_FAST_PINIO + *clkPort &= ~clkPinMask; // Clock low +#else + digitalWrite(_sck, LOW); +#endif + } else { // if (_dataMode == SPI_MODE1 || _dataMode == SPI_MODE3) + +#ifdef BUSIO_USE_FAST_PINIO + *clkPort |= clkPinMask; // Clock high +#else + digitalWrite(_sck, HIGH); +#endif + + if (bitdelay_us) { + delayMicroseconds(bitdelay_us); + } + + if (_mosi != -1) { +#ifdef BUSIO_USE_FAST_PINIO + if (send & b) + *mosiPort |= mosiPinMask; + else + *mosiPort &= ~mosiPinMask; +#else + digitalWrite(_mosi, send & b); +#endif + } + +#ifdef BUSIO_USE_FAST_PINIO + *clkPort &= ~clkPinMask; // Clock low +#else + digitalWrite(_sck, LOW); +#endif + + if (_miso != -1) { +#ifdef BUSIO_USE_FAST_PINIO + if (*misoPort & misoPinMask) { +#else + if (digitalRead(_miso)) { +#endif + reply |= b; + } + } + } + if (_miso != -1) { + buffer[i] = reply; + } + } } return; } - - /*! * @brief Transfer (send/receive) one byte over hard/soft SPI * @param send The byte to send @@ -152,29 +266,62 @@ uint8_t Adafruit_SPIDevice::transfer(uint8_t send) { return data; } +/*! + * @brief Manually begin a transaction (calls beginTransaction if hardware + * SPI) + */ +void Adafruit_SPIDevice::beginTransaction(void) { + if (_spi) { + _spi->beginTransaction(*_spiSetting); + } +} + +/*! + * @brief Manually end a transaction (calls endTransaction if hardware SPI) + */ +void Adafruit_SPIDevice::endTransaction(void) { + if (_spi) { + _spi->endTransaction(); + } +} /*! * @brief Write a buffer or two to the SPI device. * @param buffer Pointer to buffer of data to write * @param len Number of bytes from buffer to write - * @param prefix_buffer Pointer to optional array of data to write before buffer. + * @param prefix_buffer Pointer to optional array of data to write before + * buffer. * @param prefix_len Number of bytes from prefix buffer to write - * @return Always returns true because there's no way to test success of SPI writes + * @return Always returns true because there's no way to test success of SPI + * writes */ -bool Adafruit_SPIDevice::write(uint8_t *buffer, size_t len, uint8_t *prefix_buffer, size_t prefix_len) { +bool Adafruit_SPIDevice::write(uint8_t *buffer, size_t len, + uint8_t *prefix_buffer, size_t prefix_len) { if (_spi) { _spi->beginTransaction(*_spiSetting); } - digitalWrite(_cs, LOW); + setChipSelect(LOW); // do the writing - for (size_t i=0; i 0) { + _spi->transferBytes(prefix_buffer, nullptr, prefix_len); + } + if (len > 0) { + _spi->transferBytes(buffer, nullptr, len); + } + } else +#endif + { + for (size_t i = 0; i < prefix_len; i++) { + transfer(prefix_buffer[i]); + } + for (size_t i = 0; i < len; i++) { + transfer(buffer[i]); + } } - for (size_t i=0; iendTransaction(); @@ -183,17 +330,17 @@ bool Adafruit_SPIDevice::write(uint8_t *buffer, size_t len, uint8_t *prefix_buff #ifdef DEBUG_SERIAL DEBUG_SERIAL.print(F("\tSPIDevice Wrote: ")); if ((prefix_len != 0) && (prefix_buffer != NULL)) { - for (uint16_t i=0; ibeginTransaction(*_spiSetting); } - digitalWrite(_cs, LOW); - transfer(buffer, len); - digitalWrite(_cs, HIGH); + + setChipSelect(LOW); + transfer(buffer, len); + setChipSelect(HIGH); if (_spi) { _spi->endTransaction(); @@ -225,9 +375,9 @@ bool Adafruit_SPIDevice::read(uint8_t *buffer, size_t len, uint8_t sendvalue) { #ifdef DEBUG_SERIAL DEBUG_SERIAL.print(F("\tSPIDevice Read: ")); - for (uint16_t i=0; ibeginTransaction(*_spiSetting); } - digitalWrite(_cs, LOW); + setChipSelect(LOW); // do the writing - for (size_t i=0; i 0) { + _spi->transferBytes(write_buffer, nullptr, write_len); + } + } else +#endif + { + for (size_t i = 0; i < write_len; i++) { + transfer(write_buffer[i]); + } } #ifdef DEBUG_SERIAL DEBUG_SERIAL.print(F("\tSPIDevice Wrote: ")); - for (uint16_t i=0; iendTransaction(); @@ -299,3 +463,37 @@ bool Adafruit_SPIDevice::write_then_read(uint8_t *write_buffer, size_t write_len return true; } + +/*! + * @brief Write some data and read some data at the same time from SPI + * into the same buffer. This is basicaly a wrapper for transfer() with + * CS-pin and transaction management. + * This /does/ transmit-receive at the same time! + * @param buffer Pointer to buffer of data to write/read to/from + * @param len Number of bytes from buffer to write/read. + * @return Always returns true because there's no way to test success of SPI + * writes + */ +bool Adafruit_SPIDevice::write_and_read(uint8_t *buffer, size_t len) { + if (_spi) { + _spi->beginTransaction(*_spiSetting); + } + + setChipSelect(LOW); + transfer(buffer, len); + setChipSelect(HIGH); + + if (_spi) { + _spi->endTransaction(); + } + + return true; +} + +void Adafruit_SPIDevice::setChipSelect(int value) { + if (_cs == -1) + return; + digitalWrite(_cs, value); +} + +#endif // SPI exists diff --git a/lib/lib_i2c/Adafruit_BusIO/Adafruit_SPIDevice.h b/lib/lib_i2c/Adafruit_BusIO/Adafruit_SPIDevice.h index 987cb3f62..8de31d050 100644 --- a/lib/lib_i2c/Adafruit_BusIO/Adafruit_SPIDevice.h +++ b/lib/lib_i2c/Adafruit_BusIO/Adafruit_SPIDevice.h @@ -1,62 +1,109 @@ -#include - #ifndef Adafruit_SPIDevice_h #define Adafruit_SPIDevice_h +#include + +#if !defined(SPI_INTERFACES_COUNT) || \ + (defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0)) + +#include + // some modern SPI definitions don't have BitOrder enum -#if (defined(__AVR__) && !defined(ARDUINO_ARCH_MEGAAVR)) || defined(ESP8266) || defined(TEENSYDUINO) +#if (defined(__AVR__) && !defined(ARDUINO_ARCH_MEGAAVR)) || \ + defined(ESP8266) || defined(TEENSYDUINO) || defined(SPARK) || \ + defined(ARDUINO_ARCH_SPRESENSE) || defined(MEGATINYCORE) || \ + defined(DXCORE) || defined(ARDUINO_AVR_ATmega4809) || \ + defined(ARDUINO_AVR_ATmega4808) || defined(ARDUINO_AVR_ATmega3209) || \ + defined(ARDUINO_AVR_ATmega3208) || defined(ARDUINO_AVR_ATmega1609) || \ + defined(ARDUINO_AVR_ATmega1608) || defined(ARDUINO_AVR_ATmega809) || \ + defined(ARDUINO_AVR_ATmega808) || defined(ARDUINO_ARCH_ARC32) + typedef enum _BitOrder { SPI_BITORDER_MSBFIRST = MSBFIRST, SPI_BITORDER_LSBFIRST = LSBFIRST, -} BitOrder; -#endif +} BusIOBitOrder; -// some modern SPI definitions don't have BitOrder enum and have different SPI mode defines -#if defined(ESP32) +#elif defined(ESP32) || defined(__ASR6501__) || defined(__ASR6502__) + +// some modern SPI definitions don't have BitOrder enum and have different SPI +// mode defines typedef enum _BitOrder { SPI_BITORDER_MSBFIRST = SPI_MSBFIRST, SPI_BITORDER_LSBFIRST = SPI_LSBFIRST, -} BitOrder; -#endif +} BusIOBitOrder; +#else // Some platforms have a BitOrder enum but its named MSBFIRST/LSBFIRST -#if defined(ARDUINO_ARCH_SAMD) || defined(__SAM3X8E__) || defined(NRF52_SERIES) || defined(ARDUINO_ARCH_ARDUINO_CORE_STM32) || defined(ARDUINO_ARCH_MEGAAVR) || defined(_STM32_DEF_) - #define SPI_BITORDER_MSBFIRST MSBFIRST - #define SPI_BITORDER_LSBFIRST LSBFIRST +#define SPI_BITORDER_MSBFIRST MSBFIRST +#define SPI_BITORDER_LSBFIRST LSBFIRST +typedef BitOrder BusIOBitOrder; #endif -///< The class which defines how we will talk to this device over SPI +#if defined(__AVR__) || defined(TEENSYDUINO) +typedef volatile uint8_t BusIO_PortReg; +typedef uint8_t BusIO_PortMask; +#define BUSIO_USE_FAST_PINIO + +#elif defined(ESP8266) || defined(ESP32) || defined(__SAM3X8E__) || \ + defined(ARDUINO_ARCH_SAMD) +typedef volatile uint32_t BusIO_PortReg; +typedef uint32_t BusIO_PortMask; +#define BUSIO_USE_FAST_PINIO + +#elif (defined(__arm__) || defined(ARDUINO_FEATHER52)) && \ + !defined(ARDUINO_ARCH_MBED) && !defined(ARDUINO_ARCH_RP2040) +typedef volatile uint32_t BusIO_PortReg; +typedef uint32_t BusIO_PortMask; +#if !defined(__ASR6501__) && !defined(__ASR6502__) +#define BUSIO_USE_FAST_PINIO +#endif + +#else +#undef BUSIO_USE_FAST_PINIO +#endif + +/**! The class which defines how we will talk to this device over SPI **/ class Adafruit_SPIDevice { - public: - Adafruit_SPIDevice(int8_t cspin, - uint32_t freq=1000000, - BitOrder dataOrder=SPI_BITORDER_MSBFIRST, - uint8_t dataMode=SPI_MODE0, - SPIClass *theSPI=&SPI); +public: + Adafruit_SPIDevice(int8_t cspin, uint32_t freq = 1000000, + BusIOBitOrder dataOrder = SPI_BITORDER_MSBFIRST, + uint8_t dataMode = SPI_MODE0, SPIClass *theSPI = &SPI); Adafruit_SPIDevice(int8_t cspin, int8_t sck, int8_t miso, int8_t mosi, - uint32_t freq=1000000, - BitOrder dataOrder=SPI_BITORDER_MSBFIRST, - uint8_t dataMode=SPI_MODE0); + uint32_t freq = 1000000, + BusIOBitOrder dataOrder = SPI_BITORDER_MSBFIRST, + uint8_t dataMode = SPI_MODE0); + ~Adafruit_SPIDevice(); bool begin(void); - bool read(uint8_t *buffer, size_t len, uint8_t sendvalue=0xFF); - bool write(uint8_t *buffer, size_t len, uint8_t *prefix_buffer=NULL, size_t prefix_len=0); - bool write_then_read(uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len, uint8_t sendvalue=0xFF); + bool read(uint8_t *buffer, size_t len, uint8_t sendvalue = 0xFF); + bool write(uint8_t *buffer, size_t len, uint8_t *prefix_buffer = NULL, + size_t prefix_len = 0); + bool write_then_read(uint8_t *write_buffer, size_t write_len, + uint8_t *read_buffer, size_t read_len, + uint8_t sendvalue = 0xFF); + bool write_and_read(uint8_t *buffer, size_t len); uint8_t transfer(uint8_t send); void transfer(uint8_t *buffer, size_t len); + void beginTransaction(void); + void endTransaction(void); - private: - +private: SPIClass *_spi; SPISettings *_spiSetting; uint32_t _freq; - BitOrder _dataOrder; + BusIOBitOrder _dataOrder; uint8_t _dataMode; + void setChipSelect(int value); int8_t _cs, _sck, _mosi, _miso; +#ifdef BUSIO_USE_FAST_PINIO + BusIO_PortReg *mosiPort, *clkPort, *misoPort, *csPort; + BusIO_PortMask mosiPinMask, misoPinMask, clkPinMask, csPinMask; +#endif bool _begun; }; +#endif // has SPI defined #endif // Adafruit_SPIDevice_h diff --git a/lib/lib_i2c/Adafruit_BusIO/CMakeLists.txt b/lib/lib_i2c/Adafruit_BusIO/CMakeLists.txt new file mode 100644 index 000000000..880b1aa99 --- /dev/null +++ b/lib/lib_i2c/Adafruit_BusIO/CMakeLists.txt @@ -0,0 +1,11 @@ +# Adafruit Bus IO Library +# https://github.com/adafruit/Adafruit_BusIO +# MIT License + +cmake_minimum_required(VERSION 3.5) + +idf_component_register(SRCS "Adafruit_I2CDevice.cpp" "Adafruit_BusIO_Register.cpp" "Adafruit_SPIDevice.cpp" + INCLUDE_DIRS "." + REQUIRES arduino) + +project(Adafruit_BusIO) diff --git a/lib/lib_i2c/Adafruit_BusIO/README.md b/lib/lib_i2c/Adafruit_BusIO/README.md index a1830809c..1cc06a156 100644 --- a/lib/lib_i2c/Adafruit_BusIO/README.md +++ b/lib/lib_i2c/Adafruit_BusIO/README.md @@ -1,6 +1,7 @@ -# Adafruit Bus IO Library [![Build Status](https://travis-ci.com/adafruit/Adafruit_BusIO.svg?branch=master)](https://travis-ci.com/adafruit/Adafruit_BusIO) +# Adafruit Bus IO Library [![Build Status](https://github.com/adafruit/Adafruit_BusIO/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_BusIO/actions) -This is a helper libary to abstract away I2C & SPI transactions and registers + +This is a helper library to abstract away I2C & SPI transactions and registers Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! diff --git a/lib/lib_i2c/Adafruit_BusIO/component.mk b/lib/lib_i2c/Adafruit_BusIO/component.mk new file mode 100644 index 000000000..049f190ee --- /dev/null +++ b/lib/lib_i2c/Adafruit_BusIO/component.mk @@ -0,0 +1 @@ +COMPONENT_ADD_INCLUDEDIRS = . diff --git a/lib/lib_i2c/Adafruit_BusIO/examples/i2corspi_register/i2corspi_register.ino b/lib/lib_i2c/Adafruit_BusIO/examples/i2corspi_register/i2corspi_register.ino index 555cf3b0d..992a2e004 100644 --- a/lib/lib_i2c/Adafruit_BusIO/examples/i2corspi_register/i2corspi_register.ino +++ b/lib/lib_i2c/Adafruit_BusIO/examples/i2corspi_register/i2corspi_register.ino @@ -28,11 +28,11 @@ void setup() { } Adafruit_BusIO_Register id_reg = Adafruit_BusIO_Register(i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, 0x0F); - uint8_t id; + uint8_t id=0; id_reg.read(&id); Serial.print("ID register = 0x"); Serial.println(id, HEX); } void loop() { -} \ No newline at end of file +} diff --git a/lib/lib_i2c/Adafruit_BusIO/examples/spi_register_bits/spi_register_bits.ino b/lib/lib_i2c/Adafruit_BusIO/examples/spi_register_bits/spi_register_bits.ino new file mode 100644 index 000000000..e70a17b35 --- /dev/null +++ b/lib/lib_i2c/Adafruit_BusIO/examples/spi_register_bits/spi_register_bits.ino @@ -0,0 +1,192 @@ +/*************************************************** + + This is an example for how to use Adafruit_BusIO_RegisterBits from Adafruit_BusIO library. + + Designed specifically to work with the Adafruit RTD Sensor + ----> https://www.adafruit.com/products/3328 + uisng a MAX31865 RTD-to-Digital Converter + ----> https://datasheets.maximintegrated.com/en/ds/MAX31865.pdf + + This sensor uses SPI to communicate, 4 pins are required to + interface. + A fifth pin helps to detect when a new conversion is ready. + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Example written (2020/3) by Andreas Hardtung/AnHard. + BSD license, all text above must be included in any redistribution + ****************************************************/ + +#include +#include + +#define MAX31865_SPI_SPEED (5000000) +#define MAX31865_SPI_BITORDER (SPI_BITORDER_MSBFIRST) +#define MAX31865_SPI_MODE (SPI_MODE1) + +#define MAX31865_SPI_CS (10) +#define MAX31865_READY_PIN (2) + + +Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice( MAX31865_SPI_CS, MAX31865_SPI_SPEED, MAX31865_SPI_BITORDER, MAX31865_SPI_MODE, &SPI); // Hardware SPI +// Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice( MAX31865_SPI_CS, 13, 12, 11, MAX31865_SPI_SPEED, MAX31865_SPI_BITORDER, MAX31865_SPI_MODE); // Software SPI + +// MAX31865 chip related ********************************************************************************************* +Adafruit_BusIO_Register config_reg = Adafruit_BusIO_Register(&spi_dev, 0x00, ADDRBIT8_HIGH_TOWRITE, 1, MSBFIRST); +Adafruit_BusIO_RegisterBits bias_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 7); +Adafruit_BusIO_RegisterBits auto_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 6); +Adafruit_BusIO_RegisterBits oneS_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 5); +Adafruit_BusIO_RegisterBits wire_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 4); +Adafruit_BusIO_RegisterBits faultT_bits = Adafruit_BusIO_RegisterBits(&config_reg, 2, 2); +Adafruit_BusIO_RegisterBits faultR_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 1); +Adafruit_BusIO_RegisterBits fi50hz_bit = Adafruit_BusIO_RegisterBits(&config_reg, 1, 0); + +Adafruit_BusIO_Register rRatio_reg = Adafruit_BusIO_Register(&spi_dev, 0x01, ADDRBIT8_HIGH_TOWRITE, 2, MSBFIRST); +Adafruit_BusIO_RegisterBits rRatio_bits = Adafruit_BusIO_RegisterBits(&rRatio_reg, 15, 1); +Adafruit_BusIO_RegisterBits fault_bit = Adafruit_BusIO_RegisterBits(&rRatio_reg, 1, 0); + +Adafruit_BusIO_Register maxRratio_reg = Adafruit_BusIO_Register(&spi_dev, 0x03, ADDRBIT8_HIGH_TOWRITE, 2, MSBFIRST); +Adafruit_BusIO_RegisterBits maxRratio_bits = Adafruit_BusIO_RegisterBits(&maxRratio_reg, 15, 1); + +Adafruit_BusIO_Register minRratio_reg = Adafruit_BusIO_Register(&spi_dev, 0x05, ADDRBIT8_HIGH_TOWRITE, 2, MSBFIRST); +Adafruit_BusIO_RegisterBits minRratio_bits = Adafruit_BusIO_RegisterBits(&minRratio_reg, 15, 1); + +Adafruit_BusIO_Register fault_reg = Adafruit_BusIO_Register(&spi_dev, 0x07, ADDRBIT8_HIGH_TOWRITE, 1, MSBFIRST); +Adafruit_BusIO_RegisterBits range_high_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 7); +Adafruit_BusIO_RegisterBits range_low_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 6); +Adafruit_BusIO_RegisterBits refin_high_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 5); +Adafruit_BusIO_RegisterBits refin_low_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 4); +Adafruit_BusIO_RegisterBits rtdin_low_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 3); +Adafruit_BusIO_RegisterBits voltage_fault_bit = Adafruit_BusIO_RegisterBits(&fault_reg, 1, 2); + +// Print the details of the configuration register. +void printConfig( void ) { + Serial.print("BIAS: "); if (bias_bit.read() ) Serial.print("ON"); else Serial.print("OFF"); + Serial.print(", AUTO: "); if (auto_bit.read() ) Serial.print("ON"); else Serial.print("OFF"); + Serial.print(", ONES: "); if (oneS_bit.read() ) Serial.print("ON"); else Serial.print("OFF"); + Serial.print(", WIRE: "); if (wire_bit.read() ) Serial.print("3"); else Serial.print("2/4"); + Serial.print(", FAULTCLEAR: "); if (faultR_bit.read() ) Serial.print("ON"); else Serial.print("OFF"); + Serial.print(", "); if (fi50hz_bit.read() ) Serial.print("50HZ"); else Serial.print("60HZ"); + Serial.println(); +} + +// Check and print faults. Then clear them. +void checkFaults( void ) { + if (fault_bit.read()) { + Serial.print("MAX: "); Serial.println(maxRratio_bits.read()); + Serial.print("VAL: "); Serial.println( rRatio_bits.read()); + Serial.print("MIN: "); Serial.println(minRratio_bits.read()); + + if (range_high_fault_bit.read() ) Serial.println("Range high fault"); + if ( range_low_fault_bit.read() ) Serial.println("Range low fault"); + if (refin_high_fault_bit.read() ) Serial.println("REFIN high fault"); + if ( refin_low_fault_bit.read() ) Serial.println("REFIN low fault"); + if ( rtdin_low_fault_bit.read() ) Serial.println("RTDIN low fault"); + if ( voltage_fault_bit.read() ) Serial.println("Voltage fault"); + + faultR_bit.write(1); // clear fault + } +} + +void setup() { + #if (MAX31865_1_READY_PIN != -1) + pinMode(MAX31865_READY_PIN ,INPUT_PULLUP); + #endif + + while (!Serial) { delay(10); } + Serial.begin(115200); + Serial.println("SPI Adafruit_BusIO_RegisterBits test on MAX31865"); + + if (!spi_dev.begin()) { + Serial.println("Could not initialize SPI device"); + while (1); + } + + // Set up for automode 50Hz. We don't care about selfheating. We want the highest possible sampling rate. + auto_bit.write(0); // Don't switch filtermode while auto_mode is on. + fi50hz_bit.write(1); // Set filter to 50Hz mode. + faultR_bit.write(1); // Clear faults. + bias_bit.write(1); // In automode we want to have the bias current always on. + delay(5); // Wait until bias current settles down. + // 10.5 time constants of the input RC network is required. + // 10ms worst case for 10kω reference resistor and a 0.1µF capacitor across the RTD inputs. + // Adafruit Module has 0.1µF and only 430/4300ω So here 0.43/4.3ms + auto_bit.write(1); // Now we can set automode. Automatically starting first conversion. + + // Test the READY_PIN + #if (defined( MAX31865_READY_PIN ) && (MAX31865_READY_PIN != -1)) + int i = 0; + while (digitalRead(MAX31865_READY_PIN) && i++ <= 100) { delay(1); } + if (i >= 100) { + Serial.print("ERROR: Max31865 Pin detection does not work. PIN:"); + Serial.println(MAX31865_READY_PIN); + } + #else + delay(100); + #endif + + // Set ratio range. + // Setting the temperatures would need some more calculation - not related to Adafruit_BusIO_RegisterBits. + uint16_t ratio = rRatio_bits.read(); + maxRratio_bits.write( (ratio < 0x8fffu-1000u) ? ratio + 1000u : 0x8fffu ); + minRratio_bits.write( (ratio > 1000u) ? ratio - 1000u : 0u ); + + printConfig(); + checkFaults(); +} + +void loop() { + #if (defined( MAX31865_READY_PIN ) && (MAX31865_1_READY_PIN != -1)) + // Is conversion ready? + if (!digitalRead(MAX31865_READY_PIN)) + #else + // Warant conversion is ready. + delay(21); // 21ms for 50Hz-mode. 19ms in 60Hz-mode. + #endif + { + // Read ratio, calculate temperature, scale, filter and print. + Serial.println( rRatio2C( rRatio_bits.read() ) * 100.0f, 0); // Temperature scaled by 100 + // Check, print, clear faults. + checkFaults(); + } + + // Do something else. + //delay(15000); +} + + +// Module/Sensor related. Here Adafruit PT100 module with a 2_Wire PT100 Class C ***************************** +float rRatio2C(uint16_t ratio) { + // A simple linear conversion. + const float R0 = 100.0f; + const float Rref = 430.0f; + const float alphaPT = 0.003850f; + const float ADCmax = (1u << 15) - 1.0f; + const float rscale = Rref / ADCmax; + // Measured temperature in boiling water 101.08°C with factor a = 1 and b = 0. Rref and MAX at about 22±2°C. + // Measured temperature in ice/water bath 0.76°C with factor a = 1 and b = 0. Rref and MAX at about 22±2°C. + //const float a = 1.0f / (alphaPT * R0); + const float a = (100.0f/101.08f) / (alphaPT * R0); + //const float b = 0.0f; // 101.08 + const float b = -0.76f; // 100.32 > 101.08 + + return filterRing( ((ratio * rscale) - R0) * a + b ); +} + +// General purpose ********************************************************************************************* +#define RINGLENGTH 250 +float filterRing( float newVal ) { + static float ring[RINGLENGTH] = { 0.0 }; + static uint8_t ringIndex = 0; + static bool ringFull = false; + + if ( ringIndex == RINGLENGTH ) { ringFull = true; ringIndex = 0; } + ring[ringIndex] = newVal; + uint8_t loopEnd = (ringFull) ? RINGLENGTH : ringIndex + 1; + float ringSum = 0.0f; + for (uint8_t i = 0; i < loopEnd; i++) ringSum += ring[i]; + ringIndex++; + return ringSum / loopEnd; +} diff --git a/lib/lib_i2c/Adafruit_BusIO/examples/spi_registers/spi_registers.ino b/lib/lib_i2c/Adafruit_BusIO/examples/spi_registers/spi_registers.ino index e24f1aa9a..091a35315 100644 --- a/lib/lib_i2c/Adafruit_BusIO/examples/spi_registers/spi_registers.ino +++ b/lib/lib_i2c/Adafruit_BusIO/examples/spi_registers/spi_registers.ino @@ -15,12 +15,12 @@ void setup() { } Adafruit_BusIO_Register id_reg = Adafruit_BusIO_Register(&spi_dev, 0x0F, ADDRBIT8_HIGH_TOREAD); - uint8_t id; + uint8_t id = 0; id_reg.read(&id); Serial.print("ID register = 0x"); Serial.println(id, HEX); Adafruit_BusIO_Register thresh_reg = Adafruit_BusIO_Register(&spi_dev, 0x0C, ADDRBIT8_HIGH_TOREAD, 2, LSBFIRST); - uint16_t thresh; + uint16_t thresh = 0; thresh_reg.read(&thresh); Serial.print("Initial threshold register = 0x"); Serial.println(thresh, HEX); @@ -31,4 +31,4 @@ void setup() { void loop() { -} \ No newline at end of file +} diff --git a/lib/lib_i2c/Adafruit_BusIO/library.properties b/lib/lib_i2c/Adafruit_BusIO/library.properties index f63425a7d..68cd6259b 100644 --- a/lib/lib_i2c/Adafruit_BusIO/library.properties +++ b/lib/lib_i2c/Adafruit_BusIO/library.properties @@ -1,5 +1,5 @@ name=Adafruit BusIO -version=1.0.10 +version=1.11.0 author=Adafruit maintainer=Adafruit sentence=This is a library for abstracting away UART, I2C and SPI interfacing