Kraklog
Avalon PWM, PWM Interrupt 본문
728x90
Avalon bus를 활용해 pwm ip를 설계하는것이 목표.
Avalon Interface
-master 와 slave간 상호 동작을 나타낸 폼
-slave가 보내는 신호는 wait request, readdata 그 외에는 master에서 보내는 신호
-byteenable은 내가 보내는 data 중 일부만 보내고 싶을때 data를 선택하게 한다.
`timescale 1ns / 1ns
`define APWM
module avalon_module (
input clk ,
input rst ,
input mp_waitR , //Avalon bus
input [31:0] mp_rData ,
output reg [31:0] mp_addr ,
output reg [ 3:0] mp_bEn ,
output reg mp_rD ,
output reg mp_wR ,
output reg [31:0] mp_wData
);
parameter FF = 1;
initial begin
mp_addr =32'hx; //unknown value
mp_bEn =4'bx;
mp_rD =1'b0;
mp_wR =1'b0;
//mp_waitR =;
//mp_rData =;
mp_wData =32'hx;
#200;
`ifdef APWM
avalon_write(32'd0,32'd10); //set period
avalon_write(32'd1,32'd7); //set duty
avalon_read(32'h0000);
avalon_read(32'h0001);
`else
avalon_write(32'h1000,32'hAABBCCDD);
avalon_write(32'h1000,32'hDEADBEEF);
avalon_read(32'h1000);
avalon_read(32'h2000);
`endif
end
//avalon write (bus modeling)
task avalon_write;
input [31:0] wAddr;
input [31:0] wData;
begin
@(posedge clk);
#(FF); //step 1 delay
mp_addr = wAddr;
mp_bEn = 4'b1;
mp_wR = 1'b1 ;
mp_wData = wData ;
@(posedge clk);
while (mp_waitR) begin //mp_waitR == 0
@(posedge clk);
end
#(FF);
//initial value
mp_addr = 32'hx ;
mp_bEn = 4'bx ;
mp_wR = 1'b0 ;
mp_wData = 32'hx ;
end
endtask
task avalon_read;
input [31:0] rAddr;
begin
@(posedge clk);
#(FF); //step 1 delay
mp_addr = rAddr;
mp_bEn = 4'b1;
mp_rD = 1'b1 ;
@(posedge clk);
while (mp_waitR) begin //mp_waitR == 0
@(posedge clk);
end
#(FF);
$display("AV rAddr 0x%x, rData 0x%x", mp_addr, mp_rData);
//initial value
mp_addr = 32'hx ;
mp_bEn = 4'bx ;
mp_rD = 1'b0 ;
@(posedge clk);
end
endtask
endmodule
module avalon_pwm
(
clk, wr_data, wr_n, addr, clr_n, rd_data, pwm_out
);
input clk;
input [31:0] wr_data;
input wr_n; //data write control signal
input addr;
input clr_n;
output [31:0] rd_data;
output [7:0] pwm_out;
//resistor wire assign
reg [7:0] div3, div2, div1, div0; //주파수 설정을 위한 분주비 레지스터
reg [7:0] duty3, duty2, duty1, duty0; //duty cycle set resistor
reg [31:0] counter; //pwm period counter
reg off; //pwm output on/off
reg [31:0] rd_data;
wire div_en3, div_en2, div_en1, div_en0, duty_en3, duty_en2, duty_en1, duty_en0;
//data set
always @(posedge clk or negedge clr_n)
begin
if (clr_n == 0)
begin
div3 <= 8'h 00;
div2 <= 8'h 00;
div1 <= 8'h 00;
div0 <= 8'h 00;
duty3 <= 8'h 00;
duty2 <= 8'h 00;
duty1 <= 8'h 00;
duty0 <= 8'h 00;
end
else
begin //주파수 및 duty cycle을 읽어와 wr_data reg에 저장
if (div_en3)
div3 <= wr_data[31:24];
else
div3 <= div3;
if (div_en2)
div2 <= wr_data[23:16];
else
div2 <= div2;
if (div_en1)
div1 <= wr_data[15:8];
else
div1 <= div1;
if (div_en0)
div0 <= wr_data[7:0];
else
div0 <= div0;
if (duty_en3)
duty3 <= wr_data[31:24];
else
duty3 <= duty3;
if (duty_en2)
duty2 <= wr_data[23:16];
else
duty2 <= duty2;
if (duty_en1)
duty1 <= wr_data[15:8];
else
duty1 <= duty1;
if (duty_en0)
duty0 <= wr_data[7:0];
else
duty0 <= duty0;
end
end
//pwm period counter (pwm 주기 카운터)
always @(posedge clk or negedge clr_n)
begin
if (clr_n == 0)
counter <= 0;
else
if (counter >= {div3, div2, div1, div0})
counter <= 0;
else
counter <= counter + 1;
end
//pwm output control
always @(posedge clk or negedge clr_n)
begin
if (clr_n == 0)
off <= 0;
else
if (counter >= {duty3, duty2, duty1, duty0})
off <= 1;
else
if (counter == 0)
off <= 0;
else
off <= off;
end
//read,write by address
always @(addr or div3 or div2 or div1 or div0 or duty3 or duty2 or duty1 or duty0)
if (addr == 0)
rd_data = {div3, div2, div1, div0};
else
rd_data = {duty3, duty2, duty1, duty0};
assign div_en3 = !wr_n & !addr ; //data write control logic
assign div_en2 = !wr_n & !addr ; //address=0 registor -> div
assign div_en1 = !wr_n & !addr ;
assign div_en0 = !wr_n & !addr ;
assign duty_en3 = !wr_n & addr ; //address=1 registor -> duty
assign duty_en2 = !wr_n & addr ;
assign duty_en1 = !wr_n & addr ;
assign duty_en0 = !wr_n & addr ;
assign pwm_out[0] = ! off; //pwm output control
assign pwm_out[1] = ! off;
assign pwm_out[2] = ! off;
assign pwm_out[3] = ! off;
assign pwm_out[4] = ! off;
assign pwm_out[5] = ! off;
assign pwm_out[6] = ! off;
assign pwm_out[7] = ! off;
endmodule
`define clk_50MHz 20
//`define regs
`define pwms
module tb_avalon_module;
reg clk ;
reg rst ;
//Avalon bus
`ifdef regs
wire mp_waitR ;
wire [31:0] mp_rData ;
`elsif pwms
wire mp_waitR ;
wire [31:0] mp_rData ;
wire [07:0] pwm_out ;
`else
reg mp_waitR ;
reg [31:0] mp_rData ;
`endif
wire [31:0] mp_wData ;
wire [31:0] mp_addr ;
wire [ 3:0] mp_bEn ;
wire mp_rD ;
wire mp_wR ;
avalon_module uAvalon_module (
.clk (clk ),
.rst (rst ),
.mp_waitR (mp_waitR),
.mp_rData (mp_rData),
.mp_addr (mp_addr ),
.mp_bEn (mp_bEn ),
.mp_rD (mp_rD ),
.mp_wR (mp_wR ),
.mp_wData (mp_wData)
);
`ifdef regs
my_reg uMy_reg (
.clk(clk) ,
.rst(rst) ,
//Avalon Bus
.addr (mp_addr ),
.bEn (mp_bEn ),
.rD (mp_rD ),
.wR (mp_wR ),
.waitR(mp_waitR),
.rData(mp_rData),
.wData(mp_wData)
);
`elsif pwms
avalon_pwm uAvalon_pwm_0 (
.clk (clk ),
.wr_data(mp_wData),
.wr_n (~mp_wR),
.addr (mp_addr[0]),
.clr_n (~rst),
.rd_data(mp_rData),
.pwm_out(pwm_out)
);
`else
`endif
initial fork
clk_gen;
rst_gen;
`ifdef regs
`elsif pwms
`else
data_gen;
`endif
join
task clk_gen;
begin
clk = 1'b0;
forever #(`clk_50MHz/2) clk = ~clk;
end
endtask
task rst_gen;
begin
rst =1'b0;
repeat(2) @(posedge clk);
rst =1'b1;
repeat(2) @(posedge clk);
rst =1'b0;
end
endtask
`ifdef regs
`elsif pwms
`else
task data_gen;
begin
#75;
mp_rData = 32'h11223344;
end
endtask
`endif
endmodule
Period는 10, duty는 7로 설정했다.
write signal이 High가 되었을때 0번 address에서 Data의 값은 10이 할당되고
write signal이 다시 high 되었을때 1번 address에서 Data의 값이 7이 할당된다.
Read signal이 들어오면 각각 0번과 1번 address 의 값인 10과 7이 출력됨을 보인다.
-Interrupt 발생
728x90
'[Harman] 하만 반도체 설계 > NiosII' 카테고리의 다른 글
IIC - bit bang (0) | 2024.01.03 |
---|---|
GPIO , UART (0) | 2023.09.09 |
Avalon BUS + reg 설계 (0) | 2023.08.28 |
PWM / CRC (0) | 2023.08.28 |
Nios Processor (0) | 2023.07.28 |