mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
0.4.2 AD9833
This commit is contained in:
parent
66e9ef06bb
commit
1fd76995da
@ -2,12 +2,14 @@
|
||||
// FILE: AD9833.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// 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
|
||||
//
|
||||
|
||||
|
||||
#include "AD9833.h"
|
||||
|
||||
|
||||
// FREQUENCY REGISTER BITS
|
||||
#define AD9833_FREG1 0x8000
|
||||
#define AD9833_FREG0 0x4000
|
||||
@ -25,7 +27,6 @@
|
||||
#define AD9833_MODE (1 << 1)
|
||||
|
||||
|
||||
|
||||
// HARDWARE SPI
|
||||
AD9833::AD9833(uint8_t slaveSelect, __SPI_CLASS__ * mySPI)
|
||||
{
|
||||
@ -34,6 +35,7 @@ AD9833::AD9833(uint8_t slaveSelect, __SPI_CLASS__ * mySPI)
|
||||
_mySPI = mySPI;
|
||||
}
|
||||
|
||||
|
||||
// SOFTWARE SPI
|
||||
AD9833::AD9833(uint8_t slaveSelect, uint8_t spiData, uint8_t spiClock)
|
||||
{
|
||||
@ -67,6 +69,15 @@ void AD9833::begin()
|
||||
pinMode(_clockPin, OUTPUT);
|
||||
digitalWrite(_dataPin, LOW);
|
||||
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();
|
||||
}
|
||||
@ -94,16 +105,23 @@ void AD9833::hardwareReset()
|
||||
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
|
||||
// clear previous power bits
|
||||
_control &= ~(AD9833_SLEEP1 | AD9833_SLEEP12);
|
||||
_control |= (mode << 6); // set the new power bits
|
||||
writeControlRegister(_control);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint8_t AD9833::getPowerMode()
|
||||
{
|
||||
return (_control & (AD9833_SLEEP1 | AD9833_SLEEP12)) >> 6;
|
||||
}
|
||||
|
||||
|
||||
void AD9833::setWave(uint8_t waveform)
|
||||
{
|
||||
if (waveform > 4) return;
|
||||
if (waveform > AD9833_TRIANGLE) return;
|
||||
|
||||
// store waveform
|
||||
_waveform = waveform;
|
||||
@ -143,24 +161,29 @@ uint8_t AD9833::getWave()
|
||||
float AD9833::setFrequency(float frequency, uint8_t channel)
|
||||
{
|
||||
if (channel > 1) return -1;
|
||||
_freq[channel] = frequency;
|
||||
if (_freq[channel] > AD9833_MAX_FREQ) _freq[channel] = AD9833_MAX_FREQ;
|
||||
if (_freq[channel] < 0) _freq[channel] = 0;
|
||||
// if (_freq[channel] == frequency) return frequency;
|
||||
// local variable is faster.
|
||||
float newFrequency = frequency;
|
||||
if (newFrequency < 0) newFrequency = 0;
|
||||
else if (newFrequency > AD9833_MAX_FREQ) newFrequency = AD9833_MAX_FREQ;
|
||||
|
||||
// convert to bit pattern
|
||||
// fr = round(frequency * pow(2, 28) / 25 MHz)); // 25 MHz == crystal frequency.
|
||||
// _crystalFreqFactor == (pow(2, 28) / crystal frequency);
|
||||
// rounding
|
||||
uint32_t freq = round(_freq[channel] * _crystalFreqFactor);
|
||||
// round() to minimize error / use the whole range
|
||||
uint32_t freq = round(newFrequency * _crystalFreqFactor);
|
||||
|
||||
writeFrequencyRegister(channel, freq);
|
||||
|
||||
return _freq[channel];
|
||||
// cache the newFrequency;
|
||||
_freq[channel] = newFrequency;
|
||||
return newFrequency;
|
||||
}
|
||||
|
||||
|
||||
float AD9833::getFrequency(uint8_t channel)
|
||||
{
|
||||
// return round(_freq[channel] * _crystalFreqFactor) / _crystalFreqFactor;
|
||||
return _freq[channel];
|
||||
}
|
||||
|
||||
@ -184,23 +207,43 @@ void AD9833::setFrequencyChannel(uint8_t channel)
|
||||
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;
|
||||
// local variable is faster.
|
||||
float newPhase = 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);
|
||||
|
||||
return _phase[channel];
|
||||
// cache the newPhase
|
||||
_phase[channel] = newPhase;
|
||||
return newPhase;
|
||||
}
|
||||
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
|
||||
// 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()
|
||||
{
|
||||
return AD9833_MAX_PHASE;
|
||||
@ -289,12 +332,14 @@ void AD9833::writePhaseRegister(uint8_t channel, uint16_t value)
|
||||
void AD9833::setCrystalFrequency(float crystalFrequency)
|
||||
{
|
||||
// calculate the often used factor
|
||||
// 268435456.0 == POW2TO28
|
||||
_crystalFreqFactor = 268435456.0 / crystalFrequency;
|
||||
}
|
||||
|
||||
|
||||
float AD9833::getCrystalFrequency()
|
||||
{
|
||||
// 268435456.0 == POW2TO28
|
||||
return 268435456.0 / _crystalFreqFactor;
|
||||
}
|
||||
|
||||
@ -335,7 +380,7 @@ void AD9833::writeFrequencyRegisterMSB(uint8_t channel, uint16_t MSB)
|
||||
_control |= AD9833_HLB;
|
||||
writeControlRegister(_control);
|
||||
|
||||
// send the least significant 14 bits
|
||||
// send the most significant 14 bits
|
||||
writeData(MSB);
|
||||
}
|
||||
|
||||
@ -356,17 +401,40 @@ void AD9833::writeData(uint16_t data)
|
||||
}
|
||||
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.
|
||||
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(dao, (data & mask) != 0 ? HIGH : LOW);
|
||||
digitalWrite(clk, LOW);
|
||||
digitalWrite(clk, HIGH);
|
||||
}
|
||||
digitalWrite(dao, LOW);
|
||||
|
||||
#endif
|
||||
}
|
||||
if (_useSelect) digitalWrite(_selectPin, HIGH);
|
||||
}
|
||||
@ -384,25 +452,57 @@ void AD9833::writeData28(uint16_t LSB, uint16_t MSB)
|
||||
}
|
||||
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.
|
||||
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(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(dao, (MSB & mask) != 0 ? HIGH : LOW);
|
||||
digitalWrite(clk, LOW);
|
||||
digitalWrite(clk, HIGH);
|
||||
}
|
||||
|
||||
digitalWrite(dao, LOW);
|
||||
#endif
|
||||
}
|
||||
if (_useSelect) digitalWrite(_selectPin, HIGH);
|
||||
}
|
||||
|
@ -3,7 +3,8 @@
|
||||
// FILE: AD9833.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// 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
|
||||
|
||||
|
||||
@ -11,7 +12,7 @@
|
||||
#include "SPI.h"
|
||||
|
||||
|
||||
#define AD9833_LIB_VERSION (F("0.4.1"))
|
||||
#define AD9833_LIB_VERSION (F("0.4.2"))
|
||||
|
||||
|
||||
#ifndef __SPI_CLASS__
|
||||
@ -53,7 +54,7 @@ public:
|
||||
void hardwareReset();
|
||||
// mode = 0..3 (datasheet)
|
||||
bool setPowerMode(uint8_t mode = 0);
|
||||
|
||||
uint8_t getPowerMode();
|
||||
|
||||
void setWave(uint8_t waveform = AD9833_OFF);
|
||||
uint8_t getWave();
|
||||
@ -72,6 +73,10 @@ public:
|
||||
float getPhase(uint8_t channel = 0);
|
||||
float getMaxPhase();
|
||||
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
|
||||
@ -107,8 +112,14 @@ private:
|
||||
SPISettings _spi_settings;
|
||||
|
||||
// PINS
|
||||
uint8_t _dataPin = 0;
|
||||
uint8_t _clockPin = 0;
|
||||
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
|
||||
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;
|
||||
bool _useSelect = false;
|
||||
|
||||
@ -119,6 +130,7 @@ private:
|
||||
float _freq[2] = { 0, 0 }; // Hz
|
||||
float _phase[2] = { 0, 0 }; // angle 0..360
|
||||
|
||||
// POW2TO28 / 25 MHz
|
||||
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/).
|
||||
|
||||
|
||||
## [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
|
||||
- add support for ARDUINO_ARCH_MBED
|
||||
- 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.
|
||||
Returns false if mode is out of range.
|
||||
Details see datasheet.
|
||||
- **uint8_t getPowerMode()** returns current powerMode bits.
|
||||
|
||||
| powerMode | meaning |
|
||||
|:-----------:|:------------------------------|
|
||||
@ -190,12 +191,18 @@ Returns the phase set in degrees.
|
||||
- **float getMaxPhase()** returns the maximum phase to set (convenience).
|
||||
- **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
|
||||
|
||||
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.
|
||||
- **uint32_t getSPIspeed()** returns SPI transfer rate.
|
||||
@ -292,24 +299,31 @@ As this implementation is experimental, the interface might change in the future
|
||||
|
||||
#### Should
|
||||
|
||||
- evaluate the **setCrytalFrequency()** implementation / performance.
|
||||
- runtime adjust-ability is preferred however...
|
||||
- investigate external clock
|
||||
- investigate timing (response time)
|
||||
- change freq
|
||||
- change channels etc.
|
||||
- test on ESP32 (3V3)
|
||||
|
||||
#### 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
|
||||
- add examples
|
||||
- for ESP32 HWSPI interface
|
||||
- solve MAGIC numbers (defaults)
|
||||
- extend performance measurements
|
||||
- add defines AD9833_POWERMODE_xxxx ?
|
||||
- investigate compatibility AD9834 a.o.
|
||||
- add **setPhaseRadians(float radians, uint8_t channel)** wrapper.
|
||||
- add **getPhaseRadians(uint8_t channel)** wrapper.
|
||||
- need time / HW for this.
|
||||
|
||||
|
||||
#### Wont
|
||||
|
||||
|
@ -23,14 +23,14 @@ uint32_t start, stop;
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while(!Serial);
|
||||
while (!Serial);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AD9833_LIB_VERSION: ");
|
||||
Serial.println(AD9833_LIB_VERSION);
|
||||
Serial.println();
|
||||
delay(10);
|
||||
|
||||
SPI.begin();
|
||||
// SPI.begin();
|
||||
|
||||
AD.begin();
|
||||
|
||||
@ -72,6 +72,20 @@ void setup()
|
||||
Serial.print("writeFrequencyRegisterMSB:\t");
|
||||
Serial.println(stop - start);
|
||||
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"
|
||||
|
||||
|
||||
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;
|
||||
bool up = true;
|
||||
@ -22,6 +25,7 @@ void setup()
|
||||
Serial.println(AD9833_LIB_VERSION);
|
||||
Serial.println();
|
||||
|
||||
// comment next line if HWSPI pins are used for SW SPI
|
||||
SPI.begin();
|
||||
AD.begin();
|
||||
AD.setWave(AD9833_SINE);
|
||||
@ -37,7 +41,7 @@ void loop()
|
||||
if (freq <= 100) up = true;
|
||||
AD.setFrequency(freq);
|
||||
|
||||
delay(100); // to simulate other tasks
|
||||
delay(10); // to simulate other tasks
|
||||
}
|
||||
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/AD9833.git"
|
||||
},
|
||||
"version": "0.4.1",
|
||||
"version": "0.4.2",
|
||||
"license": "MIT",
|
||||
"frameworks": "*",
|
||||
"platforms": "*",
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=AD9833
|
||||
version=0.4.1
|
||||
version=0.4.2
|
||||
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