diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..1b045cf --- /dev/null +++ b/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +#source .venv/bin/activate + +# TODO init shell +#guix shell + +env=${1:-main} +port=${2:-/dev/ttyUSB0} + +#pio run --target=upload -e "$env" --upload-port "$port" + +avrdude -p esp32s3 -c arduino diff --git a/flash.sh b/flash.sh index c22d120..f0a86e5 100755 --- a/flash.sh +++ b/flash.sh @@ -3,6 +3,6 @@ source .venv/bin/activate env=${1:-main} -port=${2:-/dev/ttyUSB0} +port=${2:-/dev/ttyACM0} pio run --target=upload -e "$env" --upload-port "$port" diff --git a/lib/Adafruit BusIO/.github/ISSUE_TEMPLATE.md b/lib/Adafruit BusIO/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..f0e2614 --- /dev/null +++ b/lib/Adafruit BusIO/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,46 @@ +Thank you for opening an issue on an Adafruit Arduino library repository. To +improve the speed of resolution please review the following guidelines and +common troubleshooting steps below before creating the issue: + +- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use + the forums at http://forums.adafruit.com to ask questions and troubleshoot why + something isn't working as expected. In many cases the problem is a common issue + that you will more quickly receive help from the forum community. GitHub issues + are meant for known defects in the code. If you don't know if there is a defect + in the code then start with troubleshooting on the forum first. + +- **If following a tutorial or guide be sure you didn't miss a step.** Carefully + check all of the steps and commands to run have been followed. Consult the + forum if you're unsure or have questions about steps in a guide/tutorial. + +- **For Arduino projects check these very common issues to ensure they don't apply**: + + - For uploading sketches or communicating with the board make sure you're using + a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes + very hard to tell the difference between a data and charge cable! Try using the + cable with other devices or swapping to another cable to confirm it is not + the problem. + + - **Be sure you are supplying adequate power to the board.** Check the specs of + your board and plug in an external power supply. In many cases just + plugging a board into your computer is not enough to power it and other + peripherals. + + - **Double check all soldering joints and connections.** Flakey connections + cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. + + - **Ensure you are using an official Arduino or Adafruit board.** We can't + guarantee a clone board will have the same functionality and work as expected + with this code and don't support them. + +If you're sure this issue is a defect in the code and checked the steps above +please fill in the following fields to provide enough troubleshooting information. +You may delete the guideline and text above to just leave the following details: + +- Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE** + +- Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO + VERSION HERE** + +- List the steps to reproduce the problem below (if possible attach a sketch or + copy the sketch code in too): **LIST REPRO STEPS BELOW** diff --git a/lib/Adafruit BusIO/.github/PULL_REQUEST_TEMPLATE.md b/lib/Adafruit BusIO/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..7b641eb --- /dev/null +++ b/lib/Adafruit BusIO/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,26 @@ +Thank you for creating a pull request to contribute to Adafruit's GitHub code! +Before you open the request please review the following guidelines and tips to +help it be more easily integrated: + +- **Describe the scope of your change--i.e. what the change does and what parts + of the code were modified.** This will help us understand any risks of integrating + the code. + +- **Describe any known limitations with your change.** For example if the change + doesn't apply to a supported platform of the library please mention it. + +- **Please run any tests or examples that can exercise your modified code.** We + strive to not break users of the code and running tests/examples helps with this + process. + +Thank you again for contributing! We will try to test and integrate the change +as soon as we can, but be aware we have many GitHub repositories to manage and +can't immediately respond to every request. There is no need to bump or check in +on a pull request (it will clutter the discussion of the request). + +Also don't be worried if the request is closed or not integrated--sometimes the +priorities of Adafruit's GitHub code (education, ease of use) might not match the +priorities of the pull request. Don't fret, the open source community thrives on +forks and GitHub makes it easy to keep your changes in a forked repo. + +After reviewing the guidelines above you can delete this text from the pull request. diff --git a/lib/Adafruit BusIO/.github/workflows/githubci.yml b/lib/Adafruit BusIO/.github/workflows/githubci.yml new file mode 100644 index 0000000..8a57d75 --- /dev/null +++ b/lib/Adafruit BusIO/.github/workflows/githubci.yml @@ -0,0 +1,33 @@ +name: Arduino Library CI + +on: [pull_request, push, repository_dispatch] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/setup-python@v4 + with: + python-version: '3.x' + - uses: actions/checkout@v3 + - uses: actions/checkout@v3 + with: + repository: adafruit/ci-arduino + path: ci + + - name: Install the prerequisites + run: bash ci/actions_install.sh + + - name: Check for correct code formatting with clang-format + run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r . + + - name: Check for correct documentation with doxygen + env: + GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }} + PRETTYNAME : "Adafruit Bus IO Library" + run: bash ci/doxy_gen_and_deploy.sh + + - name: Test the code on supported platforms + run: python3 ci/build_platform.py main_platforms zero feather32u4 + diff --git a/lib/Adafruit BusIO/.piopm b/lib/Adafruit BusIO/.piopm new file mode 100644 index 0000000..de3a7bf --- /dev/null +++ b/lib/Adafruit BusIO/.piopm @@ -0,0 +1 @@ +{"type": "library", "name": "Adafruit BusIO", "version": "1.16.1", "spec": {"owner": "adafruit", "id": 6214, "name": "Adafruit BusIO", "requirements": null, "uri": null}} \ No newline at end of file diff --git a/lib/Adafruit BusIO/Adafruit_BusIO_Register.cpp b/lib/Adafruit BusIO/Adafruit_BusIO_Register.cpp new file mode 100644 index 0000000..a28193f --- /dev/null +++ b/lib/Adafruit BusIO/Adafruit_BusIO_Register.cpp @@ -0,0 +1,365 @@ +#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) + * @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 width The width of the register data 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 byteorder, + uint8_t address_width) { + _i2cdevice = i2cdevice; + _spidevice = nullptr; + _addrwidth = address_width; + _address = reg_addr; + _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 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 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 byteorder, + uint8_t address_width) { + _spidevice = spidevice; + _spiregtype = type; + _i2cdevice = nullptr; + _addrwidth = address_width; + _address = reg_addr; + _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 nullptr for the unused interface, + * allowing libraries to mass-define all the registers + * @param i2cdevice The I2CDevice to use for underlying I2C access, if + * nullptr we use SPI + * @param spidevice The SPIDevice to use for underlying SPI access, if + * nullptr 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 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 byteorder, uint8_t address_width) { + _spidevice = spidevice; + _i2cdevice = i2cdevice; + _spiregtype = type; + _addrwidth = address_width; + _address = reg_addr; + _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) + */ +bool Adafruit_BusIO_Register::write(uint8_t *buffer, uint8_t len) { + + 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; + } + 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; +} + +/*! + * @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) + */ +bool Adafruit_BusIO_Register::write(uint32_t value, uint8_t numbytes) { + if (numbytes == 0) { + numbytes = _width; + } + if (numbytes > 4) { + return false; + } + + // store a copy + _cached = value; + + for (int i = 0; i < numbytes; i++) { + if (_byteorder == LSBFIRST) { + _buffer[i] = value & 0xFF; + } else { + _buffer[numbytes - i - 1] = value & 0xFF; + } + value >>= 8; + } + return write(_buffer, numbytes); +} + +/*! + * @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)) { + return -1; + } + + uint32_t value = 0; + + for (int i = 0; i < _width; i++) { + value <<= 8; + if (_byteorder == LSBFIRST) { + value |= _buffer[_width - i - 1]; + } else { + value |= _buffer[i]; + } + } + + 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) + */ +bool Adafruit_BusIO_Register::read(uint8_t *buffer, uint8_t len) { + 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; +} + +/*! + * @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) + */ +bool Adafruit_BusIO_Register::read(uint16_t *value) { + if (!read(_buffer, 2)) { + return false; + } + + if (_byteorder == LSBFIRST) { + *value = _buffer[1]; + *value <<= 8; + *value |= _buffer[0]; + } else { + *value = _buffer[0]; + *value <<= 8; + *value |= _buffer[1]; + } + return true; +} + +/*! + * @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) + */ +bool Adafruit_BusIO_Register::read(uint8_t *value) { + if (!read(_buffer, 1)) { + return false; + } + + *value = _buffer[0]; + return true; +} + +/*! + * @brief Pretty printer for this register + * @param s The Stream to print to, defaults to &Serial + */ +void Adafruit_BusIO_Register::print(Stream *s) { + uint32_t val = read(); + s->print("0x"); + s->print(val, HEX); +} + +/*! + * @brief Pretty printer for this register + * @param s The Stream to print to, defaults to &Serial + */ +void Adafruit_BusIO_Register::println(Stream *s) { + print(s); + s->println(); +} + +/*! + * @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) { + _register = reg; + _bits = bits; + _shift = shift; +} + +/*! + * @brief Read 4 bytes of data from the register + * @return data The 4 bytes to read + */ +uint32_t Adafruit_BusIO_RegisterBits::read(void) { + uint32_t val = _register->read(); + val >>= _shift; + 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) + */ +bool Adafruit_BusIO_RegisterBits::write(uint32_t data) { + uint32_t val = _register->read(); + + // mask off the data before writing + uint32_t mask = (1 << (_bits)) - 1; + data &= mask; + + mask <<= _shift; + val &= ~mask; // remove the current data at that spot + val |= data << _shift; // and add in the new data + + return _register->write(val, _register->width()); +} + +/*! + * @brief The width of the register data, helpful for doing calculations + * @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/Adafruit BusIO/Adafruit_BusIO_Register.h b/lib/Adafruit BusIO/Adafruit_BusIO_Register.h new file mode 100644 index 0000000..c6d58de --- /dev/null +++ b/lib/Adafruit BusIO/Adafruit_BusIO_Register.h @@ -0,0 +1,105 @@ +#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) + */ +class Adafruit_BusIO_Register { +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 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); + + uint8_t width(void); + + void setWidth(uint8_t width); + void setAddress(uint16_t address); + void setAddressWidth(uint16_t address_width); + + 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, _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) + */ +class Adafruit_BusIO_RegisterBits { +public: + Adafruit_BusIO_RegisterBits(Adafruit_BusIO_Register *reg, uint8_t bits, + uint8_t shift); + bool write(uint32_t value); + uint32_t read(void); + +private: + Adafruit_BusIO_Register *_register; + uint8_t _bits, _shift; +}; + +#endif // SPI exists +#endif // BusIO_Register_h diff --git a/lib/Adafruit BusIO/Adafruit_I2CDevice.cpp b/lib/Adafruit BusIO/Adafruit_I2CDevice.cpp new file mode 100644 index 0000000..92c1731 --- /dev/null +++ b/lib/Adafruit BusIO/Adafruit_I2CDevice.cpp @@ -0,0 +1,317 @@ +#include "Adafruit_I2CDevice.h" + +//#define DEBUG_SERIAL Serial + +/*! + * @brief Create an I2C device at a given address + * @param addr The 7-bit I2C address for the device + * @param theWire The I2C bus to use, defaults to &Wire + */ +Adafruit_I2CDevice::Adafruit_I2CDevice(uint8_t addr, TwoWire *theWire) { + _addr = addr; + _wire = theWire; + _begun = false; +#ifdef ARDUINO_ARCH_SAMD + _maxBufferSize = 250; // as defined in Wire.h's RingBuffer +#elif defined(ESP32) + _maxBufferSize = I2C_BUFFER_LENGTH; +#else + _maxBufferSize = 32; +#endif +} + +/*! + * @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 + * don't respond well to 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 + * if there's no pullups on I2C + * @return True if I2C initialized and a device with the addr found + */ +bool Adafruit_I2CDevice::detected(void) { + // Init I2C if not done yet + if (!_begun && !begin()) { + return false; + } + + // A basic scanner, see if it ACK's + _wire->beginTransmission(_addr); +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.print(F("Address 0x")); + DEBUG_SERIAL.print(_addr); +#endif + 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. 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. 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(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 :/ +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println(F("\tI2CDevice could not write such a large buffer")); +#endif + return false; + } + + _wire->beginTransmission(_addr); + + // Write the prefix data (usually an address) + if ((prefix_len != 0) && (prefix_buffer != nullptr)) { + if (_wire->write(prefix_buffer, prefix_len) != prefix_len) { +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println(F("\tI2CDevice failed to write")); +#endif + return false; + } + } + + // Write the data itself + if (_wire->write(buffer, len) != len) { +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println(F("\tI2CDevice failed to write")); +#endif + return false; + } + +#ifdef DEBUG_SERIAL + + DEBUG_SERIAL.print(F("\tI2CWRITE @ 0x")); + DEBUG_SERIAL.print(_addr, HEX); + DEBUG_SERIAL.print(F(" :: ")); + if ((prefix_len != 0) && (prefix_buffer != nullptr)) { + for (uint16_t i = 0; i < prefix_len; i++) { + DEBUG_SERIAL.print(F("0x")); + DEBUG_SERIAL.print(prefix_buffer[i], HEX); + DEBUG_SERIAL.print(F(", ")); + } + } + for (uint16_t i = 0; i < len; i++) { + DEBUG_SERIAL.print(F("0x")); + DEBUG_SERIAL.print(buffer[i], HEX); + DEBUG_SERIAL.print(F(", ")); + if (i % 32 == 31) { + DEBUG_SERIAL.println(); + } + } + + if (stop) { + DEBUG_SERIAL.print("\tSTOP"); + } +#endif + + if (_wire->endTransmission(stop) == 0) { +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println(); + // DEBUG_SERIAL.println("Sent!"); +#endif + return true; + } else { +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println("\tFailed to send!"); +#endif + return false; + } +} + +/*! + * @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. + * @param stop Whether to send an I2C STOP signal on read + * @return True if read was successful, otherwise false. + */ +bool Adafruit_I2CDevice::read(uint8_t *buffer, size_t len, bool stop) { + 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); +#elif defined(ARDUINO_ARCH_MEGAAVR) + size_t recv = _wire->requestFrom(_addr, len, stop); +#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 + DEBUG_SERIAL.print(F("\tI2CDevice did not receive enough data: ")); + DEBUG_SERIAL.println(recv); +#endif + return false; + } + + for (uint16_t i = 0; i < len; i++) { + buffer[i] = _wire->read(); + } + +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.print(F("\tI2CREAD @ 0x")); + DEBUG_SERIAL.print(_addr, HEX); + DEBUG_SERIAL.print(F(" :: ")); + for (uint16_t i = 0; i < len; i++) { + DEBUG_SERIAL.print(F("0x")); + DEBUG_SERIAL.print(buffer[i], HEX); + DEBUG_SERIAL.print(F(", ")); + if (len % 32 == 31) { + DEBUG_SERIAL.println(); + } + } + DEBUG_SERIAL.println(); +#endif + + return true; +} + +/*! + * @brief Write some data, then read some data from I2C into another buffer. + * Cannot be more than maxBufferSize() bytes. The buffers can point to + * same/overlapping locations. + * @param write_buffer Pointer to buffer of data to write from + * @param write_len Number of bytes from buffer to write. + * @param read_buffer Pointer to buffer of data to read into. + * @param read_len Number of bytes from buffer to read. + * @param stop Whether to send an I2C STOP signal between the write and read + * @return True if write & read was successful, otherwise false. + */ +bool Adafruit_I2CDevice::write_then_read(const uint8_t *write_buffer, + size_t write_len, uint8_t *read_buffer, + size_t read_len, bool stop) { + if (!write(write_buffer, write_len, stop)) { + return false; + } + + return read(read_buffer, read_len); +} + +/*! + * @brief Returns the 7-bit address of this device + * @return The 7-bit address of this device + */ +uint8_t Adafruit_I2CDevice::address(void) { return _addr; } + +/*! + * @brief Change the I2C clock speed to desired (relies on + * underlying Wire support! + * @param desiredclk The desired I2C SCL frequency + * @return True if this platform supports changing I2C speed. + * Not necessarily that the speed was achieved! + */ +bool Adafruit_I2CDevice::setSpeed(uint32_t desiredclk) { +#if defined(__AVR_ATmega328__) || \ + defined(__AVR_ATmega328P__) // fix arduino core set clock + // calculate TWBR correctly + + if ((F_CPU / 18) < desiredclk) { +#ifdef DEBUG_SERIAL + Serial.println(F("I2C.setSpeed too high.")); +#endif + return false; + } + uint32_t atwbr = ((F_CPU / desiredclk) - 16) / 2; + if (atwbr > 16320) { +#ifdef DEBUG_SERIAL + Serial.println(F("I2C.setSpeed too low.")); +#endif + return false; + } + + if (atwbr <= 255) { + atwbr /= 1; + TWSR = 0x0; + } else if (atwbr <= 1020) { + atwbr /= 4; + TWSR = 0x1; + } else if (atwbr <= 4080) { + atwbr /= 16; + TWSR = 0x2; + } else { // if (atwbr <= 16320) + atwbr /= 64; + TWSR = 0x3; + } + TWBR = atwbr; + +#ifdef DEBUG_SERIAL + Serial.print(F("TWSR prescaler = ")); + Serial.println(pow(4, TWSR)); + Serial.print(F("TWBR = ")); + Serial.println(atwbr); +#endif + return true; +#elif (ARDUINO >= 157) && !defined(ARDUINO_STM32_FEATHER) && \ + !defined(TinyWireM_h) + _wire->setClock(desiredclk); + return true; + +#else + (void)desiredclk; + return false; +#endif +} diff --git a/lib/Adafruit BusIO/Adafruit_I2CDevice.h b/lib/Adafruit BusIO/Adafruit_I2CDevice.h new file mode 100644 index 0000000..6bda7ba --- /dev/null +++ b/lib/Adafruit BusIO/Adafruit_I2CDevice.h @@ -0,0 +1,36 @@ +#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); + uint8_t address(void); + 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(const uint8_t *buffer, size_t len, bool stop = true, + const uint8_t *prefix_buffer = nullptr, 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 */ + size_t maxBufferSize() { return _maxBufferSize; } + +private: + uint8_t _addr; + TwoWire *_wire; + bool _begun; + size_t _maxBufferSize; + bool _read(uint8_t *buffer, size_t len, bool stop); +}; + +#endif // Adafruit_I2CDevice_h diff --git a/lib/Adafruit BusIO/Adafruit_I2CRegister.h b/lib/Adafruit BusIO/Adafruit_I2CRegister.h new file mode 100644 index 0000000..186850f --- /dev/null +++ b/lib/Adafruit BusIO/Adafruit_I2CRegister.h @@ -0,0 +1,10 @@ +#ifndef _ADAFRUIT_I2C_REGISTER_H_ +#define _ADAFRUIT_I2C_REGISTER_H_ + +#include +#include + +typedef Adafruit_BusIO_Register Adafruit_I2CRegister; +typedef Adafruit_BusIO_RegisterBits Adafruit_I2CRegisterBits; + +#endif diff --git a/lib/Adafruit BusIO/Adafruit_SPIDevice.cpp b/lib/Adafruit BusIO/Adafruit_SPIDevice.cpp new file mode 100644 index 0000000..034dc08 --- /dev/null +++ b/lib/Adafruit BusIO/Adafruit_SPIDevice.cpp @@ -0,0 +1,508 @@ +#include "Adafruit_SPIDevice.h" + +//#define DEBUG_SERIAL Serial + +/*! + * @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 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, + BusIOBitOrder dataOrder, + uint8_t dataMode, SPIClass *theSPI) { +#ifdef BUSIO_HAS_HW_SPI + _cs = cspin; + _sck = _mosi = _miso = -1; + _spi = theSPI; + _begun = false; + _spiSetting = new SPISettings(freq, dataOrder, dataMode); + _freq = freq; + _dataOrder = dataOrder; + _dataMode = dataMode; +#else + // unused, but needed to suppress compiler warns + (void)cspin; + (void)freq; + (void)dataOrder; + (void)dataMode; + (void)theSPI; +#endif +} + +/*! + * @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 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 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, 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; + _begun = false; +} + +/*! + * @brief Release memory allocated in constructors + */ +Adafruit_SPIDevice::~Adafruit_SPIDevice() { + if (_spiSetting) + delete _spiSetting; +} + +/*! + * @brief Initializes SPI bus and sets CS pin high + * @return Always returns true because there's no way to test success of SPI + * init + */ +bool Adafruit_SPIDevice::begin(void) { + if (_cs != -1) { + pinMode(_cs, OUTPUT); + digitalWrite(_cs, HIGH); + } + + if (_spi) { // hardware SPI +#ifdef BUSIO_HAS_HW_SPI + _spi->begin(); +#endif + } else { + pinMode(_sck, OUTPUT); + + 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); + digitalWrite(_mosi, HIGH); + } + if (_miso != -1) { + pinMode(_miso, INPUT); + } + } + + _begun = true; + return true; +} + +/*! + * @brief Transfer (send/receive) a buffer over hard/soft SPI, without + * transaction management + * @param buffer The buffer to send and receive at the same time + * @param len The number of bytes to transfer + */ +void Adafruit_SPIDevice::transfer(uint8_t *buffer, size_t len) { + // + // HARDWARE SPI + // + if (_spi) { +#ifdef BUSIO_HAS_HW_SPI +#if defined(SPARK) + _spi->transfer(buffer, buffer, len, nullptr); +#elif defined(STM32) + for (size_t i = 0; i < len; i++) { + _spi->transfer(buffer[i]); + } +#else + _spi->transfer(buffer, len); +#endif + return; +#endif + } + + // + // SOFTWARE SPI + // + 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 (size_t i = 0; i < len; i++) { + uint8_t reply = 0; + uint8_t send = buffer[i]; + + /* + Serial.print("\tSending software SPI byte 0x"); + Serial.print(send, HEX); + Serial.print(" -> 0x"); + */ + + // Serial.print(send, HEX); + for (uint8_t b = startbit; b != 0; + b = (_dataOrder == SPI_BITORDER_LSBFIRST) ? b << 1 : b >> 1) { + + 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 = *mosiPort | mosiPinMask; + else + *mosiPort = *mosiPort & ~mosiPinMask; +#else + digitalWrite(_mosi, towrite); +#endif + lastmosi = towrite; + } + +#ifdef BUSIO_USE_FAST_PINIO + *clkPort = *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 = *clkPort & ~clkPinMask; // Clock low +#else + digitalWrite(_sck, LOW); +#endif + } else { // if (_dataMode == SPI_MODE1 || _dataMode == SPI_MODE3) + +#ifdef BUSIO_USE_FAST_PINIO + *clkPort = *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 = *mosiPort | mosiPinMask; + else + *mosiPort = *mosiPort & ~mosiPinMask; +#else + digitalWrite(_mosi, send & b); +#endif + } + +#ifdef BUSIO_USE_FAST_PINIO + *clkPort = *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, without + * transaction management + * @param send The byte to send + * @return The byte received while transmitting + */ +uint8_t Adafruit_SPIDevice::transfer(uint8_t send) { + uint8_t data = send; + transfer(&data, 1); + return data; +} + +/*! + * @brief Manually begin a transaction (calls beginTransaction if hardware + * SPI) + */ +void Adafruit_SPIDevice::beginTransaction(void) { + if (_spi) { +#ifdef BUSIO_HAS_HW_SPI + _spi->beginTransaction(*_spiSetting); +#endif + } +} + +/*! + * @brief Manually end a transaction (calls endTransaction if hardware SPI) + */ +void Adafruit_SPIDevice::endTransaction(void) { + if (_spi) { +#ifdef BUSIO_HAS_HW_SPI + _spi->endTransaction(); +#endif + } +} + +/*! + * @brief Assert/Deassert the CS pin if it is defined + * @param value The state the CS is set to + */ +void Adafruit_SPIDevice::setChipSelect(int value) { + if (_cs != -1) { + digitalWrite(_cs, value); + } +} + +/*! + * @brief Write a buffer or two to the SPI device, with transaction + * management. + * @brief Manually begin a transaction (calls beginTransaction if hardware + * SPI) with asserting the CS pin + */ +void Adafruit_SPIDevice::beginTransactionWithAssertingCS() { + beginTransaction(); + setChipSelect(LOW); +} + +/*! + * @brief Manually end a transaction (calls endTransaction if hardware SPI) + * with deasserting the CS pin + */ +void Adafruit_SPIDevice::endTransactionWithDeassertingCS() { + setChipSelect(HIGH); + endTransaction(); +} + +/*! + * @brief Write a buffer or two to the SPI device, with transaction + * management. + * @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_len Number of bytes from prefix buffer to write + * @return Always returns true because there's no way to test success of SPI + * writes + */ +bool Adafruit_SPIDevice::write(const uint8_t *buffer, size_t len, + const uint8_t *prefix_buffer, + size_t prefix_len) { + beginTransactionWithAssertingCS(); + + // do the writing +#if defined(ARDUINO_ARCH_ESP32) + if (_spi) { + if (prefix_len > 0) { + _spi->transferBytes((uint8_t *)prefix_buffer, nullptr, prefix_len); + } + if (len > 0) { + _spi->transferBytes((uint8_t *)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]); + } + } + endTransactionWithDeassertingCS(); + +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.print(F("\tSPIDevice Wrote: ")); + if ((prefix_len != 0) && (prefix_buffer != nullptr)) { + for (uint16_t i = 0; i < prefix_len; i++) { + DEBUG_SERIAL.print(F("0x")); + DEBUG_SERIAL.print(prefix_buffer[i], HEX); + DEBUG_SERIAL.print(F(", ")); + } + } + for (uint16_t i = 0; i < len; i++) { + DEBUG_SERIAL.print(F("0x")); + DEBUG_SERIAL.print(buffer[i], HEX); + DEBUG_SERIAL.print(F(", ")); + if (i % 32 == 31) { + DEBUG_SERIAL.println(); + } + } + DEBUG_SERIAL.println(); +#endif + + return true; +} + +/*! + * @brief Read from SPI into a buffer from the SPI device, with transaction + * management. + * @param buffer Pointer to buffer of data to read into + * @param len Number of bytes from buffer to read. + * @param sendvalue The 8-bits of data to write when doing the data read, + * defaults to 0xFF + * @return Always returns true because there's no way to test success of SPI + * writes + */ +bool Adafruit_SPIDevice::read(uint8_t *buffer, size_t len, uint8_t sendvalue) { + memset(buffer, sendvalue, len); // clear out existing buffer + + beginTransactionWithAssertingCS(); + transfer(buffer, len); + endTransactionWithDeassertingCS(); + +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.print(F("\tSPIDevice Read: ")); + for (uint16_t i = 0; i < len; i++) { + DEBUG_SERIAL.print(F("0x")); + DEBUG_SERIAL.print(buffer[i], HEX); + DEBUG_SERIAL.print(F(", ")); + if (len % 32 == 31) { + DEBUG_SERIAL.println(); + } + } + DEBUG_SERIAL.println(); +#endif + + return true; +} + +/*! + * @brief Write some data, then read some data from SPI into another buffer, + * with transaction management. The buffers can point to same/overlapping + * locations. This does not transmit-receive at the same time! + * @param write_buffer Pointer to buffer of data to write from + * @param write_len Number of bytes from buffer to write. + * @param read_buffer Pointer to buffer of data to read into. + * @param read_len Number of bytes from buffer to read. + * @param sendvalue The 8-bits of data to write when doing the data read, + * defaults to 0xFF + * @return Always returns true because there's no way to test success of SPI + * writes + */ +bool Adafruit_SPIDevice::write_then_read(const uint8_t *write_buffer, + size_t write_len, uint8_t *read_buffer, + size_t read_len, uint8_t sendvalue) { + beginTransactionWithAssertingCS(); + // do the writing +#if defined(ARDUINO_ARCH_ESP32) + if (_spi) { + if (write_len > 0) { + _spi->transferBytes((uint8_t *)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; i < write_len; i++) { + DEBUG_SERIAL.print(F("0x")); + DEBUG_SERIAL.print(write_buffer[i], HEX); + DEBUG_SERIAL.print(F(", ")); + if (write_len % 32 == 31) { + DEBUG_SERIAL.println(); + } + } + DEBUG_SERIAL.println(); +#endif + + // do the reading + for (size_t i = 0; i < read_len; i++) { + read_buffer[i] = transfer(sendvalue); + } + +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.print(F("\tSPIDevice Read: ")); + for (uint16_t i = 0; i < read_len; i++) { + DEBUG_SERIAL.print(F("0x")); + DEBUG_SERIAL.print(read_buffer[i], HEX); + DEBUG_SERIAL.print(F(", ")); + if (read_len % 32 == 31) { + DEBUG_SERIAL.println(); + } + } + DEBUG_SERIAL.println(); +#endif + + endTransactionWithDeassertingCS(); + + return true; +} + +/*! + * @brief Write some data and read some data at the same time from SPI + * into the same buffer, with transaction management. 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) { + beginTransactionWithAssertingCS(); + transfer(buffer, len); + endTransactionWithDeassertingCS(); + + return true; +} diff --git a/lib/Adafruit BusIO/Adafruit_SPIDevice.h b/lib/Adafruit BusIO/Adafruit_SPIDevice.h new file mode 100644 index 0000000..1d1f953 --- /dev/null +++ b/lib/Adafruit BusIO/Adafruit_SPIDevice.h @@ -0,0 +1,144 @@ +#ifndef Adafruit_SPIDevice_h +#define Adafruit_SPIDevice_h + +#include + +#if !defined(SPI_INTERFACES_COUNT) || \ + (defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0)) +// HW SPI available +#include +#define BUSIO_HAS_HW_SPI +#else +// SW SPI ONLY +enum { SPI_MODE0, SPI_MODE1, SPI_MODE2, _SPI_MODE4 }; +typedef uint8_t SPIClass; +#endif + +// some modern SPI definitions don't have BitOrder enum +#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) || \ + defined(ARDUINO_ARCH_XMC) + +typedef enum _BitOrder { + SPI_BITORDER_MSBFIRST = MSBFIRST, + SPI_BITORDER_LSBFIRST = LSBFIRST, +} BusIOBitOrder; + +#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, +} BusIOBitOrder; + +#else +// Some platforms have a BitOrder enum but its named MSBFIRST/LSBFIRST +#define SPI_BITORDER_MSBFIRST MSBFIRST +#define SPI_BITORDER_LSBFIRST LSBFIRST +typedef BitOrder BusIOBitOrder; +#endif + +#if defined(__IMXRT1062__) // Teensy 4.x +// *Warning* I disabled the usage of FAST_PINIO as the set/clear operations +// used in the cpp file are not atomic and can effect multiple IO pins +// and if an interrupt happens in between the time the code reads the register +// and writes out the updated value, that changes one or more other IO pins +// on that same IO port, those change will be clobbered when the updated +// values are written back. A fast version can be implemented that uses the +// ports set and clear registers which are atomic. +// typedef volatile uint32_t BusIO_PortReg; +// typedef uint32_t BusIO_PortMask; +//#define BUSIO_USE_FAST_PINIO + +#elif defined(ARDUINO_ARCH_XMC) +#undef BUSIO_USE_FAST_PINIO + +#elif 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) && \ + !defined(ARDUINO_SILABS) && !defined(ARDUINO_UNOR4_MINIMA) && \ + !defined(ARDUINO_UNOR4_WIFI) +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: +#ifdef BUSIO_HAS_HW_SPI + Adafruit_SPIDevice(int8_t cspin, uint32_t freq = 1000000, + BusIOBitOrder dataOrder = SPI_BITORDER_MSBFIRST, + uint8_t dataMode = SPI_MODE0, SPIClass *theSPI = &SPI); +#else + Adafruit_SPIDevice(int8_t cspin, uint32_t freq = 1000000, + BusIOBitOrder dataOrder = SPI_BITORDER_MSBFIRST, + uint8_t dataMode = SPI_MODE0, SPIClass *theSPI = nullptr); +#endif + Adafruit_SPIDevice(int8_t cspin, int8_t sck, int8_t miso, int8_t mosi, + 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(const uint8_t *buffer, size_t len, + const uint8_t *prefix_buffer = nullptr, 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, + 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); + void beginTransactionWithAssertingCS(); + void endTransactionWithDeassertingCS(); + +private: +#ifdef BUSIO_HAS_HW_SPI + SPIClass *_spi = nullptr; + SPISettings *_spiSetting = nullptr; +#else + uint8_t *_spi = nullptr; + uint8_t *_spiSetting = nullptr; +#endif + uint32_t _freq; + 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 // Adafruit_SPIDevice_h diff --git a/lib/Adafruit BusIO/CMakeLists.txt b/lib/Adafruit BusIO/CMakeLists.txt new file mode 100644 index 0000000..880b1aa --- /dev/null +++ b/lib/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/Adafruit BusIO/LICENSE b/lib/Adafruit BusIO/LICENSE new file mode 100644 index 0000000..860e3e2 --- /dev/null +++ b/lib/Adafruit BusIO/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Adafruit Industries + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/lib/Adafruit BusIO/README.md b/lib/Adafruit BusIO/README.md new file mode 100644 index 0000000..1cc06a1 --- /dev/null +++ b/lib/Adafruit BusIO/README.md @@ -0,0 +1,8 @@ +# 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 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! + +MIT license, all text above must be included in any redistribution diff --git a/lib/Adafruit BusIO/component.mk b/lib/Adafruit BusIO/component.mk new file mode 100644 index 0000000..049f190 --- /dev/null +++ b/lib/Adafruit BusIO/component.mk @@ -0,0 +1 @@ +COMPONENT_ADD_INCLUDEDIRS = . diff --git a/lib/Adafruit BusIO/examples/i2c_address_detect/i2c_address_detect.ino b/lib/Adafruit BusIO/examples/i2c_address_detect/i2c_address_detect.ino new file mode 100644 index 0000000..b150525 --- /dev/null +++ b/lib/Adafruit BusIO/examples/i2c_address_detect/i2c_address_detect.ino @@ -0,0 +1,21 @@ +#include + +Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(0x10); + +void setup() { + while (!Serial) { delay(10); } + Serial.begin(115200); + Serial.println("I2C address detection test"); + + if (!i2c_dev.begin()) { + Serial.print("Did not find device at 0x"); + Serial.println(i2c_dev.address(), HEX); + while (1); + } + Serial.print("Device found on address 0x"); + Serial.println(i2c_dev.address(), HEX); +} + +void loop() { + +} diff --git a/lib/Adafruit BusIO/examples/i2c_readwrite/i2c_readwrite.ino b/lib/Adafruit BusIO/examples/i2c_readwrite/i2c_readwrite.ino new file mode 100644 index 0000000..909cf31 --- /dev/null +++ b/lib/Adafruit BusIO/examples/i2c_readwrite/i2c_readwrite.ino @@ -0,0 +1,41 @@ +#include + +#define I2C_ADDRESS 0x60 +Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(I2C_ADDRESS); + + +void setup() { + while (!Serial) { delay(10); } + Serial.begin(115200); + Serial.println("I2C device read and write test"); + + if (!i2c_dev.begin()) { + Serial.print("Did not find device at 0x"); + Serial.println(i2c_dev.address(), HEX); + while (1); + } + Serial.print("Device found on address 0x"); + Serial.println(i2c_dev.address(), HEX); + + uint8_t buffer[32]; + // Try to read 32 bytes + i2c_dev.read(buffer, 32); + Serial.print("Read: "); + for (uint8_t i=0; i<32; i++) { + Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", "); + } + Serial.println(); + + // read a register by writing first, then reading + buffer[0] = 0x0C; // we'll reuse the same buffer + i2c_dev.write_then_read(buffer, 1, buffer, 2, false); + Serial.print("Write then Read: "); + for (uint8_t i=0; i<2; i++) { + Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", "); + } + Serial.println(); +} + +void loop() { + +} diff --git a/lib/Adafruit BusIO/examples/i2c_registers/i2c_registers.ino b/lib/Adafruit BusIO/examples/i2c_registers/i2c_registers.ino new file mode 100644 index 0000000..41a3043 --- /dev/null +++ b/lib/Adafruit BusIO/examples/i2c_registers/i2c_registers.ino @@ -0,0 +1,38 @@ +#include +#include + +#define I2C_ADDRESS 0x60 +Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(I2C_ADDRESS); + + +void setup() { + while (!Serial) { delay(10); } + Serial.begin(115200); + Serial.println("I2C device register test"); + + if (!i2c_dev.begin()) { + Serial.print("Did not find device at 0x"); + Serial.println(i2c_dev.address(), HEX); + while (1); + } + Serial.print("Device found on address 0x"); + Serial.println(i2c_dev.address(), HEX); + + Adafruit_BusIO_Register id_reg = Adafruit_BusIO_Register(&i2c_dev, 0x0C, 2, LSBFIRST); + uint16_t id; + id_reg.read(&id); + Serial.print("ID register = 0x"); Serial.println(id, HEX); + + Adafruit_BusIO_Register thresh_reg = Adafruit_BusIO_Register(&i2c_dev, 0x01, 2, LSBFIRST); + uint16_t thresh; + thresh_reg.read(&thresh); + Serial.print("Initial threshold register = 0x"); Serial.println(thresh, HEX); + + thresh_reg.write(~thresh); + + Serial.print("Post threshold register = 0x"); Serial.println(thresh_reg.read(), HEX); +} + +void loop() { + +} \ No newline at end of file diff --git a/lib/Adafruit BusIO/examples/i2corspi_register/i2corspi_register.ino b/lib/Adafruit BusIO/examples/i2corspi_register/i2corspi_register.ino new file mode 100644 index 0000000..992a2e0 --- /dev/null +++ b/lib/Adafruit BusIO/examples/i2corspi_register/i2corspi_register.ino @@ -0,0 +1,38 @@ +#include + +// Define which interface to use by setting the unused interface to NULL! + +#define SPIDEVICE_CS 10 +Adafruit_SPIDevice *spi_dev = NULL; // new Adafruit_SPIDevice(SPIDEVICE_CS); + +#define I2C_ADDRESS 0x5D +Adafruit_I2CDevice *i2c_dev = new Adafruit_I2CDevice(I2C_ADDRESS); + +void setup() { + while (!Serial) { delay(10); } + Serial.begin(115200); + Serial.println("I2C or SPI device register test"); + + if (spi_dev && !spi_dev->begin()) { + Serial.println("Could not initialize SPI device"); + } + + if (i2c_dev) { + if (i2c_dev->begin()) { + Serial.print("Device found on I2C address 0x"); + Serial.println(i2c_dev->address(), HEX); + } else { + Serial.print("Did not find I2C device at 0x"); + Serial.println(i2c_dev->address(), HEX); + } + } + + Adafruit_BusIO_Register id_reg = Adafruit_BusIO_Register(i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, 0x0F); + uint8_t id=0; + id_reg.read(&id); + Serial.print("ID register = 0x"); Serial.println(id, HEX); +} + +void loop() { + +} diff --git a/lib/Adafruit BusIO/examples/spi_modetest/spi_modetest.ino b/lib/Adafruit BusIO/examples/spi_modetest/spi_modetest.ino new file mode 100644 index 0000000..10168c5 --- /dev/null +++ b/lib/Adafruit BusIO/examples/spi_modetest/spi_modetest.ino @@ -0,0 +1,29 @@ +#include + +#define SPIDEVICE_CS 10 +Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS, 100000, SPI_BITORDER_MSBFIRST, SPI_MODE1); +//Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS, 13, 12, 11, 100000, SPI_BITORDER_MSBFIRST, SPI_MODE1); + + +void setup() { + while (!Serial) { delay(10); } + Serial.begin(115200); + Serial.println("SPI device mode test"); + + if (!spi_dev.begin()) { + Serial.println("Could not initialize SPI device"); + while (1); + } +} + +void loop() { + Serial.println("\n\nTransfer test"); + for (uint16_t x=0; x<=0xFF; x++) { + uint8_t i = x; + Serial.print("0x"); Serial.print(i, HEX); + spi_dev.read(&i, 1, i); + Serial.print("/"); Serial.print(i, HEX); + Serial.print(", "); + delay(25); + } +} \ No newline at end of file diff --git a/lib/Adafruit BusIO/examples/spi_readwrite/spi_readwrite.ino b/lib/Adafruit BusIO/examples/spi_readwrite/spi_readwrite.ino new file mode 100644 index 0000000..6f2c063 --- /dev/null +++ b/lib/Adafruit BusIO/examples/spi_readwrite/spi_readwrite.ino @@ -0,0 +1,39 @@ +#include + +#define SPIDEVICE_CS 10 +Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS); + + +void setup() { + while (!Serial) { delay(10); } + Serial.begin(115200); + Serial.println("SPI device read and write test"); + + if (!spi_dev.begin()) { + Serial.println("Could not initialize SPI device"); + while (1); + } + + uint8_t buffer[32]; + + // Try to read 32 bytes + spi_dev.read(buffer, 32); + Serial.print("Read: "); + for (uint8_t i=0; i<32; i++) { + Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", "); + } + Serial.println(); + + // read a register by writing first, then reading + buffer[0] = 0x8F; // we'll reuse the same buffer + spi_dev.write_then_read(buffer, 1, buffer, 2, false); + Serial.print("Write then Read: "); + for (uint8_t i=0; i<2; i++) { + Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", "); + } + Serial.println(); +} + +void loop() { + +} diff --git a/lib/Adafruit BusIO/examples/spi_register_bits/spi_register_bits.ino b/lib/Adafruit BusIO/examples/spi_register_bits/spi_register_bits.ino new file mode 100644 index 0000000..e70a17b --- /dev/null +++ b/lib/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/Adafruit BusIO/examples/spi_registers/spi_registers.ino b/lib/Adafruit BusIO/examples/spi_registers/spi_registers.ino new file mode 100644 index 0000000..091a353 --- /dev/null +++ b/lib/Adafruit BusIO/examples/spi_registers/spi_registers.ino @@ -0,0 +1,34 @@ +#include +#include + +#define SPIDEVICE_CS 10 +Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS); + +void setup() { + while (!Serial) { delay(10); } + Serial.begin(115200); + Serial.println("SPI device register test"); + + if (!spi_dev.begin()) { + Serial.println("Could not initialize SPI device"); + while (1); + } + + Adafruit_BusIO_Register id_reg = Adafruit_BusIO_Register(&spi_dev, 0x0F, ADDRBIT8_HIGH_TOREAD); + 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 = 0; + thresh_reg.read(&thresh); + Serial.print("Initial threshold register = 0x"); Serial.println(thresh, HEX); + + thresh_reg.write(~thresh); + + Serial.print("Post threshold register = 0x"); Serial.println(thresh_reg.read(), HEX); +} + +void loop() { + +} diff --git a/lib/Adafruit BusIO/library.properties b/lib/Adafruit BusIO/library.properties new file mode 100644 index 0000000..06d91e8 --- /dev/null +++ b/lib/Adafruit BusIO/library.properties @@ -0,0 +1,9 @@ +name=Adafruit BusIO +version=1.16.1 +author=Adafruit +maintainer=Adafruit +sentence=This is a library for abstracting away I2C and SPI interfacing +paragraph=This is a library for abstracting away I2C and SPI interfacing +category=Signal Input/Output +url=https://github.com/adafruit/Adafruit_BusIO +architectures=* diff --git a/lib/Adafruit Unified Sensor/.gitignore b/lib/Adafruit Unified Sensor/.gitignore new file mode 100644 index 0000000..d04184a --- /dev/null +++ b/lib/Adafruit Unified Sensor/.gitignore @@ -0,0 +1,108 @@ +# +# NOTE! Don't add files that are generated in specific +# subdirectories here. Add them in the ".gitignore" file +# in that subdirectory instead. +# +# NOTE! Please use 'git ls-files -i --exclude-standard' +# command after changing this file, to see if there are +# any tracked files which get ignored after the change. +# +# Normal rules +# +.* +*.o +*.o.* +*.a +*.s +*.ko +*.so +*.so.dbg +*.mod.c +*.i +*.lst +*.symtypes +*.order +modules.builtin +*.elf +*.bin +*.gz +*.bz2 +*.lzma +*.patch +*.gcno + +# +# Top-level generic files +# +/tags +/TAGS +/linux +/vmlinux +/vmlinuz +/System.map +/Module.markers +/Module.symvers + +# +# git files that we don't want to ignore even it they are dot-files +# +!.gitignore +!.mailmap + +# +# Generated include files +# +include/config +include/linux/version.h +include/generated + +# stgit generated dirs +patches-* + +# quilt's files +patches +series + +# cscope files +cscope.* +ncscope.* + +# gnu global files +GPATH +GRTAGS +GSYMS +GTAGS + +# QT-Creator files +Makefile.am.user +*.config +*.creator +*.creator.user +*.files +*.includes + +*.orig +*~ +\#*# +*.lo +*.la +Makefile +Makefile.in +aclocal.m4 +autoconfig.h +autoconfig.h.in +autom4te.cache/ +build-aux/ +config.log +config.status +configure +libtool +libupnp.pc +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +stamp-h1 +docs/doxygen + diff --git a/lib/Adafruit Unified Sensor/Adafruit_Sensor.cpp b/lib/Adafruit Unified Sensor/Adafruit_Sensor.cpp new file mode 100644 index 0000000..b854a5a --- /dev/null +++ b/lib/Adafruit Unified Sensor/Adafruit_Sensor.cpp @@ -0,0 +1,120 @@ +#include "Adafruit_Sensor.h" + +/**************************************************************************/ +/*! + @brief Prints sensor information to serial console +*/ +/**************************************************************************/ +void Adafruit_Sensor::printSensorDetails(void) { + sensor_t sensor; + getSensor(&sensor); + Serial.println(F("------------------------------------")); + Serial.print(F("Sensor: ")); + Serial.println(sensor.name); + Serial.print(F("Type: ")); + switch ((sensors_type_t)sensor.type) { + case SENSOR_TYPE_ACCELEROMETER: + Serial.print(F("Acceleration (m/s2)")); + break; + case SENSOR_TYPE_MAGNETIC_FIELD: + Serial.print(F("Magnetic (uT)")); + break; + case SENSOR_TYPE_ORIENTATION: + Serial.print(F("Orientation (degrees)")); + break; + case SENSOR_TYPE_GYROSCOPE: + Serial.print(F("Gyroscopic (rad/s)")); + break; + case SENSOR_TYPE_LIGHT: + Serial.print(F("Light (lux)")); + break; + case SENSOR_TYPE_PRESSURE: + Serial.print(F("Pressure (hPa)")); + break; + case SENSOR_TYPE_PROXIMITY: + Serial.print(F("Distance (cm)")); + break; + case SENSOR_TYPE_GRAVITY: + Serial.print(F("Gravity (m/s2)")); + break; + case SENSOR_TYPE_LINEAR_ACCELERATION: + Serial.print(F("Linear Acceleration (m/s2)")); + break; + case SENSOR_TYPE_ROTATION_VECTOR: + Serial.print(F("Rotation vector")); + break; + case SENSOR_TYPE_RELATIVE_HUMIDITY: + Serial.print(F("Relative Humidity (%)")); + break; + case SENSOR_TYPE_AMBIENT_TEMPERATURE: + Serial.print(F("Ambient Temp (C)")); + break; + case SENSOR_TYPE_OBJECT_TEMPERATURE: + Serial.print(F("Object Temp (C)")); + break; + case SENSOR_TYPE_VOLTAGE: + Serial.print(F("Voltage (V)")); + break; + case SENSOR_TYPE_CURRENT: + Serial.print(F("Current (mA)")); + break; + case SENSOR_TYPE_COLOR: + Serial.print(F("Color (RGBA)")); + break; + case SENSOR_TYPE_TVOC: + Serial.print(F("Total Volatile Organic Compounds (ppb)")); + break; + case SENSOR_TYPE_VOC_INDEX: + Serial.print(F("Volatile Organic Compounds (Index)")); + break; + case SENSOR_TYPE_NOX_INDEX: + Serial.print(F("Nitrogen Oxides (Index)")); + break; + case SENSOR_TYPE_CO2: + Serial.print(F("Carbon Dioxide (ppm)")); + break; + case SENSOR_TYPE_ECO2: + Serial.print(F("Equivalent/estimated CO2 (ppm)")); + break; + case SENSOR_TYPE_PM10_STD: + Serial.print(F("Standard Particulate Matter 1.0 (ppm)")); + break; + case SENSOR_TYPE_PM25_STD: + Serial.print(F("Standard Particulate Matter 2.5 (ppm)")); + break; + case SENSOR_TYPE_PM100_STD: + Serial.print(F("Standard Particulate Matter 10.0 (ppm)")); + break; + case SENSOR_TYPE_PM10_ENV: + Serial.print(F("Environmental Particulate Matter 1.0 (ppm)")); + break; + case SENSOR_TYPE_PM25_ENV: + Serial.print(F("Environmental Particulate Matter 2.5 (ppm)")); + break; + case SENSOR_TYPE_PM100_ENV: + Serial.print(F("Environmental Particulate Matter 10.0 (ppm)")); + break; + case SENSOR_TYPE_GAS_RESISTANCE: + Serial.print(F("Gas Resistance (ohms)")); + break; + case SENSOR_TYPE_UNITLESS_PERCENT: + Serial.print(F("Unitless Percent (%)")); + break; + case SENSOR_TYPE_ALTITUDE: + Serial.print(F("Altitude (m)")); + break; + } + + Serial.println(); + Serial.print(F("Driver Ver: ")); + Serial.println(sensor.version); + Serial.print(F("Unique ID: ")); + Serial.println(sensor.sensor_id); + Serial.print(F("Min Value: ")); + Serial.println(sensor.min_value); + Serial.print(F("Max Value: ")); + Serial.println(sensor.max_value); + Serial.print(F("Resolution: ")); + Serial.println(sensor.resolution); + Serial.println(F("------------------------------------\n")); +} diff --git a/lib/Adafruit Unified Sensor/Adafruit_Sensor.h b/lib/Adafruit Unified Sensor/Adafruit_Sensor.h new file mode 100644 index 0000000..8c6a07d --- /dev/null +++ b/lib/Adafruit Unified Sensor/Adafruit_Sensor.h @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software< /span> + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and + * extended sensor support to include color, voltage and current */ + +#ifndef _ADAFRUIT_SENSOR_H +#define _ADAFRUIT_SENSOR_H + +#ifndef ARDUINO +#include +#elif ARDUINO >= 100 +#include "Arduino.h" +#include "Print.h" +#else +#include "WProgram.h" +#endif + +/* Constants */ +#define SENSORS_GRAVITY_EARTH (9.80665F) /**< Earth's gravity in m/s^2 */ +#define SENSORS_GRAVITY_MOON (1.6F) /**< The moon's gravity in m/s^2 */ +#define SENSORS_GRAVITY_SUN (275.0F) /**< The sun's gravity in m/s^2 */ +#define SENSORS_GRAVITY_STANDARD (SENSORS_GRAVITY_EARTH) +#define SENSORS_MAGFIELD_EARTH_MAX \ + (60.0F) /**< Maximum magnetic field on Earth's surface */ +#define SENSORS_MAGFIELD_EARTH_MIN \ + (30.0F) /**< Minimum magnetic field on Earth's surface */ +#define SENSORS_PRESSURE_SEALEVELHPA \ + (1013.25F) /**< Average sea level pressure is 1013.25 hPa */ +#define SENSORS_DPS_TO_RADS \ + (0.017453293F) /**< Degrees/s to rad/s multiplier \ + */ +#define SENSORS_RADS_TO_DPS \ + (57.29577793F) /**< Rad/s to degrees/s multiplier */ +#define SENSORS_GAUSS_TO_MICROTESLA \ + (100) /**< Gauss to micro-Tesla multiplier */ + +/** Sensor types */ +typedef enum { + SENSOR_TYPE_ACCELEROMETER = (1), /**< Gravity + linear acceleration */ + SENSOR_TYPE_MAGNETIC_FIELD = (2), + SENSOR_TYPE_ORIENTATION = (3), + SENSOR_TYPE_GYROSCOPE = (4), + SENSOR_TYPE_LIGHT = (5), + SENSOR_TYPE_PRESSURE = (6), + SENSOR_TYPE_PROXIMITY = (8), + SENSOR_TYPE_GRAVITY = (9), + SENSOR_TYPE_LINEAR_ACCELERATION = + (10), /**< Acceleration not including gravity */ + SENSOR_TYPE_ROTATION_VECTOR = (11), + SENSOR_TYPE_RELATIVE_HUMIDITY = (12), + SENSOR_TYPE_AMBIENT_TEMPERATURE = (13), + SENSOR_TYPE_OBJECT_TEMPERATURE = (14), + SENSOR_TYPE_VOLTAGE = (15), + SENSOR_TYPE_CURRENT = (16), + SENSOR_TYPE_COLOR = (17), + SENSOR_TYPE_TVOC = (18), + SENSOR_TYPE_VOC_INDEX = (19), + SENSOR_TYPE_NOX_INDEX = (20), + SENSOR_TYPE_CO2 = (21), + SENSOR_TYPE_ECO2 = (22), + SENSOR_TYPE_PM10_STD = (23), + SENSOR_TYPE_PM25_STD = (24), + SENSOR_TYPE_PM100_STD = (25), + SENSOR_TYPE_PM10_ENV = (26), + SENSOR_TYPE_PM25_ENV = (27), + SENSOR_TYPE_PM100_ENV = (28), + SENSOR_TYPE_GAS_RESISTANCE = (29), + SENSOR_TYPE_UNITLESS_PERCENT = (30), + SENSOR_TYPE_ALTITUDE = (31) +} sensors_type_t; + +/** struct sensors_vec_s is used to return a vector in a common format. */ +typedef struct { + union { + float v[3]; ///< 3D vector elements + struct { + float x; ///< X component of vector + float y; ///< Y component of vector + float z; ///< Z component of vector + }; ///< Struct for holding XYZ component + /* Orientation sensors */ + struct { + float roll; /**< Rotation around the longitudinal axis (the plane body, 'X + axis'). Roll is positive and increasing when moving + downward. -90 degrees <= roll <= 90 degrees */ + float pitch; /**< Rotation around the lateral axis (the wing span, 'Y + axis'). Pitch is positive and increasing when moving + upwards. -180 degrees <= pitch <= 180 degrees) */ + float heading; /**< Angle between the longitudinal axis (the plane body) + and magnetic north, measured clockwise when viewing from + the top of the device. 0-359 degrees */ + }; ///< Struct for holding roll/pitch/heading + }; ///< Union that can hold 3D vector array, XYZ components or + ///< roll/pitch/heading + int8_t status; ///< Status byte + uint8_t reserved[3]; ///< Reserved +} sensors_vec_t; + +/** struct sensors_color_s is used to return color data in a common format. */ +typedef struct { + union { + float c[3]; ///< Raw 3-element data + /* RGB color space */ + struct { + float r; /**< Red component */ + float g; /**< Green component */ + float b; /**< Blue component */ + }; ///< RGB data in floating point notation + }; ///< Union of various ways to describe RGB colorspace + uint32_t rgba; /**< 24-bit RGBA value */ +} sensors_color_t; + +/* Sensor event (36 bytes) */ +/** struct sensor_event_s is used to provide a single sensor event in a common + * format. */ +typedef struct { + int32_t version; /**< must be sizeof(struct sensors_event_t) */ + int32_t sensor_id; /**< unique sensor identifier */ + int32_t type; /**< sensor type */ + int32_t reserved0; /**< reserved */ + int32_t timestamp; /**< time is in milliseconds */ + union { + float data[4]; ///< Raw data */ + sensors_vec_t acceleration; /**< acceleration values are in meter per second + per second (m/s^2) */ + sensors_vec_t + magnetic; /**< magnetic vector values are in micro-Tesla (uT) */ + sensors_vec_t orientation; /**< orientation values are in degrees */ + sensors_vec_t gyro; /**< gyroscope values are in rad/s */ + float temperature; /**< temperature is in degrees centigrade (Celsius) */ + float distance; /**< distance in centimeters */ + float light; /**< light in SI lux units */ + float pressure; /**< pressure in hectopascal (hPa) */ + float relative_humidity; /**< relative humidity in percent */ + float current; /**< current in milliamps (mA) */ + float voltage; /**< voltage in volts (V) */ + float tvoc; /**< Total Volatile Organic Compounds, in ppb */ + float voc_index; /**< VOC (Volatile Organic Compound) index where 100 is + normal (unitless) */ + float nox_index; /**< NOx (Nitrogen Oxides) index where 100 is normal + (unitless) */ + float CO2; /**< Measured CO2 in parts per million (ppm) */ + float eCO2; /**< equivalent/estimated CO2 in parts per million (ppm + estimated from some other measurement) */ + float pm10_std; /**< Standard Particulate Matter <=1.0 in parts per million + (ppm) */ + float pm25_std; /**< Standard Particulate Matter <=2.5 in parts per million + (ppm) */ + float pm100_std; /**< Standard Particulate Matter <=10.0 in parts per + million (ppm) */ + float pm10_env; /**< Environmental Particulate Matter <=1.0 in parts per + million (ppm) */ + float pm25_env; /**< Environmental Particulate Matter <=2.5 in parts per + million (ppm) */ + float pm100_env; /**< Environmental Particulate Matter <=10.0 in parts per + million (ppm) */ + float gas_resistance; /**< Proportional to the amount of VOC particles in + the air (Ohms) */ + float unitless_percent; /** +#include +#include + +/* Assign a unique ID to this sensor at the same time */ +/* Uncomment following line for default Wire bus */ +Adafruit_ADXL343 accel = Adafruit_ADXL343(12345); + +/* NeoTrellis M4, etc. */ +/* Uncomment following line for Wire1 bus */ +//Adafruit_ADXL343 accel = Adafruit_ADXL343(12345, &Wire1); + +void displaySensorDetails(void) +{ + sensor_t sensor; + accel.getSensor(&sensor); + Serial.println("------------------------------------"); + Serial.print ("Sensor: "); Serial.println(sensor.name); + Serial.print ("Driver Ver: "); Serial.println(sensor.version); + Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id); + Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" m/s^2"); + Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" m/s^2"); + Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" m/s^2"); + Serial.println("------------------------------------"); + Serial.println(""); + delay(500); +} + +void displayDataRate(void) +{ + Serial.print ("Data Rate: "); + + switch(accel.getDataRate()) + { + case ADXL343_DATARATE_3200_HZ: + Serial.print ("3200 "); + break; + case ADXL343_DATARATE_1600_HZ: + Serial.print ("1600 "); + break; + case ADXL343_DATARATE_800_HZ: + Serial.print ("800 "); + break; + case ADXL343_DATARATE_400_HZ: + Serial.print ("400 "); + break; + case ADXL343_DATARATE_200_HZ: + Serial.print ("200 "); + break; + case ADXL343_DATARATE_100_HZ: + Serial.print ("100 "); + break; + case ADXL343_DATARATE_50_HZ: + Serial.print ("50 "); + break; + case ADXL343_DATARATE_25_HZ: + Serial.print ("25 "); + break; + case ADXL343_DATARATE_12_5_HZ: + Serial.print ("12.5 "); + break; + case ADXL343_DATARATE_6_25HZ: + Serial.print ("6.25 "); + break; + case ADXL343_DATARATE_3_13_HZ: + Serial.print ("3.13 "); + break; + case ADXL343_DATARATE_1_56_HZ: + Serial.print ("1.56 "); + break; + case ADXL343_DATARATE_0_78_HZ: + Serial.print ("0.78 "); + break; + case ADXL343_DATARATE_0_39_HZ: + Serial.print ("0.39 "); + break; + case ADXL343_DATARATE_0_20_HZ: + Serial.print ("0.20 "); + break; + case ADXL343_DATARATE_0_10_HZ: + Serial.print ("0.10 "); + break; + default: + Serial.print ("???? "); + break; + } + Serial.println(" Hz"); +} + +void displayRange(void) +{ + Serial.print ("Range: +/- "); + + switch(accel.getRange()) + { + case ADXL343_RANGE_16_G: + Serial.print ("16 "); + break; + case ADXL343_RANGE_8_G: + Serial.print ("8 "); + break; + case ADXL343_RANGE_4_G: + Serial.print ("4 "); + break; + case ADXL343_RANGE_2_G: + Serial.print ("2 "); + break; + default: + Serial.print ("?? "); + break; + } + Serial.println(" g"); +} + +void setup(void) +{ + Serial.begin(9600); + while (!Serial); + Serial.println("Accelerometer Test"); Serial.println(""); + + /* Initialise the sensor */ + if(!accel.begin()) + { + /* There was a problem detecting the ADXL343 ... check your connections */ + Serial.println("Ooops, no ADXL343 detected ... Check your wiring!"); + while(1); + } + + /* Set the range to whatever is appropriate for your project */ + accel.setRange(ADXL343_RANGE_16_G); + // accel.setRange(ADXL343_RANGE_8_G); + // accel.setRange(ADXL343_RANGE_4_G); + // accel.setRange(ADXL343_RANGE_2_G); + + /* Display some basic information on this sensor */ + displaySensorDetails(); + displayDataRate(); + displayRange(); + Serial.println(""); +} + +void loop(void) +{ + /* Get a new sensor event */ + sensors_event_t event; + accel.getEvent(&event); + + /* Display the results (acceleration is measured in m/s^2) */ + Serial.print("X: "); Serial.print(event.acceleration.x); Serial.print(" "); + Serial.print("Y: "); Serial.print(event.acceleration.y); Serial.print(" "); + Serial.print("Z: "); Serial.print(event.acceleration.z); Serial.print(" ");Serial.println("m/s^2 "); + delay(500); +} diff --git a/lib/Adafruit Unified Sensor/library.properties b/lib/Adafruit Unified Sensor/library.properties new file mode 100644 index 0000000..ed5a21b --- /dev/null +++ b/lib/Adafruit Unified Sensor/library.properties @@ -0,0 +1,11 @@ +name=Adafruit Unified Sensor +version=1.1.14 +author=Adafruit +maintainer=Adafruit +sentence=Required for all Adafruit Unified Sensor based libraries. +paragraph=A unified sensor abstraction layer used by many Adafruit sensor libraries. +category=Sensors +url=https://github.com/adafruit/Adafruit_Sensor +architectures=* +includes=Adafruit_Sensor.h + diff --git a/monitor.sh b/monitor.sh index 9a88da0..f19b9b5 100755 --- a/monitor.sh +++ b/monitor.sh @@ -2,6 +2,6 @@ source .venv/bin/activate -port=${1:-/dev/ttyUSB0} +port=${1:-/dev/ttyACM0} pio device monitor -b 115200 -p "$port" diff --git a/platformio.ini b/platformio.ini index 9936df5..8a9ce9f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,25 +9,25 @@ ; https://docs.platformio.org/page/projectconf.html [env] -platform = espressif32 -board = esp32-s2-saola-1 framework = arduino +platform = espressif32 +board = lilygo-t7-s3 +upload_protocol = esptool +upload_speed = 921600 +monitor_speed = 115200 +build_flags = -D ARDUINO_USB_CDC_ON_BOOT=1 [env:main] build_src_filter = + +;; Olimex prototype sketch [env:ada] +board = esp32-s2-saola-1 build_src_filter = + [env:sprejemnik] -board = lilygo-t7-s3 -;board_build.mcu = esp32s3 -upload_protocol = esptool -upload_speed = 921600 -monitor_speed = 115200 -build_flags = -D ARDUINO_USB_CDC_ON_BOOT=1 build_src_filter = + @@ -35,18 +35,6 @@ build_src_filter = build_src_filter = + -[env:fastimu] -build_src_filter = - + - -[env:fastimu_sensors] -build_src_filter = - + - [env:detect] build_src_filter = + - -[env:bolder] -build_src_filter = - + diff --git a/src/main.cpp b/src/main.cpp index f3daef1..63ddef7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,196 +1,177 @@ #include #include -#define __x86_64__ - -// ID kegla mora bit unikaten za vsakega! (se poslje poleg parametrov) +// ID senzorja mora bit unikaten! (se poslje poleg parametrov) #define SENSOR_ID 1 -// I2C -#define SDA_PIN 1 -#define SCL_PIN 2 +// Stanje baterije +#define BATTERY_PIN 2 -// IMU libraries -#include "I2Cdev.h" -#include "RTIMUSettings.h" -#include "RTIMU.h" -#include "RTFusionRTQF.h" -#include "CalLib.h" -#include +/* LED indicator + States: + init: 3 slow blinks + error: fast blinking + running: led ON */ +#define LED_PIN 17 -//#include "RTMath.h" +// debagiranje! +#define DEBUG +// I²C pins +#define SDA_PIN 8 +#define SCL_PIN 9 +// IMU library +#include +#include + +// ESPNOW WIFI package structure +#include "sensor_msg.h" + +// ESPNOW wifi libraries #include #include +// MAC naslov sprejemnika uint8_t sprejemnikMac[] = {0x08, 0x3A, 0xF2, 0x50, 0xEF, 0x6C }; - -typedef struct sensor_msg { - uint8_t id; - float aX; - float aY; - float aZ; - float qX; - float qY; - float qZ; - float qW; -}sensor_msg; - sensor_msg odcitek; esp_now_peer_info_t peerInfo; -#define DISPLAY_INTERVAL 5 // interval between pose displays - // Motion sensor objects -RTIMU *imu; // the IMU object -RTFusionRTQF fusion; // the fusion object -RTIMUSettings settings; // the settings object +Adafruit_BNO055 bno; +sensor_t ensor; -unsigned long lastDisplay; -unsigned long lastRate; -int sampleCount; -RTQuaternion gravity; +imu::Quaternion quat; +imu::Vector<3> linearAccel; -bool reset; // For quaternion calibration +int cas = 0; -int errcode; +void error_blink() { + while(1) { + digitalWrite(LED_PIN, LOW); + delay(200); + digitalWrite(LED_PIN, HIGH); + delay(200); + }; +} void setup() { - // Basic(debug) serial init Serial.begin(115200); // set this as high as you can reliably run on your platform Serial.println("Starting up..."); - // Init EEPROM based on magnet calibration size requirement - EEPROM.begin(512); - - // I2C init Wire.begin(SDA_PIN, SCL_PIN); - Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties + // Fast mode + Wire.setClock(400000); - // create the imu object - imu = RTIMU::createIMU(&settings); - - Serial.print("ArduinoIMU starting using device "); Serial.println(imu->IMUName()); - if ((errcode = imu->IMUInit()) < 0) { - Serial.print("Failed to init IMU: "); Serial.println(errcode); + // Init - 3 one second blinks + pinMode(LED_PIN, OUTPUT); + for (int i = 0; i < 3; i++) { + Serial.println(i + 1); + digitalWrite(LED_PIN, LOW); + delay(1000); + digitalWrite(LED_PIN, HIGH); + delay(1000); } - - if (imu->getCalibrationValid()) - Serial.println("Using compass calibration"); - else - Serial.println("No valid compass calibration data"); - - // Gravity obj - gravity.setScalar(0); - gravity.setX(0); - gravity.setY(0); - gravity.setZ(1); -/* - fusion.setSlerpPower(0.02); - fusion.setGyroEnable(true); - fusion.setAccelEnable(true); - fusion.setCompassEnable(true); - */ + bno = Adafruit_BNO055(55, 0x28, &Wire); + /* Initialise the sensor */ + if(!bno.begin(OPERATION_MODE_NDOF)) { + //if(!bno.begin(OPERATION_MODE_AMG)) { + /* There was a problem detecting the BNO055 ... check your connections */ + Serial.println("Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!"); + error_blink(); + } - lastDisplay = lastRate = millis(); - sampleCount = 0; + delay(1000); + + /* Use external crystal for better accuracy? */ + bno.setExtCrystalUse(true); // WIFI init WiFi.mode(WIFI_STA); if (esp_now_init() != ESP_OK) { Serial.println("Error initializing ESP-NOW"); - return; + error_blink(); } - //esp_now_register_send_cb(paketPoslan); - memcpy(peerInfo.peer_addr, sprejemnikMac, 6); peerInfo.channel = 0; peerInfo.encrypt = false; if (esp_now_add_peer(&peerInfo) != ESP_OK){ Serial.println("WIFI registracija ni uspela"); - return; + error_blink(); } -} -void paketPoslan(const uint8_t *mac_addr, esp_now_send_status_t status) { - Serial.print("\r\nStanje poslanega paketa:\t"); - if (status == ESP_NOW_SEND_SUCCESS) { - Serial.println("Uspesno poslano!"); - } else { - Serial.println("Napaka pri posiljanju..."); - } + // Running - led on! + digitalWrite(LED_PIN, HIGH); + + // Nastavi ID senzorja + odcitek.id = SENSOR_ID; + + // Initial time + cas = millis(); } void loop() { - unsigned long now = millis(); - unsigned long delta; - RTVector3 realAccel; - RTQuaternion rotatedGravity; - RTQuaternion fusedConjugate; - RTQuaternion qTemp; - int loopCount = 0; + /* Get a new sensor event */ + //sensors_event_t event; + //bno.getEvent(&event); - // get the latest data if ready yet - while (imu->IMURead()) { - // this flushes remaining data in case we are falling behind - if (++loopCount >= 10) - continue; + // Get quat (fusion mode); 4 * 2bytes + quat = bno.getQuat(); + odcitek.qX = quat.x(); + odcitek.qY = quat.y(); + odcitek.qZ = quat.z(); + odcitek.qW = quat.w(); - fusion.newIMUData(imu->getGyro(), imu->getAccel(), imu->getCompass(), imu->getTimestamp()); - - // do gravity rotation and subtraction - - // create the conjugate of the pose - fusedConjugate = fusion.getFusionQPose().conjugate(); - - // now do the rotation - takes two steps with qTemp as the intermediate variable - qTemp = gravity * fusion.getFusionQPose(); - rotatedGravity = fusedConjugate * qTemp; - - // now adjust the measured accel and change the signs to make sense - realAccel.setX(-(imu->getAccel().x() - rotatedGravity.x())); - realAccel.setY(-(imu->getAccel().y() - rotatedGravity.y())); - realAccel.setZ(-(imu->getAccel().z() - rotatedGravity.z())); - - sampleCount++; - if ((delta = now - lastRate) >= 1000) { - - //Serial.print("Sample rate: "); Serial.print(sampleCount); - if (!imu->IMUGyroBiasValid()) { - // Serial.println(", calculating gyro bias"); - } else { - // Serial.println(); - } - - sampleCount = 0; - lastRate = now; - } + #ifdef DEBUG + Serial.print(F("Quat: ")); + Serial.print((float)odcitek.qX); + Serial.print(F(" ")); + Serial.print((float)odcitek.qY); + Serial.print(F(" ")); + Serial.print((float)odcitek.qZ); + Serial.print(F(" ")); + Serial.print((float)odcitek.qW); + Serial.println(""); + #endif - if ((now - lastDisplay) >= DISPLAY_INTERVAL) { - lastDisplay = now; - odcitek.id = SENSOR_ID; - odcitek.aX = realAccel.x(); - odcitek.aY = realAccel.y(); - odcitek.aZ = realAccel.z(); - odcitek.qX = fusion.getFusionQPose().x(); - odcitek.qY = fusion.getFusionQPose().y(); - odcitek.qZ = fusion.getFusionQPose().z(); - odcitek.qW = fusion.getFusionQPose().scalar(); - - esp_err_t result = esp_now_send(sprejemnikMac, (uint8_t *) &odcitek, sizeof(odcitek)); - - if (result == ESP_OK) { - Serial.println("Uspesno poslano"); - } else { - Serial.println("Napaka pri posiljanju"); - } - } + // Each second, read the battery + // @TODO use something more precise, like https://github.com/rlogiacco/BatterySense ? + if (millis() - cas > 1000) { + cas = millis(); + odcitek.bat = analogRead(BATTERY_PIN) * (1.1 / 8192); } + + // Get linear acceleration (3 * 2bytes) + linearAccel = bno.getVector(Adafruit_BNO055::VECTOR_LINEARACCEL); + odcitek.aX = linearAccel.x(); + odcitek.aY = linearAccel.y(); + odcitek.aZ = linearAccel.z(); + + #ifdef DEBUG + Serial.print(F("Linear acceleration: ")); + Serial.print((float)odcitek.aX); + Serial.print(F(" ")); + Serial.print((float)odcitek.aY); + Serial.print(F(" ")); + Serial.print((float)odcitek.aZ); + Serial.println(""); + #endif + + + + esp_err_t result = esp_now_send(sprejemnikMac, (uint8_t *) &odcitek, sizeof(odcitek)); + + #ifdef DEBUG + if (result == ESP_OK) { + Serial.println("Uspesno poslano"); + } else { + Serial.println("Napaka pri posiljanju"); + } + #endif } diff --git a/src/scanner.cpp b/src/scanner.cpp index eacc179..3b39771 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -30,11 +30,11 @@ #include #include -#define SDA_PIN 1 -#define SCL_PIN 2 +#define SDA_PIN 8 +#define SCL_PIN 9 void setup() { - Wire.begin(); + Wire.begin(SDA_PIN, SCL_PIN); Serial.begin(115200); while (!Serial); // Leonardo: wait for Serial Monitor diff --git a/src/sprejemnik.cpp b/src/sprejemnik.cpp index 91c54ec..338b201 100644 --- a/src/sprejemnik.cpp +++ b/src/sprejemnik.cpp @@ -11,6 +11,9 @@ //#define DEBUG +// LED indicator +#define LED_PIN 17 + #include "SLIPEncodedSerial.h" SLIPEncodedUSBSerial SLIPSerial(Serial); @@ -71,15 +74,18 @@ void setup() { poslji[i] = false; } - for (int i = 0; i < 5; i++) { - Serial.println(i); - //log_e("hmm"); + // Init - 3 one second blinks + pinMode(LED_PIN, OUTPUT); + for (int i = 0; i < 3; i++) { + Serial.println(i + 1); + digitalWrite(LED_PIN, LOW); + delay(1000); + digitalWrite(LED_PIN, HIGH); delay(1000); } // ESP32S3 - vklopi LED! - pinMode(17, OUTPUT); - digitalWrite(17, HIGH); + digitalWrite(LED_PIN, HIGH); Serial.println("Inicializiram WIFI..."); WiFi.mode(WIFI_STA);