EmbDev.net

Forum: FPGA, VHDL & Verilog Increasing dutycycle for an output signal


von Robert (Guest)


Rate this post
useful
not useful
Hi all,

I want to increase the duty cycle slowly from 0%-50% in the period of 
0-10 ms for an output signal(150KHz) generated from a clock of 50MHz.

I am able to generate the output for 50%. I am not sure how to vary the 
duty cycle from 0-50% (between 0-10ms). Below is the code:
1
entity Gen_150 is
2
port ( sys_clk,reset: in std_logic; --sys_clk:50MHz
3
a_out, b_out: out std_logic);       --a_out,b_out:150KHz
4
end Gen_150 ;
5
 
6
architecture bhv of Gen_150 is
7
 
8
signal count: integer:=0;
9
signal tmp : std_logic := '1';
10
11
begin
12
 
13
process(sys_clk,reset)
14
begin
15
if(reset='0') then
16
count<=0;
17
tmp<='1';
18
elsif(sys_clk'event and sys_clk='1') then
19
  count <=count+1;
20
21
  if (count = 166) then   -- dutycycle=50% ((50000000/150000)/2)
22
     tmp <= NOT tmp;
23
     count<= 0;  
24
  end if;
25
end if;
26
a_out <= tmp;
27
b_out <= NOT tmp after 10ns; -- output delayed by 10ns
28
end process;
29
 
30
end bhv;

Thank you!

von Duke Scarring (Guest)


Rate this post
useful
not useful
You need another 'signal' generator (triangle wave, 100Hz) and connect 
it with your comparator:

Robert wrote:
> if (count = 166) then

Constantly changing (slowly) your compare value (166), should do it.

Duke

von Okay (Guest)


Rate this post
useful
not useful
Why not compare count to another register you can dynamically set in the 
process instead of a constant?

von Lothar M. (Company: Titel) (lkmiller) (Moderator)


Rate this post
useful
not useful
Robert wrote:
> Below is the code:
> entity Gen_150 is
A VHDL code start well before the keyword "entity"...


> b_out <= NOT tmp after 10ns; -- output delayed by 10ns
Thats not synthesizeable! You know that?


> I want to increase the duty cycle slowly from 0%-50%
Try that and change the value of pwm:
1
signal count: integer:=0;
2
signal pwm: integer:=100;
3
:
4
:
5
elsif(sys_clk'event and sys_clk='1') then
6
  count <=count+1;
7
8
  if (count = 332) then
9
     count <= 0;  
10
  end if;
11
   
12
end if;
13
14
tmp <= '1' when (count < pwm) else '0';
15
:
16
:
17
end process;
Now you have a changing output signal. And the only thing you must du, 
is to produce a ramp on the "pwm" signal. Thats fairly easy...

von Robert (Guest)


Rate this post
useful
not useful
Thank you!
I implemented the ramping function with a counter=500000 (0-10ms). 
Please correct if I am wrong.

And I am getting an syntax error for the below:

tmp <= '1' when(count < pwm) else tmp <= '0';
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.numeric_std.ALL;
4
 
5
entity Gen_150 is
6
port ( sys_clk,reset: in std_logic;
7
a_out, b_out: out std_logic);
8
end Gen_150 ;
9
 
10
architecture bhv of Gen_150 is
11
 
12
signal count: integer:=0;
13
signal tmp : std_logic := '1';
14
signal counter: integer := 0;
15
signal pwm: integer := 0;
16
17
begin
18
 
19
process(sys_clk,reset)
20
begin
21
if(reset='0') then
22
count<=0;
23
tmp<='1';
24
elsif(sys_clk'event and sys_clk='1') then
25
  count <=count+1;
26
  --counter <= counter +1;
27
  if (count = 332) then
28
    -- tmp <= NOT tmp;
29
     count<= 0;  
30
  end if;
31
end if;
32
tmp <= '1' when(count < pwm) else tmp <= '0'; 
33
34
a_out <= tmp;
35
b_out <= NOT tmp;
36
37
end process;
38
39
Ramp : process (reset, sys_clk)
40
begin
41
  if reset = '0' then
42
    pwm      <= 0;
43
  elsif rising_edge(sys_clk)  then
44
    counter <= counter +1;
45
    if counter<=500000 then -- 500000 cycles =10ms
46
      
47
        case  counter  is
48
          when  50000     =>  pwm  <= 25;    
49
          when  100000  =>  pwm  <= 33;  
50
          when  150000  =>  pwm  <= 44;  
51
          when  200000  =>  pwm  <= 66;  
52
          when  250000  =>  pwm  <= 77;  
53
          when  300000  =>  pwm  <= 99;            
54
          when  350000  =>  pwm  <= 120;  
55
          when  400000  =>  pwm  <= 132;  
56
          when  450000  =>  pwm  <= 145;  
57
          when  500000  =>  pwm  <= 166;  
58
          
59
          when  others  =>  pwm  <= 0;    
60
        end case;
61
      
62
    else
63
      pwm      <= 0;
64
    end if;
65
  end if;
66
67
end process Ramp;
68
 
69
end bhv;

von Lothar M. (Company: Titel) (lkmiller) (Moderator)


Rate this post
useful
not useful
Robert wrote:
> And I am getting an syntax error for the below:
>
> tmp <= '1' when(count < pwm) else tmp <= '0';
Of course you do. What's the correct syntax for the when/else statement?
Why didn't you simply copy it from me?
Mine will not conclude in an error message.

And for the PWM value: let start it from 0. And then increment it every 
500000/166 clocks. So you will only need an additional counter from 0 to 
500000/166. And when the counter reaches that value you must reset it to 
0 and increment the PWM value until its 166.

You see that there's no whatsoever "case" statement necessary at all and 
the PWM value will increase smoothly from 0 to 166...

: Edited by Moderator
von Robert (Guest)


Rate this post
useful
not useful
Lothar M. wrote:
> Robert wrote:
>> And I am getting an syntax error for the below:
>>
>> tmp <= '1' when(count < pwm) else tmp <= '0';
> Of course you do. What's the correct syntax for the when/else statement?
> Why didn't you simply copy it from me?
> Mine will not conclude in an error message.

Sorry it was my mistake. Its fine now. But is the ramp function 
implemented correct?

von Robert (Guest)


Rate this post
useful
not useful
Thanks a ton! It works fine. :)

von Duke Scarring (Guest)


Rate this post
useful
not useful
Robert wrote:
> But is the ramp function
> implemented correct?
That's usually checked by a testbench...

von Robert (Guest)


Rate this post
useful
not useful
I want to add delays between the outputs (a_out and b_out).

Is it ok to add a min delay(is 10ns too much?) just by adding a temp 
register to delay out_b?
1
if(reset='0') then
2
count<=0;
3
tmp<='1';
4
elsif(sys_clk'event and sys_clk='1') then
5
:
6
:
7
end if;
8
end if;
9
a_out <= tmp; -- at falling edge
10
d_b_out <= NOT tmp; -- at falling edge
11
b_out <= d_b_out; -- delayed by 10ns - at rising edge
12
:
13
:

I am not sure as the Input clock has a frequeny of 50MHz and the outputs 
are at 150KHz.

von Lothar M. (Company: Titel) (lkmiller) (Moderator)


Rate this post
useful
not useful
Robert wrote:
> Is it ok to add a min delay(is 10ns too much?)
Only you know that...

> just by adding a temp register to delay out_b?
With a 100MHz clock thats the only way to do it...

von Wil (Guest)


Rate this post
useful
not useful
How do I introduce a 180° phase shift between a_out and b_out. I tried 
using an inverting output. But when dutycycle is 10% for a_out, it is 
90% for b_out. But I want a 10% dutycycle for b_out with 180° phase 
shift.

Any suggestions?

von Lothar M. (Company: Titel) (lkmiller) (Moderator)


Rate this post
useful
not useful
Wil wrote:
> How do I introduce a 180° phase shift between a_out and b_out.
> I tried using an inverting output.
A phase shift is only defined for sinusoidal signals. And then inverting 
is correct.

> How do I introduce a 180° phase shift between a_out and b_out.
What you want in fact is a delay of half the cycle duration for one of 
the signals.

: Edited by Moderator
von Wil (Guest)


Rate this post
useful
not useful
Yes. Exactly. But the main clock is 50MHz and the outputs are 150KHz. 
How do I give a synthesizable delay.

von Lothar M. (Company: Titel) (lkmiller) (Moderator)


Rate this post
useful
not useful
Wil wrote:
> How do I give a synthesizable delay.
Use a second PWM unit that counts half a cycle delayed.
Or simply use a shift register.

Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
No account? Register here.