Currently 3 bit output at 128 MHz sample rate. Available here: https://github.com/SaucySoliton/propeller-dds
The 3 bit output works well with the composite video DAC resistors on many Propeller boards. Signal purity is fairly poor, so keep your antenna wire short. I get enough leakage with just a coaxial cable to my scope. Sound quality has the potential to be very good once pre-emphasis is added as the DDS has tuning steps much smaller the 1 Hz. The high sampling rate should allow good signals below 20MHz with a simple RC lowpass filter.
While the counter PLL can generate any frequency from 500 kHz to 128+ MHz, the list of jitter-free frequencies can fit on one page. This is a frustrating limitation for RF projects. A little while ago I did some calculations for using the video generator to output a pre-calculated sine sequence. While this is useful for many more frequencies, it would not be usable for local oscillators for HF. The tuning steps were, for practical purposes, random, and could be as large as several kilohertz. One of the strengths of direct digital synthesis is very fine tuning resolution. So I began an investigation into the feasability of a proper DDS.
I decided to target the highest clock sample rate possible. This meant using the video generator to output pre-calculated groups of samples. 32 samples is the maximum, assuming each cog only outputs 1 bit. Also, it would be nice to access the hub every once in a while for frequency changes, for application like an FM transmitter. The video generators need to be synchronized exactly. It is necessary to fit the hub access between 2 WAITVIDs. Each cog's hub access is staggered by 2 clocks. This forces an additional trade-off between sample rate and number of bits. If the hub access was eliminated, it would be possible to synchronize any number of cogs together.
Other possible configurations for the DDS code, not yet implemented:
loop clocks bits/cog bits total
128MS 20 1 3 (maybe 4)
80MS 32 1 4+ ?
64MS 20 2 6 (maybe 8)
40MS 32 2 8+ ?
16MS 20 8 8+
5MS 16 32 32+
Assumes a 256-step sine table
Why is the last one 5 MS instead of 4? Recall that the Nyquist theorem says signals exceeding half the sampling rate cannot be perfectly reconstructed. They will alias to a frequency less than half the sampling rate. So, there is no logical reason to program a frequency that exceeds half the sampling rate. We could extend the table to one and a half cycles and 384 steps and only need to mask the accumulator every other addition. For groups of samples we can't assume we will only advance half the wave at a time. We could still use this trick with 2 or more full tables of 128 steps. I chose not to use the shorter table at this time.
:inline1 mov outa,0-0
addx accu,tw wc
:inline2 mov outa,0-0
addx accu,tw wc
Some of the implementations previously published
shift the accumulator to extract the MSBs with MOVS and then shift it back. We can save 2 instructions by leaving it in the shifted position. We have to use one of the instructions gained to clear the MSB carry bit so we stay in our table. But as noted above, it's possible to not need it every time. We can use ADDX to transfer the carry from LSBs to MSBs. A slight complication of this is that the carry is not added until the next addition. This would sometimes introduce an error of 1 step in the output. We could fix this by adding an offset to the accumulator so the carry happens one cycle sooner. That is simply adding a phase shift to our signal, which can be ignored for most applications.
The FM transmitter is nowhere near finished. I just it together to test the DDS. Sound quality is not so good without pre-emphasis. Signal purity is bad, but perhaps slightly better than Rasperry Pi before I fixed it.
I wish the Propeller had PLLs like the Raspberry Pi. The fractional N PLLs in that chip have a clean signal AND a wide enough loop bandwidth to modulate FM stereo. I will probably make a version of the transmitter that uses the Propeller PLL just to test the signal quality.