SOPC之NiosⅡ系统(五)

NIOS Ⅱ系统实例 

目录

2.创建BSP工程

2.1 创建BSP工程

2.2 BSP Editor

2.3 创建C代码文件

3.Nios Ⅱ实例

3.1 Hello NIOS Ⅱ

3.2 System ID与Timestamp

3.3 蜂鸣器定时鸣叫

3.4 拨码开关输入GIO控制

4.FPGA器件的代码固化

4.1 嵌入式软件HEX文件生成

4.2 程序存储器初始化文件加载

4.3 JIC文件生成和烧录配置


2.创建BSP工程

2.1 创建BSP工程

进行Nios Ⅱ嵌入式软件开发

点击Tool->Nios Ⅱ Software Buid Tools for Eclipse,创建工作空间

点击File->New->Nios Ⅱ Application and BSP from Template新建项目

点击Target hardware information中的[...] 按钮选择Quartus工程下的.sopcinfo文件,Nios II SBT for Eclipse软件会自动识别Qsys系统中CPU的名称

然后给创建的 Nios Ⅱ工程命名(名称需要以英文字母开头,可以包含字母、数字和下划线,不能有中文及特殊字符)

在取消勾选Use default location后可以修改然后将工程存放的位置

在Project template一栏中列出了一些工程模板,也可以选择创建空白工程 (Bland Project)

点击下方Next系统会自动创建一个BSP(Board Support Package,板级支持包)工程,提供了访问底层硬件(Qsys 系统)的函数库

 .sopcinfo文件是Qsys系统生成时一同产生,包含了所有Qsys系统的硬件信息,将它导入到BSP工程使得BSP获得全部硬件信息

在Project Explorer下出现了nios2bsp_bsp工程,可以看到这个文件夹下包含了各种和当前Qsys系统相关的板级动源文件和头文件,供应用软件调用。

头文件system.h将Qsys系统中的 Nios Ⅱ处理器和所有外设的名称、基地址、中断有无以及优先级号码等相关硬件信息进行了定义。

其中nios2bsp是C/C++应用工程,nios2bsp_bsp是函数库

2.2 BSP Editor

在BSPEditor中可以对板级驱动层进行一些定制化的配置,比如代码裁剪、标准输入/输出外设和定时器外设的设置等。

在Project Explorer下工程名右键点击Nios Ⅱ->BSP Editor

在左侧一栏选中Common,然后在右侧勾选两个选项:

enable_reduced_device_drivers: BSP为处理器的外设提供了两个版本的驱动库:一种是执行速度快但代码量比较大的版本:另一种是封装小的版本。默认使用的是代码量大的版本,这里通过[enable reduced device drivers]选项来选择封装小的版本,从而减少代码量。

enalbe_small_c_library: 完整的ANSIC标准库通常不适用于嵌入式系统,BSP提供了一系列经过裁剪的ANSIC标准库,占用资源比较少,通过[enalbe small c lbrary]选项来选择精简的ANSIC标准库。

在左侧一栏选中Settings,将右侧两个选项(默认勾选) 取消勾选:

enable_c_plus_plus: 使用 C 语言来编写软件程序,因此不需要使能 C+。

enable clean exit: 当选中该选项时,系统库在主函数main()返回时会调用exit()。调用 exit0时,首先会清理I/O的缓冲区,然后再调用exit()。当不选中该选项时,系统库会只调用exit(),这样将会节省程序空间。对于嵌入式系统程序来说,一般都不会从 main()返回,所以可以不勾选该选项。

设置完成后先点击Generate然后再点击Exit

2.3 创建C代码文件

在Project Explorer下工程名右键点击New->Source File新建C代码源文件

 

 在Project Explorer下工程名右键Build Project (CTRL+B)进行软件工程编译

3.Nios Ⅱ实例

3.1 Hello NIOS Ⅱ

通过JTAG UART在Nios Console中每隔3s打印一串“Hello NIOS II”的字符串

#include "system.h"     //定义Qsys中各个外设的地址、中断优先级等基本硬件信息
#include <stdio.h>      //定义标准输入、输出函数
#include <unistd.h>     //包含了延时函数usleep()函数的生命

///
//功能:每隔3s通过JTAG UART打印一条字符串“Hello NIOS Ⅱ”
///

int main(void)
{
	while(1)
	{
		printf("Hello NIOS II!\n");
		usleep(3000000);
	}
	return 0;
}

printf对应的设备在BSP Editor中设定

下载验证

先把.sof文件下载到开发板中,下载完成后开发板上没有任何实验现象

再下载.elf 文件(注意一定要先下载 sof 文件,再下载 elf 文件),Nios Ⅱ SBT for Eclipse中工具栏Run->Run AS->Nios II Hardware,将编译生成可执行文件.elf下载到硬件系统中。 

如果在程序下载的过程中弹出了“Run Configurations”窗口,提示找不到与Nios II硬件系统的连接

那么在这个窗口中点击Target Connection标签,点击Refresh Connections按钮,软件使会自动识别开发板上的 Qsys 系统,并显示 Qsys 系统的相关信息,接着点击[Apply] [Run],软件会把.elf 文件下载至开发板中

 下载结束后,程序自动开始运行,在软件下方的“Nios II Console”中会打印“Hello,Nios Ⅱ!”信息

3.2 System ID与Timestamp

读取 System ID外设的两个寄存器值,一个是id 值,另一个是Testamp值

地址偏移寄存器名称读/写功能描述
0id基于Qsys系统定义的唯一的32位数值,该id值类似于校验和;不同组件、不同选项配置的Qsys系统产生不同的id值
1timestamp基于系统生成时间的唯一32位值,该值等效于从1970年1月1日以来所经过的总秒数
#include "alt_types.h"                      //对altera定义的数据类型进行宏定义声明,alt_u32表示32位的无符号整型
#include "system.h"
#include <stdio.h>  
#include "altera_avalon_sysid_qsys_regs.h"  //定义了System ID硬件寄存器访问的接口函数

///
//功能:读取System ID的ID值核timestamp值,通过JTAG UART打印
///

int main(void)
{
	//读取%sy_id值
	alt_u32 hardware_id = IORD_ALTERA_AVALON_SYSID_QSYS_ID(SYSID_BASE);                //读取定义的System ID外设的id值,SYSID_BASE是定义的System ID外设的基址
	//读取%sy_id的timestap值
	alt_u32 hardware_timestamp = IORD_ALTERA_AVALON_SYSID_QSYS_TIMESTAMP(SYSID_BASE);  //读取定义的System ID外设的Timestamp值
	
	printf("System ID is 0x%8x\n",hardware_id);
	printf("System timestamp is 0x%8x\n",hardware_timestamp);
	
	while(1);
	return 0;
}

3.3 蜂鸣器定时鸣叫

使用Timer定时器产生秒中断信号,驱动蜂鸣器发出响声

Timer 定时器组件内部有可编程的32位定时计数器,通过编程访问该组件的控制和状态寄存器实现定时中断功能。

Timer定时器外设寄存器定义

地址偏移寄存器名称

读/写

功能描述
0status读写

bit 15~2:保留

bit 1:运行指示位。当计数寄存器运行时,该位置高。

bit 0:定时结束指示位。当计数回零时,该位置高。一旦定时结束事件发生,该位置高,直到对该寄存器读写后该位清零

1control读写

bit 15~4:保留

bit 3:停止位。该位写1将停止当前定时计数功能。

bit 2:启动位。该位写1将启动定时计数功能。

bit 1:运行指示位。该位置1后,计数器清零后将继续计数,即执行连续计数;该位清0后,计数器清零后将停止计数,即只执行一次计数。

bit 0:中断表示位。该位提高后,一旦status寄存器的bit 0拉高,即产生IRQ中断。

2periodl读写定时计数周期值-1(高16位)
3periodh读写定时计数周期值-1(低16位)
4snapl读写当前计数值(高16位)
5snaph读写当前计数值(低16位)

#include "alt_types.h"                      
#include "altera_avalon_pio_regs.h"     //声明PIO外设函数,如IOWR_ALTERA_AVALON_PIO_DATA()函数
#include "altera_avalon_timer_regs.h"   //声明Timer定时器外设函数,如IOWR_ALTERA_AVALON_TIMER_STATUS()/CONTROL()
#include "sys/alt_irq.h"                //声明中断相关的函数,如all_irq_register
#include "system.h"

int flag,second;

///
//功能:Timer定时器初始化函数
///
void init_timer(void)
{
	//注册定时器中断函数
	//TIMER_IRQ是system.h中定义的Timer定时器组件的中断号,TIMER_BASE是Timer定时器组件的基址,handle_time_interrupts为中断函数
	alt_irq_register(TIMER_IRQ,TIMER_BASE,handle_time_interrupts);
	//对Timer定时器组件的control寄存器写数据7,即启动timer定时计数功能,持续循环计数产生IRQ中断中断
	IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_BASE,7);
	//清除标志位
	flag = 0;
	//初始化函数没有对periodl和periodh寄存器进行设置,使用默认的计数值,即在Qsys中定义的1s计数周期
}


///
//功能:秒定时中断处理函数
///
static void handle_time_interrupts(void)
{
	//函数写Timer定时器组件的status寄存器,即清TO标志
	IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_BASE,0); 
	flag = 1;
	second++;
}


///
//功能:秒定时中断处理函数
///
int main(void)
{
	IOWR_ALTERA_AVALON_PIO_DATA(PIO_BEEP_BASE,0);  //拨码开关OFF
	init_timer();                                  //Timer定时器初始化函数
	
	while(1)
	{
		if(flag)
		{
			flag = 0;
			//该函数对基址为PIO_BEEP_BASE的PIO外设写数据1/0
			if(second & 0x01) IOWR_ALTERA_AVALON_PIO_DATA(PIO_BEEP_BASE,1);  //拨码开关ON
			else IOWR_ALTERA_AVALON_PIO_DATA(PIO_BEEP_BASE,0);               //拨码开关OFF
		}
	}

	return 0;
}

3.4 拨码开关输入GIO控制

使用4个拨码开关产生中断,对不同拨码开关值进行判断,相应驱动蜂鸣器发出1~4此响声

PIO组件寄存器定义

地址偏移寄存器名称

读/写

功能描述
0data读写

作为输入PIO时,读控制获取当前输入PIO的电平值;

作为输出PIO时,写控制将数据输出到PIO上

1direction读写

每个PIO引脚单独的方向控制。电平0设置PIO为输入;电平1设置PIO为输出

2interruptmask读写每个PIO引脚对应的IRQ中断使能。电平1设置IRQ中断使能
3edgecapture读写每个PIO引脚的边沿变化状态捕获

#include "alt_types.h"
#include "altera_avalon_pio_regs.h"
#include "sys/alt_irq.h"
#include "system.h"
#include <stdio.h>
#include <unistd.h>
#include <io.h>

/
//函数申明
void init_switch_pio(void);	//switch GIO初始化函数
void beep_didi(alt_u8 time);	//蜂鸣器发出“滴滴”响声函数

/
//宏定义

/
//变量申明
alt_u8 edge_capture_value;	//当前拨码开关值

/
//功  能:	拨码开关中断服务函数
/
static void handle_switch_interrupts(void)
{
    //捕获当前PIO值
    edge_capture_value = IORD_ALTERA_AVALON_PIO_DATA(PIO_SWITCH_BASE);
    //清除边沿中断标志位
    IOWR_ALTERA_AVALON_PIO_EDGE_CAP(PIO_SWITCH_BASE,0x00);
}

/
//功  能:	主函数,拨码开关从off到on拨动时,蜂鸣器发出几声清脆的“滴”响声
/
int main(void)
{

	IOWR_ALTERA_AVALON_PIO_DATA(PIO_BEEP_BASE,0);	//beep off
	init_switch_pio();	//switch GIO初始化函数
	
    while(1)
    {
    	if(~edge_capture_value & 0x01)	//蜂鸣器发出1声“滴”
        {
			beep_didi(1);
        }
    	else if(~edge_capture_value & 0x02)	//蜂鸣器发出2声“滴”
        {
			beep_didi(2);	
        }
    	else if(~edge_capture_value & 0x04)	//蜂鸣器发出3声“滴”
    	{
			beep_didi(3);
    	}
    	else if(~edge_capture_value & 0x08)	//蜂鸣器发出4声“滴”
    	{
			beep_didi(4);
    	}
    }
    return 0;
}

/
//功  能:	switch GIO初始化函数
/
void init_switch_pio(void)
{
    //初始化拨码开关状态值
    edge_capture_value = 0xff;
    //使能3个拨码开关中断
    IOWR_ALTERA_AVALON_PIO_IRQ_MASK(PIO_SWITCH_BASE, 0xff);
    //复位拨码开关边沿状态
    IOWR_ALTERA_AVALON_PIO_EDGE_CAP(PIO_SWITCH_BASE, 0x00);
    //拨码开关输入GIO中断复位申明
    alt_irq_register(PIO_SWITCH_IRQ,PIO_SWITCH_BASE,handle_switch_interrupts);
}

/
//功  能:	蜂鸣器发出“滴滴”响声函数
//参  数:	alt_u8 time 发出响声的次数
/
void beep_didi(alt_u8 time)
{
	alt_u8 i;
	for(i=0;i<time;i++)
	{
		IOWR_ALTERA_AVALON_PIO_DATA(PIO_BEEP_BASE,1);	//beep on
		usleep(20000);	//delay 100ms
		IOWR_ALTERA_AVALON_PIO_DATA(PIO_BEEP_BASE,0);	//beep off
		usleep(20000);	//delay 100ms	
	}
}

其他实例可参照参考书籍进行

4.FPGA器件的代码固化

4.1 嵌入式软件HEX文件生成

基于Nios Ⅱ处理器的FPGA器件代码固化和一般只有 FPGA 逻辑的代码固化不同

除了正常的FPGA逻辑部分代码需要固化外,还有Nios Ⅱ处理器的程序代码也需要固化。

使用FPGA片内存储器作为Nios Ⅱ处理器的代码存储器,在生成逻辑代码部分的烧录文件时,将 Nios Ⅱ处理器的代码集成在一起,就可以使用一个烧录文件完成 FPGA 器件的固化

打开工程的BSP Editor页面,选择Setting->Advanced->hal->linker,勾选allow_code_at_reset选项,然后重新编译C/C++软件工程文件和函数库文件

设置该选项的目的是在确保FPGA使用了片内存储器作Nios Ⅱ处器代码存储器时,在FPGA逻辑运行起来以后,Nios Ⅱ处理器复位后直接可以从片内存储器开始运行代码

 然后右键软件工程文件->Make Targets->Build,选择men_init-generate,点击Build

然后就可以在软件工程文件夹下发现.hex文件,为软件工程代码对应的十六进制HEX文件,即Nios Ⅱ处理器的软件代码

4.2 程序存储器初始化文件加载

进入Qsys界面,双击onchip_men组件进入配置界面的Memery initialization

勾选Initialize memory content和Enable non-default initialization file,并在User created initialization file中添加刚才生成的.hex文件

重新生成Qsys工程并且重新编译整个Quartus工程并产生新的.sof 文件

此时.sof 文件通过JTAG在线烧录到FPGA器件中则会直接运行软件程序

但.sof 文件只能在线烧录,因此需要将.sof文件转换为jic文件,实现SPI Flash的固化

4.3 JIC文件生成和烧录配置

在Quartus中选择File->Convert Programming Files

在Programming file type中选择JTAG Indirect Configuration File(.jic)

Configuration device选择配置设备,File name输入转换后的文件名(output_files 文件夹下)

在Input files to convert中

单击Flash Loader所在的行,然后单击右侧Add Device按钮在Select Devices 窗口中选择设备

单击SOF Data所在行,然后单击右侧的Add File按钮,在弹出的窗口中选择output files文件夹下的 .sof文件

完成设置后,单击 Generate 生成 *.jic,弹出如图所示的提示信息,表示成功生成jic文件

打开 Quartus的 Programmer 页面,单击Add File按钮加载的jic 文件(File下若有其他文件,请删除),并且确保勾选 Program/Configure 所在列

单击 Start 按钮执行下载操作,完成下载后,开发板默认处于不工作状态,需要重启开发板,重启后就能看到最新下载的代码已经固化到 SPI Flash 中并且掉电后重启仍然可以运行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/38542.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux进程控制(一)---进程创建和终止(写时拷贝,exit与_exit等)

目录 进程创建 fork()函数 子进程如何继承父进程的数据 1.创建时拷贝分离 2.写时拷贝★ 进程终止 进程终止时&#xff0c;操作系统做了什么&#xff1f; 进程终止的常见方式 代码运行完毕&#xff0c;结果正确 退出码★ 代码运行完毕&#xff0c;结果不正确 代码异…

自学网络安全(黑客)

一、自学网络安全学习的误区和陷阱 1.不要试图先成为一名程序员&#xff08;以编程为基础的学习&#xff09;再开始学习 行为&#xff1a;从编程开始掌握&#xff0c;前端后端、通信协议、什么都学。 缺点&#xff1a;花费时间太长、实际向安全过渡后可用到的关键知识并不多。…

字体反爬破解

1、通过 f12 查看网页相关信息① 搜索“python”相关岗位&#xff0c;想爬取下来作为分析&#xff0c;但是看到html源码为特殊字符&#xff0c;而不是页面上直观能看到的文字信息②点击对应的css样式查看css源码&#xff0c;通过源码解析字体加密过程 2、通过 DomainURI 获取到…

北邮国院物联网 Microprocessor 微处理器笔记

Introduction-随便聊 嵌入式系统是什么&#xff1f;专用的计算机系统。为专门功能可能对计算机架构&#xff0c;外设等做出一些取舍。 通常的限制&#xff1a;Cost&#xff08;比如大量部署传感器节点&#xff09;&#xff0c;Size and weight limits&#xff08;特定应用场景…

【网关】ShenYu Gateway入门Demo体验,ShenYu网关2.6.0直接调用Dubbo服务

本次为新开源框架接入ShenYu网关做基础学习指导&#xff0c;特地来下载官网的demo体验一把&#xff0c;具体是想通过网关泛化调用dubbo服务。本次使用的是最新版本2.6.0。 官网文档&#xff1a; 如何通过 Apache ShenYu 网关代理 Dubbo 服务 | Apache Dubbo 环境准备 第一步&a…

git下载源码及环境搭建下载源码之后端(一)

学习目标&#xff1a; git下载源码 步骤&#xff1a; 下载源码 使用 windows R 使用cmd调用命令框下载gitee云上面的 源码文件 输入命令&#xff1a; Git clone &#xff08;此处拼接gitee源代码 地址&#xff09; 若使用 git 命令 clone 项目时 我们需要在系统变量中进行…

vue生命周期四个阶段(created和mount)

1.四个阶段 1&#xff09;必经阶段 2&#xff09;非必经阶段 提示&#xff1a;主动调用 vm.$destroy() 函数销毁后&#xff0c;可用 vm.$mount("#app") 将断开的 new Vue() 和页面重新建立虚拟 DOM 树&#xff0c;重新绑定起来挂载界面。 2. 生命周期钩子函数&…

【Unity 实用插件篇】| ReferenceFinder 引用查找插件,提高引擎查找使用效率

前言 【Unity 实用插件篇】| ReferenceFinder 引用查找插件&#xff0c;提高引擎查找使用效率一、ReferenceFinder 介绍二、使用示例三、实现方案3.1 方案选择3.2 查找及缓存3.3 界面实现 总结 前言 ReferenceFinder 是一个比较小众的插件&#xff0c;主要用来查找资源引用和…

【Java】Java实现微信小程序发送服务通知

文章目录 前言一、文档来源二、JAR包引入三、后端工作四、编写配置文件配置一&#xff1a;WxConfig配置二&#xff1a;WxProperties 五、代码编写 前言 在上个月接到一个需求&#xff0c;大概是需要计算一条数据的最大办理时间从而发送任务超期的微信小程序服务通知&#xff0…

IDDR和ODDR

IDDR D&#xff1a;输入双倍速率数据&#xff08;IOB输入&#xff0c;且数据在时钟的上升沿和下降沿都会发生切换&#xff0c;即一个时钟周期发送2bit数据&#xff09; CE&#xff1a;时钟使能信号&#xff08;高有效&#xff09; C&#xff1a;时钟信号 S&#xff0c;R&#x…

黑马大数据学习笔记2-HDFS基本操作

目录 进程启停管理一键启停脚本单进程启停 文件系统操作命令HDFS文件系统基本信息介绍创建文件夹查看指定目录下内容上传文件到HDFS指定目录查看HDFS文件内容下载HDFS文件拷贝HDFS文件追加数据到HDFS文件HDFS数据移动HDFS数据删除其他命令HDFS WEB浏览 HDFS权限修改权限 https:…

Spark MLlib快速入门(1)逻辑回归、Kmeans、决策树、Pipeline、交叉验证

Spark MLlib快速入门(1)逻辑回归、Kmeans、决策树案例 除了scikit-learn外&#xff0c;在spark中也提供了机器学习库&#xff0c;即Spark MLlib。 在Spark MLlib机器学习库提供两套算法实现的API&#xff1a;基于RDD API和基于DataFrame API。今天&#xff0c;主要介绍下Data…

FPGA实验四:交通灯控制器设计

目录 一、实验目的 二、设计要求 三、实验代码 1.design source文件代码 2.仿真文件代码 3.代码原理分析 四、实验结果及分析 1、引脚锁定 2、仿真波形及分析 3、下载测试结果及分析 五、实验心得 1.解决实验中遇见的问题及解决 2.实验完成的心得 一、实验目的 &a…

Linux使用HTTP隧道代理代码示例模版

下面是一个在Linux上使用HTTP隧道代理的代码示例模板&#xff0c;可以根据自己的实际情况进行修改和配置&#xff1a; #!/bin/bash# 配置代理服务器信息 proxy_server"代理服务器IP或域名" proxy_port"代理服务器端口号" proxy_username"代理服务器用…

《动手学深度学习》——线性神经网络

参考资料&#xff1a; 《动手学深度学习》 3.1 线性回归 3.1.1 线性回归的基本元素 样本&#xff1a; n n n 表示样本数&#xff0c; x ( i ) [ x 1 ( i ) , x 2 ( i ) , ⋯ , x d ( i ) ] x^{(i)}[x^{(i)}_1,x^{(i)}_2,\cdots,x^{(i)}_d] x(i)[x1(i)​,x2(i)​,⋯,xd(i)​…

《实战AI低代码》:普元智能化低代码开发平台发布,结合专有模型大幅提升软件生产力

在7月6日举办的“低代码+AI”产品战略发布会上,普元智能化低代码开发平台正式发布。该平台融合了普元自主研发的专有模型,同时也接入了多款AI大模型的功能。它提供了一系列低代码产品,包括中间件、业务分析、应用开发、数据中台和业务流程自动化等,旨在简化企业的复杂软件生…

Nginx学习

文章目录 Nginx什么是NginxLinux安装与配置Nginx编译安装Nginxnignx使用nginx默认首页配置案例 localtion的匹配规则Nginx虚拟主机基于多IP的虚拟主机基于多端口的虚拟主机基于域名的虚拟机主机 反向代理案例①案例② 负载均衡案例①案例②分配策略 动静分离案例 配置Nginx网关…

文心一言 VS 讯飞星火 VS chatgpt (58)-- 算法导论6.4 2题

文心一言 VS 讯飞星火 VS chatgpt &#xff08;58&#xff09;-- 算法导论6.4 2题 二、试分析在使用下列循环不变量时&#xff0c;HEAPSORT 的正确性&#xff1a;在算法的第 2~5行 for 循环每次迭代开始时&#xff0c;子数组 A[1…i]是一个包含了数组A[1…n]中第i小元素的最大…

【Distributed】zookeeper+kafka的应用及部署

文章目录 一、zookeeper1. zookeeper的概述1.1 Zookeeper 定义1.2 Zookeeper 工作机制1.3 Zookeeper 特点1.4 Zookeeper 数据结构1.5 Zookeeper 应用场景1.6 Zookeeper 选举机制第一次启动选举机制非第一次启动选举机制选举Leader规则 2. 部署 Zookeeper 集群2.1 安装前准备2.2…

day52

思维导图 比较指令结果的条件码 练习 汇编实现1-100的累加 .text .global _strat _start: mov r0,#0mov r1,#0 add_fun:add r0,r0,#1cmp r0,#100addls r1,r1,r0bls add_fun .end