Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)

pwm generation

Altera_Forum
Honored Contributor II
1,604 Views

Hi, 

 

I would like to know is there any possibility to use always inside for loop?? 

 

please anybody explain the errors associated with my code both logical and coding syntax issues 

 

ThankYOU
(Virus scan in progress ...)
0 Kudos
5 Replies
Altera_Forum
Honored Contributor II
861 Views

 

--- Quote Start ---  

Hi, 

 

I would like to know is there any possibility to use always inside for loop?? 

 

please anybody explain the errors associated with my code both logical and coding syntax issues 

 

ThankYOU 

--- Quote End ---  

 

 

I think you have been struggling for some time with your pwm work. I am afraid Your current coding is just wrong all over. 

 

Moreover your algorithm plan is not clear. I am here volunteering the below piece of code which is almost a precision pwm generator. 

and it can't be simpler(well it depends). The only drawback is that I have done it in matlab code and leave it to you to translate to hdl. 

it is just an accumultor and comparator. Don't worry at this stage about how it works. 

 

you can also avoid division /100 on the duty cycle by some simple bit shift trick (rescale duty cycle to divide by 128) 

 

clear all; n = 1000; %this test length clk = 100; %MHz system clock f1 = 1; %MHz required output frequency %%%%%%%%%%%% accumulator %%%%%%%%%%%%%%% m = 1024; %(assumed) lut size tw = floor(m*f1/clk); %tuning word for half cycle ptr = 0; %pointer to lut for i = 1:n ptr = round(mod(ptr + tw, m)); lut_data(i) = (ptr-1)*64; %lut computed per pointer end %%%%%%%%%%%%% comparator %%%%%%%%%%%%% clkout = zeros(1,n); duty = 1; %1 ~ 100 percent threshold = 32768*duty*2/100; for i = 1:n if lut_data(i) <= threshold, clkout(i) = 32767; end; end %%%%%%%%%%%% check results %%%%%%%%%%% figure;plot(lut_data,'g-'); hold plot(clkout,'r.-'); grid; d = diff(clkout); b = find(d); c = diff(b); duty_out = round(100*c(2)/(c(1)+c(2)))
0 Kudos
Altera_Forum
Honored Contributor II
861 Views

here's a working PWM module  

 

--Author: some guy at digikey LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_unsigned.all; ENTITY pwm IS GENERIC( sys_clk : INTEGER := 50_000_000; --system clock frequency in Hz pwm_freq : INTEGER := 100_000; --PWM switching frequency in Hz bits_resolution : INTEGER := 8; --bits of resolution setting the duty cycle phases : INTEGER := 1); --number of output pwms and phases PORT( clk : IN STD_LOGIC; --system clock reset_n : IN STD_LOGIC; --asynchronous reset ena : IN STD_LOGIC; --latches in new duty cycle duty : IN STD_LOGIC_VECTOR(bits_resolution-1 DOWNTO 0); --duty cycle pwm_out : OUT STD_LOGIC_VECTOR(phases-1 DOWNTO 0); --pwm outputs pwm_n_out : OUT STD_LOGIC_VECTOR(phases-1 DOWNTO 0)); --pwm inverse outputs END pwm; ARCHITECTURE logic OF pwm IS CONSTANT period : INTEGER := sys_clk/pwm_freq; --number of clocks in one pwm period TYPE counters IS ARRAY (0 TO phases-1) OF INTEGER RANGE 0 TO period - 1; --data type for array of period counters SIGNAL count : counters := (OTHERS => 0); --array of period counters SIGNAL half_duty : INTEGER RANGE 0 TO period/2 := 0; --number of clocks in 1/2 duty cycle BEGIN PROCESS(clk, reset_n) BEGIN IF(reset_n = '0') THEN --asynchronous reset count <= (OTHERS => 0); --clear counter pwm_out <= (OTHERS => '0'); --clear pwm outputs pwm_n_out <= (OTHERS => '0'); --clear pwm inverse outputs ELSIF(clk'EVENT AND clk = '1') THEN --rising system clock edge IF(ena = '1') THEN --latch in new duty cycle half_duty <= conv_integer(duty)*period/(2**bits_resolution)/2; --determine clocks in 1/2 duty cycle END IF; FOR i IN 0 to phases-1 LOOP --create a counter for each phase IF(count(0) = period - 1 - i*period/phases) THEN --end of period reached count(i) <= 0; --reset counter ELSE --end of period not reached count(i) <= count(i) + 1; --increment counter END IF; END LOOP; FOR i IN 0 to phases-1 LOOP --control outputs for each phase IF(count(i) = half_duty) THEN --phase's falling edge reached pwm_out(i) <= '0'; --deassert the pwm output pwm_n_out(i) <= '1'; --assert the pwm inverse output ELSIF(count(i) = period - half_duty) THEN --phase's rising edge reached pwm_out(i) <= '1'; --assert the pwm output pwm_n_out(i) <= '0'; --deassert the pwm inverse output END IF; END LOOP; END IF; END PROCESS; END logic;
0 Kudos
Altera_Forum
Honored Contributor II
861 Views

 

--- Quote Start ---  

here's a working PWM module  

 

 

--- Quote End ---  

 

 

yes you can use a basic counter as such. Your design however expects a fixed freq generic but if freq is meant to be an input then you need to divide to get period cycles which can be avoided using accumulator. 

accumulator approach additionally supports fractional clk/freq and not just integer result. 

 

for a precision pwm (really precise) avoiding division is to use sine LUT + accumulator + comparator.
0 Kudos
Altera_Forum
Honored Contributor II
861 Views

Hi, 

 

Thankyou 

 

inputting a frequency and duty cycle value , using counters concepts pwm generation is successful . as u said, to overcome the limitations of counters I am trying to learn accumulator techniques. 

 

But target or problem in my code is that... I need to generate a set of frequencies and their pwm from system clock . 

Like eg... 50mhz my system clock 

range of frequency 5mhz-30mhz with stepsize 5mhz.... ie, 5,10,15,20,25,30 like that. so I would like to add a loop to select the current frequency and then rest of program will be same. 

 

Thankyou
0 Kudos
Altera_Forum
Honored Contributor II
861 Views

 

--- Quote Start ---  

Hi, 

 

Thankyou 

 

inputting a frequency and duty cycle value , using counters concepts pwm generation is successful . as u said, to overcome the limitations of counters I am trying to learn accumulator techniques. 

 

But target or problem in my code is that... I need to generate a set of frequencies and their pwm from system clock . 

Like eg... 50mhz my system clock 

range of frequency 5mhz-30mhz with stepsize 5mhz.... ie, 5,10,15,20,25,30 like that. so I would like to add a loop to select the current frequency and then rest of program will be same. 

 

Thankyou 

--- Quote End ---  

 

 

with the simple counter technique you can only generate frequencies that differ in the ratio result of clk/freq and your resolution step is inherently limited to that.  

 

In the accumulator approach you can get much finer resolution (on average) since it is based on phase accumulation. 

 

In fact you don't need frequency step as input in any case. 

 

also I notice that the duty cycle ratio approach posted by mhouse1 doesn't make sense to me for example if duty cycle is 50% then he multiplies that by period say 50*10 then divides it by 2^8/2 ? where is the 100 then as 50 is ratio to 100. May be he assumes some rescaling at the 8 bit input (duty). 

 

Thus in both cases(counter or accum) you have two divisions to be dealt with(clk/freq and conversion of duty ratio). 

The accumulator bypasses the first division i.e. it implements it inherently but you need to precompute tuning word  

in both cases, the duty ratio is better converted from /100 ratio to /128 ratio
0 Kudos
Reply