Continue to Site

[SOLVED] SPWM Generation

nliaqat

Newbie level 5
Newbie level 5
Joined
Mar 31, 2025
Messages
8
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
65
I am implementing a Phase-Shifted SPWM (Sinusoidal Pulse Width Modulation) technique to control an H-Bridge inverter using a Look-Up Table (LUT) approach. The design works correctly in ModelSim simulation, but when I program it onto an FPGA, it does not function.

I am generating a sine wave and a triangular wave using LUTs and updown counter respectively, with max amplitude is 511 and min amplitude is -511 with the resolution of 1024 sampels point, comparing them to generate PWM signals, and applying a phase shift to control multiple H-Bridge switches. However, when I program it onto an FPGA board it will programmed, but i do not get any output PWM signals of any assigned pins.

What could be the possible reasons for this discrepancy, and how can I debug and resolve this issue? Are there specific FPGA considerations (such as timing, clock domain issues, or LUT initialization) that I should check?
1743427146930.png
 

Attachments

  • PWM.zip
    8.1 MB · Views: 31
Just to give some kind of reply...
Your 7z file expands to 16 MB. 152 items total. Looks as though what started out as an electronics project has turned into a coding project. Just maybe a reader here is expert in all the methods you're using.

My less-expert eyes see four waveforms all of which carry SPWM. For one thing the H-bridge may only need for one transistor to switch SPWM at a time. Think of it as a buck converter operating in one direction through the load. Switching action should mimic that. Thus you achieve one-half of a cycle.

Then for the second half of the cycle, think of the buck converter reversing direction through the load. Switch your transistors so they mimic such a buck converter.

As a preliminary step up to eventual success, try executing SPWM in just one transistor to find out how a simpler program performs with a load.
 
Do you get any warnings during synthesis?
--- Updated ---

You can also take a look at the generated schematic to see whether the outputs were actually connected, or whether it synthesized to an empty block.
 
Essential design files (hdl + Quartus project) are only 24k

I didn't yet look into it, may be Quartus synthesis doesn't understand your way of coding the sine waveform generation.
 

Attachments

  • SPWM_essential_files.zip
    8.3 KB · Views: 16
Inferring ROM according to Quartus ROM template does the trick:

Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.sine_LUT.all;

entity sine_wave1 is
    generic (
        N_P : integer := 1024;
        CLK_FREQ : integer := 50_000_000;
        F_D : integer := 50
    );
    port (
        clk : in std_logic;
        reset : in std_logic;
        sine_wave : out std_logic_vector(9 downto 0)
    );
end sine_wave1;

architecture Behavioral of sine_wave1 is
    constant S_R : integer := CLK_FREQ / (F_D * N_P);

    signal i_sine  : integer range 0 to N_P - 1 := 0;
    signal counter : integer range 0 to S_R := 0;

    -- added Quartus ROM coding template
    type   table_type is array(0 to N_P - 1) of signed(9 downto 0);

    function init_rom
        return table_type is
        variable tmp : table_type := (others => (others => '0'));
    begin
        for addr_pos in 0 to N_P - 1 loop
            tmp(addr_pos) := to_signed(sine_data(addr_pos), 10);
        end loop;
        return tmp;
    end init_rom;    

    signal sine_tab : table_type := init_rom;
    -- end of ROM template
begin
    process (clk, reset)
    begin
        if reset = '1' then
            i_sine <= 0;
            counter <= 0;
            sine_wave <= (others => '0');
        elsif rising_edge(clk) then
            if counter = S_R then
                counter <= 0;

                -- Assign sine wave output
                -- original code isn't recognized as ROM description by Quartus synthesis
                -- sine_wave <= std_logic_vector(to_signed(sine_data(i_sine), 10));
                sine_wave <= std_logic_vector(sine_tab(i_sine));

                -- Increment i_sine with boundary check
                if i_sine = N_P - 1 then
                    i_sine <= 0;
                else
                    i_sine <= i_sine + 1;  
                end if;
            else
                counter <= counter + 1;
            end if;
        end if;
    end process;

end Behavioral;
 
Dear All Members,

Thank you for your response and support. I appreciate your time and assistance. I have resolved the issue and truly value your help.

Best regards,
Noman
 
Dear All Members,

Thank you for your response and support. I appreciate your time and assistance. I have resolved the issue and truly value your help.

Best regards,
Noman
It's good that you found a way to resolve the issue because for one like me, I only download nor open zip files in certain circumstances.

I think that posting your codes with the code tags provides more confidence to those who want to review it.
 
Here i implement phase shifting in a triangular carrier wave with a total of 1024 sample points generated using an up-down counter. Is it possible to create a general code that allows for customizable phase shifts and generates phase-shifted carriers as desired? Please help thanks.

Code:
==============CODE============
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity Triangular_HZ is
    Port (
        clk : in STD_LOGIC;       -- 50 MHz clock
        reset : in STD_LOGIC;
        wave_out : out STD_LOGIC_VECTOR(9 downto 0);  -- 10-bit output (1024 levels);
          wave_out1 : out STD_LOGIC_VECTOR(9 downto 0)  -- 10-bit output (1024 levels)
    );
end Triangular_HZ;

architecture Behavioral of Triangular_HZ is
    type state_type is (UP_POS, DOWN_POS, DOWN_NEG, UP_NEG);
    signal state : state_type := UP_POS;
    signal counter : INTEGER range -511 to 511 := 0;
  
  
    constant CLK_FREQ : integer := 50_000_000;  -- 50 MHz
    constant WAVE_FREQ : integer := 1000;         -- Desired Frequency
    constant SAMPLES_PER_CYCLE : integer := 1024; -- 1024 samples per full wave cycle
  
  
  
    constant CLK_CYCLES_PER_SAMPLE : integer := CLK_FREQ / (WAVE_FREQ * SAMPLES_PER_CYCLE);
    signal cycle_counter : integer range 0 to CLK_CYCLES_PER_SAMPLE-1 := 0;
begin

    process(clk, reset)
    begin
        if reset = '1' then
            counter <= 0;
            state <= UP_POS;
            cycle_counter <= 0;
        elsif rising_edge(clk) then
            -- Count clock cycles between sample updates
            if cycle_counter < CLK_CYCLES_PER_SAMPLE-1 then
                cycle_counter <= cycle_counter + 1;
            else
                cycle_counter <= 0;
              
              
                case state is
                    when UP_POS =>
                        if counter < 510 then
                            counter <= counter + 2;
                        else
                            counter <= 511;  -- Peak positive
                            state <= DOWN_POS;
                        end if;
                    when DOWN_POS =>
                        if counter > 2 then
                            counter <= counter - 2;
                        else
                            counter <= 0;    -- Midpoint
                            state <= DOWN_NEG;
                        end if;
                    when DOWN_NEG =>
                        if counter > -510 then
                            counter <= counter - 2;
                        else
                            counter <= -511; -- Peak negative
                            state <= UP_NEG;
                        end if;
                    when UP_NEG =>
                        if counter < -2 then
                            counter <= counter + 2;
                        else
                            counter <= 0;    -- Midpoint
                            state <= UP_POS;
                        end if;
                end case;
            end if;
        end if;
    end process;

  
    wave_out <= std_logic_vector(to_signed(counter, 10)); ----0 shifted
     wave_out1 <= std_logic_vector(to_signed(-counter, 10)); ----180 shifted

end Behavioral;
 
Inferring ROM according to Quartus ROM template does the trick:

Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.sine_LUT.all;

entity sine_wave1 is
    generic (
        N_P : integer := 1024;
        CLK_FREQ : integer := 50_000_000;
        F_D : integer := 50
    );
    port (
        clk : in std_logic;
        reset : in std_logic;
        sine_wave : out std_logic_vector(9 downto 0)
    );
end sine_wave1;

architecture Behavioral of sine_wave1 is
    constant S_R : integer := CLK_FREQ / (F_D * N_P);

    signal i_sine  : integer range 0 to N_P - 1 := 0;
    signal counter : integer range 0 to S_R := 0;

    -- added Quartus ROM coding template
    type   table_type is array(0 to N_P - 1) of signed(9 downto 0);

    function init_rom
        return table_type is
        variable tmp : table_type := (others => (others => '0'));
    begin
        for addr_pos in 0 to N_P - 1 loop
            tmp(addr_pos) := to_signed(sine_data(addr_pos), 10);
        end loop;
        return tmp;
    end init_rom;   

    signal sine_tab : table_type := init_rom;
    -- end of ROM template
begin
    process (clk, reset)
    begin
        if reset = '1' then
            i_sine <= 0;
            counter <= 0;
            sine_wave <= (others => '0');
        elsif rising_edge(clk) then
            if counter = S_R then
                counter <= 0;

                -- Assign sine wave output
                -- original code isn't recognized as ROM description by Quartus synthesis
                -- sine_wave <= std_logic_vector(to_signed(sine_data(i_sine), 10));
                sine_wave <= std_logic_vector(sine_tab(i_sine));

                -- Increment i_sine with boundary check
                if i_sine = N_P - 1 then
                    i_sine <= 0;
                else
                    i_sine <= i_sine + 1; 
                end if;
            else
                counter <= counter + 1;
            end if;
        end if;
    end process;

end Behavioral;
Good idea!
 
Is it possible to create a general code that allows for customizable phase shifts and generates phase-shifted carriers as desired?
Yes. A general approach starts with a ramp (saw tooth) waveform. It can be either generated with fixed frequency or preferably in NCO style with variable frequency. The ramp can be arbitrarily phase shifted by adding an offset in modulo arithmetic.
In a second step, the ramp is converted to triangle waveform by inverting the second half and rescaling the signal to full number range.
 
Yes. A general approach starts with a ramp (saw tooth) waveform. It can be either generated with fixed frequency or preferably in NCO style with variable frequency. The ramp can be arbitrarily phase shifted by adding an offset in modulo arithmetic.
In a second step, the ramp is converted to triangle waveform by inverting the second half and rescaling the signal to full number range.
Basically I have never work in the domain of vhdl . I have just the basic knowledge of vhdl coding, if you can share some example code I am very thankful.
 


Write your reply...

LaTeX Commands Quick-Menu:

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top