简介

NIOS II是一个建立在FPGA上的嵌入式软核处理器,除了可以根据需要任意添加已经提供的外设外,用户还可以通过定制用户逻辑外设和定制用户指令来实现各种应用要求。这节我们就来研究如何定制基于Avalon总线的用户外设。

SOPC Builder提供了一个元件编辑器,通过这个元件编辑器我们就可以将我们自己写的逻辑封装成一个SOPC Builder元件了。下面,我们就以PWM实验为例,详细介绍一下定制基于Avalon总线的用户外设的过程。

我们要将的PWM是基于Avalon总线中的Avalon Memory Mapped Interface (Avalon-MM),而Avalon总线还有其他类型的设备,比如Avalon Streaming Interface (Avalon-ST)、Avalon Memory Mapped Tristate Interface等等,在这里我就不详细叙述了,需要进一步了解的请参考ALTERA公司的《Avalon Interface Specifications》(mnl_avalon_spec.pdf)。

Avalon-MM接口是内存映射系统下的用于主从设备之间的读写的接口,下图就是一个基于Avalon-MM的主从设备系统。而我们这节需要做的就是下图高亮部分。他的地位与UART,RAM Controller等模块并驾齐驱的。

Avalon-MM接口有很多特点,其中最大的特点就是根据自己的需求自由选择信号线,不过里面还是有一些要求的。建议大家在看本文之前,先看一遍《Avalon Interface Specifications》,这样就能对Avalon-MM接口有一个整体的了解。

下图为Avalon-MM外设的一个结构图,

理论的就说这些,下面我们举例来具体说明,让大家可以更好的理解。

构建HDL

我们这一节是PWM为例,所以首先,我们要构建一个符合Avalon-MM Slave接口规范的可以实现PWM功能的时序逻辑,在这里,我们利用Verilog语言来编写。在程序中会涉及到Avalon信号,在这里,我们说明一下这些信号(其中,方向以从设备为基准)

HDL中的信号 

Avalon信号类型 

宽度 

方向 

描述 

clk

clk

1

input

同步时钟信号

reset_n

reset_n

1

input

复位信号,低电平有效

chipselect

chipselect

1

input

片选信号

address

address

2

input

2位地址,译码后确定寄存器offset

write

write

1

input

写使能信号

writedata

writedata

32

input

32位写数据值

read

read

1

input

读时能信号

byteenable

byteenable

1

input

字节使能信号

readdata

readdata

32

output

32位读数据值

此外,程序中还包括一个PWM_out信号,这个信号是PWM输出,不属于Avalon接口信号。

PWM内部还包括使能控制寄存器、周期设定寄存器以及占空比设置寄存器。设计中将各寄存器映射成Avalon Slave端口地址空间内一个单独的偏移地址。没个寄存器都可以进行读写访问,软件可以读回寄存器中的当前值。寄存器及偏移地址如下:

寄存器名 

偏移量 

访问属性 

描述 

clock_divide_reg

00

读/写

设定PWM输出周期的时钟数

duty_cycle_reg

01

读/写

设定一个周期内PWM输出低电平的始终个数

control_reg

10

读/写

使能和关闭PWM输出,为1时使能PWM输出

程序如下:

001 module PWM(
002     clk,
003     reset_n,
004     chipselect,
005     address,
006     write,
007     writedata,
008     read,
009     byteenable,
010     readdata,
011     PWM_out);
012   
013 input clk;
014 input reset_n;
015 input chipselect;
016 input [1:0]address;
017 input write;
018 input [31:0] writedata;
019 input read;
020 input [3:0] byteenable;
021 output [31:0] readdata;
022 output PWM_out;
023   
024 reg [31:0] clock_divide_reg; 
025 reg [31:0] duty_cycle_reg; 
026 reg control_reg;
027 reg clock_divide_reg_selected;
028 reg duty_cycle_reg_selected;
029 reg control_reg_selected;
030 reg [31:0] PWM_counter;
031 reg [31:0] readdata;
032 reg PWM_out;
033 wire pwm_enable;
034   
035 //地址译码
036 always @ (address)
037 begin
038     clock_divide_reg_selected<=0;
039     duty_cycle_reg_selected<=0;
040     control_reg_selected<=0;
041     case(address)
042         2'b00:clock_divide_reg_selected<=1;
043         2'b01:duty_cycle_reg_selected<=1;
044         2'b10:control_reg_selected<=1;
045         default:
046         begin
047             clock_divide_reg_selected<=0;
048             duty_cycle_reg_selected<=0;
049             control_reg_selected<=0;
050         end
051     endcase
052 end           
053   
054 //写PWM输出周期的时钟数寄存器
055 always @ (posedge clk or negedge reset_n)
056 begin
057     if(reset_n==1'b0)
058         clock_divide_reg=0;
059     else
060     begin
061         if(write & chipselect & clock_divide_reg_selected)
062         begin
063             if(byteenable[0])
064                 clock_divide_reg[7:0]=writedata[7:0];
065             if(byteenable[1])
066                 clock_divide_reg[15:8]=writedata[15:8];
067             if(byteenable[2])
068                 clock_divide_reg[23:16]=writedata[23:16];
069             if(byteenable[3])
070                 clock_divide_reg[31:24]=writedata[31:24];
071         end
072     end
073 end
074   
075 //写PWM周期占空比寄存器
076 always @ (posedge clk or negedge reset_n)
077 begin
078     if(reset_n==1'b0)
079         duty_cycle_reg=0;
080     else
081     begin
082         if(write & chipselect & duty_cycle_reg_selected)
083         begin
084             if(byteenable[0])
085                 duty_cycle_reg[7:0]=writedata[7:0];
086             if(byteenable[1])
087                 duty_cycle_reg[15:8]=writedata[15:8];
088             if(byteenable[2])
089                 duty_cycle_reg[23:16]=writedata[23:16];
090             if(byteenable[3])
091                 duty_cycle_reg[31:24]=writedata[31:24];
092         end
093     end
094 end
095   
096 //写控制寄存器
097 always @ (posedge clk or negedge reset_n)
098 begin
099     if(reset_n==1'b0)
100         control_reg=0;
101     else
102     begin
103         if(write & chipselect & control_reg_selected)
104         begin
105             if(byteenable[0])
106                 control_reg=writedata[0];
107         end
108     end
109 end
110   
111 //读寄存器
112 always @ (address or read or clock_divide_reg or duty_cycle_reg or control_reg or chipselect)
113 begin
114     if(read & chipselect)
115         case(address)
116             2'b00:readdata<=clock_divide_reg;
117             2'b01:readdata<=duty_cycle_reg;
118             2'b10:readdata<=control_reg;
119             default:readdata=32'h8888;
120         endcase 
121 end
122   
123 //控制寄存器
124 assign pwm_enable=control_reg;
125   
126 //PWM功能部分
127 always @ (posedge clk or negedge reset_n)
128 begin
129     if(reset_n==1'b0)
130         PWM_counter=0;
131     else
132     begin
133         if(pwm_enable)
134         begin
135             if(PWM_counter>=clock_divide_reg)
136                 PWM_counter<=0;
137             else
138                 PWM_counter<=PWM_counter+1;
139         end
140         else
141             PWM_counter<=0;
142     end
143 end      
144   
145 always @ (posedge clk or negedge reset_n)
146 begin
147     if(reset_n==1'b0)
148         PWM_out<=1'b0;
149     else
150     begin
151         if(pwm_enable)
152         begin
153             if(PWM_counter<=duty_cycle_reg)
154                 PWM_out<=1'b1;
155             else
156                 PWM_out<=1'b0;
157         end
158         else
159             PWM_out<=1'b0;
160     end
161 end
162   
163 endmodule

上面的程序保存好以后,命名为PWM.v,并将其存放到工程目录下。

硬件设置

接下来,我们就通过SOPC Builder,来建立PWM模块了。首先,打开Quartus软件,进入SOPC Builder。进入后,点击下图红圈处

点击后,如下图所示,点击Next,

点击后,如下图所示,点击下图红圈处,将我们刚才建立的PWM.v加进来。(我将PWM。v放到了工程目录下的pwm文件夹下)

加入后,系统会对PWM.v文件进行分析,如下图所示,出现红圈处的文字,说明分析成功,点击close,关闭对话框。

然后点击Next,如下图所示,通过下图,我们可以看到,PWM.v中的信号都出现在这里面了。我们可以根据我们的功能要求来配置这些信号,其中,Interface是Avalon接口类型 ,它包括Avalon-MM、Avalon-ST、Avalon Memory Mapped Tristate Interface等等。Signal Type指的是各个Avalon接口类型下的信号类型。PWM.v中的信号我们已经在前面都介绍过了,大家按照上面的要求设置就可以了。默认情况只有PWM_out需要改动,如下图示红圈处设置,

其中,Interface在下拉菜单中选择下图红圈处所示的选项。

上面的选项都设置好以后,点击Next,如下图所示,我们通过下图红圈处的下拉条向下拉

拉到下图所示位置停止,我们将红圈处的改选为NATIVE,这个地方就是地址对齐的选项,我们选择为静态地址对齐。其他的地方都默认,不需要改动。

这里面还有很多选项,其中Timing部分需要说明一下,PWM的Avalon Slave端口与Avalon Slave端口时钟信号同步,读/写时的建立很保持时间为0,因为读、写寄存器仅需要一个时钟周期,所以读/写时为0等待切不需要读延时。

接着点击Next,如下图所示,其中红圈处需要注意,这个地方需要可以建立新组,然后在SOPC Builder中体现出来。

点击Finish后,会出现下面的对话框,点击Yes,就会生成一个PWM_hw.tcl脚本文件,大家可以打开看一下,里面放置的是刚才我们配置PWM时候的配置信息。

上面都完成以后,我们回到了SOPC Builder界面,我们在左侧边栏中可以找到下图所示的红圈处

大家看到了吧,MyIP就是我们刚才建立的group。双击PWM,我们建立PWM模块,如下图

点击Finish,完成建立。

这里还需要设置一步,点击下图红圈处

点击后,如下图所示,点击IP Serarch Path,然后点击Add,添加PWM.v所在位置的路径

添加后,如下图所示

点击Finish完成。设置这个选项是为了让SOPC Builder可以找到PWM.v的位置。不然就会出现下次你进入SOPC Builder的时候PWM模块无效的问题。

接下来的工作就是自动分配地址,分配中断,编译,等待......

编译好以后,我们回到Quartus软件界面,我们可以看到,PWM出现了,我将它接到了一个LED上了,我们可以通过PWM改变LED的亮度,实现LED渐亮渐灭的过程。

接下来又是编译,等待.....

做好硬件部分工作以后,我们打开NIOS IDE,开始软件编程部分。

软件开发

首先对工程重新编译一次,Ctril+B,等待......

编译好以后,我们来看一下system.h的变化情况,我们可以发现,多出来PWM部分了。

下面是PWM测试代码,

01 #include <unistd.h>
02 #include "system.h"
03   
04 //根据寄存器的偏移量,我们定义一个结构体PWM
05 typedef struct{
06     volatile unsigned int divi;
07     volatile unsigned int duty;
08     volatile unsigned int enable;
09 }PWM;
10   
11 int main()
12 {
13 int dir = 1;
14   
15     //将pwm指向PWM_0_BASE首地址
16 PWM *pwm = (PWM *)PWM_0_BASE;
17 //对pwm进行初始化,divi最大值为232-1。
18     pwm->divi = 1000;
19     pwm->duty = 0;
20     pwm->enable = 1;
21    
22     //通过不断的改变duty值来改变LED一个周期亮灯的时间长短
23     while(1){
24         if(dir > 0){
25             if(pwm->duty < pwm->divi)
26                 pwm->duty += 100;
27             else
28                 dir = 0;
29         }
30         else{
31             if(pwm->duty > 0)
32                 pwm->duty -= 100;
33             else
34                 dir = 1;
35         }
36           
37         usleep(100000);
38     }
39       
40     return 0;   
41 }

niosII的那些事--基于AVALON总线的IP核定制相关推荐

  1. 基于AVALON总线的IP核定制 PWM

    简介 NIOS II是一个建立在FPGA上的嵌入式软核处理器,除了可以根据需要任意添加已经提供的外设外,用户还可以通过定制用户逻辑外设和定制用户指令来实现各种应用要求.这节我们就来研究如何定制基于Av ...

  2. 【FPGA黑金开发板】NIOSII那些事儿--基于AVALON总线的IP定制(十七)

    声明:本文为转载作品,版权归本博文作者所有,如需转载,请注明出处http://www.cnblogs.com/kingst/ 简介 NIOS II是一个建立在FPGA上的嵌入式软核处理器,除了可以根据 ...

  3. 开发自定义AXI总线外设IP核——以LED和开关为例

    http://www.eefocus.com/nightseas/blog/12-10/287343_15762.html ZedBoard学习手记(二) 开发自定义AXI总线外设IP核--以LED和 ...

  4. 如何基于Avalon总线完成QSYS IP定制

    文章目录 0. 为什么要定制QSYS IP 1. 规划IP的硬件功能 2. 定义恰当的Avalon接口 3. RTL设计 4. 使用IP编辑器封装IP 5. 编写用于描述寄存器的C头文件和IP驱动文件 ...

  5. 基于vivado的fir ip核的重采样设计与实现

    创建vivado工程 1. 首先打开vivado,创建一个新的project(勾选create project subdirectory选项),并将工程命填为firfilter. 2.选择工程创建的类 ...

  6. 基于ISE的QDR IP核调用与硬件自检

    平台:ISE(IP核用法同VIVADO) 语言:VHDL(Verilog用法类似) FPGA型号:V6-315T,ffg1156-1 QDR型号:GS8342D08GE-300I(类似) XILINX ...

  7. Avalon总线概述

    Nios系统的所有外设都是通过Avalon总线与Nios CPU相接的,Avalon总线是一种协议较为简单的片内总线,Nios通过Avalon总线与外界进行数据交换. Avalon总线接口分类 可分为 ...

  8. Avalon总线(一)Avalon-MM Signals

    最近在学习及改写dma模块,是基于Avalon总线的.正在结合手册<Avalon Interface Specifications>与相关代码进行深入了解.当然,各个信号顺序都是按照某位大 ...

  9. Avalon 总线 时序 介绍

    Avalon 总线广泛应用于外设和软核或者硬核交互,其时序简单明了,也非常适合用来作为划分模块的接口信号.本文结合quartus 关于 avalon 总线英文原版做简单介绍,重点理解时序即可. 1.A ...

最新文章

  1. is_uploaded_file
  2. iOS 开发 OpenGL 新手入门
  3. PHP中file_exists与is_file、is_dir的区别,以及执行效率的比较
  4. #!/bin/sh与#!/bin/bash的区别
  5. English trip M1 - PC9 Where am I Teacher:Jade
  6. mac 上brew加速
  7. 在Flash中接收来自页面(.NET)的值的方法.
  8. Ubuntu下vsftp安装和配置
  9. Windows必备软件效率有哪些?
  10. html能在hade中注释吗,A第1章 HTML超文本标记语言(1-20)OK.doc
  11. Spring boot 2.x+oauth2实现单点登录:基础准备之Spring Security
  12. Java基础项目 开发团队分配管理系统
  13. 面试官:谈谈对JS闭包的理解及常见应用场景(闭包的作用)
  14. [Unity]动态人物头像
  15. python定义匿名函数关键字_Python匿名函数
  16. Linux Ubuntu 22.04安装Dash to Panel替换系统自带的dock panel
  17. Cloud Native 与12-Factor
  18. SUSE安全大揭秘之“十诫”
  19. 文件排序工具sort
  20. 货币供给过程的理解_1.美联储的资产和负债

热门文章

  1. 分布式机器学习:同步并行SGD算法的实现与复杂度分析
  2. 达人评测i5 1240p 和 i7 1165g7选哪个好
  3. TestCaseManageSystem 自动化解决方案 [开源项目] 基于 AgileTC 的测试用例自动化框架完美版
  4. 2022年拼接显示屏市场前景分析及研究报告
  5. 在GitHub上搭建typora的图床
  6. 自定义一级提示符PS1,个性化显示终端
  7. 河海大学计算机科学培养方案,计算机科学与技术专业本科培养方案-河海大学计算机与信息学院.PDF...
  8. js事件重复绑定问题
  9. 调用移动云OCR识别身份证
  10. Fashion-Gen: The Generative Fashion Dataset and Challenge 论文解读数据集介绍