0% found this document useful (0 votes)
78 views

Project SoC PWM

This document describes a final project to implement pulse width modulation (PWM) using Verilog. It includes: 1) A top module for the PWM with parameters for duty cycle, frequency, alignment, and counter mode. It includes a Timer Prescaler module. 2) Figures showing the top module and overview design of the PWM. 3) A state diagram and descriptions of the finite state machine used in the PWM design. 4) Code for the PWM and Timer Prescaler modules in Verilog.

Uploaded by

Lê Đình Huy
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
78 views

Project SoC PWM

This document describes a final project to implement pulse width modulation (PWM) using Verilog. It includes: 1) A top module for the PWM with parameters for duty cycle, frequency, alignment, and counter mode. It includes a Timer Prescaler module. 2) Figures showing the top module and overview design of the PWM. 3) A state diagram and descriptions of the finite state machine used in the PWM design. 4) Code for the PWM and Timer Prescaler modules in Verilog.

Uploaded by

Lê Đình Huy
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 10

VIETNAM NATIONAL UNIVERSITY – HO CHI MINH CITY

UNIVERSITY OF SCIENCE
FACULTY OF ELECTRONICS AND TELECOMMUNICATIONS

SoC Lab
FINAL PROJECT
PULSE WIDTH MODULATION (PWM)
Lecture : MSc. Trần Tuấn Kiệt
Student : 20200017 Nguyễn Thành Đạt
: 20200018 Phan Thị Diễm
: 20200085 Nguyễn Văn Thành
: 20200110 Nguyễn Huy Trường
: 20200295 Tôn Nữ Tâm Nhi
: 20200353 Nguyễn Tiến Thông
Top module

Figure1: Top module of PWM

A Pulse Width Modulation (PWM) module with adjustable parameters for duty
cycle, frequency, alignment, and counter mode. Additionally, it includes a Timer
Prescaler module responsible for counting and generating the PWM signal.

Figure 2:Overview of PWM Design


FSM

Figure 3: State Diagram of PWM


State Descriptions:
- RESET: Initial state or state after a reset.
- IDLE/ENABLE: Waits for the enable signal to transition to the
CONFIGURE state.
- CONFIGURE: Determines whether to configure width or frequency based
on the address signal.
- PROCESS INPUT: Processes input data and sets internal parameters.
- PROCESS OUTPUT: Continuously generates the PWM output based on the
configured parameters.
- DONE: Final state.
Transitions:
- From RESET to IDLE/ENABLE: On a positive edge of i_clk when i_reset is
low.
- From IDLE/ENABLE to CONFIGURE: On a positive edge of i_clk when
i_enable is low and i_wenable is low.
- From CONFIGURE to IDLE/ENABLE: On a positive edge of i_clk when
i_enable is low and i_wenable is high.
- From CONFIGURE to PROCESS INPUT: On a positive edge of i_clk when
i_enable is low and i_wenable is low.
- From PROCESS INPUT to PROCESS OUTPUT: On a positive edge of
i_clk when i_enable is high and i_wenable is low.
- From PROCESS OUTPUT to PROCESS INPUT: On a positive edge of
i_clk when i_enable is low and i_renable is high.
- From PROCESS OUTPUT to DONE: On a positive edge of i_clk when
i_enable is high and i_renable is low.

Code:
module PWM #(
parameter DATA_WIDTH = 32,
parameter DUTY_CYCLE_WIDTH = 7,
parameter SOURCE_CLOCK_VALUE = 50000000,
parameter ADDRESS_WIDTH = 1,
parameter PRES_WIDTH = 16,
parameter PERIOD_WIDTH = 16,
parameter COUNTER_WIDTH = 26

)(
input i_clk,
input i_reset,
input i_enable,
input i_wenable,
input [ADDRESS_WIDTH - 1 : 0] i_address,
input i_renable,
input [DATA_WIDTH - 1 : 0] i_data, //dyty cycle's
unit is %
output logic [DATA_WIDTH - 1 : 0] o_pwm_pulse
);

localparam FRE_CONTROL = 32;


localparam WIDTH_CONTROL = 10;
localparam ALIGNMENT_WIDTH = 2;
localparam CNTMODE_WIDTH = 1;

logic [DUTY_CYCLE_WIDTH - 1 : 0] duty_cycle;


logic [PRES_WIDTH - 1 : 0] prescaler;
logic [PERIOD_WIDTH - 1 : 0] period;
logic [WIDTH_CONTROL - 1 : 0] pwm_widthcontrol;
logic [FRE_CONTROL - 1 : 0] pwm_frecontrol;
logic [DATA_WIDTH - 1 : 0] pwm_out;
logic prescaler_enable;
logic [ALIGNMENT_WIDTH - 1 : 0] alignment_mode;
logic [CNTMODE_WIDTH - 1 : 0] counter_mode;

logic [COUNTER_WIDTH - 1 : 0] o_clk_counter;


logic [COUNTER_WIDTH - 1 : 0] counter_pwm;

assign prescaler = pwm_frecontrol[PRES_WIDTH - 1 : 0];


assign period = pwm_frecontrol[PERIOD_WIDTH +
PRES_WIDTH - 1 : PRES_WIDTH];
assign duty_cycle = pwm_widthcontrol[DUTY_CYCLE_WIDTH - 1 :
0];
assign alignment_mode = pwm_widthcontrol[ALIGNMENT_WIDTH +
DUTY_CYCLE_WIDTH - 1 : DUTY_CYCLE_WIDTH]; // 000 left - alignment, 001 right
- alignment, 010 center - alignment
assign counter_mode = pwm_widthcontrol[CNTMODE_WIDTH +
ALIGNMENT_WIDTH + DUTY_CYCLE_WIDTH - 1 : ALIGNMENT_WIDTH + DUTY_CYCLE_WIDTH];

always_ff @(posedge i_clk, negedge i_reset) begin


if(!i_reset) begin
pwm_widthcontrol <=
{WIDTH_CONTROL{1'b0}};
pwm_frecontrol <= {FRE_CONTROL{1'b0}};
o_pwm_pulse <= {DATA_WIDTH{1'b0}};
prescaler_enable <= 1'b0;
end
else begin
if(!i_enable && !i_wenable) begin
if(!i_address) begin
pwm_widthcontrol <= i_data[WIDTH_CONTROL
- 1 : 0];
prescaler_enable <= prescaler_enable;
end
else begin
pwm_frecontrol <= i_data;
prescaler_enable <= 1'b1;
end
end
else if(!i_enable && !i_renable) begin
o_pwm_pulse <= pwm_out;
pwm_frecontrol <= pwm_frecontrol;
pwm_widthcontrol <= pwm_widthcontrol;
prescaler_enable <= prescaler_enable;
end
else begin
o_pwm_pulse <= o_pwm_pulse;
pwm_frecontrol <= pwm_frecontrol;
pwm_widthcontrol <= pwm_widthcontrol;
prescaler_enable <= prescaler_enable;
end
end
end

Timer_Prescaler #(
.DATA_WIDTH(DATA_WIDTH),
.SOURCE_CLOCK_VALUE(SOURCE_CLOCK_VALUE),
.PRES_WIDTH(PRES_WIDTH),
.PERIOD_WIDTH(PERIOD_WIDTH),
.DUTY_CYCLE_WIDTH(DUTY_CYCLE_WIDTH),
.ALIGNMENT_WIDTH(ALIGNMENT_WIDTH),
.CNTMODE_WIDTH(CNTMODE_WIDTH)
) Pres (
.i_clk_source(i_clk),
.i_reset(i_reset),
.i_CS(prescaler_enable),
.i_alignment(alignment_mode),
.i_countermode(counter_mode),
.i_prescaler(prescaler),
.i_period(period),
.i_dutycycle(duty_cycle),
.o_pwm_clk(pwm_out)
);
endmodule

module Timer_Prescaler #(
parameter DATA_WIDTH = 32,
parameter SOURCE_CLOCK_VALUE = 50000000,
parameter PRES_WIDTH = 16,
parameter PERIOD_WIDTH = 16,
parameter DUTY_CYCLE_WIDTH = 7,
parameter ALIGNMENT_WIDTH = 2,
parameter CNTMODE_WIDTH = 1,

parameter COUNTER_WIDTH = 26
)(
input i_clk_source,
input i_reset,
input i_CS,
input [ALIGNMENT_WIDTH - 1 : 0] i_alignment,
input [CNTMODE_WIDTH - 1 : 0] i_countermode,
input [PRES_WIDTH - 1:0] i_prescaler,
input [PERIOD_WIDTH - 1:0] i_period,
input [DUTY_CYCLE_WIDTH - 1 : 0] i_dutycycle,
output logic [DATA_WIDTH - 1 : 0] o_pwm_clk,
output logic [COUNTER_WIDTH - 1 : 0] o_clk_counter,
output logic [COUNTER_WIDTH - 1 : 0]
counter_pwm
);
//localparam COUNTER_WIDTH =
26;

localparam LEFT_ALIGNMENT =
2'b00;
localparam RIGHT_ALIGNMENT =
2'b01;
localparam CENTER_ALIGNMENT =
2'b10;

localparam UP_COUNTING =
1'b1;
localparam DOWN_COUNTING =
1'b0;

logic [COUNTER_WIDTH - 1 : 0] clk_counter;


logic [PRES_WIDTH + PERIOD_WIDTH + 2 - 1 : 0]
counter_divider;
logic [COUNTER_WIDTH - 1 : 0] counter_max;
logic [COUNTER_WIDTH - 1 : 0] left_edge;
logic [COUNTER_WIDTH - 1 : 0] right_edge;

assign counter_divider = (i_CS == 1'b1) ? (i_prescaler + 1) *


(i_period + 1) : (PRES_WIDTH + PERIOD_WIDTH + 2 - 1)'('d1);
assign counter_max = (i_CS == 1'b1) ? SOURCE_CLOCK_VALUE /
counter_divider : {COUNTER_WIDTH{1'b0}};
assign counter_pwm = (i_CS == 1'b0) ?
{COUNTER_WIDTH{1'b0}} : ((((i_countermode == UP_COUNTING) && (i_alignment ==
LEFT_ALIGNMENT)) || ((i_countermode == DOWN_COUNTING) && (i_alignment ==
RIGHT_ALIGNMENT)))) ? i_dutycycle * counter_max / 100 : (((i_countermode ==
DOWN_COUNTING) && (i_alignment == LEFT_ALIGNMENT)) || ((i_countermode ==
UP_COUNTING) && (i_alignment == RIGHT_ALIGNMENT))) ? ((100 - i_dutycycle) *
counter_max / 100) : {COUNTER_WIDTH{1'b0}};
assign left_edge = (i_CS == 1'b0) ?
{COUNTER_WIDTH{1'b0}} : (i_alignment == CENTER_ALIGNMENT) ? ((100 -
i_dutycycle) * counter_max / 200) : {COUNTER_WIDTH{1'b0}};
assign right_edge = (i_CS == 1'b0) ?
{COUNTER_WIDTH{1'b0}} : (i_alignment == CENTER_ALIGNMENT) ? ((100 +
i_dutycycle) * counter_max / 200) : {COUNTER_WIDTH{1'b0}};
assign o_clk_counter = clk_counter;

always_ff@(posedge i_clk_source, negedge i_reset) begin


if(!i_reset) begin
clk_counter <= {COUNTER_WIDTH{1'b0}};
end
else begin
if(i_CS) begin
if(i_countermode == DOWN_COUNTING) begin
if(clk_counter == 0) begin
clk_counter <= counter_max;
end
else begin
clk_counter <= clk_counter - 1;
end
end
else begin
if(clk_counter == counter_max) begin
clk_counter <= {COUNTER_WIDTH'('d1)};
end
else begin
clk_counter <= clk_counter + 1;

end
end
end
else begin
clk_counter <= clk_counter;
end
end
end

always_comb begin

o_pwm_clk = {(DATA_WIDTH-1)'('b0), 1'b0};

if (!i_reset) begin
o_pwm_clk = {(DATA_WIDTH-1)'('b0), 1'b0};
end
else begin
if (i_CS) begin
if (i_countermode == DOWN_COUNTING) begin
if (i_alignment == LEFT_ALIGNMENT) begin
o_pwm_clk = (clk_counter > counter_pwm) ?
{(DATA_WIDTH-1)'('b0), 1'b1} : {(DATA_WIDTH-1)'('b0), 1'b0};
end
else if (i_alignment == RIGHT_ALIGNMENT) begin
o_pwm_clk = (clk_counter > counter_pwm) ?
{(DATA_WIDTH-1)'('b0), 1'b0} : {(DATA_WIDTH-1)'('b0), 1'b1};
end
else if (i_alignment == CENTER_ALIGNMENT) begin
if (clk_counter < left_edge) begin
o_pwm_clk = {(DATA_WIDTH-1)'('b0), 1'b0};
end
else if (clk_counter >= left_edge && clk_counter <=
right_edge) begin
o_pwm_clk = {(DATA_WIDTH-1)'('b0), 1'b1};
end
else if (clk_counter > right_edge) begin
o_pwm_clk = {(DATA_WIDTH-1)'('b0), 1'b0};
end
else begin
o_pwm_clk = o_pwm_clk; // This case seems
redundant
end
end
else begin
o_pwm_clk = o_pwm_clk; // Default case
end
end
else begin
if (i_alignment == LEFT_ALIGNMENT) begin
o_pwm_clk = (clk_counter <= counter_pwm) ?
{(DATA_WIDTH-1)'('b0), 1'b1} : {(DATA_WIDTH-1)'('b0), 1'b0};
end
else if (i_alignment == RIGHT_ALIGNMENT) begin
o_pwm_clk = (clk_counter <= counter_pwm) ?
{(DATA_WIDTH-1)'('b0), 1'b0} : {(DATA_WIDTH-1)'('b0), 1'b1};
end
else if (i_alignment == CENTER_ALIGNMENT) begin
if (clk_counter < left_edge) begin
o_pwm_clk = {(DATA_WIDTH-1)'('b0), 1'b0};
end
else if (clk_counter >= left_edge && clk_counter <=
right_edge) begin
o_pwm_clk = {(DATA_WIDTH-1)'('b0), 1'b1};
end
else if (clk_counter > right_edge) begin
o_pwm_clk = {(DATA_WIDTH-1)'('b0), 1'b0};
end
else begin
o_pwm_clk = o_pwm_clk; // This case seems
redundant
end
end
else begin
o_pwm_clk = o_pwm_clk; // Default case
end
end
end
else begin
o_pwm_clk = {(DATA_WIDTH-1)'('b0), 1'b0};
end
end
end

endmodule
Explain code:
Module Overview:
• Inputs:
o i_clk: System clock
o i_reset: Reset signal
o i_enable: Enables PWM functionality
o i_wenable: Enables writing to control registers
o i_address: Selects which control register to write to
o i_renable: Enables reading the PWM output
o i_data: Data to be written to control registers
• Outputs:
o o_pwm_pulse: The generated PWM signal
Key Components:
• Parameters: Define various constants such as data width, duty cycle width,
source clock value, etc.
• Signals: Declare internal signals used for control and data flow.
• Timer_Prescaler Instance: A module instance responsible for dividing the
clock frequency and generating the PWM waveform.
• Combinational Logic: Assigns values to signals based on inputs and
parameters.
• Sequential Logic: Implements state-based behavior using an always_ff
block, controlled by the clock and reset signals.
Code Structure:
• Parameter Declarations: Sets fixed values for various parameters.
• Signal Declarations: Declares internal signals.
• Assignment Statements: Assigns values to signals based on calculations and
parameter values.
• Always_ff Block: Implements the main state machine logic, handling clock
events and reset.
• Timer_Prescaler Instance: Instantiates the Timer_Prescaler module with
necessary connections.
Functionality:
• Initialization: Upon reset, signals are set to default values.
• Data Writing: When i_wenable is active, writes data to control registers for
frequency and duty cycle.
• PWM Generation: When i_enable is active, enables the prescaler and starts
PWM generation based on configured parameters.
• Output Reading: When i_renable is active, outputs the generated PWM
signal.
Key Points:
• The code uses a state machine to control the PWM generation process.
• The Timer_Prescaler module handles clock division and PWM waveform
creation.
• Control registers allow configuring frequency and duty cycle.
• The code supports different alignment modes (left, right, center) for the
PWM pulse.

You might also like