0.2.0 AD56X8

This commit is contained in:
Rob Tillaart 2023-11-27 13:57:22 +01:00
parent 675e9eb012
commit 47494fb848
10 changed files with 195 additions and 183 deletions

View File

@ -1,7 +1,7 @@
//
// FILE: AD56X8.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.4
// VERSION: 0.2.0
// DATE: 2022-07-28
// PURPOSE: Arduino library for AD56X8, SPI 8 channel Digital Analog Convertor.
@ -21,22 +21,23 @@
#define AD56X8_REG_SETUP_REF 0x08 // not implemented
AD56X8::AD56X8(uint8_t slaveSelect)
// HARDWARE SPI
AD56X8::AD56X8(uint8_t slaveSelect, __SPI_CLASS__ * mySPI)
{
_hwSPI = true;
_select = slaveSelect;
_hwSPI = true;
_mySPI = mySPI;
for (int i = 0; i < 8; i++) _value[i] = 0;
}
AD56X8::AD56X8(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect)
// SOFTWARE SPI
AD56X8::AD56X8(uint8_t slaveSelect, uint8_t spiData, uint8_t spiClock)
{
_select = slaveSelect;
_hwSPI = false;
_mySPI = NULL;
_dataOut = spiData;
_clock = spiClock;
_select = slaveSelect;
for (int i = 0; i < 8; i++) _value[i] = 0;
}
@ -52,37 +53,17 @@ void AD56X8::begin()
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
_mySPI->end();
_mySPI->begin();
delay(1);
}
else // software SPI
else // SOFTWARE SPI
{
pinMode(_dataOut, OUTPUT);
pinMode(_clock, OUTPUT);
digitalWrite(_dataOut, LOW);
digitalWrite(_clock, LOW);
}
// TODO RESET REGISTERS
// _register = 0;
// _value = 0;
}
@ -244,48 +225,6 @@ bool AD56X8::usesHWSPI()
}
// ESP32 specific
#if defined(ESP32)
void AD56X8::selectHSPI()
{
_useHSPI = true;
}
void AD56X8::selectVSPI()
{
_useHSPI = false;
}
bool AD56X8::usesHSPI()
{
return _useHSPI;
}
bool AD56X8::usesVSPI()
{
return !_useHSPI;
}
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
//////////////////////////////////////////////////////////////////
//
// PRIVATE
@ -309,12 +248,12 @@ 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();
_mySPI->beginTransaction(_spi_settings);
_mySPI->transfer(a);
_mySPI->transfer(b);
_mySPI->transfer(c);
_mySPI->transfer(d);
_mySPI->endTransaction();
}
else // Software SPI
{
@ -345,15 +284,15 @@ void AD56X8::swSPI_transfer(uint8_t value)
//
// DERIVED CLASSES
//
AD5668_3::AD5668_3(uint8_t slaveSelect) : AD56X8(slaveSelect)
AD5668_3::AD5668_3(uint8_t slaveSelect, __SPI_CLASS__ * mySPI) : AD56X8(slaveSelect, mySPI)
{
_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)
AD5668_3::AD5668_3(uint8_t slaveSelect, uint8_t spiData, uint8_t spiClock)
: AD56X8(slaveSelect, spiData, spiClock)
{
_type = 16;
// AD5668_3 starts up at midscale
@ -368,40 +307,38 @@ void AD5668_3::reset()
}
AD5668::AD5668(uint8_t slaveSelect) : AD56X8(slaveSelect)
AD5668::AD5668(uint8_t slaveSelect, __SPI_CLASS__ * mySPI) : AD56X8(slaveSelect, mySPI)
{
_type = 16;
}
AD5668::AD5668(uint8_t slaveSelect, uint8_t spiData, uint8_t spiClock)
: AD56X8(slaveSelect, spiData, spiClock)
{
_type = 16;
}
AD5668::AD5668(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect)
: AD56X8(spiData, spiClock, slaveSelect)
AD5648::AD5648(uint8_t slaveSelect, __SPI_CLASS__ * mySPI) : AD56X8(slaveSelect, mySPI)
{
_type = 16;
_type = 14;
}
AD5648::AD5648(uint8_t slaveSelect) : AD56X8(slaveSelect)
AD5648::AD5648(uint8_t slaveSelect, uint8_t spiData, uint8_t spiClock)
: AD56X8(slaveSelect, spiData, spiClock)
{
_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)
AD5628::AD5628(uint8_t slaveSelect, __SPI_CLASS__ * mySPI) : AD56X8(slaveSelect, mySPI)
{
_type = 12;
}
AD5628::AD5628(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect)
: AD56X8(spiData, spiClock, slaveSelect)
AD5628::AD5628(uint8_t slaveSelect, uint8_t spiData, uint8_t spiClock)
: AD56X8(slaveSelect, spiData, spiClock)
{
_type = 12;
}

View File

@ -2,7 +2,7 @@
//
// FILE: AD56X8.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.4
// VERSION: 0.2.0
// DATE: 2022-07-28
// PURPOSE: Arduino library for AD56X8, SPI 8 channel Digital Analog Convertor.
@ -10,7 +10,14 @@
#include "Arduino.h"
#include "SPI.h"
#define AD56X8_LIB_VERSION (F("0.1.4"))
#define AD56X8_LIB_VERSION (F("0.2.0"))
#if defined(ARDUINO_ARCH_RP2040)
#define __SPI_CLASS__ SPIClassRP2040
#else
#define __SPI_CLASS__ SPIClass
#endif
#define AD56X8_PWR_NORMAL 0x00
@ -25,12 +32,13 @@
#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);
// HARDWARE SPI
AD56X8(uint8_t slaveSelect, __SPI_CLASS__ * mySPI = &SPI);
// SOFTWARE SPI
AD56X8(uint8_t slaveSelect, uint8_t spiData, uint8_t spiClock);
void begin();
uint8_t getType();
@ -80,17 +88,6 @@ public:
uint32_t getSPIspeed();
bool usesHWSPI();
// ESP32 specific
#if defined(ESP32)
void selectHSPI();
void selectVSPI();
bool usesHSPI();
bool usesVSPI();
// 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
@ -109,12 +106,8 @@ protected:
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
__SPI_CLASS__ * _mySPI;
SPISettings _spi_settings;
};
@ -125,8 +118,10 @@ protected:
class AD5668_3 : public AD56X8
{
public:
AD5668_3(uint8_t slaveSelect);
AD5668_3(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect);
// HARDWARE SPI
AD5668_3(uint8_t slaveSelect, __SPI_CLASS__ * mySPI = &SPI);
// SOFTWARE SPI
AD5668_3(uint8_t slaveSelect, uint8_t spiData, uint8_t spiClock);
void reset();
};
@ -135,24 +130,30 @@ public:
class AD5668 : public AD56X8
{
public:
AD5668(uint8_t slaveSelect);
AD5668(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect);
// HARDWARE SPI
AD5668(uint8_t slaveSelect, __SPI_CLASS__ * mySPI = &SPI);
// SOFTWARE SPI
AD5668(uint8_t slaveSelect, uint8_t spiData, uint8_t spiClock);
};
class AD5648 : public AD56X8
{
public:
AD5648(uint8_t slaveSelect);
AD5648(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect);
// HARDWARE SPI
AD5648(uint8_t slaveSelect, __SPI_CLASS__ * mySPI = &SPI);
// SOFTWARE SPI
AD5648(uint8_t slaveSelect, uint8_t spiData, uint8_t spiClock);
};
class AD5628 : public AD56X8
{
public:
AD5628(uint8_t slaveSelect);
AD5628(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect);
// HARDWARE SPI
AD5628(uint8_t slaveSelect, __SPI_CLASS__ * mySPI = &SPI);
// SOFTWARE SPI
AD5628(uint8_t slaveSelect, uint8_t spiData, uint8_t spiClock);
};

View File

@ -5,6 +5,14 @@ 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.2.0] - 2023-11-27
- refactor constructor interface - breaking changes.
- minimize conditional code. -- create SPI_CLASS macro to solve it.
- reordered parameters software SPI constructor.
- update readme.md
- update examples
----
## [0.1.4] - 2023-09-19
- add hardware LDAC support

View File

@ -44,6 +44,16 @@ At least it lacks support for:
- other points mentioned in future section below.
#### 0.2.0 breaking change
The version 0.2.0 has breaking changes in the interface.
The essence is removal of ESP32 specific code from the library.
This makes it possible to support the ESP32-S3 and other processors in the future.
Also it makes the library a bit simpler to maintain.
Note the order of the parameters of the software SPI constructor has changed in 0.2.0.
## Related
This library is partly inspired by https://github.com/bobhart/AD5668-Library, kudo's to Bob!
@ -52,9 +62,8 @@ Discussed here - https://forum.arduino.cc/t/new-library-for-the-ad5668-dac/34039
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.
This allows value range checking.
- 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
@ -75,18 +84,32 @@ This allows value range checking in the future. Not Implemented Yet.
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.
- **AD56X8(uint8_t slaveSelect, SPIClassRP2040 \* mySPI = &SPI)** constructor HW SPI (RP2040 specific).
Sets internal value to zero.
- **AD56X8(uint8_t slaveSelect, SPIClass \* mySPI = &SPI)** constructor HW SPI.
Sets internal value to zero.
- **AD56X8(uint8_t spiData, uint8_t spiClock, uint8_t slaveSelect)** constructor,
sets SW SPI.
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.
- **void begin()** initializes the SPI and sets internal state.
- **uint8_t getType()** returns bit depth (see below).
#### Derived classes (preferred use)
The parameters for the specific constructors are identical to the base class.
One should use these, as these set the bit resolution!
- **AD5628(uint8_t slaveSelect, ..)** constructor, 16 bit. Starts up at **midscale = 32768**.
- **AD5648(uint8_t slaveSelect, ..)** constructor, 14 bit.
- **AD5668(uint8_t slaveSelect, ..)** constructor, 16 bit.
- **AD5668_3(uint8_t slaveSelect, ..)** constructor, 16 bit.
#### Set DAC
- **bool setValue(uint8_t channel, uint16_t value)** set value to the output immediately, effectively a prepare + update in one call.
- **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).
@ -96,7 +119,8 @@ At power up the DAC's will be reset to 0 V except the AD5668-3 (2.5V).
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).
- **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.
@ -164,34 +188,10 @@ of the ADC first to get optimal speed.
#### 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.
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.
## Operation
@ -210,10 +210,7 @@ Note that the library is not tested with hardware yet.
- test the library
- write unit test
- check TODO in code
- investigate different type for AD5668_3
- it does midscale
- need different reset?
- keep in sync with AD5680 + AD568X library
#### Should
@ -226,7 +223,6 @@ Note that the library is not tested with hardware yet.
- support for EXTERNAL VREF
- how?
#### Could
- CCmode + reset implies start value for getValue(ch)
@ -239,7 +235,7 @@ Note that the library is not tested with hardware yet.
- should value be clipped instead?
- **setPercentage()** idem.
- user responsibility
## Support

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,50 @@
//
// FILE: AD56X8_test_ESP32.ino
// AUTHOR: Rob Tillaart
// PUPROSE: test
#include "AD56X8.h"
#ifndef ESP32
#error ESP32 only example, please select appropriate board
#endif
// HSPI uses default SCLK=14, MISO=12, MOSI=13, SELECT=15
// VSPI uses default SCLK=18, MISO=19, MOSI=23, SELECT=5
SPIClass * myspi = new SPIClass(VSPI);
AD56X8 AD16_HW(5, myspi);
AD56X8 AD16_SW(15, 13, 14);
int value = 0;
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()
{
AD16_SW.setValue(0, value);
value++;
if (value == 4096) value = 0;
Serial.println(value);
delay(10);
}
// -- END OF FILE --

View File

@ -33,19 +33,11 @@ setPowerMode 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

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/AD56X8.git"
},
"version": "0.1.4",
"version": "0.2.0",
"license": "MIT",
"frameworks": "*",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=AD56X8
version=0.1.4
version=0.2.0
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.

View File

@ -210,4 +210,4 @@ unittest(set_clear_code)
unittest_main()
// -- END OF FILE --
// -- END OF FILE --