nios ii9.0编译后 出错 而且打不开头文件 怎么回事???

nios ii9.0编译后 出错 而且打不开头文件 怎么回事???,第1张

最近扮稿也在做SOPC,刚开始也遇到相同的问题,打不开头文件的原因可能有很多,

但是我告诉你一种方法,你肯定能打开的

1.新建NIOS II C/C++ APPLICATION工程,最好将位置放在你的quartusII中的Software文件夹中(这只是推荐),文枣缺升件夹自己新建吧!然后在Select Target中选择你用是SOPC建立的相应工程的PTF文件在Select Project Template中选择Blank Project!点击Next,然后一般凳老使用默认的方式点击finish。

2.为工程添加新的文件这里举例用C文件,这个步骤楼主应该会吧!

3.在文件中输入以下几行代码

#include<io.h>

#include "system.h"

void main()

{

}

只是将最简单的框架输入,然后在你的工程上点击右键选择System libarary Propertities在复选框中选择

program never exits

lightweight device driver API

Reduced device drivers

Small C Library

同时取消选择

Support C++

Clean Exit(Flush buffers)

然后在工程名上单击右键选择build Project

应该在左侧的OutLine中可以打开system.h了

一、背景

FIFO是FPGA项目中使用最多的IP核,一个项目使用几个,甚至是几十个FIFO都是很正常的。通常情况下,每个FIFO的参数,特别是位宽和深度,是不同的。

明德扬(MDY)在2021年承担了多个基于XILINX芯片的研发项目,包括VPX网络透明传输项目(芯片为XC7K325T-2FBG900)、某高端测试仪项目(芯片为XCKU060-FFVA1156)、某网闸设备项目(芯片为XC7Z030-FBG676)等,另外,明德扬自研了基于XC7K325T-2FBG900和基于XC7K410T-2FBG900芯片的核心板,在XILINX研发领域拥有丰富的经验。

这些项目都必须用到FIFO。如果按照通常做法,每种位宽和深度的IP,都要打开FIFO IP核界面、命名(命名不好不好分辨需要的FIFO)、设置参数、生成并编译IP核,工作量可以想象出来是非常多的。更重要的是随之而来的管理问题,如何管理这几十个不同FIFO,如何检查FIFO的设置是否正确,都是一个不小的挑战。

对于我们专门承接项目的团队,绝不可忍受如此重复、枯燥、容易出错的工作。经过精心研究,终于找到了一条实用的方法:使用XILINX的原语--xpm_fifo_async和xpm_fifo_sync。

XILINX原语xpm_fifo_async和xpm_fifo_sync在FPGA中,可以直接例化使用,并且可以参数化FIFO的位宽和深度的。即在设计时,不用生成FIFO IP,直接例化就可以使用了。

二、获得参考代码

打开VIVADO软件,点击上图中的Language Templates,将会d出Language Templates窗口,如下图。

在Language Templates窗口中,依次点击verilog、Xilinx Parameterized Macros(XPM)、XPM、XPM_FIFO,如上图。可以看到有三种FIFO,分别是异步绝掘的XPM FIFO:xpm_fifo_async、AXI总线的FIFO:xpm_fifo_axis和同步的XMP FIFO:xpm_fifo_sync。

选择xpm_fifo_async,右边的Preview窗口,将出现xpm_fifo_async的注释以及参考代码。将此部分代码拷出来,并将注释删除,剩下的是xpm_fifo_async的例化参考。

上图是对xpm_fifo_async的参数例化部分。下面是需要重点关并慎核注并经常使用的参数。

Ø FIFO_WRITE_DEPTH:FIFO的写深度,其实就是在这里设置FIFO的深度,注意该值通常是2的N次方,如8、16、32、64等数。

Ø PROG_EMPTY_THRESH:FIFO的快空的水线。当FIFO存储的数据量小于该水线时,FIFO的快空信号将会变高。

Ø PROG_FULL_THRESH:FIFO的快满的水线。当FIFO存储的数据量大于该水线时,FIFO的快满信号将会变高,表示有孝察效。

Ø READ_DATA_WIDTH:读数据的位宽。

Ø WRITE_DATA_WIDTH:将数据的位宽。

Ø RD_DATA_COUNT_WIDHT:读侧数据统计值的位宽。

Ø WR_DATA_COUNT_WIDTH:写侧数据统计值的位宽。

上图是对xpm_fifo_async的接口信号部分。下面是需要重点关注并经常使用的信号。

Ø wr_clk:FIFO的写时钟

Ø rst:FIFO的复位信号,高电平有效。要注意的是,该信号是属于写时钟域的。

Ø wr_en:FIFO的写使能信号。

Ø din:FIFO的写数据

Ø full:写满指示信号,当FIFO写满时,该信号变高。

Ø wr_data_count:FIFO存储数据量指示信号,用来指示当前FIFO已经写入但未读出的数据个数。

Ø rd_clk:FIFO的读时钟。

Ø rd_en:FIFO的读使能。

Ø dout:FIFO读出的数据。

Ø empty:FIFO的空指示信号。当其为1表示FIFO处于空状态,当其为0,表示FIFO内有数据。

三、定义自用的FIFO模块

从第二步可以看出,xpm_fifo_async是可以参数化深度和位宽的。但xpm_fifo_async有很多参数和信号,并且其中有部分是不使用的。为了使用上的方便,可以自定义自用的FIFO模块。

例如,明德扬就定义了一个模块mdyFifoAsy,该信号的接口信号如下图。可以看出,名称更加规范,并且定义常用的信号,如读时钟rd_clk,写时钟wrclk、写使能wrreq等信号。

明德扬还在模块mdyFifoAsy定义了一些常用的参数,分别是FIFO深度参数:DEPT_W;FIFO位宽的参数:DATA_W,还有FIFO快满参数AL_FUL和快空参数AL_EMP,如下图。

接下来,就是在mdyFifoAsy中例化并使用xpm_fifo_async了。如下图,就是对xpm_fifo_async的参数例化。将DEPT_W传给FIFO_WRITE_DEPTH,DATA_W传给READ_DATA_WIDTH等。

下图是对xpm_fifo_async的信号例化。将不用的信号留空,将dout连到q,din连到data,wr_en连到wrreq等。您可以根据自己情况来定制FIFO。

四、应用

定制完自己的FIFO后,就可以直接例化使用了。

上图就是使用了一个位宽为8,深度为256的FIFO。

上图就是使用了一个位宽为18,深度为1024的FIFO。

FIFO是FPGA、芯片设计中,最常用的IP核,在存储控制、算法实现、接口设计中,都少不了FIFO,因此合理并正确使用FIFO的技术就非常有必要了,明德扬录制了FIFO的训练视频,掌握后技术能力将有大提升。

通过上面介绍可知,通过此种方式,再也不用生成FIFO IP核啦,整个工程大小基本上可以减少一大半。

上面举的例子是xpm_fifo_async,同步FIFO:xpm_fifo_sync的使用方法是类似的。

步骤1 在SOPC Builder中例化Interval Timer核:戚做州

1. 在SOPC Builder中例化Interval Timer核,命名为sys_clk_timer。

图1 例化Interval Timer核

注意:命名为sys_clk_timer只是为了和BSP中sys_clk_timer一致,也可以命名为其他高蔽名称。

图2 BSP中的相关设置

2. 配置Interval Timer核

图3 配置Interval Timer核

Timerout period配置为1ms,表示每个tick是1ms;关于tick的概念,后面会提到。Timer counter size默认为32位。Hardware options可以自行配置;因为此处只是用到了sys_clk_timer服务,所以选择默认选项之一Simple periodic interrupt即可,即简单的周期中断。关于Timerout period的概念,手册中的介绍如下,大家可自行阅读。

图4 手册中的Timerout period的概念

注意:由于Writeable period选项没有用,所以Timerout period是固定的。

步骤2 NIOS II EDS中编写相应的C程序

1. 查看system.h中的相应内容

#define ALT_MODULE_CLASS_sys_clk_timer altera_avalon_timer

#define SYS_CLK_TIMER_ALWAYS_RUN 1

#define SYS_CLK_TIMER_BASE 0x1002000

#define SYS_CLK_TIMER_COUNTER_SIZE 32

#define SYS_CLK_TIMER_FIXED_PERIOD 1

#define SYS_CLK_TIMER_FREQ 125000000u

#define SYS_CLK_TIMER_IRQ 2

#define SYS_CLK_TIMER_IRQ_INTERRUPT_CONTROLLER_ID 0

#define SYS_CLK_TIMER_LOAD_VALUE 124999ULL

#define SYS_CLK_TIMER_MULT 0.0010

#define SYS_CLK_TIMER_NAME "/dev/sys_clk_timer"

#define SYS_CLK_TIMER_PERIOD 1

#define SYS_CLK_TIMER_PERIOD_UNITS "ms"

#define SYS_CLK_TIMER_RESET_OUTPUT 0

#define SYS_CLK_TIMER_SNAPSHOT 0

#define SYS_CLK_TIMER_SPAN 32

#define SYS_CLK_TIMER_TICKS_PER_SEC 1000u

#define SYS_CLK_TIMER_TIMEOUT_PULSE_OUTPUT 0

#define SYS_CLK_TIMER_TYPE "altera_avalon_timer"

第5行,固定的Timerout period,为1;第13行,胡告是Timerout period的单位。

第17行,由于每个tick是1ms,因此1s有1000个ticks。

第6行,Nios II软核的输入时钟频率,此处为125MHz。

2. 示范程序

#include "system.h" // SOPC Builder配置后的存储映射头文件

#include "altera_avalon_pio_regs.h" // PIO核的存储映射头文件

#include "alt_types.h" // Altera的数据类型

#include "sys/alt_alarm.h" // Interval Timer核的驱动头文件

#include "unistd.h" // NULL

// 用户回调函数

alt_u32 timer_CallBackFunc(void* context)

alt_alarm timer_addr // 指向结构体alt_alarm的指针

alt_u32 ticks_num = 100 // 100 ticks * 1 ms/tick = 100 ms

int main()

{

/*

* 函数功能:启动sys_clk_timer服务

* 函数备注:#include "sys/alt_alarm.h"

* 入口参数:timer_addr,指向结构体alt_alarm的指针

*ticks_num,每隔ticks_num执行一次回调函数

*timer_CallBackFunc,用户回调函数

*context,传给用户回调函数的参数,此处为NULL

*/

alt_alarm_start(&timer_addr, ticks_num, timer_CallBackFunc, NULL)

while(1)

return 0

}

/*

* 函数功能:用户回调函数

* 函数备注:用户自己编写

* 入口参数:*context, 从alt_alarm_start()传来的参数

* 出口参数:ticks_num, sys_clk_timer服务的周期数

*/

alt_u32 timer_CallBackFunc(void* context)

{

static alt_u8 temp = 0 // static 定义时,只可赋值一次

IOWR_ALTERA_AVALON_PIO_DATA(Q_LED_BASE, temp)

temp = ~temp// 翻转temp

return ticks_num// 返回下一次sys_clk_timer服务的ticks_num

}

对应前面提到的Simple periodic interrupt,34行到40行的用户回调函数,可以看作是定时器中断服务程序;23行的alt_alarm_start()可以看作是定时器中断的注册函数。ticks_num有什么用呢,前面已经提到1个tick是1ms(SOPC Builder中配置的),那么一旦定时器使用alt_alarm_start()运行起来,回调函数就会每ticks_num*1ms/tick执行一次。

注意:第36行,用户回调函数内,变量的声明必须加上关键字static,以防止被编译器优化以致错误出现。第23行的ticks_num为首次sys_clk_timer服务的ticks_num;第39行的ticks_num为下一次sys_clk_timer服务的ticks_num;两者可以不同;读者可以在第36行用数字替换试试。还有每个tick的时间只与SOPC Builder中的配置有关,和Nios II软核的输入时钟没有太大的关系。

至于为什么叫回调函数,我们可以打开sys/alt_alarm.h,查看相关函数的原型。此处由于水平有限,不做相关解析。请读者自行分析。

/*

* "alt_alarm" is a structure type used by applications to register an alarm

* callback function. An instance of this type must be passed as an input

* argument to alt_alarm_start(). The user is not responsible for initialising

* the contents of the instance. This is done by alt_alarm_start().

*/

typedef struct alt_alarm_s alt_alarm

/*

* alt_alarm_start() can be called by an application/driver in order to register

* a function for periodic callback at the system clock frequency. Be aware that

* this callback is likely to occur in interrupt context.

*/

extern int alt_alarm_start (alt_alarm* the_alarm,

alt_u32nticks,

alt_u32(*callback) (void* context),

void* context)

/*

* alt_alarm_stop() is used to unregister a callback. Alternatively the callback

* can return zero to unregister.

*/

extern void alt_alarm_stop (alt_alarm* the_alarm)

/*

* Obtain the system clock rate in ticks/s.

*/

static ALT_INLINE alt_u32 ALT_ALWAYS_INLINE alt_ticks_per_second (void)

{

return _alt_tick_rate

}

/*

* alt_sysclk_init() is intended to be only used by the system clock driver

* in order to initialise the value of the clock frequency.

*/

static ALT_INLINE int ALT_ALWAYS_INLINE alt_sysclk_init (alt_u32 nticks)

{

if (! _alt_tick_rate)

{

_alt_tick_rate = nticks

return 0

}

else

{

return -1

}

}

/*

* alt_nticks() returns the elapsed number of system clock ticks since reset.

*/

static ALT_INLINE alt_u32 ALT_ALWAYS_INLINE alt_nticks (void)

{

return _alt_nticks

}


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/tougao/12295822.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-24
下一篇 2023-05-24

发表评论

登录后才能评论

评论列表(0条)

保存