打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
基于DE2 与Nios II的音频录放系统的设计

目录

目录1

写在前面的话1

初识DE2开发板2

DE2的资源2

DE2的使用2

关于DE2资料光盘的使用3

程序下载方3

关于管脚分配3

认识Nios II 系统4

Avalon总线5

利用SPOC  Builder 创建 Nios II 系统6

SPOC Builder 生成的文件12

基于Nios系统的顶层结构图14

Avalon总线创建自定义组件15

Nios IDE C语言编写程序17

技术总结20

 

——DE2 Board NIOS II 系统篇

写在前面的话

         经过一周的艰苦奋战,我们的语音录放系统终于摆脱了只用FPGA实现的困境,终于上了核!真正的构建了一个基于NiosII的嵌入式软硬件开发环境。

         最开始的时候,通过对例程里面的i2soundWM8731芯片资料的学习,我们完成了“语音录放系统V1.0”,主要内容是通过I2C电路将WM8731配置到特定的模式,然后按照一定的时须将WM8731ADC输出信号存储起来,必要的时候再从存储器中读取数字信号到WM8731DAC输出,这样就完成了录音放音的基本功能。

但是诺大一个CycloneII 2C35加上DE2配置的超豪华外设,仅仅用来做这个事情显然有点大材小用,而且不便于扩展功能,这就引出了本文要说的内容。

初识DE2开发板

       DE2的资源

 

         DE2的资源非常丰富,包括

1. 核心的FPGA芯片-Cyclone II 2C35 F672C6,从名称可以看出,它包含有35千个LE,在Altera的芯片系列中,不算最多,但也绝对够用。Altera下载控制芯片- EPCS16以及USB-BlasteJtag的支持。

2.存储用的芯片有: 512-KB SRAM8-Mbyte SDRAM4-Mbyte Flash memory

3. 经典IO配置:拥有4个按钮,18个拨动开关,18个红色发光二极管,9个绿色发光二极管,8个七段数码管,16*2字符液晶显示屏,

4. 超强多媒体:24CD音质音频芯片WM8731(Mic输入+LineIn+ 标准音频输出),视频解码芯片(支持NTSC/PAL制式),带有高速DAC视屏输出VGA模块。

5.更多标准接口:通用串行总线USB控制模块以及AB型接口,SD Card接口,IrDA红外模块, 10/100M自适应以太网络适配器,RS-232标准串口, PS/2键盘接口

6.其他:50M27M晶振各一个,支持外部时钟, 80针带保护电路的外接IO

         7.此外还有:配套的光盘资料,QutuarsII6软件,NiosII 6.0IDE,例程与说明文档。

DE2的使用        

         关于DE2资料光盘的使用

主要的可以参看他的用户手册,里面有关于DE2的资料的详细使用说明,板子的电路原理图,模块图,管脚图,和各个模块的Datasheet等等。

可以这样来看:

DE2_System

\Datasheet                  DE2板子上的各个模块的详细的官方Datasheet,来自各个芯片厂商。

\DE2_demonstrations   丰富的例程,里面很多适用的例子,比如SD_Music_Player.

\DE2_lab_exercises     DE2提供的试验内容,里面有很详细的操作步骤截图。

\DE2_schematics        DE2板子资料,包括布线,电路板的资料

\DE2_tutorials           例如详细的讲解SOPC Builder的使用。

\DE2_user_manual    用户使用指南与手册.综合的说明。

\Altera_Debug_Client   DE2的调试工具,可以直接下载Nios处理器的汇编代码,C语言代码等。

\DE2_control_panel      DE2控制面板,直接操作DE2板子上的各个模块的工作状态。

程序下载方法

         第一种成为RUN模式,需要将板上RUN/PROG开关(LCD旁)拨到RUN,是用USB-Blaster直接将sof文件烧到 Cyclone FPGA芯片,这样掉电之后就没有了,重启后需要再次烧写。

         第二种模式为AS模式,将RUN/PROG开关拨到PROG模式,然后在Qutuars下载模式设置为AS模式,选择pof文件下载,这样直接下载到EPCS16 Configure芯片中,每次复位,会根据EPCS16里面的内容重新烧写Cyclone II芯片。

 

关于管脚分配

   当我们创建一个FPGA用户系统的时候,到最后要做的工作就是下载,在下载之前必须根据芯片的型号分配管脚,这样才能将程序中特定功能的管脚与实际中的FPGA片外硬件电路一一对应。

         通常的管脚分配使用的是拖拽法,然而在一个庞大的系统中,这样是非常的不现实,可以使用CSV文件分配法,方法是在Qurtus IIAssignment菜单下面的Import Assignment项中,定位到要分配的管脚文件即可(对于做Nios核必的通用管脚分配,可以参照de2_system\DE2_lab_exercises\DE2_pin_assignments.csv文件),这里有个前提,就是你的顶层文件管脚命名必须与CSV文件中管脚一致。所以顶层文件如果用Verilog来写的话那将更加的方便,当然这是对于对于做Nios核而言的,你可以直接从Demo中拷贝一个顶层文件作为你的顶层。只要稍加修改即可,也可以定义自己的额外管教分配。

         分配管脚的有一个方法是,直接修改工程文件夹里面的“qsf”文件,将相应的端口与芯片的预设相连即可。例如:

 

 

认识Nios II 系统

    现在开始写一些关于Nios的东西,初次接触Nios II,只能写一些简单初级的东西,主要是个人对它的一点认识,希望能对今后新手学习提供一定的帮助。

 Nios II ,准确的说,是一个IP核,即知识产权核,使用特定的硬件描叙语言写成的一堆代码罢了,如果不将它烧到特定的FPGA或者CPLD芯片中是没有任何意义的。

AlteraNiosII软核,说白了就是一个CPU,内部像其他处理器一样,都包括指令解码,地址译码,指令队列,中断管理,总线时须控制,DMA控制等等。

NiosII还支持最多两套用户自定义指令集,者可以有用户自定义模块来实现。

一个Nios系统应该至少包括一个Nios CPU1个片上RAMOnchip-RAM),当然还可以添加其他厂商的IP Core和自定义用户逻辑。这些模块共同使用者一块包含有大量逻辑阵列的FPGA芯片,组成片上可编程系统,也称为SOPC System On Programmable Chip)。

 这个片上系统然后与外电路连接,构成一个具有特定功能的完整的用户系统。下面给出一个NiosII系统的典型模块图:

 

Avalon总线

在这里不得不提Avalon总线,Avalon总线是NiosII系统各模块之间的纽带,它内部复杂,但对外部却保留着相对简单的接口,没有复杂的总线应答等等,因此我们可以很方便的使用它来连接我们的自定义模块。

一个标准的用户逻辑与Avalon总线的接口并不需要包含所有的Avalon端口类型的接口,可以一般的有以下类型的信号中的部分:

 

比如你的用户逻辑中主要负责采集数据给总线,那么你充当的角色就是数据的提供者,你至少应该给Avalon总线readreaddataclk的接口,其中read为总线的读取请求信号,对用户模块为input, readdata信号为81632位数据,对用户模块而言为outputclk为总线为你提供的统一时钟信号,可以为读取你的设备提供时钟。当然总线提供的reset信号可以用作你的设备的初始化。

    同理如果你是输出模块,从总线上面接收数据,那么你应该向Avalon总线提供writewritedataclk的接口,如果你的模块即是输入又是输出,那么你应该他们都包括进去。

  还有就是Avalon总线提供的信号类型的名称,一般的是高电平有效,如果是低电平有效,那么在后面会加上一个“_n”例如reset是复位类型的信号(高电平复位),那么reset_n就是低电平有效。

关与Avalon总线其他信号线,比如irqreaddatavalidwaitrequest flush等等,用到的时候Google吧。

利用SPOC  Builder 创建 Nios II 系统

         Qurtus II给我们提供了一个方便的创建Nios系统的工具,即SOPC Builder,这个工具只有在新建了一个Quartus工程文件后才能使用。下面我们创建一个Qurtus工程:

 

输入名称,定位文件位置以后,选择器件为我们使用的“Cyclone II 2C35

运行SPOC Builder,新建Nios项目,输入名称,选择Verilog作为生成文件的语言:

 

然后就是添加Nios系统组件了:

首线添加nios_cpu:

 

         双击左边的系统模块Nios II Processor ,弹出如下对话框:

 

设置CPU类型,这里就使用最简单的一种。

添加以后,你可以重新给CPU命名,名一个容易记忆的名称。

 

然后就是选择一个最片上RAM,选择Avalon Components > Memory > On-Chip Memory (RAM or ROM),双击就添加了,设置类型,选择的大小要根据开发板来定,比如我们使用的是DE2,那么最有最大Memory限制,根据情况而定。

添加好了以后系统会自动将RAMAvalon总线连上,窗口中个模块前面的曲线就是这个含义。

 

这时一个最简单的系统就做好了。

注意,此时如果点击生成“Generate”的话,会报错,你还必须制定CPUboot Addressreset Address

双击cpu_0模块,在弹出的属性对话框中,选择地址为你添加的On-chip Memory即可。

当然你可以添加更多模块,也可以人工修改每个模块的基地址。但要注意的是若果要加上CFI Flash MemoryCommon Flash Interface)的话,必须要加上Avalon Tristate Bridge,即Avalon三态桥接器。通过Avalon Tristate Bridge来连接结Avalon master Avalon Slave

         如果你需要在运行的时候进行调试,你应该加上jtag_uart模块。

你可以为你的模块选择参数,比如,你添加了一个PIO,可以选择它是输入还是输出,或者是输入输出都有,SOPC Builder会根据你的参数产生相应的HDL文件,如图:

你还可以为你加上的IO模块产生中断,比如在你自定义的模块中向Avalon总线提供irq类型的信号,那么在SOPC Builder产生系统的时候会给你定义中断号,比如你添加4BitPIO4Button的时候,可以选择是否产生中断,如图:

你还可以为指定为你的模块产生仿真元数据,提供给像ModelSim这样的仿真软件仿真信息,当然Qurtus自己也能够进行波形仿真。

SPOC Builder 生成的文件

         SOPC Builder生成的文件包括:核模块的ptf文件,.sopc_builder文件加下面的install.ptf文件,nios系统的顶层模块的HDL文件,例如:你的Nios工程名为nios,那么顶层文件名应该是nios_0.v,还包括了nios_0.v调用了各个子模块的Verilog文件。仿真文件和一些其他的其他的文件。

         其中ptf文件是Nios系统的描叙文件,此文件在后面创建Nios Project时候会用到,Nios IDE通过这个文件来生成并且编译Nios Project的库文件,以便你在用户C语言程序中引用。下面来看一个ptf文件:

 

         下面来看看它生成的另外一个文件:nios_0.v

这是nios系统的核心模块,但是还不是顶层模块,它有时需要外部提供PLL时钟,或者是需要将自己模块的export管脚连接到核外用户逻辑上。看一个nios_0.v:

一个nios系统主模块中包括很多module,但是只有只有一个module与模块的文件名相同,这个就是主模块,它调用了很多组件的HDL模块,然后将其他组件的export引脚对外暴露,各组件与CPU的连线即Avalon总线对外封闭。

这里提一下核的顶层模块(这里是nios_0.v)里面的管脚命名规则:

凡是input,则为“模块端口名称”+to+“模块实例名称”,

凡是output,则为“模块端口名称”+from+“模块实例名称”

例如上图中的nios_0.v的核中实例化了AUDIO_MOD模块,命名为the_AUDIO_MOD

那么AUDIO_MOD的外部输入adcclk命名为:

dacclk_to_the_AUDIO_MOD.

基于Nios系统的顶层结构图

         这里说明以下,这里的系统顶层图不是Nios的顶层图,而是用户创建的项目的顶层图,它调用了用SOPC Builder创建的nios系统顶层模块,除了包括系统的nios模块外,还包括一些核外用户逻辑,例如PLL时钟,I2C控制块等等。下面给出我们的音频系统的顶层结构图。

         我们可以在系统的顶层图中使用用户逻辑,此时的用户逻辑是与系统总线没有关系的,他是与Nios系统没有直接关系的电路,在这儿称之为“核外用户逻辑”,比如说在我们系统中的I2CAV的配置(当然这也能够通过OpenI2C模块加到总线系统中去),核外逻辑可以用于与核无关的部分(直接连接到外部),也可以为核提供输入,或者接收输出。

         Nios总线系统内部,也可以添加用户自定义逻辑,这时候成为用户自定义组件,Interface To User Logics,但是这个时候就要和Avalon总线打交道了,因此必须满足Avalon总线的规则,下面就我们的系统中使用的模块做简单介绍。

Avalon总线创建自定义组件

         在假设WM8731芯片初始化到正常模式后,我们的用户逻辑只需要做两件事情:

1.     WM8731ADC输入采集转换成并行的16位数据,送到Avalon总线

2.     从总线上读取16并行数据,经过转换,串行的送到WM8731DAC通道上

 

这是一个经过测试后的独立模块,用图形描述如下:

 

 

Avalon总线接口有两个FIFO

ADC FIFO对总线有(iRD, iRD_CLK, iRST_N ,  oDATA

其中 iRDread类型,iRD_CLKclk信号,iRST_Nreset_n信号,oDATAreaddata

DAC FIFO对总线有(iWR, iWR_CLK, iRST_N , iDATA

其中 iRDread类型,iWR_CLKclk信号,iRST_Nreset_n信号,iDATAwritedata

         该模块还与三个PIO间接与总线相连,一个为输入控制信号,另外两个为FIFO对于总线的状态信号。模块的其余管脚均为export类型,连接到WM8731的硬件端口。

         下面简要说明一下在SOPC Builder里面添加自定义组件的步骤.

 

         打开SOPC Builder ,在左边的组件列表中选择Interface to User Logic 双击,在弹出对话框中添加已经封装好的自定义模块的Verilog文件,注意先添加顶层模块,然后添加底层被调用的模块,在添加之前首先要将这些文件拷贝到工程文件目录。

         然后点击Read ports from files,然后按照刚才定义的信号类型,选择Type,最后Filished

添加完成后,重新生成你的nios系统,这时ptf文件,以及niosverilog文件都会做相应的改变。但是你的QurtusII 工程顶层文件中的核模块任然没有更新,这个需要手动更新。你需要编辑顶层的Verilog文件,在调用nios_0.v的地方加入你的模块,去掉无用的模块。

按照前面所说的nios系统的管脚命名规则,可以直接根据输入或输出类型直接添加模块引脚,并且与外部电路相连,这里指的是从自定义模块中export的管脚。

例如下图所示:

经过上面的步骤,在原来的核的基础上,添加了自定义模块,只要编译成功,我们的核就完成了,接着就是去Nios IDE下面写C语言程序了,前提条件是你的自定义模块已经测试成功。

Nios IDE C语言编写程序

         接下来我们就可以打开Nios II IDE,新建工程了。启动Nios II IDE (实际上是Eclipse的插件),将Workspase设置为我们的QurtusII工程目录。New  a Project ,选择Nios II project,如图:

        

 点击下一步。输入工程名称,选择ptf文件,就是SOPC Builder建成后的ptf文件,定位好文件放置的目录,然后就可以下一步了。

新建一个工程后,就可一写C语言程序了,新建的软件项目统称会包含一个syslib,这个C语言库就是根据ptf文件生成的特定Nios系统的库文件,里面定义了Nios系统中的每一个模块的基址,中断地址,等等。

通常,比如你有一个模块叫做sdram_0的模块,那么Nios II会生成相应的模块基址常量名为SDRAM_0_BASE,全部是大些字母,以表明是全局常量,比如你在核中加了一个button_pio的模块,并且要求SOPC Builder产生中断,那么这时你可以访问BUTTON_PIO_IRQ来获取中断时间,或者捕捉中断信号。

说白了,在Nios里面用C语言编程实际上就是使用两个函数:

         IORDMODULE_BASE , OFFSET_ADDR //读取总线上面特定设备的值,

例如读取名为sram_0SRAM地址偏移量为0x00001的数据(假设没有越界,数据宽度为16位),那么也可以这样写:

int  i=0 ;   i=IORDSRAM_0_BASE0x00001);

IOWRMODULE_BASE , OFFSET_ADDRDATA //向特定模块,特定偏移地址写入DATA数据。

例如向名称为sdram_0SDRAM地址为0x0002ffff的地址中写入0x55AA数据。可以这样写:

IOWRSDRAM_0_BASE0x0002ffff0x55AA);

初写程序,主要也就用到这两个函数,原因是目前只涉及到了总线设备的读和写。

必要的时候,可以从Demo中拷贝一些现成的函数,例如LCD的测试函数,DM9000网卡读写等等,经过整理,工程文件加里面的函数文件越来越多,你可以编写复杂的程序了。

下面是Nios II IDE的工作环境:

 

 

还有一个值得注意的就是中断的设置函数,以下举按钮的中断设置为例:

void Button_Irq_Init()

{

  /* Enable all 4 button interrupts. */

  set_pio_irq_mask(BUTTON_PIO_BASE, BUTTON_INT_MASK);

  /* Reset the edge capture register. */

  set_pio_edge_cap(BUTTON_PIO_BASE, 0x0);

  /* Register the interrupt handler. */

  alt_irq_register( BUTTON_PIO_IRQ, NULL, (void*)Button_Handle);

}

 

int Button_Handle()

{

KEY_STATUS=get_pio_edge_cap(BUTTON_PIO_BASE); //获取按钮的值

outport(LED_GREEN_BASE,KEY_STATUS);           //亮灯显示  set_pio_edge_cap(BUTTON_PIO_BASE,0x0);        

     usleep(BUTTON_STOP_TIME);

outport(LED_GREEN_BASE,0);

 

switch(KEY_STATUS)  //判断按钮值

     {

      case 1 :   { break;}        //按了button_0

      case 2 :   { break; }       //按了button_1

      case 4 :   {break; }       //按了button_2

      case 8 :   {;break; }      //按了button_3

     };

}

   说明:这样通过alt_irq_register()函数注册了中断之后,只要在Main函数中加上这个函数,那么以后就可以相应按键事件了。

   关于Nios的编程就写到这里,可以参考我们的源程序。

 

技术总结

1. 关于FPAG芯片

FPGA就是一块可编程门阵列,可以只烧写用户逻辑,也可以只上核,也可以两个同时使用。

不上核的优点是:电路简单,时序易懂,易于仿真,编译。

                            缺点是:扩展性不好,芯片利用率不高

上核的优点是:可以添加第三方IP Core,可以处理复杂任务,上操作系统,处理中断

                            缺点:测试,仿真需要的时间长,还有软件版本的限制。

                   得到的经验是:做小模块的测试,不上核,等到各个模块都测试成功之后,上核测试。

 

2.     关于自定义用户逻辑

一定要有明确的接口的概念,在弄清楚输入,输出后,尽量将模块封装好,不必要的输出最好不要,能够节省的输入尽量节省,把事情尽量放在模块内部来完成。

读懂规则,少走弯路。

3.       关于软硬结合编程

先熟悉硬件,完整的理解Datasheet,熟悉硬件的工作模式,一旦选准工作模式,规划好设计方案后,就尽量避免更改方案,进而进行有效率的开始软件的开发

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Altera SOPC专题竞赛-经验总结
基于分布式参数电路模型检测电缆故障
不用处理器控制FPGA总线的方法
【FPGA黑金开发板】NIOS II那些事儿--硬件开发(一)
如何在20分钟内建立一个NIOS II开发环境
Altera MAX10 FPGA
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服