Modifying the DDS Engine
Time-Variant DDS
The aforementioned design of a DDS engine relies on modifying the Tuning Word to achieve a wide variety of output waveforms. However, that particular design loses waveform sample precision as the represented frequency increases above the sampling capabilities of the Sample Table and the Source Clock. This occurs whenever the Tuning Word becomes larger than 1, since that indicates that a sample is eventually skipped to maintain synchronization with the desired output frequency. In some systems, this behavior is undesirable. To combat this, a Time-Variant DDS engine exists. The Tuning Word is always set to 1, and the effective Source Clock is instead adjusted to change the amount of time between each sample selection in the DDS engine. To calculate the required delta time for each sample selection, the base FPGA clock frequency (assume 40MHz), the target output frequency, and the Sample Table need to be considered. The Accumulator will no longer track the position in the Sample Table, but instead manage clock drift from non-integer Source Clock periods. The decimal will be stored, accumulated, and will occasionally generate addition clock tick(s) of wait time in between each execution of the DDS engine.
Example: Basic Sinusoid Output
Target Output Frequency: 2500.25 Hz
Base FPGA Clock: 40MHz
Sample Table: 360 Samples
Effective Source Clock Period: 44.44 Ticks/Sample
Math: SourceClockPeriod = FPGAClockFreq / (TargetFrequency * SampleTableSize)
Rationale: In this case, the DDS engine is controlled by a dynamically changing period. Each execution of the DDS engine will take 44 ticks of the base FPGA clock, with the Accumulator tracking the 0.44 partial ticks of drift on each execution. Upon the Accumulator growing above a value of 1, the integer component of that value is removed from the Accumulator and added to the period of the next DDS engine execution. The non-integer component is stored back in the Accumulator to continue tracking drift correctly.
Non-Sinusoidal Data
A DDS engine (assume the normal DDS engine for this discussion, not the Time-Variant version) can be leveraged to output non-waveform values, given that the behavior is fundamentally cyclic. That is to say, as long as the output can be represented by iterating through the Sample Table it is possible to produce that value for output reliably. As a point of warning, don't build a DDS engine when you know you only need to output slow DC values. These examples are only meant to show that such behavior is possible with minimal/no changes to a pre-existing DDS engine.
Example: Simple DC Output
Target Output Frequency: 0 Hz (DC)
Target DC Value: 2.5V
Source Clock: 10MHz
Sample Table: 100 Samples
Tuning Word: 1-100 (Doesn't really matter)
Rationale: In this particular instance, we fill the Sample Table completely with the target output value. Since the sample table is all the same value, it doesn't matter what value the tuning word is. Accessing any index in the Sample Table will produce a 2.5 output. This is a very simple and reliable mechanism to produce a DC output.
Example 1 will reliably utilize the existing DDS engine to produce a DC value output. It's somewhat non-ideal though, since we always need to write to the entire Sample Table to make a new output. It's possible that we can do better with a minor update to the DDS engine. With this slight addition, we add in a non-accumulated offset that allows the controller software to influence the accessed Sample Table index directly. Since it is a non-accumulated value, this offset must occur after the floor/truncation operation and cannot effect the normal behavior of the Accumulator.
Example: More Efficient DC Updates
Target Output Frequency: 0 Hz (DC)
Target DC Values: 0-9.9V (0.1V Increments)
Source Clock: 10MHz
Sample Table: 100 Samples
Tuning Word: 100
Offset Index: 0-99
Rationale: In this example, we've added the Offset Index. This is simply a U32 that gets added directly to the output of the accumulation logic after the floor/truncation operation. With the tuning word set to 100, we're simply telling the DDS engine to access a particular index in the Sample Table directly. From that, we fill the Sample Table with the complete range of values we want to output.
Online Resources
Related Links
- ryanvallieres's blog
- Log in or register to post comments