Giter Club home page Giter Club logo

ad985x's Introduction

Arduino CI Arduino-lint JSON check GitHub issues

License: MIT GitHub release PlatformIO Registry

AD985X

Arduino library for AD9850 and AD9851 function generators.

Description

Library for the AD9850 and AD9851 function generators. These devices can produce a square and a sine wave

type max freq phase (step size) Notes
AD9850 40 MHz 0..31 x 11.25°
AD9851 70 MHz 0..31 x 11.25° has more options.

Note that at the max frequency the devices do not give a nice sine any more. You need to check what is acceptable for your project.

The library has a AD9850 as base class that implements the commonalities. The AD9851 is derived and has its own setFrequency() methods. Furthermore the AD9851 also has function to select the reference clock, a feature the AD9850 does not have. This feature improves the tuning for both low and high frequencies.

Warning The library is not suitable for AD9852 as that is a function generator with way more functionality.

Note: mainly tested on Arduino UNO.

0.5.0 Breaking change

Version 0.5.0 introduced a breaking change to improve handling the SPI dependency. The user has to call SPI.begin() or equivalent before calling AD.begin(). Optionally the user can provide parameters to the SPI.begin(...)

0.4.0 Breaking change

The version 0.4.0 has breaking changes in the interface. The essence is removal of ESP32 specific code from the library. Furthermore it moved parameters from begin() to the constructor. Finally made a specific constructor for HW SPI and SW SPI. This makes it possible to support the ESP32-S3 and other processors in the future. Also it makes the library a bit simpler to maintain.

Connection

Schema break-out

          TOP VIEW
        +-----------+
        |   X-TAL   |
        |         L |
    VCC | o       o | VCC
    CLK | o       o | D0
   PUFD | o       o | D1
   DATA | o       o | D2
  RESET | o       o | D3
    GND | o CCC   o | D4
  QOUT1 | o CCC   o | D5
  QOUT2 | o       o | D6
  ZOUT1 | o       o | D7 ----- SELECT SERIAL LOW
  ZOUT2 | o  PP   o | GND
        |    PP     |
        +-----------+

  XTAL = crystal
  L    = LED
  C    = chip
  P    = potentiometer => for duty cycle square wave

Related

Multi device

See Multi_AD985X_devices.pdf

Discussion leading to the document see - #13

The AD985X board can be connected with a SPI bus like interface. However there is no Chip Select pin (CS) so one must take other measures to control multiple AD985X devices.

Trivial solution

The trivial implementation is to give each device a set of unique pins. If you have pins to spare this is the perfect solution.

Shared line solution

A more common SPI solution is to share the data and clock lines. However that would typical set all AD985X devices simultaneously. So extra hardware is needed to prevent this.

A possible solution is to put all needed lines behind an AND port that allows only communication when the SELECT is HIGH.

     Arduino        AND           AD985X
--------------------------------------------------
 
                +--------+
     SELECT ----| A      |
                |      Y |------- DATA
     DATA  -----| B      |
                +--------+
  
                +--------+
     SELECT ----| A      |
                |      Y |------- CLOCK
     CLOCK  ----| B      |
                +--------+
 
                +--------+
     SELECT ----| A      |
                |      Y |------- FQ_UD
     FQ_UD  ----| B      |
                +--------+
 
                +--------+
     SELECT ----| A      |
                |      Y |------- RESET
     RESET  ----| B      |
                +--------+

The DATA line of the device is connected to the output of an AND port.
The inputs if the AND port are (a) the SPI bus DATA line and (b) the SELECT pin.
Strictly for the DATA this is not needed as data will only clock in if there is a CLOCK.

The CLOCK pin of the device is connected to the output of an AND port.
The inputs if the AND port are (a) the SPI bus CLOCK line and (b) the SELECT pin.

The FQ_UD pin of the device is connected to the output of an AND port.
The inputs if the AND port are (a) the MCU FQ_UD line and (b) the SELECT pin. See FQ_UD note below.

The RESET pin of the device is connected to the output of an AND port.
The inputs if the AND port are (a) the MCU RESET line and (b) the SELECT pin.

A typical IC to use is the 74HC08 which has 4 AND ports in it.

In short this setup makes the lines 'switchable' pass through, with the SELECT line. It allows to have multiple AD985X devices, and even to share the SPI bus DATA and CLOCK lines with other SPI devices.

FQ_UD note

It might be possible to connect a single FQ_UD line to multiple AD985X devices directly. The FQ_UD pulse would update the frequency and as this register is not changed, the FQ_UD pulse might just have no changing effect. To be investigated to confirm this.

If confirmed this would change the above Shared line solution a bit.

If the FQ_UD line can be shared directly it offers a way to start / change multiple devices at the same time.

Interface

#include "AD985X.h"

Constructors

  • AD9850(uint8_t slaveSelect, uint8_t resetPin, uint8_t FQUDPin, SPIClassRP2040 * mySPI, uint8_t spiClock) hardware SPI constructor RP2040
  • AD9850(uint8_t slaveSelect, uint8_t resetPin, uint8_t FQUDPin, SPIClass * mySPI, uint8_t spiClock) hardware SPI constructor
  • AD9850(uint8_t slaveSelect, uint8_t resetPin, uint8_t FQUDPin, uint8_t spiData, uint8_t spiClock)
    • slaveSelect = chip select. The library uses HIGH as active and LOW as not selected.
    • resetPin = reset
    • FQUDPin = Frequency UpDate Pin
  • AD9851(...) constructors with same interface as AD9850

Common interface

  • void begin() initializes library internals.
  • void reset() resets the function generator.
  • void powerDown() idem.
  • void powerUp() idem.
  • bool setFrequency(uint32_t freq) SetFrequency sets the frequency and is limited by the MaxFrequency of the class used. Returns false if limited. For the AD9850 => 40 MHz, for the AD9851 => 70 MHz.
    • Note that the quality of the signal gets less at higher frequencies.
    • Note setFrequency is affected by the autoUpdateFlag.
  • bool setFrequencyF(float freq) SetFrequencyF sets the frequency with a float with a maximum of two decimals.
    • Note that a float only has a mantissa of 6-7 digits so for frequencies above above ~1.000.000 = 1MHz all decimals are lost.
    • Note setFrequencyF is affected by the autoUpdateFlag. The frequency is limited by the MaxFrequency of the class used. Returns false if limited.
  • uint32_t getMaxFrequency() returns the maximum frequency that can be set.
    • For the AD9850 this is 20 MHz.
    • For the AD9851 this is 70 MHz.
  • float getFrequency() returns the frequency set. As it returns a float it might loose some accuracy at higher frequencies.
  • bool setPhase(uint8_t phase = 0) set the phase in units of 11.25° 0..31 allowed. Default it sets the phase to 0. Returns false if phase > 31, no change to phase in that case.
  • uint8_t getPhase() returns the phase set, 0 by default.
    • multiply by 11.25° to get the actual phase angle in degrees.
    • multiply by (PI * 0.0625) to get actual phase angle in radians.

Calibration

Warning: use with care.

  • void setCalibrationOffset(int32_t offset = 0) sets an offset to calibrate the frequency.
  • uint32_t getCalibrationOffset() reads back the offset set.
  • uint32_t getFactor() internal factor, for debugging

Note: reset() resets the offset to 0.. Note: setting the offset reduces the range of frequencies (at the ends of scale).

Auto update / manual update

(new since 0.2.2)

Warning: use with care.

  • void setAutoUpdate(bool update) sets the autoUpdate flag, default set to true.
  • bool getAutoUpdate() reads the autoUpdate flag.
  • void update() manually toggle the FQ_UD flag to update the frequency.

Manual updating allows one to prepare the frequency, and actually apply it at a later moment.

Note: The default of the autoUpdate flag is true.
Note: reset() resets the autoUpdateFlag to true.

Hardware SPI

To be used only if one needs a specific speed.

  • void setSPIspeed(uint32_t speed) set SPI transfer rate.
  • uint32_t getSPIspeed() returns SPI transfer rate.
  • bool usesHWSPI() returns true if HW SPI is used.

AD9851 additional

  • void setRefClockHigh() set reference clock to 180 Mhz.

  • void setRefClockLow() set reference clock to 30 Mhz.

  • uint8_t getRefClock() returns 30 or 180.

  • void setAutoRefClock(bool arc) sets a flag so the library switches automatically to the reference clock of 180 MHz when the frequency is set above 10 MHz and to 30 MHz when the frequency is set to 10 MHz or lower. The initial value is false == OFF for backwards compatibility.

  • bool getAutoRefClock() returns true if autoRefClock is set.

  • void setARCCutOffFreq(uint32_t Hz = 10000000UL ) set cut off frequency for the auto reference clock. Maximum value is 30 MHz, typical is 10 MHz.

  • uint32_t getARCCutOffFreq() returns cut off frequency set.

  • Note: the autoRefClock mode does NOT automatically adjust the calibration offset.

  • Note: reset() does NOT reset the autoRefClock flag.

Operation

See examples.

Operational notes

  • The quality of the signal becomes less at higher frequencies. Switch the reference clock to find your optimal quality.
  • If the calibration offset is not 0, it needs to be set by the user after every startup, and after switching the reference clock. The user is also responsible to store it e.g. in EEPROM to make it persistent.
  • Experimental parts may change or removed in the future.

Future

Must

  • improve documentation

Should

  • test on ESP32
  • test on RP2040

Could

  • performance measurements
  • move code to .cpp
  • create defines for MAGIC numbers (defaults)

Wont

  • bool setARCCutOffFreq() no need
  • should setSPIspeed(uint32_t speed) return bool?
    • out of range?
  • wave quality measurements

Support

If you appreciate my libraries, you can support the development and maintenance. Improve the quality of the libraries by providing issues and Pull Requests, or donate through PayPal or GitHub sponsors.

Thank you,

ad985x's People

Contributors

robtillaart avatar wh201906 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

mind2hand

ad985x's Issues

You could implement decimals in frequency.

Hello Rob.
First thank you for your great work
You could implement decimals in frequency.
I am doing a project that needs to generate frequencies with decimals and it is very complicated for me.
I wish if you can integrate at least 3 decimal places.
10,564 Hz.
Thanks

Update readme.md

  • connection diagram
  • ... cut off frequency = 10 MHz
  • calibration still experimental?

Multiple device configuartion

I am using Arduino Mega 2560. I have 2 devices that need to generate different frequencies almost simultaneously. I have pins to spare. I don't want to use AND logic.

I don't quite understand how to wire.

For the begin, is the first parameter (select), where I have D7 connected? I assume the rest of the pins are obvious.

For the Mega 2560, can I use any pins I want?

Multi-AD985X how to do

In issue #9 (decimals in frequency) a discussion started how to connect multiple AD985X devices to one MCU.

Problem description

The problem identified is that the device does NOT have a Chip Select pin (CS) like many SPI devices do have.
So sharing the DATA and CLOCK lines would result in preparing all AD985X devices with a new frequency.

How bad is that? As long as they do not get an update pulse it should not matter, however it is not a nice as an
glitch of the FQ_UD line (also not nice) would update to an unexpected frequency. So we need better solutions.

Note the library already has a select pin in the begin() function to be "SPI compatible"

You could implement decimals in frequency Ver 2

Hello again Rob.
something happens with the last updates in the decimal version, which does not change the frequency when uploading.
it only changes integers not decimals.
Can you check to see if something changed in the code?
if I change values ​​below the decimal places, the frequency does not change

`AD9851::setRefClockHigh()` doesn't work

To reproduce this bug:

ad9851.begin();
ad9851.powerUp();
ad9851.setAutoRefClock(false);
ad9851.setRefClockHigh();
ad9851.setFrequency(1000);

The output frequency is not 1kHz.


This can be fixed by #32

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.