mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-09-19 16:46:11 -04:00
0.4.2 AD9833
This commit is contained in:
parent
66e9ef06bb
commit
1fd76995da
@ -2,12 +2,14 @@
|
|||||||
// FILE: AD9833.cpp
|
// FILE: AD9833.cpp
|
||||||
// AUTHOR: Rob Tillaart
|
// AUTHOR: Rob Tillaart
|
||||||
// PURPOSE: Arduino library for AD9833 function generator
|
// PURPOSE: Arduino library for AD9833 function generator
|
||||||
// VERSION: 0.4.1
|
// DATE: 2023-08-25
|
||||||
|
// VERSION: 0.4.2
|
||||||
// URL: https://github.com/RobTillaart/AD9833
|
// URL: https://github.com/RobTillaart/AD9833
|
||||||
//
|
|
||||||
|
|
||||||
#include "AD9833.h"
|
#include "AD9833.h"
|
||||||
|
|
||||||
|
|
||||||
// FREQUENCY REGISTER BITS
|
// FREQUENCY REGISTER BITS
|
||||||
#define AD9833_FREG1 0x8000
|
#define AD9833_FREG1 0x8000
|
||||||
#define AD9833_FREG0 0x4000
|
#define AD9833_FREG0 0x4000
|
||||||
@ -25,7 +27,6 @@
|
|||||||
#define AD9833_MODE (1 << 1)
|
#define AD9833_MODE (1 << 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// HARDWARE SPI
|
// HARDWARE SPI
|
||||||
AD9833::AD9833(uint8_t slaveSelect, __SPI_CLASS__ * mySPI)
|
AD9833::AD9833(uint8_t slaveSelect, __SPI_CLASS__ * mySPI)
|
||||||
{
|
{
|
||||||
@ -34,6 +35,7 @@ AD9833::AD9833(uint8_t slaveSelect, __SPI_CLASS__ * mySPI)
|
|||||||
_mySPI = mySPI;
|
_mySPI = mySPI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// SOFTWARE SPI
|
// SOFTWARE SPI
|
||||||
AD9833::AD9833(uint8_t slaveSelect, uint8_t spiData, uint8_t spiClock)
|
AD9833::AD9833(uint8_t slaveSelect, uint8_t spiData, uint8_t spiClock)
|
||||||
{
|
{
|
||||||
@ -67,6 +69,15 @@ void AD9833::begin()
|
|||||||
pinMode(_clockPin, OUTPUT);
|
pinMode(_clockPin, OUTPUT);
|
||||||
digitalWrite(_dataPin, LOW);
|
digitalWrite(_dataPin, LOW);
|
||||||
digitalWrite(_clockPin, HIGH);
|
digitalWrite(_clockPin, HIGH);
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
|
||||||
|
uint8_t _port = digitalPinToPort(_dataPin);
|
||||||
|
_dataOutRegister = portOutputRegister(_port);
|
||||||
|
_dataOutBit = digitalPinToBitMask(_dataPin);
|
||||||
|
_port = digitalPinToPort(_clockPin);
|
||||||
|
_clockRegister = portOutputRegister(_port);
|
||||||
|
_clockBit = digitalPinToBitMask(_clockPin);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
@ -94,16 +105,23 @@ void AD9833::hardwareReset()
|
|||||||
bool AD9833::setPowerMode(uint8_t mode)
|
bool AD9833::setPowerMode(uint8_t mode)
|
||||||
{
|
{
|
||||||
if (mode > 3) return false;
|
if (mode > 3) return false;
|
||||||
_control &= 0xFF3F; // clear previous power flags
|
// clear previous power bits
|
||||||
_control |= (mode << 6); // set the new power flags
|
_control &= ~(AD9833_SLEEP1 | AD9833_SLEEP12);
|
||||||
|
_control |= (mode << 6); // set the new power bits
|
||||||
writeControlRegister(_control);
|
writeControlRegister(_control);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t AD9833::getPowerMode()
|
||||||
|
{
|
||||||
|
return (_control & (AD9833_SLEEP1 | AD9833_SLEEP12)) >> 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void AD9833::setWave(uint8_t waveform)
|
void AD9833::setWave(uint8_t waveform)
|
||||||
{
|
{
|
||||||
if (waveform > 4) return;
|
if (waveform > AD9833_TRIANGLE) return;
|
||||||
|
|
||||||
// store waveform
|
// store waveform
|
||||||
_waveform = waveform;
|
_waveform = waveform;
|
||||||
@ -143,24 +161,29 @@ uint8_t AD9833::getWave()
|
|||||||
float AD9833::setFrequency(float frequency, uint8_t channel)
|
float AD9833::setFrequency(float frequency, uint8_t channel)
|
||||||
{
|
{
|
||||||
if (channel > 1) return -1;
|
if (channel > 1) return -1;
|
||||||
_freq[channel] = frequency;
|
// if (_freq[channel] == frequency) return frequency;
|
||||||
if (_freq[channel] > AD9833_MAX_FREQ) _freq[channel] = AD9833_MAX_FREQ;
|
// local variable is faster.
|
||||||
if (_freq[channel] < 0) _freq[channel] = 0;
|
float newFrequency = frequency;
|
||||||
|
if (newFrequency < 0) newFrequency = 0;
|
||||||
|
else if (newFrequency > AD9833_MAX_FREQ) newFrequency = AD9833_MAX_FREQ;
|
||||||
|
|
||||||
// convert to bit pattern
|
// convert to bit pattern
|
||||||
// fr = round(frequency * pow(2, 28) / 25 MHz)); // 25 MHz == crystal frequency.
|
// fr = round(frequency * pow(2, 28) / 25 MHz)); // 25 MHz == crystal frequency.
|
||||||
// _crystalFreqFactor == (pow(2, 28) / crystal frequency);
|
// _crystalFreqFactor == (pow(2, 28) / crystal frequency);
|
||||||
// rounding
|
// round() to minimize error / use the whole range
|
||||||
uint32_t freq = round(_freq[channel] * _crystalFreqFactor);
|
uint32_t freq = round(newFrequency * _crystalFreqFactor);
|
||||||
|
|
||||||
writeFrequencyRegister(channel, freq);
|
writeFrequencyRegister(channel, freq);
|
||||||
|
|
||||||
return _freq[channel];
|
// cache the newFrequency;
|
||||||
|
_freq[channel] = newFrequency;
|
||||||
|
return newFrequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float AD9833::getFrequency(uint8_t channel)
|
float AD9833::getFrequency(uint8_t channel)
|
||||||
{
|
{
|
||||||
|
// return round(_freq[channel] * _crystalFreqFactor) / _crystalFreqFactor;
|
||||||
return _freq[channel];
|
return _freq[channel];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,23 +207,43 @@ void AD9833::setFrequencyChannel(uint8_t channel)
|
|||||||
float AD9833::setPhase(float phase, uint8_t channel)
|
float AD9833::setPhase(float phase, uint8_t channel)
|
||||||
{
|
{
|
||||||
if (channel > 1) return -1;
|
if (channel > 1) return -1;
|
||||||
_phase[channel] = phase;
|
// local variable is faster.
|
||||||
while (_phase[channel] >= AD9833_MAX_PHASE) _phase[channel] -= AD9833_MAX_PHASE;
|
float newPhase = phase;
|
||||||
while (_phase[channel] < 0) _phase[channel] += AD9833_MAX_PHASE;
|
while (newPhase >= AD9833_MAX_PHASE) newPhase -= AD9833_MAX_PHASE;
|
||||||
|
while (newPhase < 0) newPhase += AD9833_MAX_PHASE;
|
||||||
|
|
||||||
uint16_t ph = _phase[channel] * (4095.0 / 360.0);
|
// round() to minimize error / use the whole range 0..4095
|
||||||
|
uint16_t ph = round(newPhase * (4095.0 / 360.0));
|
||||||
writePhaseRegister(channel, ph);
|
writePhaseRegister(channel, ph);
|
||||||
|
|
||||||
return _phase[channel];
|
// cache the newPhase
|
||||||
|
_phase[channel] = newPhase;
|
||||||
|
return newPhase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float AD9833::getPhase(uint8_t channel)
|
float AD9833::getPhase(uint8_t channel)
|
||||||
{
|
{
|
||||||
|
// more precise => more math;
|
||||||
|
// return round(_phase[channel] * (4095.0 / 360.0)) / (4095.0 / 360.0);
|
||||||
return _phase[channel];
|
return _phase[channel];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// returns phase set (radians) - not optimized.
|
||||||
|
// [0 .. 2 PI>
|
||||||
|
float AD9833::setPhaseRadians(float phase, uint8_t channel)
|
||||||
|
{
|
||||||
|
return setPhase(phase * RAD_TO_DEG, channel) * DEG_TO_RAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float AD9833::getPhaseRadians(uint8_t channel)
|
||||||
|
{
|
||||||
|
return getPhase(channel) * DEG_TO_RAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
float AD9833::getMaxPhase()
|
float AD9833::getMaxPhase()
|
||||||
{
|
{
|
||||||
return AD9833_MAX_PHASE;
|
return AD9833_MAX_PHASE;
|
||||||
@ -289,12 +332,14 @@ void AD9833::writePhaseRegister(uint8_t channel, uint16_t value)
|
|||||||
void AD9833::setCrystalFrequency(float crystalFrequency)
|
void AD9833::setCrystalFrequency(float crystalFrequency)
|
||||||
{
|
{
|
||||||
// calculate the often used factor
|
// calculate the often used factor
|
||||||
|
// 268435456.0 == POW2TO28
|
||||||
_crystalFreqFactor = 268435456.0 / crystalFrequency;
|
_crystalFreqFactor = 268435456.0 / crystalFrequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float AD9833::getCrystalFrequency()
|
float AD9833::getCrystalFrequency()
|
||||||
{
|
{
|
||||||
|
// 268435456.0 == POW2TO28
|
||||||
return 268435456.0 / _crystalFreqFactor;
|
return 268435456.0 / _crystalFreqFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,7 +380,7 @@ void AD9833::writeFrequencyRegisterMSB(uint8_t channel, uint16_t MSB)
|
|||||||
_control |= AD9833_HLB;
|
_control |= AD9833_HLB;
|
||||||
writeControlRegister(_control);
|
writeControlRegister(_control);
|
||||||
|
|
||||||
// send the least significant 14 bits
|
// send the most significant 14 bits
|
||||||
writeData(MSB);
|
writeData(MSB);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,17 +401,40 @@ void AD9833::writeData(uint16_t data)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// SPI MODE2
|
||||||
|
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
|
||||||
|
|
||||||
|
uint8_t cbmask1 = _clockBit;
|
||||||
|
uint8_t cbmask2 = ~_clockBit;
|
||||||
|
uint8_t outmask1 = _dataOutBit;
|
||||||
|
uint8_t outmask2 = ~_dataOutBit;
|
||||||
|
|
||||||
|
// MSBFIRST
|
||||||
|
for (uint16_t mask = 0x8000; mask; mask >>= 1)
|
||||||
|
{
|
||||||
|
uint8_t oldSREG = SREG;
|
||||||
|
noInterrupts();
|
||||||
|
if (data & mask) *_dataOutRegister |= outmask1;
|
||||||
|
else *_dataOutRegister &= outmask2;
|
||||||
|
*_clockRegister &= cbmask2;
|
||||||
|
*_clockRegister |= cbmask1;
|
||||||
|
SREG = oldSREG;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // REFERENCE IMPLEMENTATION
|
||||||
|
|
||||||
// local variables is fast.
|
// local variables is fast.
|
||||||
uint8_t clk = _clockPin;
|
uint8_t clk = _clockPin;
|
||||||
uint8_t dao = _dataPin;
|
uint8_t dao = _dataPin;
|
||||||
// MSBFIRST
|
// MSBFIRST
|
||||||
for (uint16_t mask = 0x8000; mask; mask >>= 1)
|
for (uint16_t mask = 0x8000; mask; mask >>= 1)
|
||||||
{
|
{
|
||||||
digitalWrite(dao, (data & mask) !=0 ? HIGH : LOW);
|
digitalWrite(dao, (data & mask) != 0 ? HIGH : LOW);
|
||||||
digitalWrite(clk, LOW);
|
digitalWrite(clk, LOW);
|
||||||
digitalWrite(clk, HIGH);
|
digitalWrite(clk, HIGH);
|
||||||
}
|
}
|
||||||
digitalWrite(dao, LOW);
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (_useSelect) digitalWrite(_selectPin, HIGH);
|
if (_useSelect) digitalWrite(_selectPin, HIGH);
|
||||||
}
|
}
|
||||||
@ -384,25 +452,57 @@ void AD9833::writeData28(uint16_t LSB, uint16_t MSB)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// SPI MODE2
|
||||||
|
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
|
||||||
|
|
||||||
|
uint8_t cbmask1 = _clockBit;
|
||||||
|
uint8_t cbmask2 = ~_clockBit;
|
||||||
|
uint8_t outmask1 = _dataOutBit;
|
||||||
|
uint8_t outmask2 = ~_dataOutBit;
|
||||||
|
|
||||||
|
for (uint16_t mask = 0x8000; mask; mask >>= 1)
|
||||||
|
{
|
||||||
|
uint8_t oldSREG = SREG;
|
||||||
|
noInterrupts();
|
||||||
|
if (LSB & mask) *_dataOutRegister |= outmask1;
|
||||||
|
else *_dataOutRegister &= outmask2;
|
||||||
|
*_clockRegister &= cbmask2;
|
||||||
|
*_clockRegister |= cbmask1;
|
||||||
|
SREG = oldSREG;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint16_t mask = 0x8000; mask; mask >>= 1)
|
||||||
|
{
|
||||||
|
uint8_t oldSREG = SREG;
|
||||||
|
noInterrupts();
|
||||||
|
if (MSB & mask) *_dataOutRegister |= outmask1;
|
||||||
|
else *_dataOutRegister &= outmask2;
|
||||||
|
*_clockRegister &= cbmask2;
|
||||||
|
*_clockRegister |= cbmask1;
|
||||||
|
SREG = oldSREG;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // REFERENCE IMPLEMENTATION
|
||||||
|
|
||||||
// local variables is fast.
|
// local variables is fast.
|
||||||
uint8_t clk = _clockPin;
|
uint8_t clk = _clockPin;
|
||||||
uint8_t dao = _dataPin;
|
uint8_t dao = _dataPin;
|
||||||
// MSBFIRST
|
|
||||||
for (uint16_t mask = 0x8000; mask; mask >>= 1)
|
for (uint16_t mask = 0x8000; mask; mask >>= 1)
|
||||||
{
|
{
|
||||||
digitalWrite(dao, (LSB & mask) !=0 ? HIGH : LOW);
|
digitalWrite(dao, (LSB & mask) != 0 ? HIGH : LOW);
|
||||||
digitalWrite(clk, LOW);
|
digitalWrite(clk, LOW);
|
||||||
digitalWrite(clk, HIGH);
|
digitalWrite(clk, HIGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint16_t mask = 0x8000; mask; mask >>= 1)
|
for (uint16_t mask = 0x8000; mask; mask >>= 1)
|
||||||
{
|
{
|
||||||
digitalWrite(dao, (MSB & mask) !=0 ? HIGH : LOW);
|
digitalWrite(dao, (MSB & mask) != 0 ? HIGH : LOW);
|
||||||
digitalWrite(clk, LOW);
|
digitalWrite(clk, LOW);
|
||||||
digitalWrite(clk, HIGH);
|
digitalWrite(clk, HIGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
digitalWrite(dao, LOW);
|
#endif
|
||||||
}
|
}
|
||||||
if (_useSelect) digitalWrite(_selectPin, HIGH);
|
if (_useSelect) digitalWrite(_selectPin, HIGH);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
// FILE: AD9833.h
|
// FILE: AD9833.h
|
||||||
// AUTHOR: Rob Tillaart
|
// AUTHOR: Rob Tillaart
|
||||||
// PURPOSE: Arduino library for AD9833 function generator.
|
// PURPOSE: Arduino library for AD9833 function generator.
|
||||||
// VERSION: 0.4.1
|
// DATE: 2023-08-25
|
||||||
|
// VERSION: 0.4.2
|
||||||
// URL: https://github.com/RobTillaart/AD9833
|
// URL: https://github.com/RobTillaart/AD9833
|
||||||
|
|
||||||
|
|
||||||
@ -11,7 +12,7 @@
|
|||||||
#include "SPI.h"
|
#include "SPI.h"
|
||||||
|
|
||||||
|
|
||||||
#define AD9833_LIB_VERSION (F("0.4.1"))
|
#define AD9833_LIB_VERSION (F("0.4.2"))
|
||||||
|
|
||||||
|
|
||||||
#ifndef __SPI_CLASS__
|
#ifndef __SPI_CLASS__
|
||||||
@ -53,7 +54,7 @@ public:
|
|||||||
void hardwareReset();
|
void hardwareReset();
|
||||||
// mode = 0..3 (datasheet)
|
// mode = 0..3 (datasheet)
|
||||||
bool setPowerMode(uint8_t mode = 0);
|
bool setPowerMode(uint8_t mode = 0);
|
||||||
|
uint8_t getPowerMode();
|
||||||
|
|
||||||
void setWave(uint8_t waveform = AD9833_OFF);
|
void setWave(uint8_t waveform = AD9833_OFF);
|
||||||
uint8_t getWave();
|
uint8_t getWave();
|
||||||
@ -72,6 +73,10 @@ public:
|
|||||||
float getPhase(uint8_t channel = 0);
|
float getPhase(uint8_t channel = 0);
|
||||||
float getMaxPhase();
|
float getMaxPhase();
|
||||||
void setPhaseChannel(uint8_t channel);
|
void setPhaseChannel(uint8_t channel);
|
||||||
|
// returns phase set (radians)
|
||||||
|
// [0 .. 2 PI>
|
||||||
|
float setPhaseRadians(float phase, uint8_t channel = 0);
|
||||||
|
float getPhaseRadians(uint8_t channel = 0);
|
||||||
|
|
||||||
|
|
||||||
// Hardware SPI settings
|
// Hardware SPI settings
|
||||||
@ -107,8 +112,14 @@ private:
|
|||||||
SPISettings _spi_settings;
|
SPISettings _spi_settings;
|
||||||
|
|
||||||
// PINS
|
// PINS
|
||||||
uint8_t _dataPin = 0;
|
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
|
||||||
uint8_t _clockPin = 0;
|
volatile uint8_t *_dataOutRegister;
|
||||||
|
uint8_t _dataOutBit;
|
||||||
|
volatile uint8_t *_clockRegister;
|
||||||
|
uint8_t _clockBit;
|
||||||
|
#endif
|
||||||
|
uint8_t _dataPin;
|
||||||
|
uint8_t _clockPin;
|
||||||
uint8_t _selectPin = 0;
|
uint8_t _selectPin = 0;
|
||||||
bool _useSelect = false;
|
bool _useSelect = false;
|
||||||
|
|
||||||
@ -119,6 +130,7 @@ private:
|
|||||||
float _freq[2] = { 0, 0 }; // Hz
|
float _freq[2] = { 0, 0 }; // Hz
|
||||||
float _phase[2] = { 0, 0 }; // angle 0..360
|
float _phase[2] = { 0, 0 }; // angle 0..360
|
||||||
|
|
||||||
|
// POW2TO28 / 25 MHz
|
||||||
float _crystalFreqFactor = 268435456.0 / 25000000.0;
|
float _crystalFreqFactor = 268435456.0 / 25000000.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,6 +6,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
|||||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
|
||||||
|
## [0.4.2] - 2024-07-03
|
||||||
|
- optimize AVR SW SPI (about factor 3.4 faster)
|
||||||
|
- add rounding in **setPhase()** to minimize error.
|
||||||
|
- add **float setPhaseRadians(float phase, uint8_t channel = 0)**
|
||||||
|
- add **float getPhaseRadians(uint8_t channel = 0)**
|
||||||
|
- add **getPowerMode()** for completeness
|
||||||
|
- extend performance measurements (examples)
|
||||||
|
- minor edits
|
||||||
|
|
||||||
## [0.4.1] - 2024-05-24
|
## [0.4.1] - 2024-05-24
|
||||||
- add support for ARDUINO_ARCH_MBED
|
- add support for ARDUINO_ARCH_MBED
|
||||||
- add sweep example
|
- add sweep example
|
||||||
|
@ -139,6 +139,7 @@ and sets the control register to B28 for the **setFrequency()**
|
|||||||
Default is 0, wake up. So use ```setPowerMode(0)``` to wake up the device.
|
Default is 0, wake up. So use ```setPowerMode(0)``` to wake up the device.
|
||||||
Returns false if mode is out of range.
|
Returns false if mode is out of range.
|
||||||
Details see datasheet.
|
Details see datasheet.
|
||||||
|
- **uint8_t getPowerMode()** returns current powerMode bits.
|
||||||
|
|
||||||
| powerMode | meaning |
|
| powerMode | meaning |
|
||||||
|:-----------:|:------------------------------|
|
|:-----------:|:------------------------------|
|
||||||
@ -190,12 +191,18 @@ Returns the phase set in degrees.
|
|||||||
- **float getMaxPhase()** returns the maximum phase to set (convenience).
|
- **float getMaxPhase()** returns the maximum phase to set (convenience).
|
||||||
- **void setPhaseChannel(uint8_t channel)** select the active phase channel (0 or 1).
|
- **void setPhaseChannel(uint8_t channel)** select the active phase channel (0 or 1).
|
||||||
|
|
||||||
The library does not support get and set the phase in radians (yet).
|
Since 0.4.2 the library supports get and set the phase in radians.
|
||||||
|
|
||||||
|
- **float setPhaseRadians(float phase, uint8_t channel = 0)**
|
||||||
|
setPhase sets the phase and is limited to 0 - 2PI.
|
||||||
|
Returns the phase set in radians.
|
||||||
|
- **float getPhaseRadians(uint8_t channel = 0)** returns the phase set in radians.
|
||||||
|
|
||||||
|
|
||||||
#### Hardware SPI
|
#### Hardware SPI
|
||||||
|
|
||||||
To be used only if one needs a specific speed.
|
To be used only if one needs a specific speed.
|
||||||
|
Has no effect when using SW SPI.
|
||||||
|
|
||||||
- **void setSPIspeed(uint32_t speed)** set SPI transfer rate.
|
- **void setSPIspeed(uint32_t speed)** set SPI transfer rate.
|
||||||
- **uint32_t getSPIspeed()** returns SPI transfer rate.
|
- **uint32_t getSPIspeed()** returns SPI transfer rate.
|
||||||
@ -292,24 +299,31 @@ As this implementation is experimental, the interface might change in the future
|
|||||||
|
|
||||||
#### Should
|
#### Should
|
||||||
|
|
||||||
- evaluate the **setCrytalFrequency()** implementation / performance.
|
|
||||||
- runtime adjust-ability is preferred however...
|
|
||||||
- investigate external clock
|
- investigate external clock
|
||||||
- investigate timing (response time)
|
|
||||||
- change freq
|
|
||||||
- change channels etc.
|
|
||||||
- test on ESP32 (3V3)
|
- test on ESP32 (3V3)
|
||||||
|
|
||||||
#### Could
|
#### Could
|
||||||
|
|
||||||
|
- **setFrequency()** if cache value equals new frequency?
|
||||||
|
- ```if (_freq[channel] == frequency) return frequency;```
|
||||||
|
- **setPhase()** if cache value equals new phase?
|
||||||
|
- ```if (_phase[channel] == phase) return phase;```
|
||||||
|
- make phase array 16 bit "register value"?
|
||||||
|
- **getFrequency()** calculate freq back from set register value?
|
||||||
|
- slower
|
||||||
|
- more accurate.
|
||||||
|
- separate function **getFrequencyFromRegister()** !
|
||||||
|
- **getPhase()** calculate phase back from set register value?
|
||||||
|
- idem.
|
||||||
- extend unit tests
|
- extend unit tests
|
||||||
- add examples
|
- add examples
|
||||||
- for ESP32 HWSPI interface
|
- for ESP32 HWSPI interface
|
||||||
- solve MAGIC numbers (defaults)
|
- solve MAGIC numbers (defaults)
|
||||||
- extend performance measurements
|
- extend performance measurements
|
||||||
|
- add defines AD9833_POWERMODE_xxxx ?
|
||||||
- investigate compatibility AD9834 a.o.
|
- investigate compatibility AD9834 a.o.
|
||||||
- add **setPhaseRadians(float radians, uint8_t channel)** wrapper.
|
- need time / HW for this.
|
||||||
- add **getPhaseRadians(uint8_t channel)** wrapper.
|
|
||||||
|
|
||||||
#### Wont
|
#### Wont
|
||||||
|
|
||||||
|
@ -23,14 +23,14 @@ uint32_t start, stop;
|
|||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
while(!Serial);
|
while (!Serial);
|
||||||
Serial.println(__FILE__);
|
Serial.println(__FILE__);
|
||||||
Serial.print("AD9833_LIB_VERSION: ");
|
Serial.print("AD9833_LIB_VERSION: ");
|
||||||
Serial.println(AD9833_LIB_VERSION);
|
Serial.println(AD9833_LIB_VERSION);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
delay(10);
|
delay(10);
|
||||||
|
|
||||||
SPI.begin();
|
// SPI.begin();
|
||||||
|
|
||||||
AD.begin();
|
AD.begin();
|
||||||
|
|
||||||
@ -72,6 +72,20 @@ void setup()
|
|||||||
Serial.print("writeFrequencyRegisterMSB:\t");
|
Serial.print("writeFrequencyRegisterMSB:\t");
|
||||||
Serial.println(stop - start);
|
Serial.println(stop - start);
|
||||||
delay(10);
|
delay(10);
|
||||||
|
|
||||||
|
start = micros();
|
||||||
|
AD.setFrequencyChannel(0);
|
||||||
|
stop = micros();
|
||||||
|
Serial.print("setFrequencyChannel(0):\t");
|
||||||
|
Serial.println(stop - start);
|
||||||
|
delay(10);
|
||||||
|
|
||||||
|
start = micros();
|
||||||
|
AD.setPhaseChannel(0);
|
||||||
|
stop = micros();
|
||||||
|
Serial.print("setPhaseChannel(0):\t");
|
||||||
|
Serial.println(stop - start);
|
||||||
|
delay(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
Board: UNO (16 Mhz)
|
||||||
|
IDE: 1.8.19
|
||||||
|
|
||||||
|
AD9833_performance.ino
|
||||||
|
AD9833_LIB_VERSION: 0.4.1
|
||||||
|
hardware: 1 (hardware SPI)
|
||||||
|
setFrequency: 72 (increased after 0.3.1 setCrystalFrequency() )
|
||||||
|
setPhase: 20
|
||||||
|
setWave: 20
|
||||||
|
writeFrequencyRegisterLSB: 40
|
||||||
|
writeFrequencyRegisterMSB: 40
|
||||||
|
|
||||||
|
|
||||||
|
AD9833_LIB_VERSION: 0.4.1
|
||||||
|
hardware: 0 (software SPI)
|
||||||
|
setFrequency: 660 (increased after 0.3.1 setCrystalFrequency() )
|
||||||
|
setPhase: 216
|
||||||
|
setWave: 216
|
||||||
|
writeFrequencyRegisterLSB: 436
|
||||||
|
writeFrequencyRegisterMSB: 428
|
||||||
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
Board: UNO (16 Mhz)
|
||||||
|
IDE: 1.8.19
|
||||||
|
|
||||||
|
AD9833_performance.ino
|
||||||
|
AD9833_LIB_VERSION: 0.4.2
|
||||||
|
hardware: 1 (hardware SPI)
|
||||||
|
setFrequency: 72 (increased after 0.3.1 setCrystalFrequency() )
|
||||||
|
setPhase: 20
|
||||||
|
setWave: 20
|
||||||
|
writeFrequencyRegisterLSB: 40
|
||||||
|
writeFrequencyRegisterMSB: 40
|
||||||
|
setFrequencyChannel(0): 20
|
||||||
|
setPhaseChannel(0): 20
|
||||||
|
|
||||||
|
|
||||||
|
AD9833_LIB_VERSION: 0.4.2 - AVR SWSPI REGISTER OPTIMIZED
|
||||||
|
hardware: 0 (software SPI)
|
||||||
|
setFrequency: 192
|
||||||
|
setPhase: 60
|
||||||
|
setWave: 60
|
||||||
|
writeFrequencyRegisterLSB: 116
|
||||||
|
writeFrequencyRegisterMSB: 116
|
||||||
|
setFrequencyChannel(0): 60
|
||||||
|
setPhaseChannel(0): 56
|
||||||
|
|
||||||
|
|
@ -7,7 +7,10 @@
|
|||||||
#include "AD9833.h"
|
#include "AD9833.h"
|
||||||
|
|
||||||
|
|
||||||
AD9833 AD(10); // HW SPI, select pin 10
|
// AD9833 AD(10); // HW SPI, select pin 10
|
||||||
|
// comment SPI.begin if HW SPI pins are used for SW SPI
|
||||||
|
// AD9833 AD(10, 11, 13); // SW SPI, select, data , clock
|
||||||
|
AD9833 AD(5,6,7); // SW SPI, select, data , clock
|
||||||
|
|
||||||
int freq = 100;
|
int freq = 100;
|
||||||
bool up = true;
|
bool up = true;
|
||||||
@ -22,6 +25,7 @@ void setup()
|
|||||||
Serial.println(AD9833_LIB_VERSION);
|
Serial.println(AD9833_LIB_VERSION);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
|
|
||||||
|
// comment next line if HWSPI pins are used for SW SPI
|
||||||
SPI.begin();
|
SPI.begin();
|
||||||
AD.begin();
|
AD.begin();
|
||||||
AD.setWave(AD9833_SINE);
|
AD.setWave(AD9833_SINE);
|
||||||
@ -37,7 +41,7 @@ void loop()
|
|||||||
if (freq <= 100) up = true;
|
if (freq <= 100) up = true;
|
||||||
AD.setFrequency(freq);
|
AD.setFrequency(freq);
|
||||||
|
|
||||||
delay(100); // to simulate other tasks
|
delay(10); // to simulate other tasks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/RobTillaart/AD9833.git"
|
"url": "https://github.com/RobTillaart/AD9833.git"
|
||||||
},
|
},
|
||||||
"version": "0.4.1",
|
"version": "0.4.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"frameworks": "*",
|
"frameworks": "*",
|
||||||
"platforms": "*",
|
"platforms": "*",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
name=AD9833
|
name=AD9833
|
||||||
version=0.4.1
|
version=0.4.2
|
||||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||||
sentence=Arduino library for AD9833 function generator. Supports hardware SPI and software SPI.
|
sentence=Arduino library for AD9833 function generator. Supports hardware SPI and software SPI.
|
||||||
|
Loading…
Reference in New Issue
Block a user