diff --git a/libraries/MCP4261/.arduino-ci.yml b/libraries/MCP4261/.arduino-ci.yml new file mode 100644 index 00000000..a7a93bac --- /dev/null +++ b/libraries/MCP4261/.arduino-ci.yml @@ -0,0 +1,32 @@ +platforms: + rpipico: + board: rp2040:rp2040:rpipico + package: rp2040:rp2040 # name:architecture:board + gcc: + features: + defines: + - ARDUINO_ARCH_RP2040 + warnings: + flags: + + +packages: + rp2040:rp2040: + url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json + teensy:Teensy: + url: https://www.pjrc.com/teensy/package_teensy_index.json + + +compile: + # Choosing to run compilation tests on 2 different Arduino platforms + platforms: + - uno + # - due + # - zero + # - leonardo + - m4 + - esp32 + - esp8266 + # - mega2560 + - rpipico + diff --git a/libraries/MCP4261/.github/FUNDING.yml b/libraries/MCP4261/.github/FUNDING.yml new file mode 100644 index 00000000..554358c3 --- /dev/null +++ b/libraries/MCP4261/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# These are supported funding model platforms + +github: RobTillaart +custom: "https://www.paypal.me/robtillaart" diff --git a/libraries/MCP4261/.github/workflows/arduino-lint.yml b/libraries/MCP4261/.github/workflows/arduino-lint.yml new file mode 100644 index 00000000..7f8f4ef4 --- /dev/null +++ b/libraries/MCP4261/.github/workflows/arduino-lint.yml @@ -0,0 +1,13 @@ +name: Arduino-lint + +on: [push, pull_request] +jobs: + lint: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + - uses: arduino/arduino-lint-action@v1 + with: + library-manager: update + compliance: strict \ No newline at end of file diff --git a/libraries/MCP4261/.github/workflows/arduino_test_runner.yml b/libraries/MCP4261/.github/workflows/arduino_test_runner.yml new file mode 100644 index 00000000..dbd0ce79 --- /dev/null +++ b/libraries/MCP4261/.github/workflows/arduino_test_runner.yml @@ -0,0 +1,17 @@ +name: Arduino CI + +on: [push, pull_request] + +jobs: + runTest: + runs-on: ubuntu-latest + timeout-minutes: 20 + + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.6 + - run: | + gem install arduino_ci + arduino_ci.rb diff --git a/libraries/MCP4261/.github/workflows/jsoncheck.yml b/libraries/MCP4261/.github/workflows/jsoncheck.yml new file mode 100644 index 00000000..1cbb5e2c --- /dev/null +++ b/libraries/MCP4261/.github/workflows/jsoncheck.yml @@ -0,0 +1,18 @@ +name: JSON check + +on: + push: + paths: + - '**.json' + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + - name: json-syntax-check + uses: limitusus/json-syntax-check@v2 + with: + pattern: "\\.json$" \ No newline at end of file diff --git a/libraries/MCP4261/CHANGELOG.md b/libraries/MCP4261/CHANGELOG.md new file mode 100644 index 00000000..4f96407a --- /dev/null +++ b/libraries/MCP4261/CHANGELOG.md @@ -0,0 +1,10 @@ +# Change Log MCP4261 + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + + +## [0.1.0] - 2024-02-21 +- initial version diff --git a/libraries/MCP4261/LICENSE b/libraries/MCP4261/LICENSE new file mode 100644 index 00000000..37fe70e5 --- /dev/null +++ b/libraries/MCP4261/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024-2024 Rob Tillaart + +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. diff --git a/libraries/MCP4261/MCP4261.cpp b/libraries/MCP4261/MCP4261.cpp new file mode 100644 index 00000000..1da20392 --- /dev/null +++ b/libraries/MCP4261/MCP4261.cpp @@ -0,0 +1,386 @@ +// +// FILE: MCP4261.cpp +// AUTHOR: Rob Tillaart +// VERSION: 0.1.0 +// DATE: 2024-02-21 +// PURPOSE: Arduino library for MCP4261 SPI based digital potentiometers. +// URL: https://github.com/RobTillaart/MCP4261 + + +#include "MCP4261.h" + + +// see page 18 datasheet +#define MCP4261_IGNORE_CMD 0x00 +#define MCP4261_WRITE_CMD 0x00 +#define MCP4261_SHUTDOWN_CMD 0x20 +#define MCP4261_NONE_CMD 0x30 + + + // HARDWARE SPI +MCP4261::MCP4261(uint8_t select, uint8_t shutdown, __SPI_CLASS__ * mySPI) +{ + _pmCount = 2; + _maxValue = 255; + _select = select; + _shutdown = shutdown; + _dataIn = 255; + _dataOut = 255; + _clock = 255; + _hwSPI = true; + _mySPI = mySPI; + _spi_settings = SPISettings(_SPIspeed, MSBFIRST, SPI_MODE0); +} + + +// SOFTWARE SPI +MCP4261::MCP4261(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock) +{ + _pmCount = 2; + _maxValue = 255; + _select = select; + _shutdown = shutdown; + _dataIn = dataIn; + _dataOut = dataOut; + _clock = clock; + _hwSPI = false; + _mySPI = NULL; +} + + +void MCP4261::begin(uint16_t value) +{ + pinMode(_select, OUTPUT); + digitalWrite(_select, HIGH); + pinMode(_shutdown, OUTPUT); + digitalWrite(_shutdown, HIGH); + + setSPIspeed(1000000); + + if(_hwSPI) + { + // _mySPI->end(); + // _mySPI->begin(); + // delay(1); + } + else + { + pinMode(_dataIn, INPUT); + pinMode(_dataOut, OUTPUT); + pinMode(_clock, OUTPUT); + digitalWrite(_dataOut, LOW); + digitalWrite(_clock, LOW); + } + reset(value); +} + + +void MCP4261::reset(uint16_t value) +{ + digitalWrite(_shutdown, LOW); + digitalWrite(_shutdown, HIGH); + setValue(value); // set all to same value. +} + + + +///////////////////////////////////////////////////////////////////////////// +// +// SET VOLATILE VALUE +// +bool MCP4261::setValue(uint16_t value) +{ + setValue(0, value); + setValue(1, value); + return true; +} + + +bool MCP4261::setValue(uint8_t pm, uint16_t value) +{ + if (pm >= _pmCount) return false; + if (value > _maxValue) return false; + _value[pm] = value; + + uint8_t cmd = 0x00; + if (pm == 1) cmd = 0x10; + if (value > 0xFF) cmd |= (value >> 8); // high bits + writeDevice(2, cmd, value & 0xFF); + return true; +} + + +uint16_t MCP4261::getValue(uint8_t pm) +{ + if (pm >= _pmCount) return 0; + return _value[pm]; +} + + +bool MCP4261::incrValue(uint8_t pm) +{ + if (pm >= _pmCount) return false; + if (_value[pm] >= _maxValue) return false; + _value[pm]++; + + uint8_t cmd = 0x04; + if (pm == 1) cmd = 0x14; + writeDevice(1, cmd, cmd); // value2 = DUMMY + return true; +} + + +bool MCP4261::decrValue(uint8_t pm) +{ + if (pm >= _pmCount) return false; + if (_value[pm] == 0) return false; + _value[pm]--; + + uint8_t cmd = 0x08; + if (pm == 1) cmd = 0x18; + writeDevice(1, cmd, cmd); // value2 = DUMMY + return true; +} + + + +///////////////////////////////////////////////////////////////////////////// +// +// SET NON-VOLATILE VALUE +// +bool MCP4261::setValueNV(uint8_t pm, uint16_t value) +{ + if (pm >= _pmCount) return false; + if (value > _maxValue) return false; + + uint8_t cmd = 0x20; + if (pm == 1) cmd = 0x30; + if (value > 0xFF) cmd |= (value >> 8); // high bits + writeDevice(2, cmd, value & 0xFF); + return true; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// MISC +// +uint8_t MCP4261::pmCount() +{ + return _pmCount; +} + + +void MCP4261::powerOn() +{ + digitalWrite(_shutdown, HIGH); +} + + +void MCP4261::powerOff() +{ + digitalWrite(_shutdown, LOW); +} + + +bool MCP4261::isPowerOn() +{ + return digitalRead(_shutdown) == HIGH; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// SPI +// +void MCP4261::setSPIspeed(uint32_t speed) +{ + _SPIspeed = speed; + _spi_settings = SPISettings(_SPIspeed, MSBFIRST, SPI_MODE0); +} + + +uint32_t MCP4261::getSPIspeed() +{ + return _SPIspeed; +} + + +bool MCP4261::usesHWSPI() +{ + return _hwSPI; +} + + +///////////////////////////////////////////////////////////////////////////// +// +// PROTECTED +// + +/* +TODO - see page 46 +- need read8, read16 +- bid8, bidi16 +*/ + + +// +// USES SPI MODE 0 +// +void MCP4261::writeDevice(uint8_t count, uint8_t value1, uint8_t value2) +{ + digitalWrite(_select, LOW); + if (_hwSPI) + { + _mySPI->beginTransaction(_spi_settings); + _mySPI->transfer(value1); + if (count == 2) _mySPI->transfer(value2); + _mySPI->endTransaction(); + } + else // Software SPI + { + swSPI_write(value1); + if (count == 2) swSPI_write(value2); + } + digitalWrite(_select, HIGH); +} + + +// MSBFIRST +void MCP4261::swSPI_write(uint8_t value) +{ + uint8_t clk = _clock; + uint8_t dao = _dataOut; + + // MSBFIRST + for (uint8_t mask = 0x80; mask; mask >>= 1) + { + digitalWrite(dao,(value & mask)); + digitalWrite(clk, HIGH); + digitalWrite(clk, LOW); + } +} + + + +//////////////////////////////////////////////////////////////////////////// +// +// DERIVED CLASSES MCP41xx SERIES +// +MCP4141::MCP4141(uint8_t select, uint8_t shutdown, __SPI_CLASS__ * mySPI) + :MCP4261(select, shutdown, mySPI) +{ + _pmCount = 1; + _maxValue = MCP41XX_MAX_VALUE; +} + +MCP4141::MCP4141(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock) + :MCP4261(select, shutdown, dataIn, dataOut, clock) +{ + _pmCount = 1; + _maxValue = MCP41XX_MAX_VALUE; +} + +// + +MCP4142::MCP4142(uint8_t select, uint8_t shutdown, __SPI_CLASS__ * mySPI) + :MCP4261(select, shutdown, mySPI) +{ + _pmCount = 1; + _maxValue = MCP41XX_MAX_VALUE; +} + +MCP4142::MCP4142(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock) + :MCP4261(select, shutdown, dataIn, dataOut, clock) +{ + _pmCount = 1; + _maxValue = MCP41XX_MAX_VALUE; +} + +// + +MCP4161::MCP4161(uint8_t select, uint8_t shutdown, __SPI_CLASS__ * mySPI) + :MCP4261(select, shutdown, mySPI) +{ + _pmCount = 1; + _maxValue = MCP41XX_MAX_VALUE; +} + +MCP4161::MCP4161(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock) + :MCP4261(select, shutdown, dataIn, dataOut, clock) +{ + _pmCount = 1; + _maxValue = MCP41XX_MAX_VALUE; +} + +// + +MCP4162::MCP4162(uint8_t select, uint8_t shutdown, __SPI_CLASS__ * mySPI) + :MCP4261(select, shutdown, mySPI) +{ + _pmCount = 1; + _maxValue = MCP41XX_MAX_VALUE; +} + +MCP4162::MCP4162(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock) + :MCP4261(select, shutdown, dataIn, dataOut, clock) +{ + _pmCount = 1; + _maxValue = MCP41XX_MAX_VALUE; +} + + +//////////////////////////////////////////////////////////////////////////// +// +// DERIVED CLASSES MCP42xx SERIES +// +MCP4241::MCP4241(uint8_t select, uint8_t shutdown, __SPI_CLASS__ * mySPI) + :MCP4261(select, shutdown, mySPI) +{ + _pmCount = 2; + _maxValue = MCP42XX_MAX_VALUE; +} + +MCP4241::MCP4241(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock) + :MCP4261(select, shutdown, dataIn, dataOut, clock) +{ + _pmCount = 2; + _maxValue = MCP42XX_MAX_VALUE; +} + +// + +MCP4242::MCP4242(uint8_t select, uint8_t shutdown, __SPI_CLASS__ * mySPI) + :MCP4261(select, shutdown, mySPI) +{ + _pmCount = 2; + _maxValue = MCP42XX_MAX_VALUE; +} + +MCP4242::MCP4242(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock) + :MCP4261(select, shutdown, dataIn, dataOut, clock) +{ + _pmCount = 2; + _maxValue = MCP42XX_MAX_VALUE; +} + +// + +MCP4262::MCP4262(uint8_t select, uint8_t shutdown, __SPI_CLASS__ * mySPI) + :MCP4261(select, shutdown, mySPI) +{ + _pmCount = 2; + _maxValue = MCP42XX_MAX_VALUE; +} + +MCP4262::MCP4262(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock) + :MCP4261(select, shutdown, dataIn, dataOut, clock) +{ + _pmCount = 2; + _maxValue = MCP42XX_MAX_VALUE; +} + + + +// -- END OF FILE -- + diff --git a/libraries/MCP4261/MCP4261.h b/libraries/MCP4261/MCP4261.h new file mode 100644 index 00000000..75b94642 --- /dev/null +++ b/libraries/MCP4261/MCP4261.h @@ -0,0 +1,174 @@ +#pragma once +// +// FILE: MCP4261.h +// AUTHOR: Rob Tillaart +// VERSION: 0.1.0 +// DATE: 2024-02-21 +// PURPOSE: Arduino library for MCP4261 SPI based digital potentiometers. +// URL: https://github.com/RobTillaart/MCP4261 + + +#include "Arduino.h" +#include "SPI.h" + + +#define MCP4261_LIB_VERSION (F("0.1.0")) + + +#ifndef MCP41XX_MIDDLE_VALUE +#define MCP41XX_MIDDLE_VALUE 64 +#endif + +#ifndef MCP41XX_MAX_VALUE +#define MCP41XX_MAX_VALUE 129 +#endif + + +#ifndef MCP42XX_MIDDLE_VALUE +#define MCP42XX_MIDDLE_VALUE 129 +#endif + +#ifndef MCP42XX_MAX_VALUE +#define MCP42XX_MAX_VALUE 257 +#endif + + +#ifndef __SPI_CLASS__ + // MBED must be tested before RP2040 + #if defined(ARDUINO_ARCH_MBED) + #define __SPI_CLASS__ SPIClass + #elif defined(ARDUINO_ARCH_RP2040) + #define __SPI_CLASS__ SPIClassRP2040 + #else + #define __SPI_CLASS__ SPIClass + #endif +#endif + + +class MCP4261 +{ +public: + // HARDWARE SPI + MCP4261(uint8_t select, uint8_t shutdown, __SPI_CLASS__ * mySPI = &SPI); + // SOFTWARE SPI + MCP4261(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock); + + void begin(uint16_t value); + void reset(uint16_t value); + uint8_t pmCount(); + + + // set both potmeters (just a wrapper) + bool setValue(uint16_t value); + // set single potmeter (0 or 1) + bool setValue(uint8_t pm, uint16_t value); + uint16_t getValue(uint8_t pm = 0); + + bool incrValue(uint8_t pm); + bool decrValue(uint8_t pm); + + // Set non volatile potmeter + // not tested + bool setValueNV(uint8_t pm, uint16_t value); + + // speed in Hz + void setSPIspeed(uint32_t speed); + uint32_t getSPIspeed(); + bool usesHWSPI(); // debugging + + + // MISC + void powerOn(); + void powerOff(); + bool isPowerOn(); + + +protected: + uint8_t _dataIn; + uint8_t _dataOut; + uint8_t _clock; + uint8_t _select; + uint8_t _shutdown; + bool _hwSPI; + uint32_t _SPIspeed; + + uint16_t _value[2] = { 0, 0 }; + uint8_t _pmCount; + uint16_t _maxValue; + + void writeDevice(uint8_t count, uint8_t value1, uint8_t value2); + void swSPI_write(uint8_t value); + + __SPI_CLASS__ * _mySPI; + SPISettings _spi_settings; +}; + + + +//////////////////////////////////////////////////// +// +// DERIVED CLASSES MCP41xx SERIES +// +class MCP4141 : public MCP4261 +{ +public: + MCP4141(uint8_t select, uint8_t shutdown, __SPI_CLASS__ * mySPI = &SPI); + MCP4141(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock); +}; + + +class MCP4142 : public MCP4261 +{ +public: + MCP4142(uint8_t select, uint8_t shutdown, __SPI_CLASS__ * mySPI = &SPI); + MCP4142(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock); +}; + + +class MCP4161 : public MCP4261 +{ +public: + MCP4161(uint8_t select, uint8_t shutdown, __SPI_CLASS__ * mySPI = &SPI); + MCP4161(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock); +}; + + +class MCP4162 : public MCP4261 +{ +public: + MCP4162(uint8_t select, uint8_t shutdown, __SPI_CLASS__ * mySPI = &SPI); + MCP4162(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock); +}; + + +///////////////////////////////////////////////////////////////////////////// +// +// DERIVED CLASSES MCP42xx SERIES +// +class MCP4241 : public MCP4261 +{ +public: + MCP4241(uint8_t select, uint8_t shutdown, __SPI_CLASS__ * mySPI = &SPI); + MCP4241(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock); +}; + + +class MCP4242 : public MCP4261 +{ +public: + MCP4242(uint8_t select, uint8_t shutdown, __SPI_CLASS__ * mySPI = &SPI); + MCP4242(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock); +}; + + +class MCP4262 : public MCP4261 +{ +public: + MCP4262(uint8_t select, uint8_t shutdown, __SPI_CLASS__ * mySPI = &SPI); + MCP4262(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock); +}; + + + +// -- END OF FILE -- + diff --git a/libraries/MCP4261/README.md b/libraries/MCP4261/README.md new file mode 100644 index 00000000..7d4ca383 --- /dev/null +++ b/libraries/MCP4261/README.md @@ -0,0 +1,208 @@ + +[![Arduino CI](https://github.com/RobTillaart/MCP4261/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci) +[![Arduino-lint](https://github.com/RobTillaart/MCP4261/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/MCP4261/actions/workflows/arduino-lint.yml) +[![JSON check](https://github.com/RobTillaart/MCP4261/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/MCP4261/actions/workflows/jsoncheck.yml) +[![GitHub issues](https://img.shields.io/github/issues/RobTillaart/MCP4261.svg)](https://github.com/RobTillaart/MCP4261/issues) + +[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/MCP4261/blob/master/LICENSE) +[![GitHub release](https://img.shields.io/github/release/RobTillaart/MCP4261.svg?maxAge=3600)](https://github.com/RobTillaart/MCP4261/releases) +[![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/MCP4261.svg)](https://registry.platformio.org/libraries/robtillaart/MCP4261) + +[![Commits since latest](https://img.shields.io/github/commits-since/RobTillaart/MCP4261/latest)](https://github.com/RobTillaart/MCP4261/commits/master) + + +# MCP4261 + +Arduino library for MCP4261 SPI based digital potentiometers and compatibles. + + +## Description + +**Experimental** + +The MCP4261 library supports both hardware SPI and software SPI up to 10 MHz. + +These series of potmeters (rheostats) come in values of 5, 10, 50 and 100 kΩ (±20%). + +Where other potmeters uses a range of 0..127 or 0.255, these series potmeters +use a range 0..129 and 0..257. This implies some extra care to set the wiper +to end position. + +The library supports setting the value of the potmeters and caches this setting. +This way it can be retrieved very fast. + +Furthermore the library has two functions to increase and decrease +the value of a potmeter. + + +Feedback, issues and improvements are welcome, +Please open an issue on GitHub. + + +### Not implemented yet + +The library is under development and not all functionality is implemented. +(as I only needed to set values). + +- EEPROM, 10 addresses of 10 bits. (MCP4261 et al ) +- Non volatile registers for power on setup.. (partially) +- read back from device +- read status +- TCON register +- High Voltage something? + + +### Compatibles + +These are the devices that should work with this library. +Only the 4261 is tested. + +| Number | Type | pots | POR | MaxValue | Notes | +|:--------:|:--------:|:------:|:--------:|:----------:|:--------| +| MCP4141 | Potmeter | 1 | NV-Wiper | 129 | +| MCP4142 | Rheostat | 1 | NV-Wiper | 129 | +| MCP4161 | Potmeter | 1 | NV-Wiper | 257 | +| MCP4162 | Rheostat | 1 | NV-Wiper | 257 | +| MCP4241 | Potmeter | 2 | NV-Wiper | 129 | +| MCP4242 | Rheostat | 2 | NV-Wiper | 129 | +| MCP4261 | Potmeter | 2 | NV-Wiper | 257 | base class +| MCP4262 | Rheostat | 2 | NV-Wiper | 257 | + +To investigate: + +MCP4131/32/51/52, MCP4231/32/51/52, these have no NV RAM so they +have a POR power on reset of middle value (= half max value. + + +MCP4151 Reichelt +MCP4262 Mouser + + +### Related + +TODO: list of other digital pot meters / rheostats. + + +#### Related + + + +| Address | Function | Memory Type | +|:---------:|:------------------------:|:--------------| +| 00h | Volatile Wiper 0 | RAM | +| 01h | Volatile Wiper 1 | RAM | +| 02h | Non-Volatile Wiper 0 | EEPROM | +| 03h | Non-Volatile Wiper 1 | EEPROM | +| 04h | Volatile TCON Register | RAM | +| 05h | Status Register | RAM | +| 06h | Data EEPROM | EEPROM | +| 07h | Data EEPROM | EEPROM | +| 08h | Data EEPROM | EEPROM | +| 09h | Data EEPROM | EEPROM | +| 0Ah | Data EEPROM | EEPROM | +| 0Bh | Data EEPROM | EEPROM | +| 0Ch | Data EEPROM | EEPROM | +| 0Dh | Data EEPROM | EEPROM | +| 0Eh | Data EEPROM | EEPROM | +| 0Fh | Data EEPROM | EEPROM | + + +## Interface + +```cpp +#include "MCP4261.h" +``` + + +### Constructor + +- **MCP4261(uint8_t select, uint8_t shutdown, \__SPI_CLASS__ \* mySPI = &SPI)** +HW SPI constructor. +- **MCP4261(uint8_t select, uint8_t shutdown, uint8_t dataIn, uint8_t dataOut, uint8_t clock)** +SW SPI Constructor. The dataIn pin is not used yet. +- **void begin(uint8_t value)** user must explicit set initial value. +- **void reset(uint8_t value)** user must explicit set initial value. +- **uint8_t pmCount()** returns 1 or 2, depending on device type. + + +### Set Volatile Values + +- **bool setValue(uint8_t value)** set all potmeters to the same value. (wrapper). +Returns true. +- **bool setValue(uint8_t pm, uint8_t value)** set single potmeter (0 or 1). +Returns false if pm > pmCount. +- **uint8_t getValue(uint8_t pm = 0)** returns value from cache. +- **bool incrValue(uint8_t pm)** +- **bool decrValue(uint8_t pm)** + + +### Set Volatile Values + +**Experimental** + +TODO: how does this fit in interface as reset() always sets a value. + +- **bool setValueNV(uint8_t pm, uint16_t value)** + + +### EEPROM + +Not implemented yet + +### SPI + +Note changing the SPI speed might affect other devices on the same SPI bus. +So use with care. + +- **void setSPIspeed(uint32_t speed)** default 1MHz, typical 4 MHz. +- **uint32_t getSPIspeed()** idem. +- **bool usesHWSPI()** idem. + + +### Power + +- **void powerOn()** idem. +- **void powerOff()** idem. +- **bool isPowerOn()** idem. + + +## Future + +#### Must + +- improve documentation + +#### Should + +- read registers. + - read values. + - status register + - TCON + +#### Could + +- EEPROM support + - 10 registers, 10 bit + - bool writeEEPROM(address, uint16_t value); + - uint16_t readEEPROM(address); +- write to non-volatile register 02/03 to set Power On Reset values + - read when reset? + - how to fit in use model. +- unit tests +- examples +- error handling + - improve return values +- investigate performance + - AVR SW SPI? + +#### Won't + + +## Support + +If you appreciate my libraries, you can support the development and maintenance. +Improve the quality of the libraries by providing issues and Pull Requests, or +donate through PayPal or GitHub sponsors. + +Thank you, + diff --git a/libraries/MCP4261/documents/MCP4151_MIC.pdf b/libraries/MCP4261/documents/MCP4151_MIC.pdf new file mode 100644 index 00000000..5e62288f Binary files /dev/null and b/libraries/MCP4261/documents/MCP4151_MIC.pdf differ diff --git a/libraries/MCP4261/documents/MCP4261.pdf b/libraries/MCP4261/documents/MCP4261.pdf new file mode 100644 index 00000000..3b28ecdd Binary files /dev/null and b/libraries/MCP4261/documents/MCP4261.pdf differ diff --git a/libraries/MCP4261/examples/MCP4261_demo/MCP4261_demo.ino b/libraries/MCP4261/examples/MCP4261_demo/MCP4261_demo.ino new file mode 100644 index 00000000..f6faf4f7 --- /dev/null +++ b/libraries/MCP4261/examples/MCP4261_demo/MCP4261_demo.ino @@ -0,0 +1,147 @@ +// +// FILE: MCP4261_demo.ino +// AUTHOR: Rob Tillaart +// PURPOSE: demo +// URL: https://github.com/RobTillaart/MCP4261 + + +#include "MCP4261.h" + + +uint32_t start, stop; + + +// select, shutdown, dataIn, dataOut, clock == SOFTWARE SPI +// MCP4261 pot(10, 6, 7, 8, 9); + +// select, shutdown, &SPI === HW SPI UNO clock = 13, dataOut = 11 +MCP4261 pot(10, 6, &SPI); + + +void setup() +{ + Serial.begin(115200); + Serial.println(__FILE__); + + SPI.begin(); + + pot.begin(0); // initial value + + // test_extremes(); + //test_sinus(); + test_sawtooth(); + test_incr_decr(); + //test_timing(); + + Serial.println("\nDone..."); +} + + +void loop() +{ + test_incr_decr(); +} + + +void test_extremes() +{ + Serial.println(__FUNCTION__); + delay(10); + + Serial.println("0"); + pot.setValue(0, 0); + delay(2000); + + Serial.println(MCP42XX_MIDDLE_VALUE); + pot.setValue(0, MCP42XX_MIDDLE_VALUE); + delay(2000); + + Serial.println(MCP42XX_MAX_VALUE); + pot.setValue(0, MCP42XX_MAX_VALUE); + delay(2000); +} + + +// connect all A GND and B 5V +// every W will have a different signal (same freq). +void test_sinus() +{ + Serial.println(__FUNCTION__); + delay(10); + + start = millis(); + uint32_t i = 0; + while (millis() - start < 10000) + { + int8_t value = 127 * sin(i * TWO_PI / 100); + pot.setValue(0, 128 + value); + pot.setValue(1, 128 + value / 2); + i++; + } +} + +// straightforward sawtooth. +void test_sawtooth() +{ + Serial.println(__FUNCTION__); + delay(10); + + for (int i = 0; i < 255; i++) + { + pot.setValue(0, i); // auto wrap is fast... + pot.setValue(1, i++); // auto wrap is fast... + delay(100); + } +} + + +void test_incr_decr() +{ + Serial.println(__FUNCTION__); + delay(10); + pot.setValue(0, 0); + for (int i = 0; i < 255; i++) + { + pot.incrValue(0); + pot.incrValue(1); + delay(100); + } + for (int i = 0; i < 255; i++) + { + pot.decrValue(0); + pot.decrValue(1); + delay(100); + } +} + + +void test_timing() +{ + Serial.println(__FUNCTION__); + delay(10); + + start = micros(); + for (int i = 0; i < 1000; i++) + { + pot.setValue(0, i++); // auto wrap is fast... + } + stop = micros(); + Serial.print("1000 x setValue():\t"); + Serial.println(stop - start); + delay(10); + + volatile int x = 0; + start = micros(); + for (int i = 0; i < 500; i++) + { + x += pot.getValue(0); + x += pot.getValue(1); + } + stop = micros(); + Serial.print("1000 x getValue():\t"); + Serial.println(stop - start); + delay(10); +} + + +// -- END OF FILE -- diff --git a/libraries/MCP4261/examples/MCP4261_performance/MCP4261_performance.ino b/libraries/MCP4261/examples/MCP4261_performance/MCP4261_performance.ino new file mode 100644 index 00000000..e57ea985 --- /dev/null +++ b/libraries/MCP4261/examples/MCP4261_performance/MCP4261_performance.ino @@ -0,0 +1,117 @@ +// +// FILE: MCP4261_performance.ino +// AUTHOR: Rob Tillaart +// PURPOSE: demo +// URL: https://github.com/RobTillaart/MCP4261 +// +// under investigation. + +#include "MCP4261.h" + + +uint32_t start, stop; + + +// select, shutdown, dataIn, dataOut, clock == SOFTWARE SPI +// MCP4261 pot(10, 6, 7, 8, 9); + +// select, shutdown, &SPI === HW SPI UNO clock = 13, data = 11 +MCP4261 pot(10, 6, &SPI); + + +void setup() +{ + Serial.begin(115200); + Serial.println(__FILE__); + Serial.print("MCP4261_LIB_VERSION: "); + Serial.println(MCP4261_LIB_VERSION); + Serial.println(); + + SPI.begin(); + + pot.begin(0); // initial value + pot.setSPIspeed(1000000); + test_timing(); + pot.setSPIspeed(2000000); + test_timing(); + pot.setSPIspeed(4000000); + test_timing(); + pot.setSPIspeed(8000000); + test_timing(); + + Serial.println("\nDone..."); +} + + +void loop() +{ +} + + + +void test_timing() +{ + Serial.println(); + Serial.println(__FUNCTION__); + Serial.print("SPI:\t"); + Serial.println(pot.getSPIspeed()); + delay(100); + + start = micros(); + for (int i = 0; i < 250; i++) + { + pot.setValue(0, 42); + pot.setValue(1, 43); + } + stop = micros(); + Serial.print("500 x setValue():\t"); + Serial.print(stop - start); + Serial.print("\t"); + Serial.println((stop - start) / 500.0); + delay(100); + + volatile int x = 0; + start = micros(); + for (int i = 0; i < 250; i++) + { + x += pot.getValue(0); + x += pot.getValue(1); + } + stop = micros(); + Serial.print("500 x getValue():\t"); + Serial.print(stop - start); + Serial.print("\t"); + Serial.println((stop - start) / 500.0); + delay(100); + + pot.setValue(0); + start = micros(); + for (int i = 0; i < 250; i++) + { + pot.incrValue(0); + pot.incrValue(1); + } + stop = micros(); + Serial.print("500 x incrValue():\t"); + Serial.print(stop - start); + Serial.print("\t"); + Serial.println((stop - start) / 500.0); + delay(100); + + pot.setValue(255); + start = micros(); + for (int i = 0; i < 250; i++) + { + pot.decrValue(0); + pot.decrValue(1); + } + stop = micros(); + Serial.print("500 x decrValue():\t"); + Serial.print(stop - start); + Serial.print("\t"); + Serial.println((stop - start) / 500.0); + delay(100); +} + + +// -- END OF FILE -- diff --git a/libraries/MCP4261/examples/MCP4261_performance/performance_0.1.0.txt b/libraries/MCP4261/examples/MCP4261_performance/performance_0.1.0.txt new file mode 100644 index 00000000..75fc3f10 --- /dev/null +++ b/libraries/MCP4261/examples/MCP4261_performance/performance_0.1.0.txt @@ -0,0 +1,48 @@ + +BOARD: Arduino UNO +IDE: 1.8.19 + +MCP4261_performance.ino +MCP4261_LIB_VERSION: 0.1.0 + +HW SPI + + +test_timing +SPI: 1000000 +500 x setValue(): 15404 30.81 +500 x getValue(): 380 0.76 +500 x incrValue(): 10776 21.55 +500 x decrValue(): 10660 21.32 + +test_timing +SPI: 2000000 +500 x setValue(): 11380 22.76 +500 x getValue(): 384 0.77 +500 x incrValue(): 8768 17.54 +500 x decrValue(): 8640 17.28 + +test_timing +SPI: 4000000 +500 x setValue(): 9400 18.80 +500 x getValue(): 380 0.76 +500 x incrValue(): 7768 15.54 +500 x decrValue(): 7644 15.29 + +test_timing +SPI: 8000000 +500 x setValue(): 8400 16.80 +500 x getValue(): 376 0.75 +500 x incrValue(): 7268 14.54 +500 x decrValue(): 7140 14.28 + + +SW SPI + +500 x setValue(): 107264 214.53 +500 x getValue(): 380 0.76 +500 x incrValue(): 56556 113.11 +500 x decrValue(): 56432 112.86 + + +Done... diff --git a/libraries/MCP4261/keywords.txt b/libraries/MCP4261/keywords.txt new file mode 100644 index 00000000..e48e0142 --- /dev/null +++ b/libraries/MCP4261/keywords.txt @@ -0,0 +1,43 @@ +# Syntax Colouring Map For MCP4261 + +# Data types (KEYWORD1) +MCP4141 KEYWORD1 +MCP4142 KEYWORD1 +MCP4161 KEYWORD1 +MCP4162 KEYWORD1 + +MCP4241 KEYWORD1 +MCP4242 KEYWORD1 +MCP4261 KEYWORD1 +MCP4262 KEYWORD1 + + +# Methods and Functions (KEYWORD2) +begin KEYWORD2 +reset KEYWORD2 +pmCount KEYWORD2 + +setValue KEYWORD2 +getValue KEYWORD2 + +incrValue KEYWORD2 +decrValue KEYWORD2 + +setValueNV KEYWORD2 + +setSPIspeed KEYWORD2 +getSPIspeed KEYWORD2 + +powerOn KEYWORD2 +powerOff KEYWORD2 +isPowerOn KEYWORD2 + +usesHWSPI KEYWORD2 + +# Constants (LITERAL1) +MCP4261_LIB_VERSION LITERAL1 + +MCP41XX_MIDDLE_VALUE LITERAL1 +MCP41XX_MAX_VALUE LITERAL1 +MCP42XX_MIDDLE_VALUE LITERAL1 +MCP42XX_MAX_VALUE LITERAL1 diff --git a/libraries/MCP4261/library.json b/libraries/MCP4261/library.json new file mode 100644 index 00000000..740ffc2e --- /dev/null +++ b/libraries/MCP4261/library.json @@ -0,0 +1,23 @@ +{ + "name": "MCP4261", + "keywords": "MCP4141,MCP4142,MCP4161,MCP4162,MCP4241,MCP4242,MCP4261,MCP4262", + "description": "Arduino library for MCP4261 SPI based digital potentiometers.", + "authors": + [ + { + "name": "Rob Tillaart", + "email": "Rob.Tillaart@gmail.com", + "maintainer": true + } + ], + "repository": + { + "type": "git", + "url": "https://github.com/RobTillaart/MCP4261.git" + }, + "version": "0.1.0", + "license": "MIT", + "frameworks": "*", + "platforms": "*", + "headers": "MCP4261.h" +} diff --git a/libraries/MCP4261/library.properties b/libraries/MCP4261/library.properties new file mode 100644 index 00000000..1d2bf69f --- /dev/null +++ b/libraries/MCP4261/library.properties @@ -0,0 +1,11 @@ +name=MCP4261 +version=0.1.0 +author=Rob Tillaart +maintainer=Rob Tillaart +sentence=Arduino library for MCP4261 SPI based digital potentiometers. +paragraph=MCP4141,MCP4142,MCP4161,MCP4162,MCP4241,MCP4242,MCP4261,MCP4262 +category=Signal Input/Output +url=https://github.com/RobTillaart/MCP4261 +architectures=* +includes=MCP4261.h +depends= diff --git a/libraries/MCP4261/test/unit_test_001.cpp b/libraries/MCP4261/test/unit_test_001.cpp new file mode 100644 index 00000000..7ff9eaae --- /dev/null +++ b/libraries/MCP4261/test/unit_test_001.cpp @@ -0,0 +1,71 @@ +// +// FILE: unit_test_001.cpp +// AUTHOR: Rob Tillaart +// DATE: 2022-12-01 +// PURPOSE: unit tests for the A1301 magnetic sensor +// URL: https://github.com/RobTillaart/A1301 +// https://www.adafruit.com/product/2857 +// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md +// + +// supported assertions +// ---------------------------- +// assertEqual(expected, actual) +// assertNotEqual(expected, actual) +// assertLess(expected, actual) +// assertMore(expected, actual) +// assertLessOrEqual(expected, actual) +// assertMoreOrEqual(expected, actual) +// assertTrue(actual) +// assertFalse(actual) +// assertNull(actual) + + +#include + +#include "Arduino.h" +#include "MCP4261.h" + + +unittest_setup() +{ + fprintf(stderr, "MCP4261_LIB_VERSION: %s\n", (char *) MCP4261_LIB_VERSION); +} + +unittest_teardown() +{ +} + + +unittest(test_constants) +{ + assertEqual(64, MCP41XX_MIDDLE_VALUE); + assertEqual(129, MCP41XX_MAX_VALUE); + assertEqual(129, MCP42XX_MIDDLE_VALUE); + assertEqual(257, MCP42XX_MAX_VALUE); +} + + +unittest(test_constructor) +{ + MCP4261 mcp(10, 6); + // before begin. + assertEqual(2, mcp.pmCount()); + assertEqual(0, mcp.getValue()); + +} + + +/* + TODO + setValue false test + setValue, getValue + incrValue + decrValue +*/ + +unittest_main() + + +// -- END OF FILE -- +