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

Generate PWM signal

Altera_Forum
Honored Contributor II
4,544 Views

Hello everyone, 

I am new in fpga and right now I need to generate PWM signal. 

I do not understand how the following syntax work in order to generate PWM. 

 

1. module PWM(clk, PWM_in, PWM_out); 

2. input clk; 

3. input [7:0] PWM_in; 

4. output PWM_out; 

 

5. reg [8:0] PWM_accumulator; 

6. always @(posedge clk) PWM_accumulator <= PWM_accumulator[7:0] + PWM_in; 

 

7. assign PWM_out = PWM_accumulator[8]; 

8. endmodule 

 

How could the positive edge signal of 'PWM_accumulator <= PWM_accumulator[7:0] + PWM_in' become PWM signal? 

 

What is your suggestion about this syntax?  

Thank you very much.
0 Kudos
11 Replies
Altera_Forum
Honored Contributor II
3,339 Views

PWM is pulse width modulation. The presented code generates a signal with variable frequency and fixed 50 % duty cycle. It misses a PWM feature.

0 Kudos
Altera_Forum
Honored Contributor II
3,339 Views

I think it can if PWM_in is varied in time. But it needs some sort of control tracking of accumulator result.

0 Kudos
Altera_Forum
Honored Contributor II
3,339 Views

Thanks FvM. 

 

How if I want to make it become 20% duty cycle? 

I need it to operate my servo motor, therefore the PWM signal is used to control the angle of my workpiece.
0 Kudos
Altera_Forum
Honored Contributor II
3,339 Views

Thanks Kaz. 

Do you mean if pwm_in is 00000000 will be 0 degree and if it is 11111111 will be 180 degree? (assuming the servo only can rotate from 0 to 180 degree) 

I still have no idea of what line 6 and 7 do.  

Thanks for the explanation.
0 Kudos
Altera_Forum
Honored Contributor II
3,339 Views

It needs some math to establish a relation between input word and duty cycle. Imagine your input word is 51 then try this work in Matlab: 

x = 1:51:10000; 

x2 = mod(x,256); 

size(find(x2 < 128))/size(x) 

 

I got 0.47 i.e. .47 of time the bit 8 is low and rest it is high 

 

I hope this helps
0 Kudos
Altera_Forum
Honored Contributor II
3,339 Views

Just to add this note, the vector x2 represents accumulator result. In fact in the above matlab code I got this pattern semi-settled: 

21 72 123 174 225 

 

i.e. 0 0 0 1 1 for bit 8
0 Kudos
Altera_Forum
Honored Contributor II
3,339 Views

Hi again, 

 

for 20% duty cycle, one way is to pass regular pattern on PWM_in so that you force adder to have 0 1 1 1 1 repeatedly 

 

for example if you run PWM_in = 128,1,1,1,125 then adder result will be: 

0 (start) 

128 

129 

130 

131 

0  

 

Of course you can also use a simple counting for that but I think the adder could be more versatile
0 Kudos
Altera_Forum
Honored Contributor II
3,339 Views

As a first point, I have to correct my previous statement. For 50% duty cycle, the code has to be changed to  

PWM_accumulator <= PWM_accumulator + FREQ_in 

Originally, the output is one clock cycle high and X cyles low. But it's neither a PWM. 

 

--- Quote Start ---  

I think it can if PWM_in is varied in time. 

--- Quote End ---  

 

It can. But if you ask me for a PWM code, I'll suggest a basic PWM generator. 

 

A typical PWM generator is comprised of a ramp generator and a comparator. I keep the variable frequency feature of the previous code to show an option. 

module PWM(clk, PWM_in, PWM_out); input clk; input FREQ_in; input PWM_in; output PWM_out; reg PWM_accumulator; always @(posedge clk) begin PWM_accumulator <= PWM_accumulator + FREQ_in; PWM_out = (PWM_IN > PWM_accumulator); end endmodule
0 Kudos
Altera_Forum
Honored Contributor II
3,339 Views

The comparator looks better. The threshold for comparator would be 410 (512 *80%) for 80% high pulse. 

 

I just did some modelling and found out that another equivalent way is to restrain the accumulator maximum. 

 

For example for 20% high,80%low: 

 

stop accumulator at 320 maximum instead of free 511. 

 

then low occurs at a ratio of 256/320 = 80%  

 

Thus a comparator fixed at 256 is implied but accumulator max is changed. 

 

You can visualise this accum result as a full cycle wheel that is 0 at one half (0:255) then 1 at next half(256:511) and then you control size of each half of the wheel. 

 

The input PWM_in will be a constant that determines frequency of pulse with low value meaning low frequency. The pulse will not be exactly regular but tends towards target duty cycle on average. 

 

 

the modified version: 

 

1. module PWM(clk, PWM_in, PWM_out); 

2. input clk; 

3. input [7:0] PWM_in; 

4. output PWM_out; 

 

5. reg [8:0] PWM_accumulator; 

6. always @(posedge clk)  

if (PWM_accumulator + PWM_in) > 319 

PWM_accumulator <= 0; 

else 

PWM_accumulator <= PWM_accumulator[7:0] + PWM_in; 

 

7. assign PWM_out = PWM_accumulator[8]; 

8. endmodule 

 

But overall FvM algorithm is better for resource.
0 Kudos
Altera_Forum
Honored Contributor II
3,339 Views

Thank you so much FvM and kaz. 

Actualy I am not fully understand what both of you try to explain. 

Don't worry, I will contact my university friend to help me to understand this posting. 

Once again, thank you so much.
0 Kudos
Altera_Forum
Honored Contributor II
3,339 Views

To understand this issue I have this overview of modulo adder accumulator in general: 

 

It is very flexible and of several uses. It is just an adder that accumulates its input (for ever) and is allowed up to a maximum called modulus. for example modulo 512 adder runs from 0 to 511 (or 1 to 512 if zero not allowed by tool). 

 

It does not have to be binary but can be any value modulus. The binary case is simple to implement, just let it go freely. 

 

The flexibility comes when you choose input value (increment). The increment can be anything from 1 and up modulus-1.  

 

(1) The accumulator can be used to to generate regular addressing for waveform generators i.e. it acts as phase indicators in DSP terms. 

It is used in DDS(NCO) under the name phase accumulator. 

 

In this application, the accumulator can be as wide as the address or much much wider to increase phase resolution in which case only the MSB of result are used for addressing thus it is better called phase accumulator than address generator. 

 

(2) It is also used in cases of sampling rate converters as polyphase indicators i.e. which subfilter to choose. 

 

(3) can be used to generate any rate clock enable from a given clock 

for example you have a clock at 10MHz and want to generate 1.2288MHz then run an accumulator at a ratio of 12288/100000 

(or reduce the ratio down) i.e. add 12288 modulo 10,0000 then your clock enable is the overflow pulse. 

 

(4) similarly, in this thread we used it as duty cycle generator by looking at its MSB(option 1) or deciding a new comparator result (option 2). 

 

In all above cases, you can visualise an accumulator in space as a wheel e.g. of values from 0 to 15 and an arrow that starts from say zero. when you add incr value of say 7, arrow moves to new location at 7 then 14 then wraps around the wheel to 6 (21-15) and so on carrying info of first cycle into next. 

 

It will overflow at a rate of 7/15 of given clock that runs it. 

 

 

If you look at MSB of this accumulator then it will alternate between zero and one. In other words, zero in the first half of the wheel and one in the second half of the wheel. The ratio of 0/1 will tend to be equal because there is equal probability of both halves of the wheel in a binary adder. The increment 7 will just decide how quickly you move from first half to next half and back. If incr = 1 then that is the slowest case naturally as you run full wheel from one location to next without any jump. 

 

To work as duty cycle generator, we have to alter the ratio of 0/1 probabilty by not allowing the wheel to go free binary(one option). Or by looking at another bit (rather than MSB of accumulator) that compares accumulator result against a ref point that is not just half of max but anywhere.
0 Kudos
Reply