mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
0.3.0 AD9833
This commit is contained in:
parent
5f6d3a6196
commit
623a49ac56
@ -2,23 +2,27 @@
|
||||
// FILE: AD9833.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: Arduino library for AD9833 function generator
|
||||
// VERSION: 0.2.0
|
||||
// VERSION: 0.3.0
|
||||
// URL: https://github.com/RobTillaart/AD9833
|
||||
//
|
||||
|
||||
#include "AD9833.h"
|
||||
|
||||
// FREQUENCY REGISTER BITS
|
||||
#define AD9833_FREG1 0x8000
|
||||
#define AD9833_FREG0 0x4000
|
||||
|
||||
// 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)
|
||||
#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)
|
||||
|
||||
|
||||
|
||||
@ -71,14 +75,14 @@ void AD9833::begin()
|
||||
void AD9833::reset()
|
||||
{
|
||||
hardwareReset();
|
||||
_control = AD9833_B28;
|
||||
_control = AD9833_B28; // implicit select sine wave.
|
||||
writeControlRegister(_control);
|
||||
}
|
||||
|
||||
|
||||
void AD9833::hardwareReset()
|
||||
{
|
||||
writeControlRegister(_control | 0x0100);
|
||||
writeControlRegister(_control | AD9833_RESET);
|
||||
// reset all library variables to be in "sync" with hardware.
|
||||
_control = 0;
|
||||
_waveform = AD9833_OFF;
|
||||
@ -148,7 +152,7 @@ float AD9833::setFrequency(float freq, uint8_t channel)
|
||||
// rounding
|
||||
uint32_t fr = round(_freq[channel] * (268435456.0 / 25000000.0));
|
||||
|
||||
writeFreqRegister(channel, fr);
|
||||
writeFrequencyRegister(channel, fr);
|
||||
|
||||
return _freq[channel];
|
||||
}
|
||||
@ -233,7 +237,7 @@ bool AD9833::usesHWSPI()
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PRIVATE
|
||||
// LOW LEVEL API - Expert users only
|
||||
//
|
||||
void AD9833::writeControlRegister(uint16_t value)
|
||||
{
|
||||
@ -242,35 +246,91 @@ void AD9833::writeControlRegister(uint16_t value)
|
||||
}
|
||||
|
||||
|
||||
void AD9833::writeFreqRegister(uint8_t reg, uint32_t freq)
|
||||
void AD9833:: writeFrequencyRegister(uint8_t channel, 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
|
||||
uint16_t LSB = 0;
|
||||
uint16_t MSB = 0;
|
||||
if (channel > 1) return;
|
||||
if (channel == 0) LSB = AD9833_FREG0; // bit 15 and 14 01
|
||||
if (channel == 1) LSB = AD9833_FREG1; // bit 15 and 14 10
|
||||
// copy channel mask.
|
||||
MSB = LSB;
|
||||
|
||||
// be sure B28 bit is set.
|
||||
_control |= AD9833_B28;
|
||||
writeControlRegister(_control);
|
||||
|
||||
// 28 bits in two sets of 14
|
||||
data |= (freq & 0x3FFF); // least significant 14 bits
|
||||
writeData(data);
|
||||
LSB |= (freq & 0x3FFF);
|
||||
MSB |= ((freq >> 14) & 0x3FFF);
|
||||
|
||||
data &= 0xC000; // remove freq data LSB
|
||||
data |= (freq >> 14); // most significant 14 bits
|
||||
writeData(data);
|
||||
// faster to write them in one SPI transaction
|
||||
writeData28(LSB, MSB);
|
||||
// first send the least significant 14 bits
|
||||
// writeData(LSB);
|
||||
// then send the most significant 14 bits
|
||||
// writeData(MSB);
|
||||
}
|
||||
|
||||
|
||||
void AD9833::writePhaseRegister(uint8_t reg, uint16_t value)
|
||||
void AD9833::writePhaseRegister(uint8_t channel, 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
|
||||
if (channel > 1) return;
|
||||
if (channel == 0) data = 0xC000; // bit 15 and 14 and 13 110
|
||||
if (channel == 1) data = 0xE000; // bit 15 and 14 and 13 111
|
||||
|
||||
data |= (value & 0x0FFF);
|
||||
writeData(data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// EXPERIMENTAL
|
||||
//
|
||||
void AD9833::writeFrequencyRegisterLSB(uint8_t channel, uint16_t LSB)
|
||||
{
|
||||
if (channel > 1) return;
|
||||
// force 14 bit
|
||||
LSB &= 0x3FFF;
|
||||
if (channel == 0) LSB |= AD9833_FREG0; // bit 15 and 14 01
|
||||
if (channel == 1) LSB |= AD9833_FREG1; // bit 15 and 14 10
|
||||
|
||||
// be sure B28 and HLB bit is cleared.
|
||||
_control &= ~AD9833_B28;
|
||||
_control &= ~AD9833_HLB;
|
||||
writeControlRegister(_control);
|
||||
|
||||
// send the least significant 14 bits
|
||||
writeData(LSB);
|
||||
}
|
||||
|
||||
|
||||
void AD9833::writeFrequencyRegisterMSB(uint8_t channel, uint16_t MSB)
|
||||
{
|
||||
if (channel > 1) return;
|
||||
// force 14 bit
|
||||
MSB &= 0x3FFF;
|
||||
if (channel == 0) MSB |= AD9833_FREG0; // bit 15 and 14 01
|
||||
if (channel == 1) MSB |= AD9833_FREG1; // bit 15 and 14 10
|
||||
|
||||
// be sure B28 is cleared and HLB bit is set.
|
||||
_control &= ~AD9833_B28;
|
||||
_control |= AD9833_HLB;
|
||||
writeControlRegister(_control);
|
||||
|
||||
// send the least significant 14 bits
|
||||
writeData(MSB);
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PRIVATE
|
||||
//
|
||||
void AD9833::writeData(uint16_t data)
|
||||
{
|
||||
if (_useSelect) digitalWrite(_selectPin, LOW);
|
||||
@ -298,4 +358,41 @@ void AD9833::writeData(uint16_t data)
|
||||
}
|
||||
|
||||
|
||||
void AD9833::writeData28(uint16_t LSB, uint16_t MSB)
|
||||
{
|
||||
if (_useSelect) digitalWrite(_selectPin, LOW);
|
||||
if (_hwSPI)
|
||||
{
|
||||
_mySPI->beginTransaction(_spi_settings);
|
||||
_mySPI->transfer16(LSB);
|
||||
_mySPI->transfer16(MSB);
|
||||
_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, (LSB & mask) !=0 ? HIGH : LOW);
|
||||
digitalWrite(clk, LOW);
|
||||
digitalWrite(clk, HIGH);
|
||||
}
|
||||
|
||||
for (uint16_t mask = 0x8000; mask; mask >>= 1)
|
||||
{
|
||||
digitalWrite(dao, (MSB & mask) !=0 ? HIGH : LOW);
|
||||
digitalWrite(clk, LOW);
|
||||
digitalWrite(clk, HIGH);
|
||||
}
|
||||
|
||||
digitalWrite(dao, LOW);
|
||||
}
|
||||
if (_useSelect) digitalWrite(_selectPin, HIGH);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
@ -3,7 +3,7 @@
|
||||
// FILE: AD9833.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: Arduino library for AD9833 function generator.
|
||||
// VERSION: 0.2.0
|
||||
// VERSION: 0.3.0
|
||||
// URL: https://github.com/RobTillaart/AD9833
|
||||
|
||||
|
||||
@ -11,13 +11,15 @@
|
||||
#include "SPI.h"
|
||||
|
||||
|
||||
#define AD9833_LIB_VERSION (F("0.2.0"))
|
||||
#define AD9833_LIB_VERSION (F("0.3.0"))
|
||||
|
||||
|
||||
#if defined(ARDUINO_ARCH_RP2040)
|
||||
#define __SPI_CLASS__ SPIClassRP2040
|
||||
#else
|
||||
#define __SPI_CLASS__ SPIClass
|
||||
#if !defined(__SPI_CLASS__)
|
||||
#if defined(ARDUINO_ARCH_RP2040)
|
||||
#define __SPI_CLASS__ SPIClassRP2040
|
||||
#else
|
||||
#define __SPI_CLASS__ SPIClass
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@ -77,12 +79,18 @@ public:
|
||||
|
||||
// LOW LEVEL API - Expert users only
|
||||
void writeControlRegister(uint16_t value);
|
||||
void writeFreqRegister(uint8_t reg, uint32_t freq);
|
||||
void writePhaseRegister(uint8_t reg, uint16_t value);
|
||||
void writeFrequencyRegister(uint8_t channel, uint32_t freq);
|
||||
void writePhaseRegister(uint8_t channel, uint16_t value);
|
||||
|
||||
|
||||
// EXPERIMENTAL HLB MODE (14 bit)
|
||||
void writeFrequencyRegisterLSB(uint8_t channel, uint16_t LSB);
|
||||
void writeFrequencyRegisterMSB(uint8_t channel, uint16_t MSB);
|
||||
|
||||
|
||||
private:
|
||||
void writeData(uint16_t data);
|
||||
void writeData28(uint16_t LSB, uint16_t MSB);
|
||||
|
||||
bool _hwSPI = true;
|
||||
uint32_t _SPIspeed = 8000000;
|
||||
|
@ -6,6 +6,20 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
|
||||
## [0.3.0] - 2023-11-26
|
||||
- fix #10, explicit write control register fixes glitch.
|
||||
- rename **writeFreqRegister()** to **writeFrequencyRegister()**
|
||||
- refactor **writeFrequencyRegister()**
|
||||
- rename parameters reg => channel
|
||||
- catch define conflict __SPI_CLASS__
|
||||
- update readme.md
|
||||
- add experimental support for HLB write mode
|
||||
- **void writeFrequencyRegisterLSB(uint8_t reg, uint16_t LSB)**
|
||||
- **void writeFrequencyRegisterMSB(uint8_t reg, uint16_t MSB)**
|
||||
- update keywords.txt
|
||||
|
||||
----
|
||||
|
||||
## [0.2.0] - 2023-11-26
|
||||
- refactor constructor/begin interface - breaking changes.
|
||||
- minimize conditional code. -- create SPI_CLASS macro to solve it.
|
||||
|
@ -203,13 +203,32 @@ Use at your own risk, please read the datasheet carefully.
|
||||
Since version 0.1.1 writing to the registers is made public.
|
||||
By using the low level API to access the registers directly, one has maximum
|
||||
control over the AD9833 device.
|
||||
Especially frequency setting is improved as the float **setFrequency()** does
|
||||
Especially frequency setting is improved as the float parameter of **setFrequency()** does
|
||||
not have the 28 bits precision of the register.
|
||||
|
||||
- **void writeControlRegister(uint16_t value)** see datasheet
|
||||
- **void writeFreqRegister(uint8_t reg, uint32_t freq)** reg = 0 or 1, freq = 0 .. 134217728
|
||||
- **void writePhaseRegister(uint8_t reg, uint16_t value)** reg = 0 or 1, freq = 0 .. 4095
|
||||
|
||||
- **void writeFrequencyRegister(uint8_t channel, uint32_t freq)** channel = 0 or 1, freq = 0 .. 134217728
|
||||
- **void writePhaseRegister(uint8_t channel, uint16_t value)** channel = 0 or 1, value = 0 .. 4095
|
||||
|
||||
|
||||
#### HLB mode
|
||||
|
||||
To support the HLB mode the library supports (experimental 0.3.0) two new calls.
|
||||
These functions allow one to set the frequency in coarse steps (MSB)
|
||||
of around 3050 Hz and fine steps (LSB) of around 0.093 Hz.
|
||||
|
||||
- **void writeFrequencyRegisterLSB(uint8_t channel, uint16_t LSB)** channel = 0 or 1, LSB = 0 .. 32767
|
||||
- **void writeFrequencyRegisterMSB(uint8_t channel, uint16_t MSB)** channel = 0 or 1, MSB = 0 .. 32767 (in theory)
|
||||
|
||||
Note the HLB calls take only 2 SPI calls to adjust the frequency.
|
||||
Therefore they are slightly faster than the **setFrequency()** (uses 3 SPI calls)
|
||||
if you only need to modify one of the two frequency registers.
|
||||
|
||||
Only using the LSB register allows one to go from 0 .. 3050 Hz.
|
||||
In piano scales this covers C0 (16.35 Hz) to F#7 (2959.96 Hz).
|
||||
|
||||
https://pages.mtu.edu/~suits/notefreqs.html
|
||||
|
||||
|
||||
## External FSYNC
|
||||
|
||||
@ -243,11 +262,9 @@ As this implementation is experimental, the interface might change in the future
|
||||
#### Must
|
||||
|
||||
- update documentation
|
||||
- get hardware to test
|
||||
|
||||
#### Should
|
||||
|
||||
- investigate HLB mode versus B28 mode
|
||||
- investigate external clock
|
||||
- investigate timing (response time)
|
||||
- change freq
|
||||
@ -260,8 +277,6 @@ As this implementation is experimental, the interface might change in the future
|
||||
- add examples
|
||||
- for ESP32 HWSPI interface
|
||||
- solve MAGIC numbers (defaults)
|
||||
- setting half freq register for performance mode.
|
||||
- HLB mode
|
||||
- extend performance measurements
|
||||
- investigate compatibility AD9834 a.o.
|
||||
- add **setPhaseRadians(float radians, uint8_t channel)** wrapper.
|
||||
|
@ -0,0 +1,34 @@
|
||||
// FILE: AD9833_HLB_MODE.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test
|
||||
// URL: https://github.com/RobTillaart/AD9833/issues/10
|
||||
|
||||
|
||||
#include "AD9833.h"
|
||||
|
||||
AD9833 AD(10, 11, 13); // SW SPI UNO
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while(!Serial);
|
||||
Serial.println(__FILE__);
|
||||
|
||||
AD.begin();
|
||||
AD.setFrequency(1000, 0);
|
||||
AD.setFrequency(1000, 0);
|
||||
AD.setWave(2);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
AD.writeFrequencyRegisterLSB(0, 10000); // 931.32 Hz
|
||||
delay(2000);
|
||||
AD.writeFrequencyRegisterLSB(0, 5000); // 466.66 Hz
|
||||
delay(2000);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
@ -7,7 +7,12 @@
|
||||
|
||||
#include "AD9833.h"
|
||||
|
||||
// ESP32
|
||||
// SPIClass * myspi = new SPIClass(VSPI);
|
||||
// AD9833 AD(5, myspi);
|
||||
// AD9833 AD(15, 13, 14); // SW SPI
|
||||
|
||||
// UNO
|
||||
// AD9833 AD(10, 11, 13); // software SPI
|
||||
AD9833 AD(10); // hardware SPI
|
||||
|
||||
@ -48,6 +53,20 @@ void setup()
|
||||
Serial.print("setWave:\t");
|
||||
Serial.println(stop - start);
|
||||
delay(10);
|
||||
|
||||
start = micros();
|
||||
AD.writeFrequencyRegisterLSB(0, 10000);
|
||||
stop = micros();
|
||||
Serial.print("writeFrequencyRegisterLSB:\t");
|
||||
Serial.println(stop - start);
|
||||
delay(10);
|
||||
|
||||
start = micros();
|
||||
AD.writeFrequencyRegisterMSB(0, 10000);
|
||||
stop = micros();
|
||||
Serial.print("writeFrequencyRegisterMSB:\t");
|
||||
Serial.println(stop - start);
|
||||
delay(10);
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,24 @@
|
||||
|
||||
Board: ESP32 (240 Mhz)
|
||||
IDE: 1.8.19
|
||||
|
||||
AD9833_performance.ino
|
||||
AD9833_LIB_VERSION: 0.3.0
|
||||
|
||||
|
||||
hardware: 1 (hardware SPI)
|
||||
setFrequency: 48 (increased due to fix #10)
|
||||
setPhase: 20
|
||||
setWave: 14
|
||||
writeFrequencyRegisterLSB: 23
|
||||
writeFrequencyRegisterMSB: 23
|
||||
|
||||
|
||||
hardware: 0 (software SPI)
|
||||
setFrequency: 48 (increased due to fix #10)
|
||||
setPhase: 15
|
||||
setWave: 10
|
||||
writeFrequencyRegisterLSB: 16
|
||||
writeFrequencyRegisterMSB: 16
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
|
||||
Board: UNO (16 Mhz)
|
||||
IDE: 1.8.19
|
||||
|
||||
AD9833_performance.ino
|
||||
AD9833_LIB_VERSION: 0.3.0
|
||||
|
||||
hardware: 1 (hardware SPI)
|
||||
setFrequency: 44 (increased due to fix #10)
|
||||
setPhase: 24
|
||||
setWave: 24
|
||||
writeFrequencyRegisterLSB: 40
|
||||
writeFrequencyRegisterMSB: 40
|
||||
|
||||
|
||||
hardware: 0 (software SPI)
|
||||
setFrequency: 628 (increased due to fix #10)
|
||||
setPhase: 220
|
||||
setWave: 220
|
||||
writeFrequencyRegisterLSB: 428
|
||||
writeFrequencyRegisterMSB: 432
|
||||
|
34
libraries/AD9833/examples/AD9833_test_10/AD9833_test_10.ino
Normal file
34
libraries/AD9833/examples/AD9833_test_10/AD9833_test_10.ino
Normal file
@ -0,0 +1,34 @@
|
||||
// FILE: AD9833_test_10.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: test
|
||||
// URL: https://github.com/RobTillaart/AD9833/issues/10
|
||||
|
||||
|
||||
#include "AD9833.h"
|
||||
|
||||
AD9833 AD(10, 11, 13);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while(!Serial);
|
||||
Serial.println(__FILE__);
|
||||
|
||||
AD.begin();
|
||||
AD.setFrequency(1000, 0);
|
||||
AD.setFrequency(1000, 0);
|
||||
AD.setWave(2);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
AD.setFrequency(5000, 0);
|
||||
delay(10);
|
||||
AD.setFrequency(6000, 0);
|
||||
delay(10);
|
||||
}
|
||||
|
||||
|
||||
// -- END OF FILE --
|
@ -27,11 +27,13 @@ setSPIspeed KEYWORD2
|
||||
getSPIspeed KEYWORD2
|
||||
usesHWSPI KEYWORD2
|
||||
|
||||
selectHSPI KEYWORD2
|
||||
selectVSPI KEYWORD2
|
||||
usesHSPI KEYWORD2
|
||||
usesVSPI KEYWORD2
|
||||
setGPIOpins KEYWORD2
|
||||
|
||||
# LOW LEVEL API
|
||||
writeControlRegister KEYWORD2
|
||||
writeFrequencyRegister KEYWORD2
|
||||
writePhaseRegister KEYWORD2
|
||||
writeFrequencyRegisterLSB KEYWORD2
|
||||
writeFrequencyRegisterMSB KEYWORD2
|
||||
|
||||
|
||||
# Constants (LITERAL1)
|
||||
@ -44,4 +46,5 @@ AD9833_OFF LITERAL1
|
||||
AD9833_SINE LITERAL1
|
||||
AD9833_SQUARE1 LITERAL1
|
||||
AD9833_SQUARE2 LITERAL1
|
||||
AD9833_TRIANGLE LITERAL1
|
||||
AD9833_TRIANGLE LITERAL1
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/AD9833.git"
|
||||
},
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"license": "MIT",
|
||||
"frameworks": "*",
|
||||
"platforms": "*",
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=AD9833
|
||||
version=0.2.0
|
||||
version=0.3.0
|
||||
author=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.
|
||||
|
Loading…
Reference in New Issue
Block a user