1、Nios II PIO 的说明与双向操作注意点最近想使用 Nios II 里的并口 PIO 口进行双向操作,即需要输出的时候设置为输出方向,需要输入的时候设置为输入方向。在这期间,因为没认真仔细阅读参考文档,走了一点点的弯路。下面就简单的介绍下并行输入/输出 PIO。PIO 核概述具有 Avalon 接口的并行输入/ 输出(parallel input/output - PIO)核,在 Avalon 存储器映射(Avalon Memory-Mapped Avalon-MM)从端口和通用 I/O 端口之间提供了一个存储器映射接口。I/O 端口既可以连接片上用户逻辑,也可以连接到 FPGA 与外设
2、连接的 I/O 引脚。PIO 核提供容易的 I/O 访问用户逻辑或外部设备,在这种情况下 “位控制”的方法是有效的。下面列举了几种应用的例子: 控制 LED、获取开关数据、控制显示设备、片外设备的配置与通信,例如特定应用的标准产品(ASSP)。功能描述每个 PIO 核可以提供最多 32 个 I/O 端口。像微处理器这样的智能主机通过读 /写寄存器映射的 Avalon-MM 接口控制 PIO 端口。在主机控制下,PIO 核捕获输入端口的数据,并驱动数据到输出端口。当 PIO 端口直接与 I/O 引脚相连时,主机通过写 PIO 核中的控制寄存器对 I/O 引脚进行三态控制。图 1 是一个基于处理器
3、系统使用多个 PIO 核的例子,其中,一个用于控制 LED;一个用于捕获来自片上复位请求控制逻辑的边缘;另一个控制片外LCD 显示。在集成到 SOPC Builder 创建的系统时, PIO 核有 2 种用户可见功能部件。一个存储器映射的寄存器空间有 4 个寄存器:data、direction、interruptmask 和edgecapture。132 个 I/O 端口。I/O 端口既可与 FPGA 内部逻辑相连接,也可驱动连接到片外设备的 I/O 引脚。寄存器通过 Avalon-MM 接口提供到 I/O 端口的接口。表 1 是这些寄存器的描述。在某些硬件配置中,某些不需要的寄存器不存在,读
4、一个不存在的寄存器返回一个未定义值,而写一个不存在的寄存器无影响。图 1 使用多个 PIO 核的系统实例寄存器映射Avalon-MM 主外设,例如 CPU,通过 4 个 32 位寄存器控制并与 PIO 核通信,表 9-2假定 PIO 核的 I/O 端口被配置为 n 位宽度。表 1 PIO 核的寄存器映射偏 移 描 述 R/W (n-1) 2 1 0读访问 R 当前在 PIO 输入的数据值0 Data写访问 W 驱动 PIO 输出的新值1 Direction方向寄存器 (1) R/W 对于每个 I/O 端口独立的方向控制, 0 设置方向为输入;1 设置方向为输出2 Interruptmask中断
5、屏蔽寄存器 (1)R/W 对每个输入端口 IRQ 允许/禁用。设置某位为 1,允许相应端口的中断。3 Edgecapture 边沿捕获寄存器 (1), (2)R/W 对每个输入端口的边沿检测。4 outset W 指定输出端口的某位置 15 outclear W 指定输出端口的某位清 0(1) 该寄存器是否存在取决于硬件配置,如果寄存器不存在,读寄存器返回一个未定义的值,写寄存器无影响。(2) 写任何值到 Edgecapture,会清 0 所有位。数据寄存器读从 Data 寄存器返回的呈现在输入端口的值。如果 PIO 核硬件被配置为 output-only(只输出)模式,读 data 寄存器将
6、返回一个未定义的值。写 data 寄存器将存储值到寄存器中以驱动输出端口。如果 PIO 核硬件被配置为 input-only(只输入)模式,写 data 寄存器无影响。如果 PIO 核硬件被配置为双向模式,则仅当在 direction(方向)寄存器中相应的位被置 1(输出)时,被寄存的值才会出现在输出端口上。方向寄存器direction(方向)寄存器控制每个 PIO 端口的数据方向,假定端口是双向的,当位 n在方向寄存器中被置 1 时,端口 n 在 data(数据)寄存器的相应位驱动输出值。仅当 PIO 核硬件被配置为双向模式时,direction 寄存器才存在。模式(输入、输出或双向)在系统
7、创建时指定,并且在运行时不能修改。在输入或输出模式中,direction 寄存器不存在,在这种情况下,读 direction 返回一个未定义的值,写 direction 无影响。在复位后,方向寄存器的所有位都是 0,所以所有双向 I/O 端口都被配置为输入。如果那些 PIO 端口被连接到 FPGA 器件的引脚,则这些引脚保持高阻状态。在双向模式,为了改变 PIO 端口的方向,要重新编程 direction 寄存器。中断屏蔽寄存器设置 interruptmask Register(中断屏蔽寄存器)中的位为 1 允许相应 PIO 输入端口中断。中断行为取决于 PIO 核的硬件配置。见“ 中断行为”
8、。interruptmask 寄存器仅当硬件被配置为能产生 IRQ 时才存在。如果 PIO 核不能产生IRQ,读 interruptmask 返回一个未定义的值,写 interruptmask 无影响。在复位后,所有 interruptmask 寄存器的位都是 0,所以所有的 PIO 端口中断都被禁用。边沿捕获寄存器如果 edgecapture(边沿捕获)寄存器中的位 n 被设置位 1,在输入端口 n 上的边沿将会被探测到。Avalon-MM 主外设能够读 edgecapture 寄存器以确定是否有一个边沿出现在任何 PIO 输入端口。写任何值到 edgecapture 将清除寄存器中的所有位
9、。要探测的边沿的类型在系统创建时就已经选定在硬件中。edgecapture 寄存器只能在硬件被配置位捕获边沿时存在。如果 PIO 核没有被配置成捕获边沿,读 edgecapture 将返回一个未定义的值,写 edgecapture 无影响。输出置位和输出清零寄存器你可以使用输出置位和输出清零(outset 和 outclear)寄存器置 1 或清 0 指定的输出端口的位。例如,要设置输出端口的第六位,可以写 0x40(0100 0000)到 outset 寄存器。写0x08(0000 1000)到 outclear 寄存器可清 0 输出端口的第 3 位。这些寄存器只有在选择 Enable in
10、dividual bit set/clear output register 寄存器为开启时才可用。中断行为PIO 核输出一个能够连接到任意在系统中的主外设的单个 IRQ 信号。主外设既能够读data 寄存器, edgecapture 寄存器也能够确定那一个输入端口引发了中断。当硬件被配置为电平敏感中断时,当 data 和 interruptmask 寄存器中相应的位是 1 时,IRQ 被确定。当硬件被配置为边沿敏感中断时,当 edgecapture 和 interruptmask 寄存器中相应的位是 1 时,IRQ 被确定。 IRQ 保持确定直到禁用 interruptmask 中相应的位或
11、者写edgecapture 相应的位以明确地确认为止。数据输入/输出PIO 核的 I/O 端口既可以连接片上逻辑也可以连接片外逻辑, PIO 核可以配置为输入、输出或双向。若用来控制双向 I/O 引脚,则 PIO 核提供具有三态控制的双向模式。读和写数据寄存器的硬件逻辑是独立的。读数据寄存器返回当前输入端口的值;写数据寄存器影响驱动输出端口的值。由于这些端口是独立的,因此读数据寄存器并不返回上次写入的数据。边沿捕获PIO 核可配置为对输入端口进行边沿捕获(Edge Capture),它可以捕获低到高的跳变、高到低的跳变或者 2 种跳变均捕获。只要在输入端检测到边沿,该条件就会在 edgecap
12、ture寄存器中指示。边沿的检测类型在系统创建时指明,且不能通过寄存器进行更改。IRQ 的产生PIO 核可以配置为在不同的输入条件下产生 IRQ。IRQ 产生的条件可以是下面两种: Level-sensitive(电平检测) PIO 核硬件能检测一个高电平,可在核的外部插入一个“非”门来检测低电平。 Edge-sensitive(边沿检测) PIO 核的边沿捕获配置决定何种边沿类型能触发IRQ。每个输入端口的中断可以分别屏蔽,中断屏蔽决定哪一个输入端口能产生中断。配置实例图 2 显示了一个带输入和输出端口以及支持 IRQ 的 PIO 核配置方框图。图 2 带输入端口、输出端口和 IRQ 支持的
13、 PIO 核图 3 显示了一个双向模式、不支持 IRQ 的 PIO 核配置方框图。图 3 带双向端口的 PIO 核Avalon-MM 接口PIO 核的 Avalon-MM 接口由一个单个的 Avalon-MM 从端口组成。从端口有 Avalon-MM 读写传输的基本功能,Avalon-MM 从端口提供 IRQ 输出,使 PIO 核能够确定中断。SOPC Builder 中实例化 PIO 核设计者在 SOPC Builder 中使用 MegaWizard 向导来配置硬件特性设置。下面描述可用的选项。MegaWizard 向导有基本设置(Basic Settings)和输入选项( Input Op
14、tions)两个标签。Basic Settings(基本设置)Basic Settings(基本设置)标签页允许设计者指定 PIO 端口的宽度和方向。 Width (宽度)设置可以是 132 之间的任何整数值。如果设定值为 n,则 I/O 端口宽为 n 位。 Direction(方向)设置有 4 个选项,如下表所示。表 2 方向设置设 置 描 述Bidirectional (tristate) ports双向(三态)端口在这种模式下,每个 PIO 位共享一个设备引脚用于驱动或捕获数据。每个引脚的方向可以分别选择。如果设置 FPGA I/O 引脚的方向为输入,引脚的状态为高阻三态。Input p
15、orts only输入端口在这种模式下,PIO 端口只能捕获输入。Both input and output ports输入/输出端口在这种模式下,输入和输出端口总线是分开的,n 位宽的单向总线。Output ports only输出端口在这种模式下,PIO 端口只能捕获输出。注意 :第一种和第三种的区别,我们通过上图来说明。为了将输入和输出都使用同一个引脚,我错误的先使用了第三种方式。编译完 Nios II软核之后,在 Quartus II 中图中显示的是下图。(这只是顶层文件图中的一小部分)、从图中可以看出,正如上表里介绍的那样,在这种模式下,输入和输出端口总线是分开的。需要单独的引脚配置
16、。而如果采用第一种,将 PIO 口设置为双向(三态),在这种模式下,每个 PIO 位共享一个设备引脚用于驱动或捕获数据。在 Nios II 中选择好双向(三态)编译完之后,在Quartus II 中图中显示的是下图。从图中可以看出,输入输出可以共享于同一个引脚,具有双向性质的 PIO 口,还有一个小特征,画圆处的颜色是蓝色,而一般是紫色。在软件中,可以通过控制方向寄存器来选择 PIO 并口的控制方向。Input Options(输入选项)Input Options(输入选项)页允许设计者指定边沿捕获和 IRQ 产生设置。如果在基本设置页中选择了 Output ports only(输出端口),
17、Input Options(输入选项)页是不可用的。边沿捕获寄存器Synchronously Capture(同步捕获)当 Synchronously capture(同步捕获)打开时,PIO 核包含边沿捕获寄存器, edgecapture。用户必须进一步指定边沿探测的类型: Rising Edge(上升沿) Falling Edge(下降沿) Either Edge(上升下降沿)在输入端口,当一个指定类型的边沿出现时,边沿捕获寄存器允许核探测并且(可选)产生一个中断。当 Synchronously capture(同步捕获)关闭时,edgecapture 寄存器不存在。Enable Bit
18、Clearing for Edge Capture Register(边沿捕获寄存器的使能位清除)打开 Enable bit-clearing for edge capture register(边沿捕获寄存器的使能位清除),允许你单独清除一个或多个边沿捕获寄存器中的位。为了清除给定的位,写 1 到边沿捕获寄存器的位。例如,为了清除边沿捕获寄存器的位 6,可以写 01000000 到寄存器。中断当 Generate IRQ(产生 IRQ)被打开,且一个指定的事件在输入端口发生时, PIO 核可以断言一个 IRQ 输出,用户必须进一步指定 IRQ 事件的原因: Level(电平) 当一个指定的输
19、入为高,并且在 interruptmask(中断掩码)寄存器中该输入的中断是使能的,核产生一个 IRQ。 Edge (边沿) 当在边沿捕获寄存器中一个指定的位为高,并且在interruptmask(中断掩码)寄存器中该位的中断是使能的,核产生一个 IRQ。当 Generate IRQ(产生 IRQ)关闭时,interruptmask 寄存器不存在。仿真Simulation 页允许你在仿真期间指定输入端口的值。开启 Hardwire PIO inputs in test bench 以在测试工作台中设置 PIO 输入端口为一个特定的值,并且在 Drive inputs to 域中指定值。器件支持
20、PIO 核支持所有的 Altera 器件系列。软件编程模型这一节描述 PIO 核的软件编程模型,包括寄存器映射核用于访问硬件的软件结构。对于 Nios II 处理器用户, Altera 提供了定义 PIO 核寄存器的 HAL 系统库头文件。PIO 核不匹配由 HAL 支持的一般设备模型类型,所以不能通过 HAL API 或者 ANSI C 标准库访问。软件文件与 PIO 核相关的软件文件是 altera_avalon_pio_regs.h,该文件定义了 PIO 核的寄存器映射,提供符号常量来访问底层硬件。PIO 核配套的软件文件如下。该文件提供了对硬件的底层访问。应用程序开发者不要修改这些文件
21、。altera_avalon_pio_regs.h 该文件定义了 PIO 核的寄存器映射,提供访问底层硬件的符号常数。该文件中的符号由设备驱动函数使用。altera_avalon_pio_regs.h 文件清单:#ifndef _ALTERA_AVALON_PIO_REGS_H_#define _ALTERA_AVALON_PIO_REGS_H_#include #define IOADDR_ALTERA_AVALON_PIO_DATA(base) _IO_CALC_ADDRESS_NATIVE(base, 0)#define IORD_ALTERA_AVALON_PIO_DATA(base)
22、 IORD(base, 0) #define IOWR_ALTERA_AVALON_PIO_DATA(base, data) IOWR(base, 0, data)#define IOADDR_ALTERA_AVALON_PIO_DIRECTION(base) _IO_CALC_ADDRESS_NATIVE(base, 1)#define IORD_ALTERA_AVALON_PIO_DIRECTION(base) IORD(base, 1) #define IOWR_ALTERA_AVALON_PIO_DIRECTION(base, data) IOWR(base, 1, data)#def
23、ine IOADDR_ALTERA_AVALON_PIO_IRQ_MASK(base) _IO_CALC_ADDRESS_NATIVE(base, 2)#define IORD_ALTERA_AVALON_PIO_IRQ_MASK(base) IORD(base, 2) #define IOWR_ALTERA_AVALON_PIO_IRQ_MASK(base, data) IOWR(base, 2, data)#define IOADDR_ALTERA_AVALON_PIO_EDGE_CAP(base) _IO_CALC_ADDRESS_NATIVE(base, 3)#define IORD_
24、ALTERA_AVALON_PIO_EDGE_CAP(base) IORD(base, 3) #define IOWR_ALTERA_AVALON_PIO_EDGE_CAP(base, data) IOWR(base, 3, data)#define IOADDR_ALTERA_AVALON_PIO_SET_BIT(base) _IO_CALC_ADDRESS_NATIVE(base, 4)#define IORD_ALTERA_AVALON_PIO_SET_BITS(base) IORD(base, 4) #define IOWR_ALTERA_AVALON_PIO_SET_BITS(bas
25、e, data) IOWR(base, 4, data)#define IOADDR_ALTERA_AVALON_PIO_CLEAR_BITS(base) _IO_CALC_ADDRESS_NATIVE(base, 5)#define IORD_ALTERA_AVALON_PIO_CLEAR_BITS(base) IORD(base, 5) #define IOWR_ALTERA_AVALON_PIO_CLEAR_BITS(base, data) IOWR(base, 5, data)/* Defintions for direction-register operation with bi-directional PIOs */#define ALTERA_AVALON_PIO_DIRECTION_INPUT 0#define ALTERA_AVALON_PIO_DIRECTION_OUTPUT 1#endif /* _ALTERA_AVALON_PIO_REGS_H_ */