shabaz made a Software Defined Radio (SDR) Experiment Board. One of the components is a digital quadrature oscillator.

It's a circuit with 4 PWM outputs that are each 90° shifted.

In Shabaz' blog, the oscillator is made with flip-flops, and controlled by an external function generator.

Because it's the Summer of FPGAs, I'm proposing 2 FPGA based alternatives.

They work identical, generate the same frequency (input / 4), but the approach is different.

One works by replaying a predefined output pattern on the 4 outputs, with one clock delay for each output.

The second one by calculating the first channel based on a counter value, and left shifting the data through the outputs.

 

The entity is identical for the two approaches:

 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity quadrature_oscillator is
  Port (
    i_clk: in std_logic;
    i_nReset: in std_logic;
    o_outputs: out std_logic_vector (3 downto 0)
   );
end quadrature_oscillator;

 

This is the first implementation.

The pattern used to define the outputs is 0011001.

Each of the pins continuously cycles through a (different!) range of 4 bits of the pattern, on the cadence of the clock.

pin 0 from 3 to 6: 1100

pin 1 from 2 to 5: 0110

pin 2 from 1 to 4: 0011

pin 3 from 0 to 3: 1001

They do this at the same time, in parallel.

You can see that this generates an output where each of the pins is 90° shifted.

 

architecture Behavioral of quadrature_oscillator is
  signal s_pattern: std_logic_vector (6 downto 0) := "0011001";
  signal s_counter: natural range 0 to 3 := 0;

begin
process (i_clk, i_nReset)
begin
--  if i_nReset = '0' then
--    s_counter <= 0;
--  els
  if rising_edge(i_clk) then
    if s_counter = 3 then
      s_counter <= 0;
    else
      s_counter <= s_counter + 1;
    end if;
    o_outputs(0) <= s_pattern(s_counter + 3);
    o_outputs(1) <= s_pattern(s_counter + 2);
    o_outputs(2) <= s_pattern(s_counter + 1);
    o_outputs(3) <= s_pattern(s_counter);
  end if;
end process;

end Behavioral;

 

The second implementation takes a different approach.

The data is the output vector is shifted 1 position to the left. That generates 90° phase shift.

I only have to take care that I set the LSB correct each time. For that, I use the MSB of the counter, inversed.

The counter is 2 bits. It cycles 00 -> 01 -> 10 -> 11.

If you take the MSB each time, inversed, you get 1100.

That's the identical as the output of pin 0 in the first implementation. The left-shift does the rest of the magic for the other 3 pins.

 

architecture Behavioral of quadrature_oscillator is
  signal s_counter: UNSIGNED (1 downto 0) := "00";
  signal s_buffer: std_logic_vector (3 downto 0) := (others => '0');

begin
process (i_clk, i_nReset)
begin
  if i_nReset = '0' then
    s_counter <= "00";
    s_buffer <= (others => '0');
  elsif rising_edge(i_clk) then
    if s_counter = "11" then 
      s_counter <= (others => '0');
    else
      s_counter <= (s_counter) + 1;
    end if;
    s_buffer <= s_buffer (2 downto 0) & not(s_counter(1));
    o_outputs <= s_buffer;
  end if;
end process;

end Behavioral;

 

I've attached Vivado project and Jupyter notebook. Implementation #2 is active, approach #1 is commented out.

The VHDL for #2 is adapted, see https://www.element14.com/community/groups/fpga-group/blog/2021/08/04/learning-xilinx-zynq-a-quadrature-oscillator#comme… .

Latest source on github: https://gist.github.com/jancumps/0a1b2692ddfd6edc79e8487adc66539e

 

Which design do you prefer? Or do you have an alternative?

 

Pynq - Zync - Vivado series
Add Pynq-Z2 board to Vivado
Learning Xilinx Zynq: port a Spartan 6 PWM example to Pynq
Learning Xilinx Zynq: use AXI with a VHDL example in Pynq
VHDL PWM generator with dead time: the design
Learning Xilinx Zynq: use AXI and MMIO with a VHDL example in Pynq
Learning Xilinx Zynq: port Rotary Decoder from Spartan 6 to Vivado and PYNQ
Learning Xilinx Zynq: FPGA based PWM generator with scroll wheel control
Learning Xilinx Zynq: use RAM design for Altera Cyclone on Vivado and PYNQ
Learning Xilinx Zynq: a Quadrature Oscillator - 2 implementations
Learning Xilinx Zynq: a Quadrature Oscillator - variable frequency
Learning Xilinx Zynq: Hardware Accelerated Software
Automate Repeatable Steps in Vivado
Learning Xilinx Zynq: Try to make my own Accelerated OpenCV Function - 1: Vitis HLS
Learning Xilinx Zynq: Try to make my own Accelerated OpenCV Function - 2: Vivado Block Design
Learning Xilinx Zynq: Logic Gates in Vivado
Learning Xilinx Zynq: Interrupt ARM from FPGA fabric
Learning Xilinx Zynq: reuse and combine components to build a multiplexer