Closed pocdn closed 5 years ago
Even though I wrote this to the best of my ability, I have not been able to test it with live hardware yet because I'm changing my hardware platform at present (to a 3v3 one, so no level translators needed). As far as I know, the bi-directional level translators are strong in the step-down direction, but only weak in the other direction. So I can only ask that you carefully check the polarity and bit ordering, etc, of everything that my code emits, and perhaps (if you can) correlate it to what the GUI version does. Perhaps I've failed to set some register in the right sequence, etc? I'm very keen to know whether you succeed or why you failed. I will be able to help more after I connect my new hardware.
Some initial debug items: 1) The bit order and polarity seemed to be opposite of what the GUI produced when snooping the SDIO_0 and SCLK lines, which I remedied in your library by changing to MSBFIRST, SPI_MODE3 in spiBegin(). After that The PC control and Arduino bits matched on the scope traces. 2) To match the the GUI again, when setting the frequency I had to change the original "0" to 0xFF in the following void setAmplitude(ChannelNum chan, uint16_t amplitude) // Maximum amplitude value is 1023 { amplitude &= 0x3FF; // ten bits. We could clamp instead, but don't setChannels(chan); spiBegin(); SPI.transfer(ACR); // Amplitude control register SPI.transfer(0xFF); //!!!! changed from 0 to 0xff to match scope traces when probing under GUI control ... }; 3) there was an error in sending one more byte than defined in uint32_t write(uint8_t reg, uint32_t value) i,e the while loop guard condition was changed from (len-- >= 0) to (--len >= 0). This resolved the sending of one extra byte that wasn't necessary.
Overall, I am able to a set a frequency single tone from Arduino control. Items [1-3] above helped the bit endian order, polarity of SCLK and SDIO_O to match the observed patterns when under PC control.
The test code that worked is
void setup() { SPI.begin(); // start the SPI library:
dds = new MyAD9959(); dds->setClock(20, 0); // int mult = 20, uint32_t calibration = 0
DDS_D0 = dds->frequencyDelta(7140000UL); // slow-expensive operation DDS_A0 = 1023; DDS_P0 = 2; DDS_D1 = dds->frequencyDelta(7140000UL); // slow-expensive operation DDS_A1 = 1023; DDS_P1 = 8192; DDS_D2 = dds->frequencyDelta(7140000UL); // slow-expensive operation DDS_A2 = 1023; DDS_P2 = 12288; DDS_D3 = dds->frequencyDelta(7140000UL); // slow-expensive operation DDS_A3 = 1023; DDS_P3 = 16383;
dds->setDelta(MyAD9959::Channel0, DDS_D0); dds->setAmplitude(MyAD9959::Channel0, DDS_A0); dds->setPhase(MyAD9959::Channel0, DDS_P0);
dds->setDelta(MyAD9959::Channel1, DDS_D1); dds->setAmplitude(MyAD9959::Channel1, DDS_A1); dds->setPhase(MyAD9959::Channel1, DDS_P1);
dds->update(); }
Good progress. Many thanks for your feedback. I should add a note to my ReadME that it's not tested properly yet. Are you cross-checking with the data sheet? Alternatively there is some other code around (for a PIC, spit!) somewhere - you could see what that does.
After correcting the issues noted (bit order, SPI byte count, amplitude), were you able to get the AD9959 working correctly? (My code still has 0 for the first ACR byte, I need to check this in the data sheet)
Yes, the issues noted above (bit order, SPI byte count, amplitude) were sufficient to have the AD9959 working well to control all four channels with each being able to set amplitude, phase, and frequency.
I just spent some time trying to understand why you needed to send the top byte of ACR to 0xFF. This is the Ramp Rate byte which determines the time between ramp steps. However the following byte activates manual amplitude control and disables ramping. So the top byte is ignored anyway. I've revised the library to make this more obvious, and to allow setting amplitude to 1024, which disables the amplitude multiplier entirely (this will save power too).
Please check this change with your hardware, if you can still do this.
The new change partially worked except
1.the SPI mode needed to be SPI_MODE3
fix: SPI.beginTransaction(SPISettings(SPIRate, MSBFIRST, SPI_MODE3)); old: SPI.beginTransaction(SPISettings(SPIRate, MSBFIRST, SPI_MODE0));
fix: while (--len >= 0) old: while (len-- > 0) ... is okay but this notation leads one to incorrectly assume that len value inside the loop will never be 0, when in fact it will be 0 on last iteration.
Attached is the full working version for me.
Thank you. I applied the following changes:
Use SPI_MODE3
This is idiom. I read my version as "each time the loop test is entered, len contains the number of bytes remaining." In that sense, we continue if there are bytes remaining. "in fact it will be zero" when there is nothing left to send, no incorrect assumptions there. len is not used inside the loop.
I added a cfr parameter to the reset function. I don't want to clear the accumulators, but this should be accommodated in the API, not requiring a user to edit the library code.
Hi podn and cjheath,
I also bought a original evaluation board (https://www.digikey.com/catalog/en/partgroup/ad9959-evaluation-board/33267?utm_adgroup=Programmers%20Dev&slid=&gclid=Cj0KCQjwrrXtBRCKARIsAMbU6bFs-VywHwHHft0XwCDi_iW1I3jdZCtJ44OYY0LwUY9xU03XFs24bF4aAuF9EALw_wcB) and got it working with PC software. But still having hard time getting it working with my arduino UNO. I am wondering if the arduino code expect 20 MHz to 30 MHz crystal (sine wave) only. I was able to get it working with 10 MHz square wave from a signal generator with GUI software. Could you let me know if the arduino code is supposed to work with square wave too?
best regards, Chun Sik
@chunsik79 The 4th parameter to the template is the oscillator frequency. Have you set this correctly on your evaluation board? Is there any jumper-configuration required to use the on-board oscillator? Can you scope the oscillator to ensure that it is running? Have you got all the required control pins connected correctly to your Arduino and set to the correct polarity, and is your board configured to use those control signals?
In short, I doubt you are experiencing a problem with this library. Please re-check the EVB documentation and your connections.
@cjheath Thanks! I just looked at the back of my board and found that it came without onboard crystal soldered. I will solder 25 MHz crystal and test again. I thought the library works also with reference clock (square wave) but I guess I was wrong. Thanks!
It should work fine with any reference clock, but it doesn't provide one. You just need to tell it what the clock frequency is so it can calculate delta words correctly.
Okay thanks for clarification. Does the clock need to be between 20 MHz and 30 MHz too?
Read the AD9959 data sheet. I don't believe there's a lower limit, but the multiplier (if you use it) has upper limits on both input and output frequencies. But check it yourself.
I was able to use the GUI software with the AD9959 eval board included software from the manufacturer to correctly control and generate sinusoids on all four channels. So I felt confident the DDS board was clocked correctly and working. Then I changed the jumper headers as needed to take over control with a micro controller (Arduino MEGA) and found no sinusoid signal output. The details are as follows.
Is there a known issue with the SDIO_N pins not being set to "output" or having enough drive current capacity? The following is a screenshot of the the SDIO_0 trace with and without connection to the actual AD9959 DDS.
The actual connection is an Arduino MEGA Pin 51 to Bi-directional Level Shifter ([*1]) to the AD9959 SDIO_0 eval board pin.
Note, all the connections are the same as the AD9959.h file except the change for the MEGA SPI pins
The goal is to get a single tone out of each of the 4 channels with the following code; ` void setup() {
dds = new MyAD9959();
DDS_D0 = dds->frequencyDelta(7140000UL); // slow-expensive operation DDS_A0 = 1023; DDS_P0 = 4096; DDS_D1 = dds->frequencyDelta(7140000UL); // slow-expensive operation DDS_A1 = 1023; DDS_P1 = 8192; DDS_D2 = dds->frequencyDelta(7140000UL); // slow-expensive operation DDS_A2 = 1023; DDS_P2 = 12288; DDS_D3 = dds->frequencyDelta(7140000UL); // slow-expensive operation DDS_A3 = 1023; DDS_P3 = 16383;
dds->setDelta(MyAD9959::Channel0, DDS_D0); dds->setAmplitude(MyAD9959::Channel0, DDS_A0); dds->setPhase(MyAD9959::Channel0, DDS_P0);
dds->setDelta(MyAD9959::Channel1, DDS_D1); dds->setAmplitude(MyAD9959::Channel1, DDS_A1); dds->setPhase(MyAD9959::Channel1, DDS_P1);
dds->setDelta(MyAD9959::Channel2, DDS_D2); dds->setAmplitude(MyAD9959::Channel2, DDS_A2); dds->setPhase(MyAD9959::Channel2, DDS_P2);
dds->setDelta(MyAD9959::Channel3, DDS_D3); dds->setAmplitude(MyAD9959::Channel3, DDS_A3); dds->setPhase(MyAD9959::Channel3, DDS_P3);
dds->update(); } ` Perhaps my C-code is missing something? Or the hardware is not able to correctly drive the SDIO_N pins with enough current thru the bi-directional level shifter? Any other obvious issues?
Thank you for this library. Hoping I am doing some simple error :)
[*1] Adafruit's 8-channel Bi-directional Logic Level Converter - TXB0108. link