
今天给大侠带来今天带来FPGA 之 SOPC 系列第五篇,Nios II软件使用与程序开发 I,希望对各位大侠的学习有参考价值,话不多说,上货。

本篇首先简单介绍Nios II IDE开发环境的使用;然后重点介绍了硬件抽象层(HAL)系统库,包括HAL下的基本应用程序开发和实操训练,包括了字符型外设的应用和中断机制的实现。
以下为本篇的目录简介:
5.1 Nios II IDE简介
5.2 设置工程系统库属性和编译选项
5.3 调试/运行程序
5.4 下载程序到Flash
5.5 使用HAL开发应用程序
5.6 UART-JTAG开发和实验
5.7 LCD开发和实验
5.8 SYSTEM ID实验
5.9 中断机制和软件调试
5.1 Nios II IDE简介
+
Nios II IDE为软件开发提供4个主要功能:
一、工程管理
二、编辑器和编译器
三、调试器
四、闪存编程器
统一开发平台,用于所有Nios II处理器系统。

?
一、工程管理器
1、新工程向导
[File]→[New]→[C/C++ Application]

PIO内核结构框图
2、软件工程模板

PIO内核结构框图
3、软件组件
?
二、编辑器和编译器
1、文本编辑器
成熟的全功能源文件编辑器,包括:语法高亮显示C/C++程序代码、全面的搜索工具、文件管理、在线帮助和教程、快速定位及自动纠错、内置调试等功能。
2、C/C++编译器
Nios II IDE使用GCC编译器,并为其提供了一个图形化用户界面。图形化用户界面为GCC编译器提供了一个易用的按钮式流程,同时允许开发人员手工设置高级编译选项,使得操作更简单方便。
?
三、调试器
软件调试器(GDB):是强大的、在GNU调试器基础之上的软件调试器。该调试器提供许多基本调试功能以及一些在低成本处理器开发套件中不会经常用到的高级调试功能。
基本调试功能包括:运行控制、调用堆栈查看、软件断点、反汇编代码查看、调试信息查看、指令集仿真器。
高级调试功能包括:硬件断点调试ROM或闪存中的代码、数据触发、指令跟踪。
?
四、闪存编程器
多数使用Nios II处理器的设计都需要采用闪存(Flash)来存储FPGA配置数据和/或应用程序。Nios II IDE提供了一个方便的闪存编程方法。任何连接到FPGA的兼容通用闪存接口(CFI)的闪存器件以及主动串行配置器件EPCS都可以通过Nios II IDE闪存编程器来烧写。
5.2 设置工程系统库属性和编译选项
+
C/C++ Build 设置:
右击C/C++工程文件夹→[System Library Properties]

C/C++ Indexer设置:
右击C/C++工程文件夹→[System Library Properties]

System Library 设置:
右击C/C++工程文件夹→[System Library Properties]







5.3 调试/运行程序
+
选择Debug的目标器件:
对话框操作:[RUN]→[Debug] /[Debug As]


调试器目标连接设置--(Target Connection):
对话框操作:[RUN]→[Debug] →[Nios II Hardware] →Target Connection

JTAG cable:进行JTAG下载电缆的选择。
JTAG device:进行连接在JTAG下载电缆上带JTAG接口器件的选择。
Nios II Terminal…:进行Nios II系统中断通信工具选择。
调试器设置--(Debugger):
对话框操作:[RUN]→[Debug] →[Nios II Hardware] →Debugger

调试器设置--(Debugger 视窗模式):
对话框操作:Nios II IDE 切换到Debug视窗模式

运行程序--(Debugger 视窗模式)
对话框操作:[RUN]→[RUN] /[RUN As]

5.4 下载程序到Flash
+
当调试工作完成并确保程序无错后,就可以把程序下载到Flash中了。
5.5 使用HAL开发应用程序
+
Nios II IDE 工程结构:

Nios II IDE工程结构

一个Nios II IDE工程
与目标系统相关的system.h系统描述文件:

System.h文件构成过程
程序清单5.1 system.h描述的UART设备:

数据宽度及HAL类型定义:
表5.1 HAL数据类型定义

表5.2 Altera提供的GNU编译器下的ANSI C数据类型宽度

5.6 UART-JTAG开发和实验
+
实验目的:
使用UART-JTAG可以方便的通过下载线建立主机与SOPC的联系,这种串口方式把复杂的硬件驱动隐藏,从代码的角度来看我们可以很方便操作。

在ANSI C库的支持下,用户既可以把JTAG UART设备当作标准I/O设备使用,也可以将其当作文件操作。其实质是通过ANSI C库函数调用JTAG UART设备驱动函数访问硬件设备。

通过上面的设置,将器件JTAG_UART的输入输出映射到STDOUT\STDERR\STDIN等,那么我们就可以利用下面这些函数,操作JTAG_UART。

在上面红色部分设置好后,在CONSOLE窗口可以显示PC方的内容。

例程一:
#include <stdio.h>//字符操作库
int main()
{
printf("hahahaha");
return 0;
}扩展,利用函数:fopen、getc、fwrite、fprintf、fclose
完成一个识别键盘字符V和T的程序,要求识别到T后,利用fwrite打印出关于识别T的信息,识别到V后关闭JTAG,打印出V的信息,程序停止。
5.7 LCD开发和实验
+
The LCD controller core consists of two user-visible components:
are defined in the Optrex 16207 data sheet.

同样的LCD显示也是用写文件的方式(LCD只有输出)。如下例子:
#include <stdio.h>
#include <string.h>
#include "system.h"
#define ESC 27
#define ESC_TOP_LEFT "[1;0H"
#define ESC_BOTTOM_LEFT "[2;0H"
int main( void )
{
FILE *lcd;
lcd = fopen("/dev/lcd", "w");
fprintf(lcd, "%c%shello red logic\nLCDDisplaying.",ESC,ESC_BOTTOM_LEFT);
printf("If you can see messages scrolling on the LCD Display, then it is functional!\n");
usleep(2000000);
putchar('a');
fclose( lcd );
}扩展:将实验一中,通过键盘向JTAG-UART输入的字符 V T输出到LCD中。
5.8 SYSTEM ID实验
+
实验目的:
通过实验了解SYSTEM ID的意义和作用。
实验说明:
SOPC BUILDER生成该系统的时候,将为每一个NIOS系统生成一个标志符。该标志符会被填入SYSTEM ID寄存器中,供编译器和用户辨别所运行的程序是否与目标系统匹配。当程序运行在与之不匹配的系统上会出现错误。
使用系统ID有两种基本方法:
实现方法:
访问SYSTEMID的HAL函数为ALT_AVALON_SYSID_TEST(),该函数返回一个值来指示软件期望的系统ID是否匹配。使用头文件是<altera_avalon_sysid.h>
相匹配返回0,硬件时间标记大于软件标记返回1,软件时间标记大于硬件时间标记返回-1。
利用JTAG-UART功能将 SYSTEM ID功能加入实验中,要求程序运行首先检查ID,根据不同情况打印不同信息。
5.9 中断机制和软件调试
+
中断定义:
在特定的事件(中断源,也称中断请求信号)触发下引起CPU暂停正在运行的程序(主程序),转而先去处理一段为特定事件而编写的处理程序(中断处理程序),等中断处理程序处理完成后,再回到主程序被打断的地方继续运行。
NIOS Ⅱ 中断类型:
(1)status寄存器(ctl0)的PIE位为l;
(2)有一个中断请求输入irq产生;
(3) ienable寄存器(ctl3)的响应位n为l。
中断控制机制:
Nios II 的中断处理方式带有典型的RISC处理器的特征,所有的中断处理都从同一入口进入,然后由软件加以分配。负责分配工作的软件叫系统ISR,它是由开发系统提供的,自动的连接到可执行程序上。系统ISR维护着一个中断向量表,表中的每一项代表着一个专项处理程序的入口。所有的专项处理程序都是由用户定义然后注册到中断向量表中的,叫做用户ISR。系统ISR的入口地址是在SOPC_Builder中定义的,叫Exception Address。和中断有关的CPU寄存器有:ctl0、ctl1、ctl3、ctl4。Ctl0 是程序状态字,它的bit0位是全局中断允许位,1代表允许,0代表禁止。Ctl1是程序状字的堆栈,当发生中断时,由它保留一个程序状态字的备份。Ctl3是中断允许寄存器,其中每一位控制着一个中断源,1代表允许,0代表禁止,共计32位。Ctl4是中断申请寄存器,每一位对应着一个中断源的中断请求,1代表有中断,0代表没有……计32位。
NiosII的中断处理过程:
软中断处理程序是用来处理由软件发起的中断事件的,包括调试指令引起的中断及未定义指令引起的中断。目前未定义指令的处理主要为乘、除法运算指令的处理,不支持用自定义的操作码,除用户自己修改系统程序。如果软中断处理程序遇到了一个不识别的操作码,将返回一个不确定的结果。
完成中断的步骤:
1、注册中断函数ISR,它的函数原型如下:
Int alt_irq_register(alt_u32 id, void* context, void(*handler) (void*,alt_u32));
id:中断优先级,即所注册的ISR是为哪个中断优先级的中断服务的
Context,为所注册的ISR传递参数,可以是NULL;
Handler,中断服务函数ISR的指针。
返回值是0时,表示中断注册成功;返回为负数,表明中断注册失败。这里面有一个需要注册的地方,如果handler不是NULL,则该优先级中断在注册成功后将自动使能,也即是说,只要我们在handler处有相应的ISR,我们就不需要再进行使能处理了。
2、编写ISR函数,这个函数由我们自己来写,而不是HAL系统提供的。它跟一般的函数定义没什么区别,只是对ISR的函数原型有特定的要求: void ISR_handler( void* context, alt_u32 id );
context: 传给ISR的形参,可以是NULL;
id: 中断优先级
举例说明:
void ISR_key(void *context,unsigned long id)
{
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_BASE,0x0);
key_flag++;
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTON_BASE,0x0);
}
int init_key(void)
{
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTON_BASE,0xf);
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_BASE,0x0);
return alt_irq_register(BUTTON_IRQ,NULL,ISR_key);
}
大体上的思路是,先判断初始化是否成功,如果init_key()函数返回值是0函数返回值是0,说明注册成功,打印register。
1、alt_irq_register()是向系统ISR注册用户ISR的API函数。其原形为:int alt_irq_register( alt_u32 id,void *context,void (* isr)(void *, alt_u32)) id 代表被服务的中断向量号; context 是运行参数指针,将来作为第一个参数传给用户ISR; Isr 是一个函数指针,指向用户ISR入口;如果注册成功,函数返回0,并允许全局中断及被服务中断;不成功返回非0值。
2、alt_irq_disable()用来禁止某个中断服务。
原形为:Int alt_irq_disable(alt_u32 id)
Id 为对应的中断号;
返回值为0;
3、alt_irq_enable()与alt_irq_disable()对应,用来开启某个中断服务。
原形为:int alt_irq_enable(alt_u32 id)
4、alt_irq_disable_all()用于关闭全局中断,
原形为:alt_irq_context alt_irq_disable_all(void)
返回值为中断控制寄存器的值。
5、alt_irq_enable_all()用于开启全局中断,
原形为:void alt_irq_enable_all( alt_irq_context context)
context 代表中断控制寄存器的值

FPGA 之 SOPC 系列第五篇就到这里结束,下一篇将带来第六篇,Nios II 程序开发II 等相关内容。各位大侠,明天见!
END
后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。
大侠们,江湖偌大,继续闯荡,愿一切安好,有缘再见!