0.1.0 X9C10X

This commit is contained in:
rob tillaart 2022-02-14 20:53:03 +01:00
parent 307043c1a9
commit 1cb27fdb75
15 changed files with 847 additions and 0 deletions

View File

@ -0,0 +1,14 @@
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
# - due
# - zero
# - leonardo
- m4
- esp32
# - esp8266
# - mega2560
libraries:
- "printHelpers"

View File

@ -0,0 +1,13 @@
name: Arduino-lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: arduino/arduino-lint-action@v1
with:
library-manager: update
compliance: strict

View File

@ -0,0 +1,17 @@
---
name: Arduino CI
on: [push, pull_request]
jobs:
runTest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
- run: |
gem install arduino_ci
arduino_ci.rb

View File

@ -0,0 +1,18 @@
name: JSON check
on:
push:
paths:
- '**.json'
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: json-syntax-check
uses: limitusus/json-syntax-check@v1
with:
pattern: "\\.json$"

21
libraries/X9C10X/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022-2022 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.

105
libraries/X9C10X/README.md Normal file
View File

@ -0,0 +1,105 @@
[![Arduino CI](https://github.com/RobTillaart/X9C10X/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
[![Arduino-lint](https://github.com/RobTillaart/X9C10X/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/X9C10X/actions/workflows/arduino-lint.yml)
[![JSON check](https://github.com/RobTillaart/X9C10X/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/X9C10X/actions/workflows/jsoncheck.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/X9C10X/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/RobTillaart/X9C10X.svg?maxAge=3600)](https://github.com/RobTillaart/X9C10X/releases)
# X9C10X
Arduino Library for X9C10X series digital potentiometer.
## Description
This experimental library provides a X9C10X base class and four derived classes for specific digital potentiometer.
| type | resistance | notes |
|:------:|:----------:|:-------------|
| X9C10X | generic | base class |
| X9C102 | 1 KΩ | 10 \* 10^2 |
| X9C103 | 10 KΩ | 10 \* 10^3 |
| X9C104 | 100 KΩ | 10 \* 10^4 |
| X9C503 | 50 KΩ | 50 \* 10^3 |
_Note: Ω ohm sign = ALT-234_
The library keeps cache of the position.
## Interface
## X9C10X base class
Use **\#include "X9C10X.h"**
- **X9C10X(uint32_t ohm = 10000)** Constructor, default initializes the resistance to 10000 Ω.
To calibrate one can fill in any other value e.g. 9950 Ω.
- **void begin(uint8_t pulsePin, uint8_t directionPin, uint8_t selectPin, uint8_t position = 0)**
sets the pins used by the device, and resets the position (default to 0).
The position parameter allows to start the device with a previous stored position.
Use this position with care.
Note: **begin()** has a hard coded 500uS delay so the device can wake up.
Note: multiple devices can be controlled, just by giving them an unique selectPin.
This behaviour is similar to the SPI select pin.
- **void setPosition(uint8_t position)** sets the wiper to a position between 0 and 99.
- **uint8_t getPosition()** returns the current position.
- **void incr()** moves one position up (if possible).
- **void decr()** moves one position down (if possible).
- **uint32_t getOhm()** returns the position expressed in ohm.
The returned value does depend on the value passed in the constructor.
- **uint32_t getMaxOhm()** returns the maximum value ( = parameter from constructor).
#### Store
Warning: use with care.
- **uint8_t store()** stores the current position in the NVRAM of the device,
and returns the current position so it can later be used as position parameter for **begin()**.
If one uses an incorrect parameter position in **begin()** the internal state and the device
will probably be out of sync. One way to sync is call **begin()** with the right parameters.
The other way is to call **setPosition(0)** followed by **setPosition(99)** (or vice versa)
to get a defined internal state.
## derived classes
There are 4 derived classes, each with a other (appropriate) default value for the resistance.
- **X9C102(uint32_t ohm = 1000)**
- **X9C103(uint32_t ohm = 10000)**
- **X9C104(uint32_t ohm = 100000)**
- **X9C503(uint32_t ohm = 50000)**
These classes have the same interface as the base class.
#### Performance
No hardware to test yet.
## Operation
See examples.
## Future
- buy and test different versions of the hardware
- test different platform
- test performance
- documentation
- optimize **setPosition()**
- do we need the hardcoded 500us delay in **begin()**?
- do we need **getType()**
- add error codes?

144
libraries/X9C10X/X9C10X.cpp Normal file
View File

@ -0,0 +1,144 @@
//
// FILE: X9C10X.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: Arduino Library for X9C10X series digital potentiometer.
//
// HISTORY
// 0.1.0 2022-01-26 initial version
//
#include "X9C10X.h"
// minimum pulse width CLOCK = ? us (datasheet);
// digitalWrite takes enough time on UNO / AVR so clock_delay == 0
// Note that if clock pulses are long enough the data pulses are too.
#ifdef __AVR__
#define X9C10X_DELAYMICROS 0
#else
#define X9C10X_DELAYMICROS 1
#endif
#define X9C10X_UP HIGH
#define X9C10X_DOWN LOW
X9C10X::X9C10X(uint32_t ohm)
{
_ohm = ohm;
}
void X9C10X::begin(uint8_t pulsePin, uint8_t directionPin, uint8_t selectPin, uint8_t position)
{
_pulsePin = pulsePin;
_directionPin = directionPin;
_selectPin = selectPin;
pinMode(_pulsePin, OUTPUT);
pinMode(_directionPin, OUTPUT);
pinMode(_selectPin, OUTPUT);
digitalWrite(_pulsePin, HIGH);
digitalWrite(_directionPin, HIGH);
digitalWrite(_selectPin, HIGH);
// wiper power up time. Page 5.
delayMicroseconds(500);
// reset defined position.
_position = position;
}
// initial implementation, to be optimized.
void X9C10X::setPosition(uint8_t position)
{
if (position > 99) position = 99;
while (position > _position) incr();
while (position < _position) decr();
}
void X9C10X::incr()
{
if (_position >= 99) return;
_position++;
_move(X9C10X_UP);
}
void X9C10X::decr()
{
if (_position == 0) return;
_position--;
_move(X9C10X_DOWN);
}
uint8_t X9C10X::store()
{
// _pulsePin starts default HIGH
digitalWrite(_selectPin, LOW);
if (X9C10X_DELAYMICROS > 0) delayMicroseconds(X9C10X_DELAYMICROS);
digitalWrite(_selectPin, HIGH);
delay(20); // Tcph page 5
return _position;
}
////////////////////////////////////////////////////////////////////
//
// PRIVATE
//
void X9C10X::_move(uint8_t direction, uint8_t steps)
{
digitalWrite(_directionPin, direction);
delayMicroseconds(3); // Tdi (page 5)
// _pulsePin starts default HIGH
digitalWrite(_selectPin, LOW);
while (steps--)
{
digitalWrite(_pulsePin, HIGH);
if (X9C10X_DELAYMICROS > 0) delayMicroseconds(X9C10X_DELAYMICROS);
digitalWrite(_pulsePin, LOW);
if (X9C10X_DELAYMICROS > 0) delayMicroseconds(X9C10X_DELAYMICROS);
}
// _pulsePin == LOW, (No Store, page 7)
digitalWrite(_selectPin, HIGH);
// reset _pulsePin to default.
digitalWrite(_pulsePin, HIGH);
}
/////////////////////////////////////////////////////////
//
// DERIVED
//
X9C102::X9C102(uint32_t ohm) : X9C10X(ohm)
{
_type = 102;
}
X9C103::X9C103(uint32_t ohm) : X9C10X(ohm)
{
_type = 103;
}
X9C104::X9C104(uint32_t ohm) : X9C10X(ohm)
{
_type = 104;
}
X9C503::X9C503(uint32_t ohm) : X9C10X(ohm)
{
_type = 503;
}
// -- END OF FILE --

92
libraries/X9C10X/X9C10X.h Normal file
View File

@ -0,0 +1,92 @@
#pragma once
//
// FILE: X9C10X.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: Arduino Library for X9C10X series digital potentiometer.
//
#include "Arduino.h"
#define X9C10X_LIB_VERSION (F("0.1.0"))
class X9C10X
{
public:
// ohm can be actual measured value e.g 9950 ohm (calibration)
X9C10X(uint32_t ohm = 10000);
void begin(uint8_t pulsePin, uint8_t directionPin, uint8_t selectPin, uint8_t position = 0);
// position = 0..99
void setPosition(uint8_t position);
uint8_t getPosition() { return _position; };
// step size 1.
void incr();
void decr();
// use with care
uint8_t store();
// current resistance in ohm.
// Q: rounding needed?
uint32_t getOhm() { return (_ohm * _position) / 99; };
// misc
uint32_t getMaxOhm() { return _ohm; };
// Q: needed?
uint16_t getType() { return _type; };
protected:
uint8_t _pulsePin;
uint8_t _directionPin;
uint8_t _selectPin;
uint32_t _ohm;
uint8_t _position;
uint16_t _type = 0; // needed?
void _move(uint8_t direction, uint8_t steps = 1);
};
/////////////////////////////////////////////////////////
//
// DERIVED
//
class X9C102 : public X9C10X
{
public:
X9C102(uint32_t ohm = 1000);
};
class X9C103 : public X9C10X
{
public:
X9C103(uint32_t ohm = 10000);
};
class X9C104 : public X9C10X
{
public:
X9C104(uint32_t ohm = 100000);
};
class X9C503 : public X9C10X
{
public:
X9C503(uint32_t ohm = 50000);
};
// -- END OF FILE --

View File

@ -0,0 +1,122 @@
//
// FILE: X9C10X_performance.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
#include "Arduino.h"
#include "X9C10X.h"
X9C10X pot(12345); // 100KΩ (ALT-234)
uint32_t start, stop;
volatile uint8_t pos;
volatile uint32_t ohm;
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println();
Serial.print("X9C10X_LIB_VERSION: ");
Serial.println(X9C10X_LIB_VERSION);
pot.begin(8, 9, 10, 0); // pulse, direction, select, position
start = micros();
pos = pot.getPosition();
stop = micros();
Serial.print("getPosition:\t");
Serial.println(stop - start);
delay(100);
Serial.println("\nfrom 0 to ...");
pot.setPosition(0);
start = micros();
pot.setPosition(33);
stop = micros();
Serial.print("setPosition(33):\t");
Serial.println(stop - start);
delay(100);
pot.setPosition(0);
start = micros();
pot.setPosition(66);
stop = micros();
Serial.print("setPosition(66):\t");
Serial.println(stop - start);
delay(100);
pot.setPosition(0);
start = micros();
pot.setPosition(99);
stop = micros();
Serial.print("setPosition(99):\t");
Serial.println(stop - start);
delay(100);
Serial.println("\nfrom n to m");
pot.setPosition(0);
start = micros();
pot.setPosition(33);
stop = micros();
Serial.print("setPosition(33):\t");
Serial.println(stop - start);
delay(100);
start = micros();
pot.setPosition(66);
stop = micros();
Serial.print("setPosition(66):\t");
Serial.println(stop - start);
delay(100);
start = micros();
pot.setPosition(99);
stop = micros();
Serial.print("setPosition(99):\t");
Serial.println(stop - start);
delay(100);
Serial.println();
start = micros();
ohm = pot.getMaxOhm();
stop = micros();
Serial.print("getMaxOhm():\t");
Serial.println(stop - start);
delay(100);
start = micros();
ohm = pot.getOhm();
stop = micros();
Serial.print("getOhm():\t");
Serial.println(stop - start);
delay(100);
Serial.println();
pot.setPosition(0);
start = micros();
for (int i = 0; i < 10; i++) pot.incr();
stop = micros();
Serial.print("10 x incr():\t");
Serial.println(stop - start);
delay(100);
pot.setPosition(50);
start = micros();
for (int i = 0; i < 10; i++) pot.decr();
stop = micros();
Serial.print("10 x decr():\t");
Serial.println(stop - start);
delay(100);
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,24 @@
Tested on Arduino UNO
IDE 1.18.19
X9C10X_LIB_VERSION: 0.1.0
getPosition: 4
from 0 to ...
setPosition(33): 1024
setPosition(66): 1860
setPosition(99): 2788
from n to m
setPosition(33): 932
setPosition(66): 936
setPosition(99): 932
getMaxOhm(): 4
getOhm(): 44
10 x incr(): 284
10 x decr(): 284

View File

@ -0,0 +1,90 @@
//
// FILE: X9C10X_test.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
#include "Arduino.h"
#include "X9C10X.h"
X9C10X pot(12345); // 100KΩ (ALT-234)
void setup()
{
Serial.begin(115200);
while (!Serial);
Serial.println();
Serial.print("X9C10X_LIB_VERSION: ");
Serial.println(X9C10X_LIB_VERSION);
pot.begin(8, 9, 10, 0); // pulse, direction, select, position
Serial.print("POS:\t0\t");
Serial.println(pot.getPosition());
Serial.print("VAL:\t\t");
Serial.print(pot.getOhm());
Serial.println(" Ω");
Serial.println();
pot.setPosition(50);
Serial.print("POS:\t50\t");
Serial.println(pot.getPosition());
Serial.print("VAL:\t\t");
Serial.print(pot.getOhm());
Serial.println(" Ω");
Serial.println();
pot.setPosition(110);
Serial.print("POS:\t110\t");
Serial.println(pot.getPosition());
Serial.print("VAL:\t\t");
Serial.print(pot.getOhm());
Serial.println(" Ω");
Serial.print("OHM:\t\t");
Serial.print(pot.getMaxOhm());
Serial.println(" Ω");
Serial.println();
pot.setPosition(0);
Serial.print("POS:\t0\t");
Serial.println(pot.getPosition());
Serial.print("VAL:\t\t");
Serial.print(pot.getOhm());
Serial.println(" Ω");
Serial.print("OHM:\t\t");
Serial.print(pot.getMaxOhm());
Serial.println(" Ω");
Serial.println();
for (uint8_t i = 0; i < 100; i++)
{
pot.incr();
Serial.print(i);
Serial.print("\t");
Serial.print(pot.getPosition());
Serial.print("\t");
Serial.println(pot.getOhm());
}
Serial.println();
for (uint8_t i = 0; i < 100; i++)
{
pot.decr();
Serial.print(i);
Serial.print("\t");
Serial.print(pot.getPosition());
Serial.print("\t");
Serial.println(pot.getOhm());
}
Serial.println();
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,26 @@
# Syntax Colouring Map For X9C10X
# Data types (KEYWORD1)
X9C10X KEYWORD1
X9C102 KEYWORD1
X9C103 KEYWORD1
X9C104 KEYWORD1
X9C503 KEYWORD1
# Methods and Functions (KEYWORD2)
begin KEYWORD2
setPosition KEYWORD2
getPosition KEYWORD2
incr KEYWORD2
decr KEYWORD2
getOhm KEYWORD2
getMaxOhm KEYWORD2
store KEYWORD2
# Constants (LITERAL1)
X9C10X_LIB_VERSION LITERAL1

View File

@ -0,0 +1,23 @@
{
"name": "X9C10X",
"keywords": "potentiometer,X9C102,X9C103,X9C104,X9C503",
"description": "Arduino Library for X9C10X series digital potentiometer.",
"authors":
[
{
"name": "Rob Tillaart",
"email": "Rob.Tillaart@gmail.com",
"maintainer": true
}
],
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/X9C10X.git"
},
"version": "0.1.0",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",
"headers": "X9C10X.h"
}

View File

@ -0,0 +1,11 @@
name=X9C10X
version=0.1.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino Library for X9C10X series digital potentiometer.
paragraph=X9C102, X9C103, X9C104, X9C503
category=Signal Input/Output
url=https://github.com/RobTillaart/X9C10X
architectures=*
includes=X9C10X.h
depends=

View File

@ -0,0 +1,127 @@
//
// FILE: unit_test_001.cpp
// AUTHOR: Rob Tillaart
// DATE: 2022-02-11
// PURPOSE: unit tests for the X9C10X library
// https://github.com/RobTillaart/X9C10X
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
//
// supported assertions
// https://github.com/Arduino-CI/arduino_ci/blob/master/cpp/unittest/Assertion.h#L33-L42
// ----------------------------
// assertEqual(expected, actual)
// assertNotEqual(expected, actual)
// assertLess(expected, actual)
// assertMore(expected, actual)
// assertLessOrEqual(expected, actual)
// assertMoreOrEqual(expected, actual)
// assertTrue(actual)
// assertFalse(actual)
// assertNull(actual)
// assertNotNull(actual)
#include <ArduinoUnitTests.h>
#include "Arduino.h"
#include "X9C10X.h"
unittest_setup()
{
fprintf(stderr, "X9C10X_LIB_VERSION: %s\n", (char *) X9C10X_LIB_VERSION);
}
unittest_teardown()
{
}
unittest(test_constructor)
{
X9C10X dp0;
X9C10X dp1(1000);
X9C10X dp2(900);
X9C10X dp3(1100);
assertEqual(10000, dp0.getMaxOhm());
assertEqual(1000, dp1.getMaxOhm());
assertEqual(900, dp2.getMaxOhm());
assertEqual(1100, dp3.getMaxOhm());
X9C102 x102;
X9C103 x103;
X9C104 x104;
X9C503 x503;
assertEqual(1000, x102.getMaxOhm());
assertEqual(10000, x103.getMaxOhm());
assertEqual(100000, x104.getMaxOhm());
assertEqual(50000, x503.getMaxOhm());
}
unittest(test_position)
{
X9C10X dp0;
dp0.begin(7, 8, 9);
assertEqual(0, dp0.getPosition());
fprintf(stderr, "setPosition step 9\n");
for (uint8_t pos = 0; pos < 100; pos += 9)
{
dp0.setPosition(pos);
assertEqual(pos, dp0.getPosition());
}
X9C10X dp1;
dp1.begin(7, 8, 9, 50);
assertEqual(50, dp1.getPosition());
}
unittest(test_incr_decr)
{
X9C10X dp0;
dp0.begin(7, 8, 9);
assertEqual(0, dp0.getPosition());
dp0.setPosition(0);
for (uint8_t pos = 0; pos < 10; pos++)
{
assertEqual(pos, dp0.getPosition());
dp0.incr();
}
for (uint8_t pos = 0; pos < 5; pos++)
{
assertEqual(10 - pos, dp0.getPosition());
dp0.decr();
}
}
unittest(test_getOhm)
{
X9C10X dp0;
dp0.begin(7, 8, 9);
assertEqual(0, dp0.getPosition());
assertEqual(10000, dp0.getMaxOhm());
for (uint8_t pos = 0; pos < 100; pos += 9)
{
fprintf(stderr, "VALUE: %d %d Ω\n", dp0.getPosition(), dp0.getOhm());
dp0.incr();
}
}
unittest_main()
// --------