## Verilog Examples - PWM or programmable clock duty cycle

We will now try yo generate a square with that has width of the positive or negative cycle - programmable. Also called PWM, it finds many application, the most recent one is in controlling the intensity of the backlight of an LCD screen. If the period on the ON time is much larger than the period of the off time, the LCD backlight brightness is high. If the period of ON time is much smaller than the period of the OFF time, the LCD brightness will be low. By programming the relative values of the ON and OFF time , we can generate the variable screen intensity.

Let us now formally state the problem

Problem - Generate a square wave with programmable ON (logic 1) and OFF (logic 0) intervals. An interval is defined as one clock period. The durations of the intervals are specified by two 4-bit control signals - call these rise and fall. Design a programmable square-wave generator circuit. It will also have a reset input. Whenever , any of the 4 rise or any of the 4 fall inputs change that output should change. The module obviously has a clock in.

Solution -

This is the main code clock.v

 `// referencedesigner.com// Example of a Pulse Width Modulation// Or a square wave with programmable positive and negative width module sqwaveGen(clk,reset,rise,fall,clk_out);input wire clk;input wire reset;output wire clk_out;input wire [3:0] rise; input wire [3:0] fall;reg [3:0] count, count_on, count_off;reg pos_or_neg;  always @(posedge clk, negedge reset) begin if(~reset) begin  count<= 0; count <= 0; pos_or_neg <=1;  end else if ( (pos_or_neg ==1) ) begin if ((count == count_on-1) ) begin count <=0; pos_or_neg <=0; end else count <= count+1; end else if ( (pos_or_neg ==0) ) begin if ((count == count_off-1) ) begin count <=0; pos_or_neg <=1; end else count <= count+1; endend  always @(rise, fall)begincount_on <= rise;count_off <= fall; end  assign clk_out = pos_or_neg; endmodule   `

Here is the test bench clocktb.v

 ``timescale 1ns/1nsmodule sqwavegentb;input clk_out;output reg clk,reset;output reg [3:0] rise,fall;sqwaveGen sqwave(clk,reset,rise,fall,clk_out);initialclk = 1'b0;always#20 clk = ~clk;initialbegin\$monitor(\$time,"clk = %b,reset = %b,clk_out = %b,rise = %b,fall = %b",clk,reset,clk_out,rise,fall); reset=0;#50 reset = 1;rise = 4'b0011;fall = 4'b0100;#2000 rise = 4'b0101;#10000 \$finish;endinitialbegin \$dumpfile ("sqwavegentb.vcd"); \$dumpvars (0,sqwavegentb);endendmodule   `

Here is the result of the simulation when rise = 3 and fall = 4

the result of the simulation when rise = 5 and fall = 4

Explanation

1. Whenever the required input changes, it is stored in two registers count_on and count_off

 ```input wire [3:0] rise; input wire [3:0] fall; .. .. always @(rise, fall) begin count_on <= rise; count_off <= fall; end```

We now count for for count_on and keep the value of pos_or_neg at 1 while it is counting using a counter `count`. Once `count` reaches the value count_on, we toggle pos_or neg, we reset, count to 0 and then we start counting again till it reaches, count_off.

Rest of the code should be self explanatory.