mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
330 lines
6.6 KiB
C++
330 lines
6.6 KiB
C++
//
|
|
// FILE: AD9833.cpp
|
|
// AUTHOR: Rob Tillaart
|
|
// PURPOSE: Arduino library for AD9833 function generator
|
|
// VERSION: 0.1.2
|
|
// URL: https://github.com/RobTillaart/AD9833
|
|
//
|
|
|
|
#include "AD9833.h"
|
|
|
|
// CONTROL REGISTER BITS
|
|
#define AD9833_B28 (1 << 13)
|
|
#define AD9833_HLB (1 << 12)
|
|
#define AD9833_FSELECT (1 << 11)
|
|
#define AD9833_PSELECT (1 << 10)
|
|
#define AD9833_RESET (1 << 8)
|
|
#define AD9833_SLEEP1 (1 << 7)
|
|
#define AD9833_SLEEP12 (1 << 6)
|
|
#define AD9833_OPBITEN (1 << 5)
|
|
#define AD9833_DIV2 (1 << 3)
|
|
#define AD9833_MODE (1 << 1)
|
|
|
|
|
|
AD9833::AD9833()
|
|
{
|
|
}
|
|
|
|
|
|
void AD9833::begin(uint8_t selectPin, uint8_t dataPin, uint8_t clockPin)
|
|
{
|
|
_selectPin = selectPin;
|
|
_dataPin = dataPin;
|
|
_clockPin = clockPin;
|
|
|
|
_useSelect = (_selectPin != 255);
|
|
if (_useSelect)
|
|
{
|
|
pinMode(_selectPin, OUTPUT);
|
|
digitalWrite(_selectPin, HIGH);
|
|
}
|
|
|
|
_hwSPI = ((dataPin == 0) || (clockPin == 0));
|
|
|
|
_spi_settings = SPISettings(8000000, MSBFIRST, SPI_MODE2);
|
|
|
|
if (_hwSPI)
|
|
{
|
|
#if defined(ESP32)
|
|
if (_useHSPI) // HSPI
|
|
{
|
|
mySPI = new SPIClass(HSPI);
|
|
mySPI->end();
|
|
mySPI->begin(14, 12, 13, selectPin); // CLK = 14 MISO = 12 MOSI = 13
|
|
}
|
|
else // VSPI
|
|
{
|
|
mySPI = new SPIClass(VSPI);
|
|
mySPI->end();
|
|
mySPI->begin(18, 19, 23, selectPin); // CLK = 18 MISO = 19 MOSI = 23
|
|
}
|
|
#else // generic hardware SPI
|
|
mySPI = &SPI;
|
|
mySPI->end();
|
|
mySPI->begin();
|
|
#endif
|
|
}
|
|
else // software SPI
|
|
{
|
|
pinMode(_dataPin, OUTPUT);
|
|
pinMode(_clockPin, OUTPUT);
|
|
digitalWrite(_dataPin, LOW);
|
|
digitalWrite(_clockPin, HIGH);
|
|
}
|
|
reset();
|
|
}
|
|
|
|
|
|
void AD9833::begin(uint8_t selectPin, SPIClass * spi)
|
|
{
|
|
_selectPin = selectPin;
|
|
_useSelect = (_selectPin != 255);
|
|
if (_useSelect)
|
|
{
|
|
pinMode(_selectPin, OUTPUT);
|
|
digitalWrite(_selectPin, HIGH);
|
|
}
|
|
|
|
_hwSPI = true;
|
|
_spi_settings = SPISettings(8000000, MSBFIRST, SPI_MODE2);
|
|
|
|
mySPI = spi;
|
|
mySPI->end();
|
|
mySPI->begin();
|
|
|
|
reset();
|
|
}
|
|
|
|
|
|
void AD9833::reset()
|
|
{
|
|
hardwareReset();
|
|
_control = AD9833_B28;
|
|
writeControlRegister(_control);
|
|
}
|
|
|
|
|
|
void AD9833::hardwareReset()
|
|
{
|
|
writeControlRegister(_control | 0x0100);
|
|
// reset all library variables to be in "sync" with hardware.
|
|
_control = 0;
|
|
_waveform = AD9833_OFF;
|
|
_freq[0] = _freq[1] = 0;
|
|
_phase[0] = _phase[1] = 0;
|
|
}
|
|
|
|
|
|
bool AD9833::setPowerMode(uint8_t mode)
|
|
{
|
|
if (mode > 3) return false;
|
|
_control &= 0xFF3F; // clear previous power flags
|
|
_control |= (mode << 6); // set the new power flags
|
|
writeControlRegister(_control);
|
|
return true;
|
|
}
|
|
|
|
|
|
void AD9833::setWave(uint8_t waveform)
|
|
{
|
|
if (waveform > 4) return;
|
|
|
|
// store waveform
|
|
_waveform = waveform;
|
|
|
|
// clear bits in control register
|
|
_control &= ~(AD9833_SLEEP1 | AD9833_SLEEP12 | AD9833_OPBITEN | AD9833_MODE | AD9833_DIV2);
|
|
|
|
// set bits in control register
|
|
switch(_waveform)
|
|
{
|
|
case AD9833_OFF:
|
|
_control |= (AD9833_SLEEP1 | AD9833_SLEEP12);
|
|
break;
|
|
case AD9833_SINE:
|
|
// no bits need to set
|
|
break;
|
|
case AD9833_SQUARE1:
|
|
_control |= (AD9833_DIV2 | AD9833_OPBITEN);
|
|
break;
|
|
case AD9833_SQUARE2:
|
|
_control |= (AD9833_OPBITEN);
|
|
break;
|
|
case AD9833_TRIANGLE:
|
|
_control |= (AD9833_MODE);
|
|
break;
|
|
}
|
|
writeControlRegister(_control);
|
|
}
|
|
|
|
|
|
uint8_t AD9833::getWave()
|
|
{
|
|
return _waveform;
|
|
}
|
|
|
|
|
|
float AD9833::setFrequency(float freq, uint8_t channel)
|
|
{
|
|
if (channel > 1) return -1;
|
|
_freq[channel] = freq;
|
|
if (_freq[channel] > AD9833_MAX_FREQ) _freq[channel] = AD9833_MAX_FREQ;
|
|
if (_freq[channel] < 0) _freq[channel] = 0;
|
|
|
|
// convert to bit pattern
|
|
// fr = round(freq * pow(2, 28) / 25 MHz));
|
|
// rounding
|
|
uint32_t fr = round(_freq[channel] * (268435456.0 / 25000000.0));
|
|
|
|
writeFreqRegister(channel, fr);
|
|
|
|
return _freq[channel];
|
|
}
|
|
|
|
|
|
float AD9833::getFrequency(uint8_t channel)
|
|
{
|
|
return _freq[channel];
|
|
}
|
|
|
|
|
|
float AD9833::getMaxFrequency()
|
|
{
|
|
return AD9833_MAX_FREQ;
|
|
}
|
|
|
|
|
|
void AD9833::setFrequencyChannel(uint8_t channel)
|
|
{
|
|
if (channel > 1) return;
|
|
|
|
if (channel == 0) _control &= ~AD9833_FSELECT;
|
|
if (channel == 1) _control |= AD9833_FSELECT;
|
|
writeControlRegister(_control);
|
|
}
|
|
|
|
|
|
float AD9833::setPhase(float phase, uint8_t channel)
|
|
{
|
|
if (channel > 1) return -1;
|
|
_phase[channel] = phase;
|
|
while (_phase[channel] >= AD9833_MAX_PHASE) _phase[channel] -= AD9833_MAX_PHASE;
|
|
while (_phase[channel] < 0) _phase[channel] += AD9833_MAX_PHASE;
|
|
|
|
uint16_t ph = _phase[channel] * (4095.0 / 360.0);
|
|
writePhaseRegister(channel, ph);
|
|
|
|
return _phase[channel];
|
|
}
|
|
|
|
|
|
float AD9833::getPhase(uint8_t channel)
|
|
{
|
|
return _phase[channel];
|
|
}
|
|
|
|
|
|
float AD9833::getMaxPhase()
|
|
{
|
|
return AD9833_MAX_PHASE;
|
|
}
|
|
|
|
|
|
void AD9833::setPhaseChannel(uint8_t channel)
|
|
{
|
|
if (channel > 1) return;
|
|
|
|
if (channel == 0) _control &= ~AD9833_PSELECT;
|
|
if (channel == 1) _control |= AD9833_PSELECT;
|
|
writeControlRegister(_control);
|
|
}
|
|
|
|
|
|
void AD9833::setSPIspeed(uint32_t speed)
|
|
{
|
|
_SPIspeed = speed;
|
|
_spi_settings = SPISettings(_SPIspeed, MSBFIRST, SPI_MODE2);
|
|
}
|
|
|
|
|
|
uint32_t AD9833::getSPIspeed()
|
|
{
|
|
return _SPIspeed;
|
|
}
|
|
|
|
|
|
bool AD9833::usesHWSPI()
|
|
{
|
|
return _hwSPI;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
//
|
|
// PRIVATE
|
|
//
|
|
void AD9833::writeControlRegister(uint16_t value)
|
|
{
|
|
uint16_t data = value & 0x3FFF; // bit 15 and 14 == 00
|
|
writeData(data);
|
|
}
|
|
|
|
|
|
void AD9833::writeFreqRegister(uint8_t reg, uint32_t freq)
|
|
{
|
|
uint16_t data = 0;
|
|
if (reg > 1) return;
|
|
if (reg == 0) data = 0x4000; // bit 15 and 14 01
|
|
if (reg == 1) data = 0x8000; // bit 15 and 14 10
|
|
|
|
// 28 bits in two sets of 14
|
|
data |= (freq & 0x3FFF); // least significant 14 bits
|
|
writeData(data);
|
|
|
|
data &= 0xC000; // remove freq data LSB
|
|
data |= (freq >> 14); // most significant 14 bits
|
|
writeData(data);
|
|
}
|
|
|
|
|
|
void AD9833::writePhaseRegister(uint8_t reg, uint16_t value)
|
|
{
|
|
uint16_t data = 0;
|
|
if (reg > 1) return;
|
|
if (reg == 0) data = 0xC000; // bit 15 and 14 and 13 110
|
|
if (reg == 1) data = 0xE000; // bit 15 and 14 and 13 111
|
|
|
|
data |= (value & 0x0FFF);
|
|
writeData(data);
|
|
}
|
|
|
|
|
|
void AD9833::writeData(uint16_t data)
|
|
{
|
|
if (_useSelect) digitalWrite(_selectPin, LOW);
|
|
if (_hwSPI)
|
|
{
|
|
mySPI->beginTransaction(_spi_settings);
|
|
mySPI->transfer16(data);
|
|
mySPI->endTransaction();
|
|
}
|
|
else
|
|
{
|
|
// local variables is fast.
|
|
uint8_t clk = _clockPin;
|
|
uint8_t dao = _dataPin;
|
|
// MSBFIRST
|
|
for (uint16_t mask = 0x8000; mask; mask >>= 1)
|
|
{
|
|
digitalWrite(dao, (data & mask) !=0 ? HIGH : LOW);
|
|
digitalWrite(clk, LOW);
|
|
digitalWrite(clk, HIGH);
|
|
}
|
|
digitalWrite(dao, LOW);
|
|
}
|
|
if (_useSelect) digitalWrite(_selectPin, HIGH);
|
|
}
|
|
|
|
|
|
// -- END OF FILE --
|