一乐电子

 找回密码
 请使用微信账号登录和注册会员

QQ登录

只需一步,快速开始

微信扫码登录

手机号码,快捷登录

手机号码,快捷登录

搜索
查看: 8711|回复: 0

NIOS整体开发结构基础

[复制链接]
发表于 2009-1-2 21:19 | 显示全部楼层 |阅读模式
上个例子中,我们使用VHDL语言,根据FPGA管脚与数码管和按键管脚的连接,通过一系列的语句控制管脚电平的高低,从而让FPGA实现数码管显示功 能。可见,对于比较简单的功能实现,可以像这个例子中那样,直接控制最底层资源,甚至对每个管脚在每个时刻的电平输出了如指掌。       但是,如果设计稍显复杂,那么对底层细节的过多关注就会成为一种累赘。& v1 _1 W) t- r. L4 m1 H% i) }  A  [' e
       试想我们平时在电脑上编写C程序,比如在显示器上输出一行字,我们只用一句printf()即可完成,至于打印命令怎么传到显示芯片上,哪个芯片管脚怎么 变化,又怎么传到显示器上输出,诸如此类涉及底层硬件的问题,我们没必要关注太多。于是,我们把用printf()这类高级语言描述设计逻辑的工作称为软 件设计。显然,软件只是一种抽象的看不见摸不着的东西,它的结构接近于人类思维逻辑。无论软件再怎样构思精妙,只有在硬件上才能体现出实际效果。
2 X- @! m; p# g/ o, E+ x- u) ?       做计算机开发应用程序的时候,硬件是现成的,软硬件之间的桥梁早就由操作系统给你搭好了,我们只需专心完成软件的构思和设计就OK。& X, Y# C! a8 B: B2 x
       显而易见,软硬件的分工会给电子设计带来极大的方便,自然有人把这种分工方式引进FPGA设计领域,琢磨着怎么在小小的FPGA上也搞个软硬件协同设计,负责硬件设计的和负责软件的各司其职,最后pia一整合,效率倍增。
" w' E3 p9 W. j5 K       来看看nios是怎么做的。拿出DE2开发板,上面很多外设接口和与之连接的芯片,那是硬件,中间有一块大的CycloneII芯片,里面是空的,等着我 们编写程序下载到里面运行,前篇文章我们用最原始的方法写了个数码管控制器,这次我们换种方法,同样是数码管控制器,用软硬件协同设计来完成。( k+ Z, l9 u6 e1 w1 G2 }
       跟计算机对比,硬件我们有了,软件就用C语言来写,但是nios系统可没提供WinXP,也就是说软件和硬件之间的那座桥还得自己解决。
! A  o; N& w. m- r" Z& F* y7 Ohttp://hiphotos.baidu.com/nios4fun/pic/item/19558e2e5b1e40404fc226d8.jpg: @6 K) ?5 I& g. w% G5 y5 I, A
       看上图,这座桥分为3个层次:硬件控制层,设备驱动层,硬件抽象层(简称HAL)。既然是软硬件的过渡部分,那么这3层的设计需要对硬件和软件都有一定程度的了解,姑且称之为“软硬件混杂设计”吧。
5 K5 Q. _+ p  E& W1 k       每一层所要完成的任务,就是整合和简化硬件操作细节,整合,再整合,使其一目了然。
3 w8 T2 E- ?4 _http://hiphotos.baidu.com/nios4fun/pic/item/f8aec1598e50343a2934f077.jpg, X( y) z" T" v' j2 m7 t3 s3 e* |
       <1> 硬件控制层
5 `' z$ Z5 E3 J& M$ x- v       与硬件直接打交道的是硬件控制层。
. C6 |' ?: f& r& H& U$ @* i- k+ l6 }       上面提到,搭“桥”的目的是让软件设计人员可以完全忽略硬件操作细节,因此,我们希望所有的硬件细节都能在这层解决,并向设备驱动层提供整齐的“接口”。之前的例子可看作硬件控制器的雏形,但还缺少与设备驱动层的接口。
+ D; A# J/ J7 u( l2 I       何为“整齐”呢?比如说,设计数码管控制器,我想让它显示数字“5”,最好的方法是,我将数据“5”和表示“显示”的命令从设备驱动层传给硬件控制层,直 接告诉它:我要“数码管”“显示”“5”。至于要控制哪个管脚电平高低才能显示“5”,全由硬件控制层负责。
( w. S* }/ o# M3 ~5 O/ }# B       类似这样分工合作的例子在日常生活中屡见不鲜。比如说,邮局要将一封信送给家住A小区的张三,邮递员把信放入A小区的信箱,小区物业再去确认张三的具体住处,把信最终送到张三手中。
' H3 f! I+ t9 ^8 W       类比可见,邮局相当于设备驱动,物业相当于硬件管理器,张三则是具体的硬件,邮局和物业之间的接口是物业提供的信箱,设备驱动和硬件管理层之间的接口,我们称之为“寄存器”,同样由硬件管理层提供,“寄存器”是两层之间得以明确分工和相互联系的关键。" \( T1 `  ]: |$ M; Q& Z" @& K" A  `  v
       设备驱动开发人员眼中的硬件就是一组寄存器的抽象,通过读写寄存器间接控制硬件行为。- j. x2 p" G0 R# A) l4 v) |
        那么,在数码管控制器里加入一个数据寄存器和一个命令寄存器:
2 A, @7 ?0 s( T) Ihttp://hiphotos.baidu.com/nios4fun/pic/item/5468f5e7d6e2f43eb93820ad.jpg) R- d0 m7 X+ v2 B
       data_reg存储待显示的数据,cmd_reg为‘1’时显示,为‘0’时清空。- M, L& O: x0 Z6 E# n& W7 e4 P
http://hiphotos.baidu.com/nios4fun/pic/item/86682b13e911b9c0f7039ea8.jpg4 u3 W- @+ Q; G9 o7 k
       <2> Avalon总线
3 }" |, L3 j; y8 f3 i- E$ V$ @       你可能会说,这有什么?在每个硬件管理器和设备驱动之间都建立一个通道呗。这是最直接的办法,但显然不是最好的办法。试想,城市为什么要建高速公路呢?多 修几十根羊肠小道不也一样能跑车吗?有人回答:为了收养路费呗。$%@&&! 小路上开车,速度慢且不说,管理协调是个大问题,是一条大公路容易管理,还是几十根羊肠容易理顺?0 F) f: h. i3 n0 [- i
       好了,回到正题,nios系统需要一条“高速公路”,称为“总线”,“总线仲裁器”则行使“交通管理局”的角色,控制数据的进出,并为每个硬件提供一个进 出“高速公路”的接口,用“地址”来标识这个接口的位置。nios采用的是Avalon总线,它有着一套接口规范:1 q; N6 U* Z) |" C4 M( T9 z
       同步时钟 clk& L( S9 ?, I' F
       片选信号 chipselect
$ [4 l  E( [; \# X/ u! R       地址 address5 ^. Z0 Z/ w- A
       读请求 read
0 y% T* D, b# G0 c- K( I       读传输 readdata8 n2 z0 X* Q) J* W) U" i" h# D# C
       写请求 write
% w% z9 ~" _7 U9 H# ^+ H) i& ]       写传输 writedata
+ Z9 I- p4 \. t9 y: E- R6 |
       这些是比较重要的接口信号,其它的不一一列举了。硬件控制器要接入总线,必须遵循接口规范,就像高速公路出口必须摆个收费站一样。
( i1 n! Y. M7 d9 a' N+ G1 N* k; nhttp://hiphotos.baidu.com/nios4fun/pic/item/237090ad1967ad194a36d67a.jpg
1 N- _6 ~! m$ J) \2 I       那么在在数码管控制器里加入Avalon总线信号:% @& }2 ^. T, ~, ^
http://hiphotos.baidu.com/nios4fun/pic/item/918dca635061b0700c33fabf.jpg' ^$ t- a3 z8 v9 c- D: r
       既然加入了两个寄存器和avalon信号,就需要对硬件逻辑进行必要改动,大致过程是,当chipselect和write有效时,将 write_data赋给address对应的寄存器;当chipselect和write有效时,将address对应寄存器的值赋给 read_data。另外,根据这两个寄存器的内容决定数码管输出信号oSEG0。代码不贴出来了,具体见工程压缩包。, B3 f) h; E+ D& h/ x: _. [
       <3> 设备驱动程序) w# s7 F4 L3 u4 p; Z( }/ ?
       其实,“总线仲裁器”也可看作一种硬件控制器,只不过它管的不是具体的硬件,而是负责数据的传输。那么它也有自己的设备驱动,封装了总线操作的细节。既然总线是现成的,我们秉承“拿来主义”的原则,甭管它怎么实现的,会用就行。
3 N) m9 `# J! Q' t       例如,数码管设备驱动要把数据“5”和“显示”命令传给数码管控制器,设计两个函数,由于数据和命令的传递必须经过总线,那么需调用总线驱动函数IOWR(基地址, 偏移量, 数据),另外,读取寄存器用到IORD(基地址, 偏移量),这两个函数在<io.h>里。) h$ U  f" H/ x: C
       <io.h>的路径是"..\altera\kits\nios2_60\components\altera_nios2\HAL\inc"。
/ d* _/ `, {' \0 q$ n$ |! Z       至此,“桥”搭完。
$ {; O; V, `8 f1 t
+ M8 _) `# u; ^% V) t9 c: b1 fhttp://hiphotos.baidu.com/nios4fun/pic/item/82ea7cc466f15adb39db49a4.jpg8 Y' H- k- d3 X6 a
       函数功能从字面上很好理解。刚才定义两个寄存器时,data_reg在前面,所以偏移量是0,cmd_reg在后面,偏移量是1。××_REG_MSK称 为掩码,avalon总线数据接口共32位,但我们设计的data_reg位宽是3,cmd_reg位宽为1,掩码的作用在于告知寄存器宽度,知道就行, 实际上用不着。××_REG_OFST是寄存器内的偏移量,这里同样用不着,先写上吧。; _6 h0 o6 e* R5 y" X
       OK,我们的数码管设备驱动文件正式出炉了,看看是不是简洁明了很多啊?0 [/ V4 j3 A. \3 S' D& G9 w$ q6 |
       <4> 硬件抽象层(HAL)
' h+ L/ |3 N' ]4 Z8 {: B0 Y: Q0 X       设备驱动程序封装的仅仅是对某个寄存器的一次读写操作,功能单一,需要在硬件抽象层再做一次封装。
' h3 X( l) S0 k6 z9 D      直接将这些函数列出来,一目了然,不作多余的解释了。3 \! M3 ]! I9 m3 v/ Q
http://hiphotos.baidu.com/nios4fun/pic/item/9d953213752d11906538db8d.jpg: B/ h- R2 E1 W/ `5 [. N+ }
       至此,“桥”搭完。! i; _9 g/ s) S, ?* c
       接下来在把我们的“数码管控制器”加入sopc builder系统中。4 n$ j! a1 Z, L9 m! B, x3 A
       现在几乎所有讲nios的书都会提及自定义用户外设,而且用的都是altera官方提供的例子PWM,本文的“数码管控制器”就是照着它依葫芦画瓢改过来 的,呵呵,惭愧惭愧,之所以想改它,一是因为它用的是verilog而不是VHDL,而大多数人先接触却是VHDL;二来PWM的显示效果似乎不太明显, 改成数码管显示相对比较有成就感;第三,PWM的逻辑稍微有一点点复杂,我们的重点在于说明怎样自定义外设,当然例子越简单越好。
; w' u7 b% v& p# Z( m       既然是照着PWM原样改的,所以本文工程的结构与之保持高度一致,将其加入sopc builder的步骤也差不多,这里我就不再码字了,各位照着书上做吧:
8 \1 {2 ]4 c! t* S$ o      《SOPC嵌入式系统基础教程(周立功等著)》第8章……
, S0 r. Z5 F3 K       再接下来,建立一个包含“数码管控制器”的nios系统,并编写应用程序,实现从0到9计数。
# M( s3 p# |/ \6 d. B, k( i1 [       贴张官方的nios设计流程图,看起来很漂亮是吧,不愧是altera的东西,大而全而不乱。
* O7 ~  f8 e; v! xhttp://hiphotos.baidu.com/nios4fun/pic/item/dd9b1f09cfbe2a346a60fb17.jpg
* r( }5 [! e& ]# B! Q       先说最中间的"SOPC Builder",它的任务是建立一个“以Nios CPU为核心,以Avalon总线为纽带,将各种硬件设备连接起来”的nios系统;这个系统要在FPGA中运行,所以必须挂靠一个Quartus II工程,用左边的Quartus II进行分配引脚等等工作,生成硬件系统;接着,右边的Nios II IDE就可以在这个硬件系统上设计应用程序了;最后将硬件系统和软件程序分别下载到FPGA芯片上,大功告成。6 R" M$ Q* V( U2 @7 r
       下面step by step
% m7 a  s% P' S       <1> Quartus II 新建一个工程名,工程名"DE2_SEG7"。
, W$ g0 D& \8 J1 b* {$ j       <2> "Tool" → "SOPC Builder" 打开SOPC Builder。
5 \; {- [* z: f       <3> "System Name": nios2_system   选VHDL。
( I9 [6 {0 {' q. d1 k       一个包含“数码管控制器”的最小系统至少由3部分组成:CPU必不可少,RAM存储代码,还有刚才设计的"seg7_avalon"。
% i. g# k( h) s( M2 m6 H       <4> 加入"Nios II Processor",选"Nios II/e",精简型够用了。+ @: X/ j, K8 s
       <5> 加入"On-Chip Memory",类型选"RAM",位宽默认"32 bits","Total Memory"选"48Kbytes",等会儿软件要占用四十多K空间。
- F1 j& b6 T3 `, u3 o1 K+ W       <6> 加入"seg7_avalon"。- C5 ?0 w/ Y: e6 c; g; ?% d2 P5 ^
       <7> 将这三个组件的名称改好看点,然后设定RAM的基地址为"0x00000000",再右键锁定基地址,如图:
4 K; [0 I9 X$ t' j: c3 |% thttp://hiphotos.baidu.com/nios4fun/pic/item/fabd170083ebe797e950cdca.jpg
3 F- c# p9 z' M- Y! |6 `, G! ~) H       为什么要锁定RAM的基地址为0呢?点选第二个选项卡,可以看到"Reset Address"对应着RAM,系统的复位肯定要从地址0开始。+ ?0 _* P, ], W1 u8 a
http://hiphotos.baidu.com/nios4fun/pic/item/26a77c54561c4f48d1090683.jpg! g3 @( z$ e# H9 k5 W, ^% J: j- h* x
       <8> 由于刚才人为改动了地址分配,弄乱了,让系统自动再分配一次,当然被锁定的RAM基地址是不会变的。"System" →"Auto-Assign Base Addresses"。最终系统组件列表如下:
$ P. r! j! C9 j2 S5 I% U* _( c( Xhttp://hiphotos.baidu.com/nios4fun/pic/item/8b46dc1ee27ad3e41bd57692.jpg# D! B9 |; Y3 E4 u
       注意,seg7的地址范围是"0x00010800"→"0x00010807",占8个地址,nios系统的地址按字节分配,也就是说,每个字节占用一 个地址,数码管控制器中定义了两个寄存器,avalon总线规定每个寄存器占32位(实际上是不是32位它就不管了,反正按最大32位分配),这样两个寄 存器共占去8个字节,自然需要8个地址。( V- ^- ^8 l4 v2 |! t
       <9> 点击"Generate"生成nios系统,回到Quartus II。
4 K/ n+ Y' q. B+ J# F       <10> 新建一个顶层文件"File"→"New"→"Block Diagram/Schematic File",引入nios II系统,增加输入输出引脚。然后,"Assignment"→"Import Assignment",添加引脚分配文件(在DE2光盘目录下的\DE2_tutorials\design_files\ DE2_pin_assignments.csv),改动顶层文件的引脚名称使其与.csv文件中保持一致。- `  v) Z. I; E6 ?
http://hiphotos.baidu.com/nios4fun/pic/item/766a9c6dc7786feb4216947d.jpg5 }2 Y8 d0 u; F
       <11> 编译,查看编译报告,可见,48K的RAM占用了芯片83%的memory bits,差不多耗光了。
2 m( U( S4 P8 o2 O7 Q4 hhttp://hiphotos.baidu.com/nios4fun/pic/item/f6b7699599d4705bd0135e48.jpg+ K. J" ~. ]. W- P# b, T
       <12> 硬件部分已经搞定,关掉Quartus II,打开Nios II IDE,切换到工作目录下。9 ^$ J. }1 k4 H8 s4 l8 x- F
       <13> "File"→"New"→"C/C++ Application","SOPC Builder System"选择"nios2_system.ptf"(就是刚才Generate Nios II系统生成的东东),再选模板"Hello World"(纯属偷懒http://img.baidu.com/hi/face/i_f01.gif),顶上的"name"改成"seg_example","Finish"。' r" k- `0 ]/ l$ X; ]3 j
       <14> 改动hello_world.c,代码的功能为:先初始化数码管,等待2秒钟,再进行0-9的循环,循环过程中穿插2秒钟的清屏。SEG7_BASE的宏 定义在system.h中,实际上就是在SOPC Builder中的seg7_avalon的基地址0x00010800。
) w9 ^  Y+ s1 a. Hhttp://hiphotos.baidu.com/nios4fun/pic/item/ec4a62fdd5bc4f55d7887d30.jpg/ J' O- r( B! d" k4 J4 H# O- F' G$ t2 }# d
       <15> "Project"→"Build Project",得到编译报告,软件占用了7K空间……6 o% S0 h; H5 ?- z* s. K; @$ U. I7 f
http://hiphotos.baidu.com/nios4fun/pic/item/ec4a62fdd4034c55d6887df1.jpg. k3 ~! s4 U% w; F7 C) X( D' U# O
       <16> 下载到DE2板上,运行,数码管不停地闪啊闪。$ s% m  S9 K# L$ H. ?! h
       OK,从硬件到软件的一条龙讲完了。

本版积分规则

QQ|一淘宝店|手机版|商店|一乐电子 ( 粤ICP备09076165号 ) 公安备案粤公网安备 44522102000183号

GMT+8, 2025-10-28 06:20 , Processed in 0.029389 second(s), 18 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表