EmbDev.net

Forum: FPGA, VHDL & Verilog PWM with 4-bits control in Verilog


Author: Cm Y. (cmyang)
Posted on:
Attached files:

Rate this post
0 useful
not useful
Greetings,

I'm designing a PWM module,with a 4 bits control.
My specs,a 4-bits input control,input clock 50MHz,
a single bit output PWM_o,

when control changes,the duty cycle of PWM_o changes,
like control = 0,PWM_o = 0;Control = 1,PWM_o = 6.25%...increase 6.25% 
each time(meaning that PWM_o should be wider and wider each time it 
outputs when Control increase).Desired result should be like marked with 
red rectangular in the first photo.

I've tried so many version of ways to write it,I've noticed the common 
issue is that my Control changing too fast and I don't know how to delay 
it,I need to make the Control change after 16 pulses of input Clock,I 
just can't figure out how to do it...

I don't understand how to delay a set of multiple bits of input...

Here down below are my attempting,my attempting's output is almost 
correct,but just the issue with the Control..
Noted: Control is named as `value` in the codes;

Attempting 1:
 module pwm_c(clk,value,rst,PWM_out,counter,rst);
input clk,rst;
input [3:0] value;
output PWM_out;
reg PWM_out;

output reg [3:0]counter;


always@(posedge clk)
    begin
        if(!rst)
            counter <= 4'd0;
        else
            counter <= counter + 4'd1;
    end

always@(counter or value)
    begin
        if(value == 4'd0)
            PWM_out = 1'b0;
        else if(value == 4'd1)
            PWM_out = (counter >=4'd1) ? 1'b0:1'b1;
        else if(value == 4'd2)
            PWM_out = (counter >=4'd2) ? 1'b0:1'b1;
        else if(value == 4'd3)
            PWM_out = (counter >= 4'd3) ? 1'b0:1'b1;
        else if(value == 4'd4)
            PWM_out = (counter >= 4'd4) ? 1'b0:1'b1;

        else if(value == 4'd5)
            PWM_out = (counter >= 4'd5) ? 1'b0:1'b1;
        else if(value == 4'd6)
            PWM_out = (counter >= 4'd6) ? 1'b0:1'b1;
        else if(value == 4'd7)
            PWM_out = (counter >= 4'd7) ? 1'b0:1'b1;
        else if(value == 4'd8)
            PWM_out = (counter >= 4'd8) ? 1'b0:1'b1;


        else if(value == 4'd9)
            PWM_out = (counter >= 4'd9) ? 1'b0:1'b1;
        else if(value == 4'd10)
            PWM_out = (counter >= 4'd10) ? 1'b0:1'b1;
        else if(value == 4'd11)
            PWM_out = (counter >= 4'd11) ? 1'b0:1'b1;
        else if(value == 4'd12)
            PWM_out = (counter >= 4'd12) ? 1'b0:1'b1;

        else if(value == 4'd13)
            PWM_out = (counter >= 4'd13) ? 1'b0:1'b1;
        else if(value == 4'd14)
            PWM_out = (counter >= 4'd14) ? 1'b0:1'b1;
        else if(value == 4'd15)
            PWM_out = (counter >= 4'd15) ? 1'b0:1'b1;


        else
            PWM_out = 1'b0;
    end 
 endmodule 

Attempting 2:
module pwm_c(clk,value,rst,PWM_out,counter);
input clk,rst;
input wire [3:0] value;
output PWM_out;
reg PWM_out;

output reg [3:0]counter;


  

always@(posedge clk)
    begin
        if(!rst)
            counter <= 4'd0;
        else
            counter <= counter + 4'd1;
    end

always@(counter or value)
    begin
        if(value == 4'd0)
            PWM_out = 1'b0;
        else if(value == 4'd1)
            PWM_out = counter<2;
        else if(value == 4'd2)
            PWM_out = counter<2;
        else if(value == 4'd3)
            PWM_out = counter<2;
        else if(value == 4'd4)
            PWM_out = counter<2;

        else if(value == 4'd5)
            PWM_out = counter<4;
        else if(value == 4'd6)
            PWM_out = counter<4;
        else if(value == 4'd7)
            PWM_out = counter<4;
        else if(value == 4'd8)
            PWM_out = counter<4;


        else if(value == 4'd9)
            PWM_out = counter<6;
        else if(value == 4'd10)
            PWM_out = counter<6;
        else if(value == 4'd11)
            PWM_out = counter<6;
        else if(value == 4'd12)
            PWM_out = counter<6;

        else if(value == 4'd13)
            PWM_out = counter<15;
        else if(value == 4'd14)
            PWM_out = counter<15;
        else if(value == 4'd15)
            PWM_out = counter<15;


        else
            PWM_out = 1'b0;
    end

endmodule 

Attempting 3:
 module pwm_c
(
   input clk,rst,
   input [3:0] value,
   output PWM_out,
   output reg [3:0]counter
);
  
 
  
  always@(posedge clk)
      begin
          if(!rst)
              counter <= 4'd0;
       else
              counter <= counter + 4'd1;
      end

  assign PWM_out = (counter > value) ? 1'b1 : 1'b0;

endmodule 

Author: Hallo (Guest)
Posted on:

Rate this post
0 useful
not useful
Try to register value when the counter runs over and compare (attemp 3) 
the registered value with counter.

Author: Cm Y. (cmyang)
Posted on:

Rate this post
0 useful
not useful
Hallo wrote:
> Try to register value when the counter runs over and compare (attemp 3)
But the `value` is an `input`,I don't think that the `input` can be 
declared as a register.Or perhaps you can enlighten me...

although,I still tried to use D-Flip Flops to delay the `input`
,but the result came out wrong...and error.
My DFF attempting looks like this:
 always@(posedge clk)
        begin
           if(!rst)
              DFF1<=0;
              DFF2<=0;
              DFF3<=0;
           else
              DFF1<=value;
              DFF2<=DFF1;
              DFF3<=DFF2;
        end
       assign DFF_out <= DFF3;
So far,using DFF is the only way I could think of to delay the 
input...But it came out nothing...
>the registered value with counter.
Do you mean compare the registered value with counter?

Author: Hallo (Guest)
Posted on:

Rate this post
0 useful
not useful
Smith like:
reg [3:0] value_dly;
always_ff@(posedge clk) begin 
 if(!rst) begin
  value_dly<=4'h0; 
 end else if (counter == 4'hf) begin
  value_dly <= value;
 end
end

 assign PWM_out = (counter > value_dly) ? 1'b1 : 1'b0; 

Code not tested, is also not complete solution but should point into 
right direction...

Author: Hallo (Guest)
Posted on:

Rate this post
0 useful
not useful
It's also hard to say what really should happen since value changes more 
frequently than the counter run over. What should happen when value 
changes from 0 to 3 and then stay stable for 4*16 clock cycles?

Author: Cm Y. (cmyang)
Posted on:

Rate this post
0 useful
not useful
Hallo wrote:
> Smith like:
>
> reg [3:0] value_dly;
> always_ff@(posedge clk) begin
>  if(!rst) begin
>   value_dly<=4'h0;
>  end else if (counter == 4'hf) begin
>   value_dly <= value;
>  end
> end
> 
>  assign PWM_out = (counter > value_dly) ? 1'b1 : 1'b0;
> 
>
> Code not tested, is also not complete solution but should point into
> right direction...

I know your idea and I thought about this as well and used a 8bits 
counter to delay as well,but the problem remain...it won't actually 
delay the input value,instead it make the counter stop at the value...
always@(posedge clk)
begin
 if(!rst)
   begin
     counter<=8'd0;
   end
 else if(counter == 8'd15)
   begin
     delay<=value;
   end
 else
   begin
     counter <= counter + 8'd1;
   end
end

I even tried the much more simpler way to express the PWM_out result,but 
the input value issue still remain...it still changing too fast,it won't 
wait till 16 pulses of clock before change...
module pwm_c
(
 input clk;
 input [3:0]value;
 output counter,pwm;
 reg [3:0]counter=0;
);
reg pwm;
always @(posedge clk)
begin
  counter=counter+1;
  if(counter<=value/2) 
  pwm=1;
  else
  pwm=0;
  if(counter>=15)
  counter=0;
end
endmodule

Author: Cm Y. (cmyang)
Posted on:
Attached files:

Rate this post
0 useful
not useful
Hallo wrote:
> It's also hard to say what really should happen since value changes more
> frequently than the counter run over. What should happen when value
> changes from 0 to 3 and then stay stable for 4*16 clock cycles?

No,The first attachment is what I'm trying to show,that the each value 
should wait for 16 clock cycles before going to the next,like;
value = 0 and PWM_out = 0 and equal to 16 clock cycles then value 
changes to 1,PWM_out= almost 1 clock cycle and equal to 16 clock cycles 
then value changes to 2,PWM_out = 1 clock cycle...etc...

Maybe I'll put it in this way,each `value` is equal to 16 clock cycles.

PWM_out only output at counter==15,and value's 16 clock cycle.

I've redraw the photo...maybe you'll be much more clearly.
But noted,by continue to repeat,I meant that to when value changes to 4 
...PWM_out output equal to 4 clock cycles and value is equal to 16 clock 
cycles. I don't mean 0-1-2-3 to continue repeat but rather the clock 
cycles pattern.

: Edited by User
Author: Hallo (Guest)
Posted on:

Rate this post
0 useful
not useful
Your new drawing and my proposal should fit very well

If you would like to have every change of value been "processed", even 
value changes more often than the counter runs over you need an FIFO and 
push data in if value change and pull data out when the counter runs 
over.

Author: Cm Y. (cmyang)
Posted on:

Rate this post
0 useful
not useful
Hallo wrote:
> Your new drawing and my proposal should fit very well
>
> If you would like to have every change of value been "processed", even
> value changes more often than the counter runs over you need an FIFO and
> push data in if value change and pull data out when the counter runs
> over.

If your proposal will do what I wanted,
But I only see data in in your proposal,How can I pull it out? I might 
need more hint,'cause I'm really stuck.
reg [3:0] value_dly;
always_ff@(posedge clk) begin
  if(!rst) begin
   value_dly<=4'h0;
  end else if (counter == 4'hf) begin
   value_dly <= value;
  end
 //Here suppose to have a else begin counter <= counter + 4'h1; end , right? 
 end
 
  assign PWM_out = (counter > value_dly) ? 1'b1 : 1'b0;

then why mine doesn't work?
always@(posedge clk)
begin
 if(!rst)
   begin
     counter<=8'd0;
   end
 else if(counter == 8'd15)
   begin
     delay<=value;
   end
 else
   begin
     counter <= counter + 8'd1;
   end
end

Author: Hallo (Guest)
Posted on:

Rate this post
0 useful
not useful
Okay I think I got it, here with an downward counter:
// Code your design here
 module pwm_c
(
   input clk,rst,
   input [3:0] value,
   output PWM_out,
   output reg [3:0]counter
);
  
  
  always@(posedge clk)
      begin
          if(!rst)
              counter <= 4'hf;
       else
              counter <= counter - 4'd1;
      end

   assign PWM_out = (counter < value) ? 1'b1 : 1'b0;

endmodule 

If this is not okay you need to "invert" value:
// Code your design here
 module pwm_c
(
   input clk,rst,
   input [3:0] value,
   output PWM_out,
  output reg [3:0]counter
);
  
  always@(posedge clk)
      begin
          if(!rst)
              counter <= 4'h0;
       else
              counter <= counter + 4'd1;
      end
   wire [3:0]value_inv;
   assign value_inv = 4'hf-value;
   assign PWM_out = (counter <= value_inv) ? 1'b0 : 1'b1;

endmodule 

Author: Hallo (Guest)
Posted on:
Attached files:

Rate this post
0 useful
not useful
Added simulation screenshot

Author: Cm Y. (cmyang)
Posted on:
Attached files:

Rate this post
0 useful
not useful
Hallo wrote:
> Added simulation screenshot

Not Sure What I did wrong...but my simulation result is way different 
from yours...and so much wronger than before...

I tried added your inverted code...

Author: Hallo (Guest)
Posted on:

Rate this post
0 useful
not useful
You change value with every clock cycle.
Change of value must be proper specified and I just assumed now that it 
is only allowed to change when the counter runs over.

Author: Cm Y. (cmyang)
Posted on:

Rate this post
0 useful
not useful
Hallo wrote:
> You change value with every clock cycle.
> Change of value must be proper specified and I just assumed now that it
> is only allowed to change when the counter runs over.

Ok,I finally understood it,the change of value is what I should set it 
when I simulate it...and 16 clock cycles is what I should count and then 
set the value...

So...It was never the code's problem...

I've got stuck at this for days...THANK YOU SO MUCH.

Reply

Entering an e-mail address is optional. If you want to receive reply notifications by e-mail, please log in.

Rules — please read before posting

  • Post long source code as attachment, not in the text
  • Posting advertisements is forbidden.

Formatting options

  • [c]C code[/c]
  • [avrasm]AVR assembler code[/avrasm]
  • [vhdl]VHDL code[/vhdl]
  • [code]code in other languages, ASCII drawings[/code]
  • [math]formula (LaTeX syntax)[/math]




Bild automatisch verkleinern, falls nötig