mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
0.3.5 AD985X
This commit is contained in:
parent
78d08d65d2
commit
ec8922a413
@ -6,7 +6,7 @@ jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: arduino/arduino-lint-action@v1
|
||||
with:
|
||||
library-manager: update
|
||||
|
@ -8,7 +8,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 2.6
|
||||
|
@ -10,7 +10,7 @@ jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: json-syntax-check
|
||||
uses: limitusus/json-syntax-check@v1
|
||||
with:
|
||||
|
@ -43,7 +43,7 @@ void AD9850::begin(uint8_t select, uint8_t resetPin, uint8_t FQUDPin, uint8_t da
|
||||
pinMode(_reset, OUTPUT);
|
||||
pinMode(_fqud, OUTPUT);
|
||||
// device select = HIGH See - https://github.com/RobTillaart/AD985X/issues/13
|
||||
digitalWrite(_select, LOW);
|
||||
digitalWrite(_select, LOW);
|
||||
digitalWrite(_reset, LOW);
|
||||
digitalWrite(_fqud, LOW);
|
||||
|
||||
@ -93,7 +93,7 @@ void AD9850::setGPIOpins(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t select
|
||||
pinMode(_select, OUTPUT);
|
||||
digitalWrite(_select, LOW);
|
||||
|
||||
mySPI->end(); // disable SPI
|
||||
mySPI->end(); // disable SPI
|
||||
mySPI->begin(clk, miso, mosi, select);
|
||||
}
|
||||
#endif
|
||||
@ -101,7 +101,7 @@ void AD9850::setGPIOpins(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t select
|
||||
|
||||
void AD9850::reset()
|
||||
{
|
||||
// be sure to select the correct device
|
||||
// be sure to select the correct device
|
||||
digitalWrite(_select, HIGH);
|
||||
pulsePin(_reset);
|
||||
if (_hwSPI)
|
||||
@ -109,7 +109,7 @@ void AD9850::reset()
|
||||
#if defined(ESP32)
|
||||
if (_useHSPI) pulsePin(14); // HSPI magic number clock
|
||||
else pulsePin(18); // VSPI magic number clock
|
||||
#else
|
||||
#else
|
||||
// UNO hardware SPI
|
||||
pulsePin(SPI_CLOCK);
|
||||
#endif
|
||||
@ -140,12 +140,19 @@ void AD9850::powerUp()
|
||||
}
|
||||
|
||||
|
||||
void AD9850::setPhase(uint8_t phase)
|
||||
bool AD9850::setPhase(uint8_t phase)
|
||||
{
|
||||
if (phase > 31) return;
|
||||
if (phase > 31) return false;
|
||||
_config &= 0x07;
|
||||
_config |= (phase << 3);
|
||||
writeData();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint8_t AD9850::getPhase()
|
||||
{
|
||||
return (_config >> 3);
|
||||
}
|
||||
|
||||
|
||||
@ -170,7 +177,7 @@ void AD9850::writeData()
|
||||
uint32_t data = _factor;
|
||||
|
||||
// used for multi device configuration only - https://github.com/RobTillaart/AD985X/issues/13
|
||||
digitalWrite(_select, HIGH);
|
||||
digitalWrite(_select, HIGH);
|
||||
if (_hwSPI)
|
||||
{
|
||||
mySPI->beginTransaction(_spi_settings);
|
||||
@ -216,37 +223,61 @@ void AD9850::swSPI_transfer(uint8_t val)
|
||||
}
|
||||
|
||||
|
||||
void AD9850::setFrequency(uint32_t freq)
|
||||
bool AD9850::setFrequency(uint32_t freq)
|
||||
{
|
||||
bool rv = true;
|
||||
// freq OUT = (Δ Phase × CLKIN)/2^32
|
||||
// 64 bit math to keep precision to the max
|
||||
if (freq > AD9850_MAX_FREQ) freq = AD9850_MAX_FREQ;
|
||||
if (freq > AD9850_MAX_FREQ)
|
||||
{
|
||||
rv = false;
|
||||
freq = AD9850_MAX_FREQ;
|
||||
}
|
||||
// _factor = round(freq * 34.359738368); // 4294967296 / 125000000
|
||||
_factor = (147573952589ULL * freq) >> 32;
|
||||
_freq = freq;
|
||||
_factor += _offset;
|
||||
writeData();
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
// especially for lower frequencies (with decimals)
|
||||
void AD9850::setFrequencyF(float freq)
|
||||
bool AD9850::setFrequencyF(float freq)
|
||||
{
|
||||
bool rv = true;
|
||||
// freq OUT = (Δ Phase × CLKIN)/2^32
|
||||
// 64 bit math to keep precision to the max
|
||||
if (freq > AD9850_MAX_FREQ) freq = AD9850_MAX_FREQ;
|
||||
if (freq > AD9850_MAX_FREQ)
|
||||
{
|
||||
rv = false;
|
||||
freq = AD9850_MAX_FREQ;
|
||||
}
|
||||
_factor = round(freq * 34.359738368); // 4294967296 / 125000000
|
||||
_freq = freq;
|
||||
_factor += _offset;
|
||||
writeData();
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
float AD9850::getFrequency()
|
||||
{
|
||||
return _freq;
|
||||
}
|
||||
|
||||
|
||||
uint32_t AD9850::getMaxFrequency()
|
||||
{
|
||||
return AD9850_MAX_FREQ;
|
||||
}
|
||||
|
||||
|
||||
void AD9850::update()
|
||||
{
|
||||
digitalWrite(_select, HIGH);
|
||||
digitalWrite(_select, HIGH);
|
||||
pulsePin(_fqud);
|
||||
digitalWrite(_select, LOW);
|
||||
digitalWrite(_select, LOW);
|
||||
}
|
||||
|
||||
|
||||
@ -255,13 +286,19 @@ void AD9850::update()
|
||||
// AD9851
|
||||
//
|
||||
|
||||
#define AD9851_REFCLK 0x01 // bit is a 6x multiplier bit P.14 datasheet
|
||||
// bit is a 6x multiplier bit P.14 datasheet
|
||||
#define AD9851_REFCLK 0x01
|
||||
|
||||
void AD9851::setFrequency(uint32_t freq)
|
||||
|
||||
bool AD9851::setFrequency(uint32_t freq)
|
||||
{
|
||||
bool rv = true;
|
||||
// PREVENT OVERFLOW
|
||||
if (freq > AD9851_MAX_FREQ) freq = AD9851_MAX_FREQ;
|
||||
|
||||
if (freq > AD9851_MAX_FREQ)
|
||||
{
|
||||
rv = false;
|
||||
freq = AD9851_MAX_FREQ;
|
||||
}
|
||||
// AUTO SWITCH REFERENCE FREQUENCY
|
||||
if (_autoRefClock)
|
||||
{
|
||||
@ -286,14 +323,20 @@ void AD9851::setFrequency(uint32_t freq)
|
||||
_freq = freq;
|
||||
_factor += _offset;
|
||||
writeData();
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
// especially for lower frequencies (with decimals)
|
||||
void AD9851::setFrequencyF(float freq)
|
||||
bool AD9851::setFrequencyF(float freq)
|
||||
{
|
||||
bool rv = true;
|
||||
// PREVENT OVERFLOW
|
||||
if (freq > AD9851_MAX_FREQ) freq = AD9851_MAX_FREQ;
|
||||
if (freq > AD9851_MAX_FREQ)
|
||||
{
|
||||
rv = false;
|
||||
freq = AD9851_MAX_FREQ;
|
||||
}
|
||||
|
||||
// AUTO SWITCH REFERENCE FREQUENCY
|
||||
if (_autoRefClock)
|
||||
@ -320,9 +363,16 @@ void AD9851::setFrequencyF(float freq)
|
||||
_freq = freq;
|
||||
_factor += _offset;
|
||||
writeData();
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
uint32_t AD9851::getMaxFrequency()
|
||||
{
|
||||
return AD9851_MAX_FREQ;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// AD9851 - AUTO REFERENCE CLOCK
|
||||
@ -334,6 +384,12 @@ void AD9851::setAutoRefClock(bool arc)
|
||||
};
|
||||
|
||||
|
||||
bool AD9851::getAutoRefClock()
|
||||
{
|
||||
return _autoRefClock;
|
||||
};
|
||||
|
||||
|
||||
void AD9851::setRefClockHigh()
|
||||
{
|
||||
_config |= AD9851_REFCLK;
|
||||
@ -353,6 +409,7 @@ uint8_t AD9851::getRefClock()
|
||||
return (_config & AD9851_REFCLK) ? 180 : 30;
|
||||
}
|
||||
|
||||
|
||||
void AD9851::setARCCutOffFreq(uint32_t Hz)
|
||||
{
|
||||
if (Hz > 30000000UL) Hz = 30000000;
|
||||
@ -360,5 +417,11 @@ void AD9851::setARCCutOffFreq(uint32_t Hz)
|
||||
};
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
uint32_t AD9851::getARCCutOffFreq()
|
||||
{
|
||||
return _ARCCutOffFreq;
|
||||
};
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
||||
|
@ -2,18 +2,17 @@
|
||||
//
|
||||
// FILE: AD985X.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.3.4
|
||||
// VERSION: 0.3.5
|
||||
// DATE: 2019-02-08
|
||||
// PURPOSE: Class for AD9850 and AD9851 function generator
|
||||
// URL: https://github.com/RobTillaart/AD985X
|
||||
//
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "SPI.h"
|
||||
|
||||
|
||||
#define AD985X_LIB_VERSION (F("0.3.4"))
|
||||
#define AD985X_LIB_VERSION (F("0.3.5"))
|
||||
|
||||
|
||||
#define AD9850_MAX_FREQ (40UL * 1000UL * 1000UL)
|
||||
@ -31,34 +30,41 @@ public:
|
||||
void powerDown();
|
||||
void powerUp();
|
||||
|
||||
void setFrequency(uint32_t freq); // 0..AD9850_MAX_FREQ
|
||||
void setFrequencyF(float freq); // works best for lower frequencies.
|
||||
float getFrequency() { return _freq; };
|
||||
uint32_t getMaxFrequency() { return AD9850_MAX_FREQ; };
|
||||
|
||||
// returns false if limited to AD9850_MAX_FREQ
|
||||
bool setFrequency(uint32_t freq); // 0..AD9850_MAX_FREQ
|
||||
bool setFrequencyF(float freq); // works best for low frequencies.
|
||||
float getFrequency();
|
||||
uint32_t getMaxFrequency();
|
||||
|
||||
// 0 .. 31 steps of 11.25 degrees
|
||||
void setPhase(uint8_t phase = 0);
|
||||
uint8_t getPhase() { return (_config >> 3); };
|
||||
// returns false if phase > 31.
|
||||
bool setPhase(uint8_t phase = 0);
|
||||
uint8_t getPhase();
|
||||
|
||||
|
||||
// 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; };
|
||||
// internal chip factor used for frequency. (debugging only)
|
||||
uint32_t getFactor() { return _factor; };
|
||||
|
||||
|
||||
// autoUpdate is default true;
|
||||
void setAutoUpdate(bool update = true) { _autoUpdate = update; };
|
||||
void setAutoUpdate(bool update = true) { _autoUpdate = update; };
|
||||
bool getAutoUpdate() { return _autoUpdate; };
|
||||
void update();
|
||||
|
||||
|
||||
// speed in Hz
|
||||
void setSPIspeed(uint32_t speed);
|
||||
uint32_t getSPIspeed() { return _SPIspeed; };
|
||||
|
||||
// debugging
|
||||
bool usesHWSPI() { return _hwSPI; };
|
||||
|
||||
// internal chip factor used for frequency. (debugging only)
|
||||
uint32_t getFactor() { return _factor; };
|
||||
|
||||
|
||||
// ESP32 specific
|
||||
#if defined(ESP32)
|
||||
void selectHSPI() { _useHSPI = true; };
|
||||
@ -102,24 +108,33 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DERIVED CLASS
|
||||
//
|
||||
class AD9851 : public AD9850
|
||||
{
|
||||
public:
|
||||
void setFrequency(uint32_t freq); // 0..AD9851_MAX_FREQ
|
||||
void setFrequencyF(float freq);
|
||||
uint32_t getMaxFrequency() { return AD9851_MAX_FREQ; };
|
||||
// returns false if limited to AD9851_MAX_FREQ
|
||||
bool setFrequency(uint32_t freq); // 0..AD9851_MAX_FREQ
|
||||
bool setFrequencyF(float freq); // works best for low frequencies.
|
||||
uint32_t getMaxFrequency();
|
||||
|
||||
|
||||
void setRefClockHigh(); // 180 MHz
|
||||
void setRefClockLow(); // 30 MHz
|
||||
uint8_t getRefClock(); // returns 180 or 30
|
||||
|
||||
void setRefClockHigh(); // 180 MHz
|
||||
void setRefClockLow(); // 30 MHz
|
||||
uint8_t getRefClock();
|
||||
|
||||
void setAutoRefClock(bool arc);
|
||||
bool getAutoRefClock() { return _autoRefClock; };
|
||||
bool getAutoRefClock();
|
||||
|
||||
|
||||
// 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 );
|
||||
uint32_t getARCCutOffFreq() { return _ARCCutOffFreq; };
|
||||
uint32_t getARCCutOffFreq();
|
||||
|
||||
|
||||
protected:
|
||||
bool _autoRefClock = false;
|
||||
|
@ -6,12 +6,19 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
|
||||
## [0.3.5] - 2023-01-11
|
||||
- update GitHub actions
|
||||
- update license
|
||||
- add bool return value to setFrequency()
|
||||
- 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
|
||||
- add URL to examples
|
||||
|
||||
|
||||
## [0.3.3] - 2021-12-10
|
||||
- update library.json, license, readme.md
|
||||
- fix reset() for ESP32 hardware SPI
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019-2022 Rob Tillaart
|
||||
Copyright (c) 2019-2023 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
|
||||
|
@ -178,20 +178,25 @@ for SW SPI you need to define the data and clock pin too.
|
||||
- resetPin = reset
|
||||
- FQUD = Frequency UpDate Pin
|
||||
- **void reset()** resets the function generator.
|
||||
- **void powerDown()** idem
|
||||
- **void powerUp()** idem
|
||||
- **void setFrequency(uint32_t freq)** SetFrequency sets the frequency and is limited by the
|
||||
MaxFrequency of the class used. For the AD9850 => 40 MHz, for the AD9851 => 70 MHz.
|
||||
- **void powerDown()** idem.
|
||||
- **void powerUp()** idem.
|
||||
- **bool setFrequency(uint32_t freq)** SetFrequency sets the frequency and is limited by the
|
||||
MaxFrequency of the class used.
|
||||
Returns false if limited.
|
||||
For the AD9850 => 40 MHz, for the AD9851 => 70 MHz.
|
||||
- Note that the quality of the signal gets less at higher frequencies.
|
||||
- Note setFrequency is affected by the autoUpdateFlag.
|
||||
- **void setFrequencyF(float freq)** SetFrequencyF sets the frequency with a float with a maximum of **two** decimals.
|
||||
- **bool setFrequencyF(float freq)** SetFrequencyF sets the frequency with a float with a maximum of **two** decimals.
|
||||
- Note that a float only has a mantissa of 6-7 digits so for frequencies above above ~1.000.000 = 1MHz all decimals are lost.
|
||||
- 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.
|
||||
- **void setPhase(uint8_t phase = 0)** set the phase in units of 11.25° 0..31 allowed.
|
||||
- **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.
|
||||
|
||||
|
||||
@ -270,7 +275,7 @@ The AD9850 has no specific functions.
|
||||
### AD9851 specific
|
||||
|
||||
- **void setRefClockHigh()** set reference clock to 180 Mhz.
|
||||
- **void setRefClockLow()** set reference clock to 30 Mhz.
|
||||
- **void setRefClockLow()** set reference clock to 30 Mhz.
|
||||
- **uint8_t getRefClock()** returns 30 or 180.
|
||||
- **void setAutoRefClock(bool arc)** sets a flag so the library switches automatically
|
||||
to the reference clock of 180 MHz when the frequency is set above 10 MHz and
|
||||
@ -278,7 +283,8 @@ to 30 MHz when the frequency is set to 10 MHz or lower.
|
||||
The initial value is **false** == OFF for backwards compatibility.
|
||||
- **bool getAutoRefClock()** returns true if autoRefClock is set.
|
||||
- **void setARCCutOffFreq(uint32_t Hz = 10000000UL )** set cut off frequency
|
||||
for the auto reference clock. Maximum value is 30 MHz, typical 10 MHz.
|
||||
for the auto reference clock.
|
||||
Maximum value is 30 MHz, typical is 10 MHz.
|
||||
- **uint32_t getARCCutOffFreq()** returns cut off frequency set.
|
||||
|
||||
|
||||
@ -303,8 +309,24 @@ The user is also responsible to store it e.g. in EEPROM to make it persistent.
|
||||
|
||||
## Future
|
||||
|
||||
#### Must
|
||||
|
||||
#### Should
|
||||
|
||||
- examples for ESP32 HWSPI interface
|
||||
- do tests on ESP32
|
||||
- performance measurements
|
||||
- move code to .cpp
|
||||
- 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() ?
|
||||
|
||||
|
||||
#### Wont
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/AD985X.git"
|
||||
},
|
||||
"version": "0.3.4",
|
||||
"version": "0.3.5",
|
||||
"license": "MIT",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "*",
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=AD985X
|
||||
version=0.3.4
|
||||
version=0.3.5
|
||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
sentence=Arduino library for AD9850 and AD9851 function generators. Supports both hardware SPI as software SPI.
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
unittest_setup()
|
||||
{
|
||||
fprintf(stderr, "VERSION: %s\n", AD985X_LIB_VERSION);
|
||||
fprintf(stderr, "AD985X_LIB_VERSION: %s\n", AD985X_LIB_VERSION);
|
||||
}
|
||||
|
||||
|
||||
@ -36,6 +36,13 @@ unittest_teardown()
|
||||
}
|
||||
|
||||
|
||||
unittest(test_constants)
|
||||
{
|
||||
assertEqual((40UL * 1000UL * 1000UL), AD9850_MAX_FREQ);
|
||||
assertEqual((70UL * 1000UL * 1000UL), AD9851_MAX_FREQ);
|
||||
}
|
||||
|
||||
|
||||
unittest(test_constructor)
|
||||
{
|
||||
AD9850 funcgen0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user