From 3188e13658504dab2667e3dd7eaa5c745e0d65e1 Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Mon, 16 Oct 2023 15:40:00 +0200 Subject: [PATCH] 0.3.6 AD985X --- libraries/AD985X/AD985X.cpp | 19 ++-- libraries/AD985X/AD985X.h | 29 +++--- libraries/AD985X/CHANGELOG.md | 9 +- libraries/AD985X/README.md | 48 ++++++---- .../AD9850_ESP32_HWSPI/.arduino-ci.yml | 27 ++++++ .../AD9850_ESP32_HWSPI/AD9850_ESP32_HWSPI.ino | 96 +++++++++++++++++++ libraries/AD985X/library.json | 4 +- libraries/AD985X/library.properties | 2 +- libraries/AD985X/test/unit_test_001.cpp | 58 ++++++++++- 9 files changed, 247 insertions(+), 45 deletions(-) create mode 100644 libraries/AD985X/examples/AD9850_ESP32_HWSPI/.arduino-ci.yml create mode 100644 libraries/AD985X/examples/AD9850_ESP32_HWSPI/AD9850_ESP32_HWSPI.ino diff --git a/libraries/AD985X/AD985X.cpp b/libraries/AD985X/AD985X.cpp index fe4a9e16..53aafb48 100644 --- a/libraries/AD985X/AD985X.cpp +++ b/libraries/AD985X/AD985X.cpp @@ -1,19 +1,17 @@ // // FILE: AD985X.cpp // AUTHOR: Rob Tillaart -// VERSION: 0.3.4 +// VERSION: 0.3.6 // DATE: 2019-02-08 // PURPOSE: Class for AD9850 and AD9851 function generator // URL: https://github.com/RobTillaart/AD985X -// -// HISTORY: see changelog.md #include "AD985X.h" // UNO HARDWARE SPI PINS -#define SPI_CLOCK 13 // not portable... +#define SPI_CLOCK 13 // not portable. #define SPI_MISO 12 #define SPI_MOSI 11 @@ -58,13 +56,13 @@ void AD9850::begin(uint8_t select, uint8_t resetPin, uint8_t FQUDPin, uint8_t da { mySPI = new SPIClass(HSPI); mySPI->end(); - mySPI->begin(14, 12, 13, select); // CLK=14 MISO=12 MOSI=13 + 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 + mySPI->begin(18, 19, 23, select); // CLK = 18 MISO = 19 MOSI = 23 } #else // generic hardware SPI mySPI = &SPI; @@ -143,8 +141,8 @@ void AD9850::powerUp() bool AD9850::setPhase(uint8_t phase) { if (phase > 31) return false; - _config &= 0x07; - _config |= (phase << 3); + _config &= 0x07; // keep last three bits + _config |= (phase << 3); // set new phase writeData(); return true; } @@ -176,7 +174,8 @@ void AD9850::writeData() // Serial.println(_config, HEX); uint32_t data = _factor; - // used for multi device configuration only - https://github.com/RobTillaart/AD985X/issues/13 + // used for multi device configuration only + // see https://github.com/RobTillaart/AD985X/issues/13 digitalWrite(_select, HIGH); if (_hwSPI) { @@ -233,7 +232,7 @@ bool AD9850::setFrequency(uint32_t freq) rv = false; freq = AD9850_MAX_FREQ; } - // _factor = round(freq * 34.359738368); // 4294967296 / 125000000 + // _factor = round(freq * 34.359738368); // 4294967296 / 125000000 _factor = (147573952589ULL * freq) >> 32; _freq = freq; _factor += _offset; diff --git a/libraries/AD985X/AD985X.h b/libraries/AD985X/AD985X.h index 25c55130..dc1d1f2d 100644 --- a/libraries/AD985X/AD985X.h +++ b/libraries/AD985X/AD985X.h @@ -2,7 +2,7 @@ // // FILE: AD985X.h // AUTHOR: Rob Tillaart -// VERSION: 0.3.5 +// VERSION: 0.3.6 // DATE: 2019-02-08 // PURPOSE: Class for AD9850 and AD9851 function generator // URL: https://github.com/RobTillaart/AD985X @@ -12,13 +12,19 @@ #include "SPI.h" -#define AD985X_LIB_VERSION (F("0.3.5")) +#define AD985X_LIB_VERSION (F("0.3.6")) -#define AD9850_MAX_FREQ (40UL * 1000UL * 1000UL) -#define AD9851_MAX_FREQ (70UL * 1000UL * 1000UL) +#define AD9850_MAX_FREQ (40UL * 1000UL * 1000UL) +#define AD9851_MAX_FREQ (70UL * 1000UL * 1000UL) + +#define AD9851_ARC_CUTOFF_FREQ (10000000UL) +///////////////////////////////////////////////////////////////////// +// +// BASE CLASS AD9850 +// class AD9850 { public: @@ -46,12 +52,12 @@ public: // offset to calibrate the frequency (internal counter) // offset must be stored by the user. void setCalibration(int32_t offset = 0) { _offset = offset; }; - int32_t getCalibration() { return _offset; }; + int32_t getCalibration() { return _offset; }; // autoUpdate is default true; void setAutoUpdate(bool update = true) { _autoUpdate = update; }; - bool getAutoUpdate() { return _autoUpdate; }; + bool getAutoUpdate() { return _autoUpdate; }; void update(); @@ -62,7 +68,7 @@ public: // debugging bool usesHWSPI() { return _hwSPI; }; // internal chip factor used for frequency. (debugging only) - uint32_t getFactor() { return _factor; }; + uint32_t getFactor() { return _factor; }; // ESP32 specific @@ -110,7 +116,7 @@ protected: ///////////////////////////////////////////////////////////////////// // -// DERIVED CLASS +// DERIVED CLASS AD9851 // class AD9851 : public AD9850 { @@ -132,16 +138,17 @@ public: // 10 MHz is default, set in Hz. // will be kept <= 30 MHz as that is the freq of LOW mode. - void setARCCutOffFreq(uint32_t Hz = 10000000UL ); + // ARC = AutoRefClock + void setARCCutOffFreq(uint32_t Hz = AD9851_ARC_CUTOFF_FREQ); uint32_t getARCCutOffFreq(); protected: bool _autoRefClock = false; - uint32_t _ARCCutOffFreq = 10000000UL; + uint32_t _ARCCutOffFreq = AD9851_ARC_CUTOFF_FREQ; }; -// -- END OF FILE -- +// -- END OF FILE -- diff --git a/libraries/AD985X/CHANGELOG.md b/libraries/AD985X/CHANGELOG.md index 9e99cb00..c3994e91 100644 --- a/libraries/AD985X/CHANGELOG.md +++ b/libraries/AD985X/CHANGELOG.md @@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.3.6] - 2023-10-15 +- add ESP32 HSPI example +- add unit tests for setFrequency setFrequencyF +- update readme.md +- fix version number in .cpp +- minor edits + + ## [0.3.5] - 2023-01-11 - update GitHub actions - update license @@ -13,7 +21,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - add bool return value to setPhase() - add test_constants in unit test - ## [0.3.4] - 2022-10-25 - add changelog.md - add RP2040 in build-CI diff --git a/libraries/AD985X/README.md b/libraries/AD985X/README.md index 21d48a1f..f581c69b 100644 --- a/libraries/AD985X/README.md +++ b/libraries/AD985X/README.md @@ -1,9 +1,12 @@ [![Arduino CI](https://github.com/RobTillaart/AD985X/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci) -[![JSON check](https://github.com/RobTillaart/AD985X/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/AD985X/actions/workflows/jsoncheck.ym)l [![Arduino-lint](https://github.com/RobTillaart/AD985X/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/AD985X/actions/workflows/arduino-lint.yml) +[![JSON check](https://github.com/RobTillaart/AD985X/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/AD985X/actions/workflows/jsoncheck.yml) +[![GitHub issues](https://img.shields.io/github/issues/RobTillaart/AD985X.svg)](https://github.com/RobTillaart/AD985X/issues) + [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/AD985X/blob/master/LICENSE) [![GitHub release](https://img.shields.io/github/release/RobTillaart/AD985X.svg?maxAge=3600)](https://github.com/RobTillaart/AD985X/releases) +[![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/AD985X.svg)](https://registry.platformio.org/libraries/robtillaart/AD985X) # AD985X @@ -16,13 +19,13 @@ Arduino library for AD9850 and AD9851 function generators. Library for the AD9850 and AD9851 function generators. These devices can produce a square and a sine wave -| type | max frequency | phase (stepsize) | -|:---------|---------------:|-------------------:| -| AD9850 | 40 MHz | 0..31 x 11.25° | -| AD9851 | 70 MHz | 0..31 x 11.25° | +| type | max frequency | phase (step size) | +|:--------:|:--------------:|:-------------------:| +| AD9850 | 40 MHz | 0..31 x 11.25° | +| AD9851 | 70 MHz | 0..31 x 11.25° | -Note that at the max frequency the devices do not give a nice sine anymore. +Note that at the max frequency the devices do not give a nice sine any more. You need to check what is acceptable for your project. The library has a AD9850 as base class that implements the commonalities. @@ -64,7 +67,6 @@ Schema break-out L = LED C = chip P = potentiometer => for duty cycle square wave - ``` @@ -191,13 +193,17 @@ For the AD9850 => 40 MHz, for the AD9851 => 70 MHz. - Note setFrequencyF is affected by the autoUpdateFlag. The frequency is limited by the MaxFrequency of the class used. Returns false if limited. -- **uint32_t getMaxFrequency()** returns the maximum frequency that can be set. For the AD9850 this is 20 MHz. -For the AD9851 this is 70 MHz. -- **float getFrequency()** returns the frequency set. As it returns a float it might loose some accuracy at higher frequencies. +- **uint32_t getMaxFrequency()** returns the maximum frequency that can be set. + - For the AD9850 this is 20 MHz. + - For the AD9851 this is 70 MHz. +- **float getFrequency()** returns the frequency set. +As it returns a float it might loose some accuracy at higher frequencies. - **bool setPhase(uint8_t phase = 0)** set the phase in units of 11.25° 0..31 allowed. Default it sets the phase to 0. Returns false if phase > 31, no change to phase in that case. -- **uint8_t getPhase()** returns the phase set, 0 by default. One need to multiply by 11.25° to get the actual angle. +- **uint8_t getPhase()** returns the phase set, 0 by default. + - multiply by 11.25° to get the actual phase angle in degrees. + - multiply by (PI \* 0.0625) to get actual phase angle in radians. ### Calibration @@ -313,20 +319,28 @@ The user is also responsible to store it e.g. in EEPROM to make it persistent. #### Should -- examples for ESP32 HWSPI interface - do tests on ESP32 - performance measurements -- unit tests for - - bool setFrequency - - bool setPhase + #### Could - move code to .cpp - create defines for MAGIC numbers (defaults) -- should other void function return bool? - - setARCCutOffFreq() ? +- should **setSPIspeed(uint32_t speed)** return bool? + - out of range? #### Wont +- **bool setARCCutOffFreq()** no need + + +## 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/AD985X/examples/AD9850_ESP32_HWSPI/.arduino-ci.yml b/libraries/AD985X/examples/AD9850_ESP32_HWSPI/.arduino-ci.yml new file mode 100644 index 00000000..0d87f62c --- /dev/null +++ b/libraries/AD985X/examples/AD9850_ESP32_HWSPI/.arduino-ci.yml @@ -0,0 +1,27 @@ +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 diff --git a/libraries/AD985X/examples/AD9850_ESP32_HWSPI/AD9850_ESP32_HWSPI.ino b/libraries/AD985X/examples/AD9850_ESP32_HWSPI/AD9850_ESP32_HWSPI.ino new file mode 100644 index 00000000..721832b6 --- /dev/null +++ b/libraries/AD985X/examples/AD9850_ESP32_HWSPI/AD9850_ESP32_HWSPI.ino @@ -0,0 +1,96 @@ +// +// FILE: AD9850_ESP32_HWSPI.ino +// AUTHOR: Rob Tillaart +// PURPOSE: demo ESP32 hardware SPI +// URL: https://github.com/RobTillaart/AD985X + + +#include "AD985X.h" + +AD9850 freqGen; + +uint32_t freq = 0; +uint32_t prev = 0; +uint32_t maxFreq; + + +void setup() +{ + Serial.begin(115200); + Serial.println(__FILE__); + Serial.print("AD985X_LIB_VERSION: \t"); + Serial.println(AD985X_LIB_VERSION); + + help(); + + // Select HW SPI for ESP32 + freqGen.selectHSPI(); + freqGen.begin(15, 16, 17); // selectPin, resetPin, FQUDPin + + freqGen.powerUp(); + maxFreq = freqGen.getMaxFrequency(); + Serial.println(maxFreq); +} + + +void loop() +{ + if (Serial.available() > 0) + { + int c = Serial.read(); + switch (c) + { + case '?' : + help(); + break; + case 'R' : + freqGen.reset(); + freq = freqGen.getFrequency(); + break; + case 'P' : + freqGen.powerDown(); + break; + case 'U' : + freqGen.powerUp(); + break; + case '+' : + freq += 1; + break; + case '-' : + freq -= 1; + break; + case '*' : + freq *= 10; + break; + case '/' : + freq /= 10; + break; + } + if (freq > maxFreq) freq = maxFreq; + } + + // UPDATE AD985X IF NEW VALUE + if (prev != freq) + { + prev = freq; + freqGen.setFrequency(freq); + Serial.println(freq); + } +} + + +void help() +{ + Serial.println(); + Serial.println("+ : f = f + 1"); + Serial.println("- : f = f - 1"); + Serial.println("* : f = f * 10"); + Serial.println("/ : f = f / 10"); + Serial.println("? : help"); + Serial.println("R : AD9850 reset"); + Serial.println("P : AD9850 power down"); + Serial.println("U : AD9850 power up"); + Serial.println(); +} + +// -- END OF FILE -- diff --git a/libraries/AD985X/library.json b/libraries/AD985X/library.json index 3c034be0..47ffe457 100644 --- a/libraries/AD985X/library.json +++ b/libraries/AD985X/library.json @@ -15,9 +15,9 @@ "type": "git", "url": "https://github.com/RobTillaart/AD985X.git" }, - "version": "0.3.5", + "version": "0.3.6", "license": "MIT", - "frameworks": "arduino", + "frameworks": "*", "platforms": "*", "headers": "AD985X.h" } diff --git a/libraries/AD985X/library.properties b/libraries/AD985X/library.properties index 59ef543a..10d0d601 100644 --- a/libraries/AD985X/library.properties +++ b/libraries/AD985X/library.properties @@ -1,5 +1,5 @@ name=AD985X -version=0.3.5 +version=0.3.6 author=Rob Tillaart maintainer=Rob Tillaart sentence=Arduino library for AD9850 and AD9851 function generators. Supports both hardware SPI as software SPI. diff --git a/libraries/AD985X/test/unit_test_001.cpp b/libraries/AD985X/test/unit_test_001.cpp index 372c6eb6..3e723f97 100644 --- a/libraries/AD985X/test/unit_test_001.cpp +++ b/libraries/AD985X/test/unit_test_001.cpp @@ -74,7 +74,59 @@ unittest(test_auto_update) } -unittest(test_ad9850) +unittest(test_ad9850_frequency) +{ + AD9850 funcgen; + funcgen.begin(4, 5, 6); + + for (uint32_t freq = 500; freq <= 10000; freq += 500) + { + funcgen.setFrequency(freq); + assertEqual(freq, funcgen.getFrequency()); + } +} + + +unittest(test_ad9851_frequency) +{ + AD9851 funcgen; + funcgen.begin(4, 5, 6); + + for (uint32_t freq = 500; freq <= 10000; freq += 500) + { + funcgen.setFrequency(freq); + assertEqual(freq, funcgen.getFrequency()); + } +} + + +unittest(test_ad9850_frequency_float) +{ + AD9850 funcgen; + funcgen.begin(4, 5, 6); + + for (float freq = 1; freq <= 5; freq += 0.31415) + { + funcgen.setFrequencyF(freq); + assertEqualFloat(freq, funcgen.getFrequency(), 0.01); + } +} + + +unittest(test_ad9851_frequency_float) +{ + AD9851 funcgen; + funcgen.begin(4, 5, 6); + + for (float freq = 1; freq <= 5; freq += 0.31415) + { + funcgen.setFrequencyF(freq); + assertEqualFloat(freq, funcgen.getFrequency(), 0.01); + } +} + + +unittest(test_ad9850_phase) { AD9850 funcgen; funcgen.begin(4, 5, 6); @@ -92,7 +144,7 @@ unittest(test_ad9850) } -unittest(test_ad9851) +unittest(test_ad9851_phase) { AD9851 funcgen; funcgen.begin(4, 5, 6); @@ -215,4 +267,4 @@ unittest(test_ad9851_float_freq) unittest_main() -// -------- +// END OF FILE --