0.1.1 AD56X8

This commit is contained in:
rob tillaart 2022-12-01 17:28:33 +01:00
parent 7342eb296d
commit bfed88b7a0
16 changed files with 1244 additions and 0 deletions

View File

@ -0,0 +1,28 @@
platforms:
rpipico:
board: rp2040:rp2040:rpipico
package: rp2040:rp2040
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
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
# - due
# - zero
# - leonardo
- m4
- esp32
- esp8266
# - mega2560
- rpipico

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$"

334
libraries/AD56X8/AD56X8.cpp Normal file
View File

@ -0,0 +1,334 @@
//
// FILE: AD56X8.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// DATE: 2022-07-28
// PURPOSE: Arduino library for AD56X8, SPI 8 channel Digital Analog Convertor.
#include "AD56X8.h"
// not all "commands" implemented yet
#define AD56X8_REG_WRITE 0x00
#define AD56X8_REG_UPDATE 0x01
#define AD56X8_REG_WRITE_LDAC 0x02
#define AD56X8_REG_WRITE_UPDATE 0x03
#define AD56X8_REG_POWER 0x04
#define AD56X8_REG_LOAD_CLR 0x05
#define AD56X8_REG_LOAD_LDAC 0x06
#define AD56X8_REG_RESET 0x07
#define AD56X8_REG_SETUP_REF 0x08
AD56X8::AD56X8(uint8_t slaveSelect)
{
_hwSPI = true;
_select = slaveSelect;
for (int i = 0; i < 8; i++) _value[i] = 0;
}
AD56X8::AD56X8(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect)
{
_hwSPI = false;
_dataOut = spiData;
_clock = spiClock;
_select = slaveSelect;
for (int i = 0; i < 8; i++) _value[i] = 0;
}
// initializes the SPI
// and sets internal state
void AD56X8::begin()
{
pinMode(_select, OUTPUT);
digitalWrite(_select, HIGH);
_spi_settings = SPISettings(_SPIspeed, MSBFIRST, SPI_MODE1);
if(_hwSPI)
{
#if defined(ESP32)
if (_useHSPI) // HSPI
{
mySPI = new SPIClass(HSPI);
mySPI->end();
mySPI->begin(14, 12, 13, _select); // CLK=14 MISO=12 MOSI=13
}
else // VSPI
{
mySPI = new SPIClass(VSPI);
mySPI->end();
mySPI->begin(18, 19, 23, _select); // CLK=18 MISO=19 MOSI=23
}
#else // generic hardware SPI
mySPI = &SPI;
mySPI->end();
mySPI->begin();
#endif
delay(1);
}
else // software SPI
{
pinMode(_dataOut, OUTPUT);
pinMode(_clock, OUTPUT);
digitalWrite(_dataOut, LOW);
digitalWrite(_clock, LOW);
}
// TODO RESET REGISTERS
// _register = 0;
// _value = 0;
}
uint8_t AD56X8::getType()
{
return _type;
}
#if defined(ESP32)
void AD56X8::setGPIOpins(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t select)
{
_clock = clk;
_dataOut = mosi;
_select = select;
pinMode(_select, OUTPUT);
digitalWrite(_select, HIGH);
mySPI->end(); // disable SPI
mySPI->begin(clk, miso, mosi, select); // enable SPI
}
#endif
// value = 0..65535 (16 bit), 16383 (14 bit), 4095 (12 bit) depending on type)
bool AD56X8::setValue(uint8_t channel, uint16_t value)
{
if (channel > 7) return false;
if ((_type == 12) && (value > 4095)) return false;
if ((_type == 14) && (value > 16383)) return false;
_value[channel] = value;
updateDevice(AD56X8_REG_WRITE_UPDATE, channel, value);
return true;
}
// returns 0..65535 (16 bit), 16383 (14 bit), 4095 (12 bit) depending on type)
uint16_t AD56X8::getValue(uint8_t channel)
{
if (channel > 7) return 0;
return _value[channel];
}
bool AD56X8::prepareChannel(uint8_t channel, uint16_t value)
{
if (channel > 7) return false;
if ((_type == 12) && (value > 4095)) return false;
if ((_type == 14) && (value > 16383)) return false;
_value[channel] = value;
updateDevice(AD56X8_REG_WRITE, channel, value);
return true;
}
bool AD56X8::updateChannel(uint8_t channel)
{
if (channel > 7) return false;
updateDevice(AD56X8_REG_UPDATE, channel, 0);
return true;
}
void AD56X8::updateAllChannels()
{
// TODO test
// TODO replace with hardware LDAC if supported.
updateDevice(AD56X8_REG_WRITE_LDAC, 0, _value[0]);
}
void AD56X8::setLDACmask(uint8_t mask)
{
_ldacMask = mask;
updateDevice(AD56X8_REG_LOAD_LDAC, 0, 0, _ldacMask);
}
uint8_t AD56X8::getLDACmask()
{
return _ldacMask;
}
bool AD56X8::inLDACmask(uint8_t channel)
{
if (channel > 7) return false;
return (_ldacMask & (1 << channel)) > 0;
}
bool AD56X8::setPowerMode(uint8_t powerDownMode, uint8_t channelMask)
{
if (powerDownMode > 3) return false;
updateDevice(AD56X8_REG_POWER, 0, 0, channelMask);
return true;
}
void AD56X8::reset()
{
updateDevice(AD56X8_REG_RESET, 0, 0, 0);
// reset the internal values.
for (int i = 0; i < 8; i++) _value[i] = 0;
}
bool AD56X8::setClearCode(uint8_t CCmode)
{
if (CCmode > 3) return false;
updateDevice(AD56X8_REG_LOAD_CLR, 0, 0, CCmode);
return true;
}
void AD56X8::setSPIspeed(uint32_t speed)
{
_SPIspeed = speed;
_spi_settings = SPISettings(_SPIspeed, MSBFIRST, SPI_MODE1);
};
//////////////////////////////////////////////////////////////////
//
// PRIVATE
//
void AD56X8::updateDevice(uint8_t cmd, uint8_t channel, uint16_t value)
{
uint16_t val = value;
if (_type == 12) val <<= 4;
if (_type == 14) val <<= 2;
uint8_t a = cmd;
uint8_t b = (channel << 4) | (val >> 12);
uint8_t c = val >> 4;
uint8_t d = val << 4;
updateDevice(a, b, c, d);
}
void AD56X8::updateDevice(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
{
digitalWrite(_select, LOW);
if (_hwSPI)
{
mySPI->beginTransaction(_spi_settings);
mySPI->transfer(a);
mySPI->transfer(b);
mySPI->transfer(c);
mySPI->transfer(d);
mySPI->endTransaction();
}
else // Software SPI
{
swSPI_transfer(a);
swSPI_transfer(b);
swSPI_transfer(c);
swSPI_transfer(d);
}
digitalWrite(_select, HIGH);
}
// simple one mode version
void AD56X8::swSPI_transfer(uint8_t value)
{
uint8_t clk = _clock;
uint8_t dao = _dataOut;
for (uint8_t mask = 0x80; mask; mask >>= 1)
{
digitalWrite(dao,(value & mask));
digitalWrite(clk, HIGH);
digitalWrite(clk, LOW);
}
}
/////////////////////////////////////////////////////////////////////////////
//
// DERIVED
//
AD5668_3::AD5668_3(uint8_t slaveSelect) : AD56X8(slaveSelect)
{
_type = 16;
// AD5668_3 starts up at midscale
for (int i = 0; i < 8; i++) _value[i] = 32768; // MIDSCALE
}
AD5668_3::AD5668_3(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect)
: AD56X8(spiData, spiClock, slaveSelect)
{
_type = 16;
// AD5668_3 starts up at midscale
for (int i = 0; i < 8; i++) _value[i] = 32768; // MIDSCALE
}
void AD5668_3::reset()
{
updateDevice(AD56X8_REG_RESET, 0, 0, 0);
// reset the internal values.
for (int i = 0; i < 8; i++) _value[i] = 32768; // MIDSCALE
}
AD5668::AD5668(uint8_t slaveSelect) : AD56X8(slaveSelect)
{
_type = 16;
}
AD5668::AD5668(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect)
: AD56X8(spiData, spiClock, slaveSelect)
{
_type = 16;
}
AD5648::AD5648(uint8_t slaveSelect) : AD56X8(slaveSelect)
{
_type = 14;
}
AD5648::AD5648(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect)
: AD56X8(spiData, spiClock, slaveSelect)
{
_type = 14;
}
AD5628::AD5628(uint8_t slaveSelect) : AD56X8(slaveSelect)
{
_type = 12;
}
AD5628::AD5628(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect)
: AD56X8(spiData, spiClock, slaveSelect)
{
_type = 12;
}
// -- END OF FILE --

154
libraries/AD56X8/AD56X8.h Normal file
View File

@ -0,0 +1,154 @@
#pragma once
//
// FILE: AD56X8.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// DATE: 2022-07-28
// PURPOSE: Arduino library for AD56X8, SPI 8 channel Digital Analog Convertor.
#include "Arduino.h"
#include "SPI.h"
#define AD56X8_LIB_VERSION (F("0.1.1"))
#define AD56X8_PWR_NORMAL 0x00
#define AD56X8_PWR_1K 0x01
#define AD56X8_PWR_100K 0x02
#define AD56X8_PWR_TRI_STATE 0x03
// ZERO, HALF, FULL ?
#define AD56X8_CC_0000 0x00
#define AD56X8_CC_8000 0x01
#define AD56X8_CC_FFFF 0x02
#define AD56X8_CC_NOP 0x03 // do not use (read datasheet)
class AD56X8
{
public:
AD56X8(uint8_t slaveSelect);
AD56X8(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect);
void begin();
uint8_t getType();
// SET DAC
// returns false if channel out of range
// sets output immediately = prepare + update.
bool setValue(uint8_t channel, uint16_t value);
uint16_t getValue(uint8_t channel);
// prep & update separately
bool prepareChannel(uint8_t channel, uint16_t value);
bool updateChannel(uint8_t channel);
void updateAllChannels();
// LDAC
void setLDACmask(uint8_t mask = 0x00);
uint8_t getLDACmask();
bool inLDACmask(uint8_t channel);
// POWER
// mode = 0..3
// returns false if mode out of range
bool setPowerMode(uint8_t powerDownMode, uint8_t mask = 0x00);
// MISC
// software reset
void reset();
// returns false if mode out of range
// CCmode = 0..2
bool setClearCode(uint8_t CCmode); // check datasheet.
// SPI
// speed in Hz
void setSPIspeed(uint32_t speed);
uint32_t getSPIspeed() { return _SPIspeed; };
bool usesHWSPI() { return _hwSPI; };
// ESP32 specific
#if defined(ESP32)
void selectHSPI() { _useHSPI = true; };
void selectVSPI() { _useHSPI = false; };
bool usesHSPI() { return _useHSPI; };
bool usesVSPI() { return !_useHSPI; };
// to overrule ESP32 default hardware pins
void setGPIOpins(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t select);
#endif
protected:
uint8_t _type = 0; // # bits
uint8_t _dataOut = 255;
uint8_t _clock = 255;
uint8_t _select = 255;
uint16_t _value[8];
uint8_t _ldacMask = 0;
bool _hwSPI = false;
uint32_t _SPIspeed = 16000000;
void updateDevice(uint8_t cmd, uint8_t channel, uint16_t value);
void updateDevice(uint8_t a, uint8_t b, uint8_t c, uint8_t d);
void swSPI_transfer(uint8_t value);
SPIClass * mySPI;
SPISettings _spi_settings;
#if defined(ESP32)
bool _useHSPI = true;
#endif
};
/////////////////////////////////////////////////////////////////////////////
//
// DERIVED
//
class AD5668_3 : public AD56X8
{
public:
AD5668_3(uint8_t slaveSelect);
AD5668_3(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect);
void reset();
};
class AD5668 : public AD56X8
{
public:
AD5668(uint8_t slaveSelect);
AD5668(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect);
};
class AD5648 : public AD56X8
{
public:
AD5648(uint8_t slaveSelect);
AD5648(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect);
};
class AD5628 : public AD56X8
{
public:
AD5628(uint8_t slaveSelect);
AD5628(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect);
};
// -- END OF FILE --

View File

@ -0,0 +1,29 @@
# Change Log AD56X8
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.1] - 2022-12-01
- initial release
- add changelog.md
- add derived type - AD5668_3() starts up at midscale
- initialize internal values\[] array.
- improve unit tests
- clean up code
- update readme.md
## [0.1.0] - 2022-07-28
- rework (add from DAC855x + MCP_DAC)
- not released.
----
## Eons ago
- initial work

21
libraries/AD56X8/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.

214
libraries/AD56X8/README.md Normal file
View File

@ -0,0 +1,214 @@
[![Arduino CI](https://github.com/RobTillaart/AD56X8/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
[![Arduino-lint](https://github.com/RobTillaart/AD56X8/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/AD56X8/actions/workflows/arduino-lint.yml)
[![JSON check](https://github.com/RobTillaart/AD56X8/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/AD56X8/actions/workflows/jsoncheck.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/AD56X8/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/RobTillaart/AD56X8.svg?maxAge=3600)](https://github.com/RobTillaart/AD56X8/releases)
# AD56X8
Experimental Library for the AD56X8 series digital analog convertor.
NOTE: not yet tested, TODO buy hardware.
Feedback, issues, improvements are welcome.
Please file an issue on GitHub.
## Description
The AD56X8 is an 8 channel DAC convertor, that has 12, 14 or 16 bit accuracy.
Furthermore it is available in 2.5 V and 5.0 V version, see table below.
The device allows to set the outputs directly, or prepare them and update them simultaneously (Latch DAC).
| type | output | resolution | power up |
|:---------|:--------:|:----------:|:---------:|
| AD5668-1 | 2.5 V | 16 bit | 0.0 V |
| AD5648-1 | 2.5 V | 14 bit | 0.0 V |
| AD5628-1 | 2.5 V | 12 bit | 0.0 V |
| AD5668-3 | 5.0 V | 16 bit | **2.5 V** |
| AD5668-2 | 5.0 V | 16 bit | 0.0 V |
| AD5648-2 | 5.0 V | 14 bit | 0.0 V |
| AD5628-2 | 5.0 V | 12 bit | 0.0 V |
The library is usable but not functional complete yet.
At least it lacks support for:
- RESET pin,
- LDAC pin,
- VREF pin.
- other points mentioned in future section below.
## Links
This library is partly inspired by https://github.com/bobhart/AD5668-Library, kudo's to Bob!
Discussed here - https://forum.arduino.cc/t/new-library-for-the-ad5668-dac/340393
Furthermore it has the SPI part from https://github.com/RobTillaart/MCP_DAC a.o.
Some differences between this library and Bob Harts. This library
- caches the values of all channels, so they can be read back.
- has derived classes for every specific type DAC.
This allows value range checking in the future. Not Implemented Yet.
- caches the LDAC mask, so it can be read back and updated.
- has extended (ESP32) SPI interface (similar and tested with MCP_DAC)
- allows to set SPI-speed.
- has faster software SPI transfer, on ESP32 this rivals HW SPI.
- MIT license instead of GNU v3
## Interface
```cpp
#include "AD56X8.h"
```
#### Base class
Should not be used to instantiate a device as the derived types have correct number of bits.
- **AD56X8(uint8_t slaveSelect)** constructor base class, sets HW SPI.
Uses default a 16 bit interface.
Sets internal values to zero.
- **AD56X8(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect)** constructor, sets SW SPI.
Uses default a 16 bit interface.
Sets internal values to zero.
- **begin()** initializes the SPI and sets internal state.
#### Set DAC
- **bool setValue(uint8_t channel, uint16_t value)** set value to the output immediately, effectively a prepare + update in one call.
Returns false if channel out of range.
- **uint16_t getValue(uint8_t channel)** returns set OR prepared value.
At power up the DAC's will be reset to 0 V except the AD5668-3 (2.5V).
- **bool prepareChannel(uint8_t channel, uint16_t value)** prepares the value for a channel.
Returns false if channel out of range.
- **bool updateChannel(uint8_t channel)** writes the prepared value to ADC.
Returns false if channel out of range.
- **void updateAllChannels()** writes all prepared channels to their ADC simultaneously by applying a SW latch pulse (LDAC).
NOte: the valid range of **value** is not checked by the library.
#### LDAC
The AD56X8 has an LDAC register with one bit per channel.
This is to configure which channels are updated simultaneously.
Read datasheet for details.
- **void setLDACmask(uint8_t mask = 0x00)** sets 8 channels with one call by using a bit mask. Default value 0x00 clears all channels.
- **uint8_t getLDACmask()** return the current (cached) LDAC bit mask, default = 0x00.
- **bool inLDACmask(uint8_t channel)** returns true if a channel is in the current LDAC bit mask.
Returns also false if channel is out of range.
#### Powermode
- **bool setPowerMode(uint8_t powerDownMode, uint8_t mask = 0x00)** powerDownMode = 0..3.
Default is setting the channels to **PWR_NORMAL**.
Returns false if powerDownMode is out of range.
| mode | define |
|:------:|:-------------------|
| 0x00 | AD56X8_PWR_NORMAL |
| 0x01 | AD56X8_PWR_1K |
| 0x02 | AD56X8_PWR_100K |
| 0x03 | AD56X8_PWR_TRI |
#### Misc
- **void reset()** software reset.
- **bool setClearCode(uint8_t CCmode)** Set the startup value.
CCmode = 0..3, see table below.
Returns false if mode out of range.
| mode | define | notes |
|:------:|:-------------------|:--------|
| 0x00 | AD56X8_CC_0000 |
| 0x01 | AD56X8_CC_8000 |
| 0x02 | AD56X8_CC_FFFF |
| 0x03 | AD56X8_CC_NOP | do not use => Read datasheet.
#### SPI
- **void setSPIspeed(uint32_t speed)** sets SPI clock in **Hz**, please read datasheet
of the ADC first to get optimal speed.
- **uint32_t getSPIspeed()** gets current speed in **Hz**.
- **bool usesHWSPI()** returns true if HW SPI is used.
#### SPI ESP32 specific
("inherited" from MPC_DAC library)
- **void selectHSPI()** in case hardware SPI, the ESP32 has two options HSPI and VSPI.
- **void selectVSPI()** see above.
- **bool usesHSPI()** returns true if HSPI is used.
- **bool usesVSPI()** returns true if VSPI is used.
The **selectVSPI()** or the **selectHSPI()** needs to be called
BEFORE the **begin()** function.
(experimental)
- **void setGPIOpins(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t select)**
overrule GPIO pins of ESP32 for hardware SPI. needs to be called AFTER the **begin()** function.
Note: earlier experiments shows that on a ESP32 SW-SPI is equally fast as HW-SPI and in fact a bit more stable.
The SW pulses are a bit slower than the HW pulses and therefore more square. The HW-SPI has some overhead SW-SPI hasn't.
### Derived classes (preferred use)
The parameters for the specific constructors are identical
to the base class.
- **AD5668_3(..)** constructor, 16 bit.
Starts up at **midscale = 32768**.
- **AD5668(..)** constructor, 16 bit.
- **AD5648(..)** constructor, 14 bit.
- **AD5628(..)** constructor, 12 bit.
## Operation
The examples (should) show the basic working of the functions.
Note that the library is not tested with hardware yet.
(based upon datasheet)
## Future
#### Must
- update and improve documentation
- get test hardware
- test the library
- write unit test
- check TODO's in code
#### Should
- write examples
- get/setValue
- LDAC
- power mode
- support for RESET pin
- support for LDAC pin
- support for EXTERNAL VREF
- investigate value range checking for AD5648 and AD5628
- now setValue() returns false if value > max,
- should value be clipped instead?
- voltage interface(?)
- convenient.
- **bool loadLDAC()** TODO?
- investigate different type for AD5668_3 (as it does midscale)
#### Could
- CCmode + reset implies start value for getValue(ch)
- is this implementable? costs?

View File

@ -0,0 +1,78 @@
//
// FILE: AD56X8_performance.ino
// AUTHOR: Rob Tillaart
// PUPROSE: performance test
#include "AD56X8.h"
AD56X8 AD16_HW(8);
AD56X8 AD16_SW(9, 10, 11);
uint32_t start, stop;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println(__FILE__);
Serial.print("AD56X8_LIB_VERSION: ");
Serial.println(AD56X8_LIB_VERSION);
AD16_HW.begin();
AD16_SW.begin();
Serial.print("HWSPI: ");
Serial.println(AD16_HW.usesHWSPI());
Serial.print("HWSPI: ");
Serial.println(AD16_SW.usesHWSPI());
delay(10);
// test setValue()
start = micros();
for (uint16_t i = 0; i < 1000; i++)
{
AD16_HW.setValue(0, i);
}
stop = micros();
Serial.print("HW SetValue:\t");
Serial.println((stop - start) * 0.001);
delay(10);
start = micros();
for (uint16_t i = 0; i < 1000; i++)
{
AD16_SW.setValue(0, i);
}
stop = micros();
Serial.print("SW SetValue:\t");
Serial.println((stop - start) * 0.001);
delay(10);
Serial.println("\nHW SPI performance\n------------------");
for (uint32_t speed = 100000; speed <= 16000000; speed *= 2)
{
AD16_HW.setSPIspeed(speed);
start = micros();
for (uint16_t i = 0; i < 1000; i++)
{
AD16_HW.setValue(0, i);
}
stop = micros();
Serial.print(speed);
Serial.print("\tHW SetValue:\t");
Serial.println((stop - start) * 0.001);
delay(10);
}
Serial.println("\nDone...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,25 @@
IDE: 1.18.19
BOARD: UNO
AD56X8_performance.ino
AD56X8_LIB_VERSION: 0.1.1
HWSPI: 1
HWSPI: 0
HW SetValue: 21.76
SW SetValue: 470.85
HW SPI performance
------------------
100K HW SetValue: 273.79
200K HW SetValue: 273.75
400K HW SetValue: 146.28
800K HW SetValue: 81.92
1600K HW SetValue: 49.78
3200K HW SetValue: 33.81
6400K HW SetValue: 25.77
12800K HW SetValue: 21.76
Done...
---------------------------------------

View File

@ -0,0 +1,36 @@
//
// FILE: AD56X8_test.ino
// AUTHOR: Rob Tillaart
// PUPROSE: test
#include "AD56X8.h"
AD56X8 AD16_HW(8);
AD56X8 AD16_SW(9, 10, 11);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println(__FILE__);
Serial.print("AD56X8_LIB_VERSION: ");
Serial.println(AD56X8_LIB_VERSION);
AD16_HW.begin();
AD16_SW.begin();
Serial.print("HWSPI: ");
Serial.println(AD16_HW.usesHWSPI());
Serial.print("HWSPI: ");
Serial.println(AD16_SW.usesHWSPI());
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,57 @@
# Syntax Colouring Map For AD56X8
# Data types (KEYWORD1)
AD56X8 KEYWORD1
AD5668 KEYWORD1
AD5648 KEYWORD1
AD5628 KEYWORD1
# Methods and Functions (KEYWORD2)
begin KEYWORD2
getType
setValue KEYWORD2
getValue KEYWORD2
prepareChannel KEYWORD2
updateChannel KEYWORD2
updateAllChannels KEYWORD2
setLDACmask KEYWORD2
getLDACmask KEYWORD2
inLDACmask KEYWORD2
setPowerDown KEYWORD2
reset KEYWORD2
setClearCode KEYWORD2
setSPIspeed KEYWORD2
getSPIspeed KEYWORD2
usesHWSPI KEYWORD2
selectHSPI KEYWORD2
selectVSPI KEYWORD2
usesHSPI KEYWORD2
usesVSPI KEYWORD2
setGPIOpins KEYWORD2
# Constants (LITERAL1)
AD56X8_LIB_VERSION LITERAL1
AD56X8_PWR_NORMAL LITERAL1
AD56X8_PWR_1K LITERAL1
AD56X8_PWR_100K LITERAL1
AD56X8_PWR_TRI LITERAL1
AD56X8_CC_0000 LITERAL1
AD56X8_CC_8000 LITERAL1
AD56X8_CC_FFFF LITERAL1
AD56X8_CC_NOP LITERAL1

View File

@ -0,0 +1,23 @@
{
"name": "AD56X8",
"keywords": "AD5668, AD5648, AD5628, DAC, SPI",
"description": "Arduino library for AD56X8, SPI 8 channel Digital Analog Convertor.",
"authors":
[
{
"name": "Rob Tillaart",
"email": "Rob.Tillaart@gmail.com",
"maintainer": true
}
],
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/AD56X8.git"
},
"version": "0.1.1",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",
"headers": "AD56X8.h"
}

View File

@ -0,0 +1,11 @@
name=AD56X8
version=0.1.1
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for AD56X8, SPI 8 channel Digital Analog Convertor.
paragraph=Supports AD5668, AD5648, AD5628, DAC, SPI.
category=Signal Input/Output
url=https://github.com/RobTillaart/AD56X8
architectures=*
includes=AD56X8.h
depends=

View File

@ -0,0 +1,186 @@
//
// FILE: unit_test_001.cpp
// AUTHOR: Rob Tillaart
// DATE: 2022-07-28
// PURPOSE: unit tests for the AD56X8 DA convertor.
// https://github.com/RobTillaart/AD56X8
// 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 <ArduinoUnitTests.h>
#include "Arduino.h"
#include "AD56X8.h"
unittest_setup()
{
fprintf(stderr, "AD56X8_LIB_VERSION: %s\n", (char *) AD56X8_LIB_VERSION);
}
unittest_teardown()
{
}
unittest(constant)
{
assertEqual(0x00, AD56X8_PWR_NORMAL );
assertEqual(0x01, AD56X8_PWR_1K );
assertEqual(0x02, AD56X8_PWR_100K );
assertEqual(0x03, AD56X8_PWR_TRI_STATE );
assertEqual(0x00, AD56X8_CC_0000 );
assertEqual(0x01, AD56X8_CC_8000 );
assertEqual(0x02, AD56X8_CC_FFFF );
assertEqual(0x03, AD56X8_CC_NOP );
}
unittest(constructors)
{
AD56X8 AD0(8);
AD5668 AD16(9);
AD5648 AD14(10, 11, 12);
AD5628 AD12(4, 5, 6);
AD5668_3 AD16M(7, 3, 2);
assertTrue(AD0.usesHWSPI());
assertTrue(AD16.usesHWSPI());
assertFalse(AD14.usesHWSPI());
assertFalse(AD12.usesHWSPI());
assertFalse(AD16M.usesHWSPI());
}
unittest(get_type)
{
AD56X8 AD0(8);
AD5668 AD16(9);
AD5648 AD14(10, 11, 12);
AD5628 AD12(4, 5, 6);
AD5668_3 AD16M(7);
assertEqual(0, AD0.getType());
assertEqual(16, AD16.getType());
assertEqual(14, AD14.getType());
assertEqual(12, AD12.getType());
assertEqual(16, AD16M.getType());
}
unittest(get_setValue)
{
AD56X8 AD0(8);
AD0.begin();
// valid channels
for (uint8_t chan = 0; chan < 8; chan++)
{
assertTrue(AD0.setValue(chan, chan * 100));
}
for (uint8_t chan = 0; chan < 8; chan++)
{
assertEqual(chan * 100, AD0.getValue(chan));
}
// channel out of range test.
assertFalse(AD0.setValue(8, 0));
}
unittest(get_PowerUpValue)
{
AD56X8 AD0(8);
AD5668_3 AD16M(7);
AD0.begin();
AD16M.begin();
// valid channels 0 Volts
for (uint8_t chan = 0; chan < 8; chan++)
{
assertEqual(0, AD0.getValue(chan));
}
// valid channels 0 Volts
for (uint8_t chan = 0; chan < 8; chan++)
{
assertEqual(32768, AD16M.getValue(chan));
}
// invalid channel returns 0.
assertEqual(0, AD16M.getValue(8));
}
unittest(prepareChannel)
{
AD56X8 AD0(8);
AD0.begin();
// valid channels
for (uint8_t chan = 0; chan < 8; chan++)
{
assertTrue(AD0.prepareChannel(chan, chan * 100));
}
for (uint8_t chan = 0; chan < 8; chan++)
{
assertEqual(chan * 100, AD0.getValue(chan));
}
// channel out of range test.
assertFalse(AD0.prepareChannel(8, 0));
}
unittest(set_power_mode)
{
AD56X8 AD0(8);
AD0.begin();
assertTrue(AD0.setPowerMode(0, 0));
assertTrue(AD0.setPowerMode(1, 0));
assertTrue(AD0.setPowerMode(2, 0));
assertTrue(AD0.setPowerMode(3, 0));
// powerMode out of range test.
assertFalse(AD0.setPowerMode(4, 0));
}
unittest(set_clear_code)
{
AD56X8 AD0(8);
AD0.begin();
assertTrue(AD0.setClearCode(0));
assertTrue(AD0.setClearCode(1));
assertTrue(AD0.setClearCode(2));
// CCMode out of range test.
assertFalse(AD0.setClearCode(4));
}
unittest_main()
// -- END OF FILE --