sine wave generation in arty 7 35t

Recommended Posts

I want to generate a sine wave using arty7 35t board. how do I do that? can I do that using an IP? I want to use the onboard ADC. my final aim is, i want to generate a sine wave later i want to convert it back to digital signals

Share on other sites

If you want to use the on-board ADC (analog to digital converter), then you will need to feed it with an external function generator.  This is not what I think of when you write "I want to generate a sine wave using* arty7 35t board".

If you want to generate the sine wave internal to the FPGA, then you won't need the ADC.  There are a couple of approaches, depending on how good you want your sine wave to be and how much logic you want to pay for it.

1. You could build a straight table lookup.  This is usually the cheapest option in terms of hardware resources.  Feed the table with your angle (in the proper units), and get out a digitized sine wave.
2. You could do the same, but with a quarter-wave table look up.  This trades a bit of logic for a table that's one fourth the size.
3. There's always the CORDIC approach.  This one is commonly taught, and commonly used.  For a 12-16 bit sine wave, you might find this your best choice.  However, if you want to get a 32-bit sine wave, you might end up paying through the roof for this one in terms of logic.
4. Another approach would be to use an interpolator coupled with the sinewave lookup.  I've got a quadratic interpolator I use for this purpose.  (Sorry, haven't blogged about it yet)  With just a few table entries and two multiplies, you can get an amazing resolution--should be better than a similar CORDIC, but I haven't run the numbers yet.

There are some other things you'll want to think about.  Chief among them is how you are going to handle a sample rate that is much slower than your clock rate.  There's a nice strategy that I call the "global CE" strategy to solve this problem.  A second problem is what phase you will feed to the sine wave generator.  With a little bit of work with a simple adder, its not hard to make a numerically controlled oscillator that will produce any frequency you need.

Dan

Share on other sites

For the digital generation you could also try this one (in addition to above). It's based on cubic interpolation but isn't specifically optimized for sine (increase the number of segments in the wavetable, see .m file).

Unless you have a DAC as separate component, converting to analog is always a "hack" (the analog accuracy of the digital output driver becomes the bottleneck). That said, it works surprisingly well. There once was even a Xilinx app note but it was made obsolete).

The "soft-core" DAC I came up with is shown below (edited, let's hope I didn't break anything). It's very simple, actually (but might take a couple of iterations with a scope, which is a good idea anyway).
I used LVTTL33, DRIVE=24 and SLEW=FAST on the output.

PMOD outputs come with a 200 ohms resistor so I can get a lowpass filter by adding a small capacitor. Simple in theory, but finding a good ground can be challenging. Adjusting the PWM frequency to the capacitor is one option.

BTW, there are different flavors of sigma-delta converters out there, but they work best in the center of the voltage range, less so near 0 V and +3.3V.

// PWM-DAC Markus Nentwig 2016-17
// This code is in the public domain

module pn24(i_clk, o_out);
input wire 		i_clk;
output reg [23:0] 	o_out = 24'h1;

always @(posedge i_clk) begin
o_out <= o_out >> 1;
o_out[23] <= o_out[0];
o_out[22] <= o_out[23] ^ o_out[0];
o_out[21] <= o_out[22] ^ o_out[0];
o_out[16] <= o_out[17] ^ o_out[0];
end
endmodule
...

// - try as high CLKDAC frequency as possible
// - todo: use better PN generation than above

// === pseudorandom dither generator ===
wire [23:0] dither;
pn24 iDitherGenerator(CLKDAC, dither);

// === regular PWM ===
reg [4:0] dacCount = 5'd0;
always @(posedge CLKDAC)
dacCount <= dacCount + 5'd1;

// === combine ===
wire [17:0] pwm = {dacCount, dither[12:0]};

// === generate DAC output ===
reg dacOutput = 1'b0;
reg [17:0] val = <yourDataSourceHere>;
always @(posedge CLKDAC)
dacOutput <= val > pwm;

You can get some impression on the performance here

(note: but don't try to read dBc values from the plot, it would be discrete spikes vs power density)