AD9959
Recommended for New Designs
The AD9959 consists of four direct digital synthesizer (DDS)
cores that provide independent frequency, phase, and amplitude
control on each channel. This...
Datasheet
AD9959 on Analog.com
Hello,
I'm working on a new version of my 3 phase generator. The reason to use DDS is that I need to fine tune the phase shifts, what are not exactly 120 degrees(due to mechanical imperfections), but close. Frequency is low. From about 10Hz to 100Hz max.
Now, I try to work out a slow frequency ramp from 0 to 50Hz, in about 7 second: i would not do that with linear sweep, as I see it is way too fast (clock is 20MHz, but still). To have about a hundred discrete step instead of continuous ramp would not be a problem, if, I could find a way to avoid that glitch when I issue I/O update, after updating FTW. I guess it resets phase accumulator no matter where I am in the sinusoidal wave.
If I could sense digitally (I mean, without measuring back the generated analog signal) the zero phase, I would issue I/O update there, but I find no way to do that. Or, is there a function maybe that it only gets updated at certain phase?
How would you solve this?
Thanks!
JG
Any idea please?
I did tried to update frequency only through FTW, but when I write frequency only, it looses the phase difference and at i/o update. All channels restarting with zero phase and are in sync.
Hi Giordano21 ,
Have you tried activating either Autoclear phase accumulator or Clear phase accumulator. Not sure which one fits perfectly for your application.
Autoclear phase accumulator:
0 = the current state of the phase accumulator is not impacted by receipt of an I/O_UPDATE signal (default)
1 = the phase accumulator is automatically and synchronously cleared for one cycle upon receipt of an I/O_UPDATE signal.
Clear phase accumulator:
0 = the phase accumulator functions as normal (default)
1 = the phase accumulator memory elements are asynchronously cleared.
Let me know if this works for you.
All the best,
Jules
It doesn't help :-(
Both are 1 by default. In that case, with each FTW update I have to rewrite the POW also, because if I do not do it, both will be in the same phase. :
If I set bit 12, "All channels clear phase accumulator" to one, I have no signal output a all:
If I set bit 13, "All channels autoclear phase accumulator" to one, I have all output in the same phase and at IO update it jumps:
If I set both bit 13 and 12 to 1, I get no output:
Still the best option is to update POW with the frequency update, but, the problem is that I get these "glitches" at changes. The channel one here starts with 0 phase, channel 2 with 90 degrees shifted.
Unfortunately, I can not allow these "glitches". Is there any other option to try?
Thanks a lot!
JG
Hi, any other suggestion please?
Or, it is not possible with the AD9959?
Thanks,
JG
Hi Giordano21 ,
Just a question, are you planning to synchronize 2 outputs of AD9959 that they have the same frequency and same phase? Probably when changing POW, you might have to issue an IO_Update for both at the same time.
All the best,
Jules
Hi Jules,
Thank You for your reply!
No, I use 3 output, same frequency but not the same phase. It is roughly 0 - 120 - 240 degrees, but finetuned in the application.
At initialization, I write FTW into all the 4 channels once, than I select channels one by one and write POW. At the end I issue an I/O Update. It works fine.
The problem is, when I change frequency, if I only write the FTW into all channels and issue I/O Update, it "forgets" the phase offset and after I/O Update all channels are starting with the new frequency and all with zero phase. All are in the same phase.
When I update frequency (once for the 4), I have to rewrite POW also (selecting one by one) and than issue an I/O update. That way, the frequency is correct, the phase is correct, but, at I/O update the channel 0 restarts az 0 degrees, channel one at 120 degrees, channel 3 at 240 degrees, no matter what the phase was before the I/O update. With other words, it resets phase to what is written in POW.
With other words, is there a way to update frequency without resetting phase accumulator and maintaining the offset between the channels? This is to avoid the glitch the phase reset causes.
As I described above, I did played with bit 12, "All channels clear phase accumulator" and bit 13, "All channels autoclear phase accumulator" but the result is not what I need. Which is not a surprise since the default setting is zero, which is NOT to reset phase accumulator at I/O Update, but it still does reset it.
:-(
Thanks for your help!
JG
... one more note, it did work with AD9954. There I was struggling a bit too :-), but realized I did set autoclear that time. Now I do not set it for sure. I've checked multiple times :-)
and, with the 9959 I also loose the phase offset.
I thought with the 9959 it will be much easier since I do not need to sync the chips, but due to this issue I'm facing now it is actually more problematic and I do not know what is happening.
This is how I update the frequency now. If I remove the section between the stars, all channels are restarting with 0 phase.
void update_frequency_DDS(void)
{
HAL_GPIO_WritePin(led_blue_GPIO_Port, led_blue_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(DDS_reset_GPIO_Port, DDS_reset_Pin, GPIO_PIN_SET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
HAL_GPIO_WritePin(DDS_reset_GPIO_Port, DDS_reset_Pin, GPIO_PIN_RESET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
writeBuf[0] = 0x04; // address frequency tuning word
writeBuf[1] = uFTW.bFTW.b0; // MSB of FTW
writeBuf[2] = uFTW.bFTW.b1;
writeBuf[3] = uFTW.bFTW.b2;
writeBuf[4] = uFTW.bFTW.b3; // LSB of FTW
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit (&hspi1, writeBuf, 5, 100);
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_SET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
writeBuf[0] = 0b00000000; // address channel select register
writeBuf[1] = 0b00010000; // select channel 0
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit (&hspi1, writeBuf, 2, 100);
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_SET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
writeBuf[0] = 0x05; // select phase offset word
writeBuf[1] = uPOW0.bPOW0.b0;
writeBuf[2] = uPOW0.bPOW0.b1;
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit (&hspi1, writeBuf, 3, 100);
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_SET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
writeBuf[0] = 0b00000000; // address channel select register
writeBuf[1] = 0b00100000; // select channel 1
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit (&hspi1, writeBuf, 2, 100);
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_SET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
writeBuf[0] = 0x05; // select phase offset word
writeBuf[1] = uPOW1.bPOW1.b0;
writeBuf[2] = uPOW1.bPOW1.b1;
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit (&hspi1, writeBuf, 3, 100);
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_SET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
writeBuf[0] = 0b00000000; // address channel select register
writeBuf[1] = 0b01000000; // select channel 2
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit (&hspi1, writeBuf, 2, 100);
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_SET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
writeBuf[0] = 0x05; // select phase offset word
writeBuf[1] = uPOW2.bPOW2.b0;
writeBuf[2] = uPOW2.bPOW2.b1;
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit (&hspi1, writeBuf, 3, 100);
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_SET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
writeBuf[0] = 0b00000000; // address channel select register
writeBuf[1] = 0b10000000; // select channel 3
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit (&hspi1, writeBuf, 2, 100);
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_SET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
writeBuf[0] = 0x05; // select phase offset word
writeBuf[1] = uPOW3.bPOW3.b0;
writeBuf[2] = uPOW3.bPOW3.b1;
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit (&hspi1, writeBuf, 3, 100);
HAL_GPIO_WritePin(DDS_CS_GPIO_Port, DDS_CS_Pin, GPIO_PIN_SET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
HAL_GPIO_WritePin(IO_update_GPIO_Port, IO_update_Pin, GPIO_PIN_SET);
__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
HAL_GPIO_WritePin(IO_update_GPIO_Port, IO_update_Pin, GPIO_PIN_RESET);
}