Learn how to design and implement a Numerically Controlled Oscillator (NCO) in Vivado using a block design approach! This tutorial walks you through creating a variable-frequency sine wave generator using FPGA technology.
Key topics covered:
- Implementing sign and phase ramp functions with variable frequency
- Using Block RAM (BRAM) as a lookup table for sine coefficients
- Setting up a phase accumulator using the Accumulator IP
- Configuring frequency control words
- Creating and simulating the design in Vivado's block design environment
You can find the complete video here:
Block Diagram of DesignThis block diagram represents a Numerically Controlled Oscillator (NCO), commonly used to generate a digital sine wave with variable frequency. The main components include a Phase Accumulator, a Sine Phase-to-Amplitude Converter (Sine PAC), and a Frequency Control Word.
- The Frequency Control Word is an input value determines the frequency of the output sine wave.
- The control word represents the desired phase increment per clock cycle.
- By adjusting this value, you can change the step size in the phase accumulator, and thus control the frequency of the generated sine wave.
Phase Accumulator
- The Phase Accumulator is the core of the NCO. It accumulates the phase information by adding the frequency control word to its current value on each clock cycle.
- The accumulator consists of two main components:
- Adder(Σ): Adds the current phase accumulator value to the frequency control word to produce a new phase.
- Register(Z): Holds the current phase value and feeds it back for the next clock cycle.
- The output of the phase accumulator is a value that represents the current phase of the sine wave.
- This phase value continuously increases and wraps around due to the finite bit-width of the accumulator, creating a repeating phase ramp.
Sine Phase-to-Amplitude Converter (Sine PAC)
- The Sine PAC is essentially a Look-Up Table (LUT) that converts the current phase value from the phase accumulator to a corresponding sine amplitude.
- This LUT stores one period of the sine wave in digital form. The M-bit phase input indexes into this LUT to retrieve the appropriate sine amplitude.
The output of the Sine PAC is the sine amplitude, which can then be fed to a Digital-to-Analog Converter (DAC)to produce an analog sine wave or used in further digital processing.
Sawtooth pattern of phase accumulator outputThis figure represents the output of a phase accumulator with different Frequency Control Words (FCWs). The x-axis indicates clock cycles, and the y-axis shows the phase accumulator's output.
A phase accumulator is a key component in digital signal generation, such as in Direct Digital Synthesizers (DDS) or Numerically Controlled Oscillators (NCOs). It generates a digital phase that increments by a fixed value (the FCW) at each clock cycle.
The output of the accumulator acts as the phase input to a lookup table, such as a sine wave table, to produce the corresponding waveform.
Explanation of the Figure:
- FCW = 1 (Blue Line): The output increases by 1 at each clock cycle. This results in a gradual, step-by-step increment, producing the slowest rate of phase change in the plot.
- FCW = 2 (Red Line): The output increases by 2 at each clock cycle. This results in a faster phase increment compared to FCW = 1, showing steeper steps. The phase advances twice as fast as in the blue line.
- FCW = 4 (Yellow Line): The output increases by 4 at each clock cycle. This leads to the steepest slope among the three, representing the fastest phase accumulation. The phase value doubles compared to FCW = 2 and is four times faster than FCW = 1.
The phase accumulator output grows linearly over time for each clock cycle, but with varying step sizes depending on FCW output. A higher FCW leads to a quicker phase progression and, consequently, a higher output frequency when mapped to a sine LUT.
In the context of waveform generation, a higher step size (larger FCW) will produce a higher frequency sine wave since the phase wraps around to the starting point faster.
Vivado designIn Vivado, we built this NCO design using various IP blocks. You can compare block by block with the original block diagram of the NCO.
This block diagram illustrates a Numerically Controlled Oscillator (NCO) simulation in Vivado. Here is a detailed explanation of each component and how they interact to generate a sine wave from a phase ramp:
1. Frequency Control Word Module (Frequency_Control_Wo_0)
- Function: This block provides a programmable control word that sets the frequency of the output waveform. The output is a 10-bit Control_Word[9:0], which is fed into the accumulator.
- Purpose: The control word determines the increment size for each clock cycle, thus setting the rate at which the phase advances and ultimately controlling the output frequency.
The FCW is implemented as RTL code in simulation. you can add it to your design as module. Here is the FCW VHDL code sample:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.numeric_std.ALL;
entity Frequency_Control_Word is
generic(
fcw_width :integer :=10
);
Port (
Control_Word : out STD_LOGIC_VECTOR(fcw_width-1 downto 0) -- output
);
end Frequency_Control_Word;
architecture Behavioral of Frequency_Control_Word is
signal count : INTEGER range 1 to 10 := 1; -- Internal integer counter, starting from 1
signal loop_control: INTEGER :=0;
begin
process
begin
-- Loop to increment the count every fcw_wait
for i in 1 to 10 loop
Control_Word <= std_logic_vector(to_unsigned(count, fcw_width)); -- Convert count to std_logic_vector
if loop_control<5 then
count <= count + 1;
else
count <= count - 1;
end if;
loop_control <= loop_control+1;
wait for 20 us ; -- Wait for 1fcw_wait
end loop;
wait; -- Stop simulation after reaching
end process;
end Behavioral;
2. Simulation Clock Generator (sim_clk_gen_0)
- Function: Generates the system clock (clk) and synchronized reset signal (sync_rst).
- Purpose: Provides timing control for the entire simulation, ensuring consistent clocking throughout the design.
3.Accumulator (c_accum_0)
Receives the 10-bit frequency control word. The accumulator adds the frequency control word to its previous output at every clock cycle. This produces a ramp signal representing phase accumulation, shown as Phase Ramp in the diagram. it Converts the frequency control word into a phase signal, crucial for mapping to the sine LUT. Double click on Accumulator IP block and change the input and output width to 10, then it matches to the address bit-width of Block memory. Since we don’t want to bypass the input to the output, add a constant to the block design, set its value to zero and connect it to the Accumulator’s bypass port.
4.Block Memory Generator (blk_mem_gen_0)
Serves as a lookup table (LUT) that translates phase addresses into sine amplitude outputs, completing the generation of the sine wave. It has The 10-bit address input that receives the phase value from the accumulator. 11-bit data output that represents the sine wave value corresponding to the phase input. It Contains a pre-stored sine wave table with 1024 entries. The input phase value acts as an address to look up the corresponding sine value, creating a smooth, continuous sine waveform. you can find the block memory setup for this project here:
Pre-calculated sine function coefficients are stored in .coe file and can be loaded to the Block memory during the design. Since all 1000 sine values are too long to display, we only put this example file here. but you can download the.coe file for this project from our GitHub repository. Open other options tab to load a memory initialization Coefficient file. This Coefficient file is used to pre-load BRAM in an FPGA design with specific initial data. When the design is synthesized and implemented, the Block RAM will contain the values provided in the file. Then press the brows button and load the COE file. You can validate and then save it.
memory_initialization_radix=10;
memory_initialization_vector=
1
2
3
4
5
6
7
8
9
Add top wrapperDon't forget to create top HDL wrapper and let the Vivado to manage and auto handle it.
SimulationNow we can proceed with the simulation. Follow these steps:
- Run behavioral simulation.
- Increase Simulation Time: Extend the simulation duration to 200 microseconds.
- Reset and Rerun: Reset the simulation and then rerun it for the specified time.
- Adjust Signal Settings: Right-click on the simulated signals to change their settings. Set the radix to signed decimal and the waveform style to analog.
After these adjustments, you will observe a sine wave is fluctuating at different frequencies.
The simulation output signals can be explained as follows:
- First Signal (Output of FCW - Frequency Control Word):
This signal represents the step size used by the phase accumulator. It indicates the size of the increments added to the phase value on each clock cycle. The signal's value changes in stages, initially increasing and then decreasing, which directly impacts the frequency of the generated output waveform.
The output value of FCW changes every 20 microseconds. For the first five iterations, the step size increases, resulting in an increasing output frequency. In the next stages, the step size decreases, causing the output frequency to decrease. This behavior demonstrates how the code modulates the frequency, creating a variable frequency output over time.
- Second Signal (Output of Phase Accumulator):
This signal shows the accumulated phase values. It forms a sawtooth pattern that increases progressively, with the slope determined by the FCW. A higher step size from the FCW results in a steeper ramp (faster phase accumulation), while a lower step size results in a gentler ramp (slower phase accumulation). The pattern demonstrates how the phase evolves over time, wrapping around when it reaches its maximum.
- Third Signal (Output of BRAM):
This is the actual sine wave output, generated by using the phase accumulator's output as an address to read sine coefficients from the BRAM. The frequency of this sine wave changes according to the phase accumulator's ramp rate. When the FCW is larger (steeper phase accumulator ramp), the sine wave frequency is higher. Conversely, when the FCW is smaller (gentler ramp), the sine wave frequency is lower. The waveform shows sections of high-frequency output followed by sections of lower frequency, matching the FCW's variations.
Comments