// // 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 --