{"id":20989773,"url":"https://github.com/robtillaart/ad985x","last_synced_at":"2026-01-23T14:49:29.018Z","repository":{"id":41563206,"uuid":"282911926","full_name":"RobTillaart/AD985X","owner":"RobTillaart","description":"Arduino library for AD9850 and AD9851 function generators.","archived":false,"fork":false,"pushed_at":"2025-05-07T11:41:34.000Z","size":146,"stargazers_count":13,"open_issues_count":2,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-07T12:36:53.653Z","etag":null,"topics":["arduino","function-generator","waveform"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RobTillaart.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"RobTillaart","custom":"https://www.paypal.me/robtillaart"}},"created_at":"2020-07-27T13:50:00.000Z","updated_at":"2025-04-26T12:24:25.000Z","dependencies_parsed_at":"2024-04-13T09:48:29.340Z","dependency_job_id":"8a506527-509f-40ff-a79a-d87a3c3fde4b","html_url":"https://github.com/RobTillaart/AD985X","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/RobTillaart/AD985X","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FAD985X","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FAD985X/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FAD985X/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FAD985X/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RobTillaart","download_url":"https://codeload.github.com/RobTillaart/AD985X/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RobTillaart%2FAD985X/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28694457,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T14:15:13.573Z","status":"ssl_error","status_checked_at":"2026-01-23T14:09:05.534Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","function-generator","waveform"],"created_at":"2024-11-19T06:26:07.234Z","updated_at":"2026-01-23T14:49:29.002Z","avatar_url":"https://github.com/RobTillaart.png","language":"C++","funding_links":["https://github.com/sponsors/RobTillaart","https://www.paypal.me/robtillaart"],"categories":[],"sub_categories":[],"readme":"\n[![Arduino CI](https://github.com/RobTillaart/AD985X/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)\n[![Arduino-lint](https://github.com/RobTillaart/AD985X/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/AD985X/actions/workflows/arduino-lint.yml)\n[![JSON check](https://github.com/RobTillaart/AD985X/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/AD985X/actions/workflows/jsoncheck.yml)\n[![GitHub issues](https://img.shields.io/github/issues/RobTillaart/AD985X.svg)](https://github.com/RobTillaart/AD985X/issues)\n\n[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/AD985X/blob/master/LICENSE)\n[![GitHub release](https://img.shields.io/github/release/RobTillaart/AD985X.svg?maxAge=3600)](https://github.com/RobTillaart/AD985X/releases)\n[![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/AD985X.svg)](https://registry.platformio.org/libraries/robtillaart/AD985X)\n\n\n# AD985X\n\nArduino library for AD9850 and AD9851 function generators.\n\n\n## Description\n\nLibrary for the AD9850 and AD9851 function generators.\nThese devices can produce a square and a sine wave \n\n|   type   | max freq |  phase (step size)  |  Notes  |\n|:--------:|:--------:|:-------------------:|:--------|\n|  AD9850  |  40 MHz  |     0..31 x 11.25�  |\n|  AD9851  |  70 MHz  |     0..31 x 11.25�  | has more options.\n\n\nNote that at the max frequency the devices do not give a nice sine any more.\nYou need to check what is acceptable for your project.\n\nThe library has a AD9850 as base class that implements the commonalities.\nThe AD9851 is derived and has its own **setFrequency()** methods.\nFurthermore the AD9851 also has function to select the reference clock,\na feature the AD9850 does not have. \nThis feature improves the tuning for both low and high frequencies.\n\n**Warning**\nThe library is not suitable for AD9852 as that is a function generator with\nway more functionality.\n\nNote: mainly tested on Arduino UNO.\n\nFeedback as always is welcome.\n\n\n### 0.7.2 new constructors\n\nNot a breaking change (yet), the library has added new constructors as the **spiClock**\nline is not needed any more. See #37.\nAlso a new constructor is added to work without a select pin (always selected).\n\n\n### 0.5.0 Breaking change\n\nVersion 0.5.0 introduced a breaking change to improve handling the SPI dependency.\nThe user has to call **SPI.begin()** or equivalent before calling **AD.begin()**.\nOptionally the user can provide parameters to the **SPI.begin(...)**\n\n\n### 0.4.0 Breaking change\n\nThe version 0.4.0 has breaking changes in the interface. \nThe essence is removal of ESP32 specific code from the library. \nFurthermore it moved parameters from **begin()** to the constructor.\nFinally made a specific constructor for HW SPI and SW SPI.\nThis makes it possible to support the ESP32-S3 and other processors in the future. \nAlso it makes the library a bit simpler to maintain.\n\n\n## Connection\n\nSchema break-out\n\n```\n          TOP VIEW\n        +-----------+\n        |   X-TAL   |\n        |         L |\n    VCC | o       o | VCC\n    CLK | o       o | D0\n   PUFD | o       o | D1\n   DATA | o       o | D2\n  RESET | o       o | D3\n    GND | o CCC   o | D4\n  QOUT1 | o CCC   o | D5\n  QOUT2 | o       o | D6\n  ZOUT1 | o       o | D7 ----- SELECT SERIAL LOW\n  ZOUT2 | o  PP   o | GND\n        |    PP     |\n        +-----------+\n\n  XTAL = crystal\n  L    = LED\n  C    = chip\n  P    = potentiometer =\u003e for duty cycle square wave\n```\n\n\n### Related\n\n- https://github.com/RobTillaart/AD9833\n- https://github.com/RobTillaart/AD985X\n- https://github.com/RobTillaart/functionGenerator  software waveform generator\n- https://pages.mtu.edu/~suits/notefreqs.html  frequency table for notes.\n\n\n## Multi device \n\nSee **Multi_AD985X_devices.pdf**\n\nDiscussion leading to the document see - https://github.com/RobTillaart/AD985X/issues/13 \n\nThe AD985X board can be connected with a SPI bus like interface. \nHowever there is **no Chip Select pin (CS)** so one must take \nother measures to control multiple AD985X devices.\n\n\n### Trivial solution\n\nThe trivial implementation is to give each device a set of unique pins. \nIf you have pins to spare this is the perfect solution.\n\n\n### Shared line solution\n\nA more common SPI solution is to share the data and clock lines.\nHowever that would typical set all AD985X devices simultaneously.\nSo extra hardware is needed to prevent this.\n\nA possible solution is to put all needed lines behind an AND port that allows only\ncommunication when the **SELECT** is HIGH.\n\n```\n     Arduino        AND           AD985X\n--------------------------------------------------\n \n                +--------+\n     SELECT ----| A      |\n                |      Y |------- DATA\n     DATA  -----| B      |\n                +--------+\n  \n                +--------+\n     SELECT ----| A      |\n                |      Y |------- CLOCK\n     CLOCK  ----| B      |\n                +--------+\n \n                +--------+\n     SELECT ----| A      |\n                |      Y |------- FQ_UD\n     FQ_UD  ----| B      |\n                +--------+\n \n                +--------+\n     SELECT ----| A      |\n                |      Y |------- RESET\n     RESET  ----| B      |\n                +--------+\n\n```\n\n\nThe **DATA** line of the device is connected to the output of an **AND** port.  \nThe inputs if the **AND** port are (a) the SPI bus **DATA** line and (b) the **SELECT** pin.  \nStrictly for the **DATA** this is not needed as data will only clock in if there is a **CLOCK**.\n\nThe **CLOCK** pin of the device is connected to the output of an **AND** port.  \nThe inputs if the **AND** port are (a) the SPI bus **CLOCK** line and (b) the **SELECT** pin.\n\nThe **FQ_UD** pin of the device is connected to the output of an **AND** port.  \nThe inputs if the **AND** port are (a) the MCU **FQ_UD** line and (b) the **SELECT** pin.\nSee FQ_UD note below.\n\nThe **RESET** pin of the device is connected to the output of an **AND** port.  \nThe inputs if the **AND** port are (a) the MCU **RESET** line and (b) the **SELECT** pin.\n\nA typical IC to use is the **74HC08** which has 4 AND ports in it.\n\n\nIn short this setup makes the lines 'switchable' pass through, with the **SELECT** line.\nIt allows to have multiple AD985X devices, and even to share the SPI bus **DATA** and **CLOCK** \nlines with other SPI devices.\n\n\n## FQ_UD note\n\nIt might be possible to connect a single FQ_UD line to multiple AD985X devices directly.\nThe FQ_UD pulse would update the frequency and as this register is not changed, the FQ_UD \npulse might just have no changing effect. To be investigated to confirm this.\n\nIf confirmed this would change the above Shared line solution a bit. \n\nIf the FQ_UD line can be shared directly it offers a way to start / change multiple\ndevices at the same time. \n\n\n## Interface\n\n```cpp\n#include \"AD985X.h\"\n```\n\n### Constructors\n\nThere are constructors with and without SELECT pin, e.g. if device is continuously selected.\n\n- select = chip select. The library uses HIGH as active and LOW as not selected.  \n- resetPin = reset\n- FQUDPin = Frequency UpDate Pin\n\n#### HW SPI\n\n- **AD9850(uint8_t select, uint8_t resetPin, uint8_t FQUDPin, SPIClassRP2040 \\* mySPI)** hardware SPI constructor RP2040\n- **AD9850(uint8_t select, uint8_t resetPin, uint8_t FQUDPin, SPIClass \\* mySPI)** hardware SPI constructor.\n- **AD9850(uint8_t resetPin, uint8_t FQUDPin, SPIClassRP2040 \\* mySPI)** hardware SPI constructor RP2040\n- **AD9850(uint8_t resetPin, uint8_t FQUDPin, SPIClass \\* mySPI)** hardware SPI constructor.\n\n#### SW SPI\n\n- **AD9850(uint8_t select, uint8_t resetPin, uint8_t FQUDPin, uint8_t spiData, uint8_t spiClock)**\n- **AD9850(uint8_t resetPin, uint8_t FQUDPin, uint8_t spiData, uint8_t spiClock)**\n- **AD9851(...)** constructors with same interface as AD9850\n\n#### Deprecated\n\nDeprecated as spiClock no longer needed.\n\n- **AD9850(uint8_t select, uint8_t resetPin, uint8_t FQUDPin, SPIClassRP2040 \\* mySPI, uint8_t spiClock)** hardware SPI constructor RP2040.\n- **AD9850(uint8_t select, uint8_t resetPin, uint8_t FQUDPin, SPIClass \\* mySPI, uint8_t spiClock)** hardware SPI constructor.\n\n\n### Common interface\n\n- **void begin()** initializes library internals.\n- **void reset()** resets the function generator.\n- **void powerDown()** idem.\n- **void powerUp()** idem.\n\n\n### Frequency and phase\n\n- **bool setFrequency(uint32_t freq)** SetFrequency sets the frequency and is limited by the \nMaxFrequency of the class used.\nReturns false if limited. \nFor the AD9850 =\u003e 40 MHz, for the AD9851 =\u003e 70 MHz. \n  - Note that the quality of the signal gets less at higher frequencies. \n  - Note setFrequency is affected by the autoUpdateFlag.\n- **bool setFrequencyF(float freq)** SetFrequencyF sets the frequency with a float with a maximum of **two** decimals. \n  - 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.\n  - Note setFrequencyF is affected by the autoUpdateFlag.\nThe frequency is limited by the MaxFrequency of the class used.\nReturns false if limited. \n- **uint32_t getMaxFrequency()** returns the maximum frequency that can be set. \n  - For the AD9850 this is 20 MHz.\n  - For the AD9851 this is 70 MHz.\n- **float getFrequency()** returns the frequency set. \nAs it returns a float it might loose some accuracy at higher frequencies.\n- **bool setPhase(uint8_t phase = 0)** set the phase in units of 11.25�  0..31 allowed. \nDefault it sets the phase to 0.\nReturns false if phase \u003e 31, no change to phase in that case.\n- **uint8_t getPhase()** returns the phase set, 0 by default. \n  - multiply by 11.25� to get the actual phase angle in degrees.\n  - multiply by (PI \\* 0.0625) to get actual phase angle in radians.\n\n\n### Calibration\n\n**Warning:** use with care.\n\n- **void setCalibrationOffset(int32_t offset = 0)** sets an offset to calibrate the frequency.\n- **uint32_t getCalibrationOffset()** reads back the offset set.\n- **uint32_t getFactor()** internal factor, for debugging\n\nNote: **reset()** resets the offset to 0..\nNote: setting the offset reduces the range of frequencies (at the ends of scale).\n\n\n### Auto update / manual update\n\n(new since 0.2.2)\n\n**Warning:** use with care.\n\n- **void setAutoUpdate(bool update)** sets the autoUpdate flag, default set to true.\n- **bool getAutoUpdate()** reads the autoUpdate flag.\n- **void update()** manually toggle the FQ_UD flag to update the frequency.\n\nManual updating allows one to prepare the frequency, and actually apply \nit at a later moment.\n\nNote: The default of the autoUpdate flag is true.  \nNote: **reset()** resets the autoUpdateFlag to true.\n\n\n### Hardware SPI\n\nTo be used only if one needs a specific speed.\n\n- **void setSPIspeed(uint32_t speed)** set SPI transfer rate.\n- **uint32_t getSPIspeed()** returns SPI transfer rate.\n- **bool usesHWSPI()** returns true if HW SPI is used.\n\n\n## AD9851 additional\n\n- **void setRefClockHigh()** set reference clock to 180 MHz.\n- **void setRefClockLow()** set reference clock to 30 MHz.\n- **uint8_t getRefClock()** returns 30 or 180.\n- **void setAutoRefClock(bool arc)** sets a flag so the library switches automatically\nto the reference clock of 180 MHz when the frequency is set above 10 MHz and \nto 30 MHz when the frequency is set to 10 MHz or lower.\nThe initial value is **false** == OFF for backwards compatibility. \n- **bool getAutoRefClock()** returns true if autoRefClock is set. \n- **void setARCCutOffFreq(uint32_t Hz = 10000000UL )** set cut off frequency \nfor the auto reference clock. \nMaximum value is 30 MHz, typical is 10 MHz.\n- **uint32_t getARCCutOffFreq()** returns cut off frequency set.\n\n\n- Note: the autoRefClock mode does **NOT** automatically adjust the calibration offset.\n- Note: **reset()** does **NOT** reset the autoRefClock flag.\n\n\n## Operation\n\nSee examples.\n\n\n### Operational notes\n\n- The quality of the signal becomes less at higher frequencies.\nSwitch the reference clock to find your optimal quality.\n- If the calibration offset is not 0, it needs to be set by the user after every startup, \nand after switching the reference clock. \nThe user is also responsible to store it e.g. in EEPROM to make it persistent.\n- Experimental parts may change or removed in the future.\n\n\n## Future\n\n#### Must\n\n- improve documentation\n\n#### Should\n\n- test on ESP32\n- test on RP2040\n\n#### Could\n\n- performance measurements\n- move code to .cpp\n- create defines for MAGIC numbers (defaults)\n\n#### Wont\n\n- **bool setARCCutOffFreq()** no need\n- should **setSPIspeed(uint32_t speed)** return bool?\n  - out of range?\n- wave quality measurements\n\n\n## Support\n\nIf you appreciate my libraries, you can support the development and maintenance.\nImprove the quality of the libraries by providing issues and Pull Requests, or\ndonate through PayPal or GitHub sponsors.\n\nThank you,\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobtillaart%2Fad985x","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frobtillaart%2Fad985x","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobtillaart%2Fad985x/lists"}