Kraklog

Avalon PWM, PWM Interrupt 본문

[Harman] 하만 반도체 설계/NiosII

Avalon PWM, PWM Interrupt

Krakens 2023. 9. 8. 08:19
728x90

Diagram
Register map

 

Avalon bus를 활용해 pwm ip를 설계하는것이 목표.

 

Avalon Interface

-master 와 slave간 상호 동작을 나타낸 폼

-slave가 보내는 신호는 wait request, readdata 그 외에는 master에서 보내는 신호

-byteenable은 내가 보내는 data 중 일부만 보내고 싶을때 data를 선택하게 한다. 

 

period, duty

`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