NIOS II IP核


本设计是一个范例,nios通过读写寄存器来完成Verilog实现的逻辑功能。本利以PWM为例子,以后可以将逻辑功能改复杂。

PWM设计分为3个部分,一是功能逻辑设计--Verilog语言实现;二是寄存器定义;三是Avalon接口设计 

Nios <wbr> <wbr>PWM <wbr>自定义组件IP

 


Nios <wbr> <wbr>PWM <wbr>自定义组件IP

此例中,制作成SOPC IP时,可以选择为 动态地址对齐--Dynamic Bus sizing

若Verilog程序中没有byteenable,则可以设置为静态地址对齐--Native Address Alignment

一般,内存类(RAM,FLASH)常设为动态地址对齐,寄存器型的常设为静态地址对齐。IORD,IOWR主要用于静态机制对齐的读取,IORD_32DIRECT,IORD_16DIRECT,IORD_8DIRECT;IOWR_32DIRECT,IOWR_16DIRECT,IOWR_8DIRECT主要用于动态对齐的读取

 

io.h文件中看函数的宏定义:

#define IORD_32DIRECT(BASE, OFFSET) \
  __builtin_ldwio (__IO_CALC_ADDRESS_DYNAMIC ((BASE), (OFFSET)))

#define IORD(BASE, REGNUM) \
  __builtin_ldwio (__IO_CALC_ADDRESS_NATIVE ((BASE), (REGNUM)))

 

 

Verilog 程序
module PWM(clk,reset_n,chipselect,address,write,writedata,read,byteenable,readdata,PWM_out); 
input clk; 
input reset_n; 
input chipselect; 
input [1:0]address; 
input write; 
input [31:0] writedata; 
input read; 
input [3:0] byteenable; 
output [31:0] readdata; 
output PWM_out; 
   
reg [31:0] clock_divide_reg;  
reg [31:0] duty_cycle_reg;  
reg control_reg; 
reg clock_divide_reg_selected; 
reg duty_cycle_reg_selected; 
reg control_reg_selected; 
reg [31:0] PWM_counter; 
reg [31:0] readdata; 
reg PWM_out; 
wire pwm_enable; 

//地址译码 
always @ (address) 
begin   
     
     clock_divide_reg_selected=0; 
     duty_cycle_reg_selected=0; 
     control_reg_selected=0;   
     case(address) 
         2'b00:clock_divide_reg_selected=1; 
         2'b01:duty_cycle_reg_selected=1; 
         2'b10:control_reg_selected=1; 
         default: 
         begin 
             clock_divide_reg_selected=0; 
             duty_cycle_reg_selected=0; 
             control_reg_selected=0; 
         end 
     endcase 
end            

//写PWM输出周期的时钟数寄存器 
always @ (posedge clk or negedge reset_n) 
begin 
     if(reset_n==1'b0)  clock_divide_reg<=0; 
     else
     begin 
         if(write & chipselect & clock_divide_reg_selected) 
         begin 
             if(byteenable[0]) clock_divide_reg[7:0]<=writedata[7:0]; 
             if(byteenable[1]) clock_divide_reg[15:8]<=writedata[15:8]; 
             if(byteenable[2]) clock_divide_reg[23:16]<=writedata[23:16]; 
             if(byteenable[3]) clock_divide_reg[31:24]<=writedata[31:24]; 
         end 
     end 
end 

//写PWM周期占空比寄存器 
always @ (posedge clk or negedge reset_n) 
begin 
     if(reset_n==1'b0)  duty_cycle_reg<=0; 
     else
     begin 
         if(write & chipselect & duty_cycle_reg_selected) 
         begin 
            if(byteenable[0])  duty_cycle_reg[7:0]<=writedata[7:0]; 
            if(byteenable[1])  duty_cycle_reg[15:8]<=writedata[15:8]; 
            if(byteenable[2])  duty_cycle_reg[23:16]<=writedata[23:16]; 
            if(byteenable[3])  duty_cycle_reg[31:24]<=writedata[31:24]; 
         end 
     end 
end 
   
//写控制寄存器 
always @ (posedge clk or negedge reset_n) 
begin 
     if(reset_n==1'b0)   control_reg<=0; 
     else
     begin 
         if(write & chipselect & control_reg_selected) 
         begin 
             if(byteenable[0])  control_reg<=writedata[0]; 
         end 
     end 
end 

//读寄存器 
always @ (address or read or clock_divide_reg or duty_cycle_reg or control_reg or chipselect) 
begin 
    if(read & chipselect) 
         case(address) 
             2'b00:readdata<=clock_divide_reg; 
             2'b01:readdata<=duty_cycle_reg; 
             2'b10:readdata<=control_reg; 
            default:readdata<=32'hFFFFFFFF; 
         endcase  
end 
   
//控制寄存器 
assign pwm_enable=control_reg; 

 //PWM功能部分 
always @ (posedge clk or negedge reset_n) 
begin 
     if(reset_n==1'b0)  PWM_counter<=0; 
     else
     begin 
        if(pwm_enable) 
        begin 
            if(PWM_counter>=clock_divide_reg-1)  PWM_counter<=0; 
            else  PWM_counter<=PWM_counter+1; 
        end 
        else
             PWM_counter<=0; 
     end 
end       

always @ (posedge clk or negedge reset_n) 
begin 
     if(reset_n==1'b0)  PWM_out<=1'b0; 
     else
     begin 
         if(pwm_enable) 
         begin 
             if(PWM_counter<=duty_cycle_reg-1)   PWM_out<=1'b1; 
             else   PWM_out<=1'b0; 
         end 
         else PWM_out<=1'b0; 
     end 
end 
endmodule

硬件测试程序

module PWM_tb;
reg  clk,reset_n,chipselect;
reg[1:0]   address;
reg        write;
reg[31:0]  writedata;
wire[31:0] readdata;
reg        read;
reg[3:0]   byteenable;
wire       PWM_out;

initial
begin
  clk=0;reset_n=0;chipselect=0;byteenable=1;
  #100 reset_n=1;  
 
  #20  chipselect=1;   //写clock_divide_reg寄存器为10
       address=0;
       writedata=10;
  #20  write=1;
  #20     chipselect=0;
      
  #20  chipselect=1;   //写duty_cycle_reg寄存器为5
       address=1;
       writedata=5;
  #20  write=1;
  #20     chipselect=0;
      
  #20  chipselect=1;   //写control_reg寄存器为1,使能PWM输出
       address=2;
       writedata=1;
  #20  write=1;
  #20     chipselect=0;
          address=3;   //是的寄存器使能全为0
 
 
  #500
  #20  chipselect=1;   //写control_reg寄存器为0,禁止PWM输出,清零PWM寄存器
       address=2;
       writedata=0;
  #20  write=0;
  #20     chipselect=0;
      
  #20  chipselect=1;   //写duty_cycle_reg寄存器为3
       address=1;
       writedata=3;
  #20  write=1;
  #20     chipselect=0;
 
  #20  chipselect=1;   //写control_reg寄存器为1,使能PWM输出
       address=2;
       writedata=1;
  #20  write=1;
  #20  chipselect=0;
     

end

always #10 clk=!clk;  
 
PWM  exam1(
          .clk(clk),
          .reset_n(reset_n),
          .chipselect(chipselect),
          .address(address),
          .write(write),
          .writedata(writedata),
          .read(read),
          .byteenable(byteenable),
          .readdata(readdata),
          .PWM_out(PWM_out)
          ); 
endmodule

 

nios 程序测试:

程序1:

#include <stdio.h>
#include <unistd.h> 
#include "system.h" 
#include <io.h>


int main()
  
     int duty,divi;
     //将pwm指向PWM_0_BASE首地址 
     char x;
    
     IOWR(PWM_MY_BASE,0, 1000);   //divi
     IOWR(PWM_MY_BASE,1, 0);    //duty
     IOWR(PWM_MY_BASE,2, 1);    //enable
    
    
   //  pwm->divi = 1000; 
   //  pwm->duty = 0; 
    // pwm->enable = 1; 
    //通过不断的改变duty值来改变LED一个周期亮灯的时间长短 
   
     printf("请输入+或者-,来改变频率\n");
   
     while(1)
     {  
         divi=IORD(PWM_MY_BASE,0);
         duty=IORD(PWM_MY_BASE,1);
         x=getchar();
         if(x=='+')
         { 
          //   printf("占空比增加\n");
             if(duty < divi)  duty += 200; 
         } 
         else if(x=='-')
         { 
          //   printf("占空比减小\n");
             if(duty > 0)  duty -= 200; 
         } 
        
         IOWR(PWM_MY_BASE,1, duty);    //duty
         usleep(100000);       
     }
   
    return 0;   
}

程序2:

#include <unistd.h> 
#include "system.h" 
//根据寄存器的偏移量,我们定义一个结构体PWM 
typedef struct{ 
     volatile unsigned int divi; 
     volatile unsigned int duty; 
     volatile unsigned int enable; 
}PWM; 

int main() 

     int dir = 1; 
     //将pwm指向PWM_0_BASE首地址 
     PWM *pwm = (PWM *)PWM_MY_BASE; 
     pwm->divi = 1000; 
     pwm->duty = 0; 
     pwm->enable = 1; 
    //通过不断的改变duty值来改变LED一个周期亮灯的时间长短 
     while(1)
     { 
         if(dir > 0)
         { 
             if(pwm->duty < pwm->divi)  pwm->duty += 100; 
             else  dir = 0; 
         } 
         else
         { 
             if(pwm->duty > 0)  pwm->duty -= 100; 
             else  dir = 1; 
         } 
         usleep(100000); 
     } 
     return 0;    
}

  • 0
    点赞
  • 2
    收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值