I make a simple pwm module (only 1 output).
is in use in a cyclone III, without problems.
3 modules:
************************
pwm.v
************************
//modulo generador PWM
//toni salguero
//inicio: 15 de junio de 2009
module pwm(
rst_n,
clk,
//bus avalon
av_cs,
av_rd,
av_wr,
av_datain,
av_dataout,
av_addr,
//señal de salida PWM
pwm_out
);
input rst_n;
input clk;
//bus avalon
input av_cs;
input av_rd;
input av_wr;
input [1:0]av_addr;
input [31:0]av_datain;
output [31:0]av_dataout;
//señal de salida PWM
output pwm_out;
wire pwm_enable;
wire [15:0]pwm_divisor;
wire [7:0] pwm_width;
pwm_avalon_slave_if pwmif (rst_n, clk, av_cs, av_rd, av_wr, av_addr, av_datain, av_dataout, pwm_enable, pwm_divisor, pwm_width);
pwm_control pwmc (rst_n, clk, pwm_enable, pwm_divisor, pwm_width, pwm_out);
endmodule
************************
pwm_control.v
************************
//modulo de control del pwm
//toni salguero
//inicio: 15 de junio de 2009
module pwm_control(
rst_n,
clk,
pwm_enable,
pwm_divisor,
pwm_width,
pwm_out
);
input rst_n;
input clk;
input pwm_enable;
input [15:0]pwm_divisor;
input [7:0]pwm_width;
output pwm_out;
wire pwm_clk;
reg [7:0]contador;
reg [15:0]clk_div;
//generador del clock del modulo
always @ (posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
clk_div <= 0;
end
else
if(pwm_enable)
begin
clk_div <= clk_div+1;
if(clk_div == pwm_divisor)
begin
clk_div <= 0;
end
end
end
assign pwm_clk = (clk_div == 0 ) ? 1'b1 : 1'b0;
//señal de salida
always @ (posedge clk or negedge rst_n)
if(~rst_n)
begin
contador <= 0;
end
else
if(pwm_enable)
begin
if(pwm_clk)
contador <= contador+1;
end
else
contador <= 0;
assign pwm_out = (contador <= pwm_width) ? 1'b1: 1'b0;
endmodule
************************
pwm_avalon_slave_if.v
************************
//interficie con el bus avalon
//toni salguero
//inicio: 15 de junio de 2009
module pwm_avalon_slave_if(
rst_n,
clk,
chipselect,
read_n,
write_n,
address,
writedata,
readdata,
pwm_enable,
pwm_divisor,
pwm_width
);
input rst_n;
input clk;
input chipselect;
input read_n;
input write_n;
input [1:0]address;
input [31:0]writedata;
output [31:0]readdata;
output pwm_enable;
output [15:0]pwm_divisor;
output [7:0]pwm_width;
reg delayed_cs;
reg pwm_enable;
reg [15:0]pwm_divisor;
reg [7:0]pwm_width;
wire cs;
//retardo de cs
always @ (posedge clk or negedge rst_n)
if(~rst_n)
delayed_cs <= 0;
else
delayed_cs <= chipselect;
assign cs = chipselect & ~delayed_cs;
//carga datos en el registro de control
always @ (posedge clk or negedge rst_n)
if (~rst_n)
begin
pwm_enable <= 0;
pwm_divisor <= 0;
pwm_width <= 0;
end
else if (cs & ~write_n & (address == 0))
begin
pwm_width <= writedata[7:0];
end
else if (cs & ~write_n & (address == 1))
begin
pwm_enable <= writedata[31];
pwm_divisor <= writedata[15:0];
end
//lectura de los datos
//datos de salida
assign readdata = 32'b0
| {32{(~read_n & chipselect & (address == 0))}} & {24'b0, pwm_width}
| {32{(~read_n & chipselect & (address == 1))}} & {pwm_enable, 15'b0, pwm_divisor};
endmodule
Toni Salguero