The parallel input/output (PIO) core provides a memory-mapped interface between an Avalon® Memory-Mapped (Avalon-MM) slave port and general-purpose I/O ports. The I/O ports connect either to on-chip user logic, or to I/O pins that connect to devices external to the FPGA.
The PIO core provides easy I/O access to user logic or external devices in situations where a “bit banging” approach is sufficient. Some example uses are:
The PIO core interrupt request (IRQ) output can assert an interrupt based on input signals. The PIO core is SOPC Builder ready and integrates easily into any SOPC Builder-generated system.
Each PIO core can provide up to 32 I/O ports. An intelligent host such as a microprocessor controls the PIO ports by reading and writing the register-mapped Avalon-MM interface. Under control of the host, the PIO core captures data on its inputs and drives data to its outputs. When the PIO ports are connected directly to I/O pins, the host can tristate the pins by writing control registers in the PIO core. Figure 11–1 shows an example of a processor-based system that uses multiple PIO cores to blink LEDs, capture edges from on-chip reset-request control logic, and control an off-chip LCD display.
Figure 11–1. An Example System Using Multiple PIO Cores
When integrated into an SOPC Builder-generated system, the PIO core has two user-visible features:
The I/O ports can be connected to logic inside the FPGA, or to device pins that connect to off-chip devices. The registers provide an interface to the I/O ports via the Avalon-MM interface. See Table 11–2 for a description of the registers. Some registers are not necessary in certain hardware configurations, in which case the unnecessary registers do not exist. Reading a non-existent register returns an undefined value, and writing a non-existent register has no effect.
The PIO core I/O ports can connect to either on-chip or off-chip logic. The core can be configured with inputs only, outputs only, or both inputs and outputs. If the core will be used to control bidirectional I/O pins on the device, the core provides a bidirectional mode with tristate control.
The hardware logic is separate for reading and writing the data register. Reading the data register returns the value present on the input ports (if present). Writing data affects the value driven to the output ports (if present). These ports are independent; reading the data register does not return previously-written data.
The PIO core can be configured to capture edges on its input ports. It can capture low-to-high transitions, high-to-low transitions, or both. Whenever an input detects an edge, the condition is indicated in the edgecapture register. The type of edges to detect is specified at system generation time, and cannot be changed via the registers.
The PIO core can be configured to generate an IRQ on certain input conditions. The IRQ conditions can be either:
Interrupts are individually maskable for each input port. The interrupt mask determines which input port can generate interrupts.
Figure 11–2 shows a block diagram of the PIO core configured with input and output ports, as well as support for IRQs.
Figure 11–2. PIO Core with Input & Output Ports & with IRQ Support
Figure 11–3 shows a block diagram of the PIO core configured in bidirectional mode, without support for IRQs.
Figure 11–3. PIO Core with Bidirectional Ports
The PIO core’s Avalon-MM interface consists of a single Avalon-MM slave port. The slave port is capable of fundamental Avalon-MM read and write transfers. The Avalon-MM slave port provides an IRQ output so that the core can assert interrupts.
The hardware feature set is configured via the PIO core’s SOPC Builder configuration wizard. The following sections describe the available options.
The configuration wizard has two tabs, Basic Settings and Input Options.
The Basic Settings tab allows the designer to specify the width and direction of the I/O ports.
Table 11–1. Direction Settings
|Bidirectional (tristate) ports||In this mode, each PIO bit shares one device pin for driving and capturing data. The direction of each pin is individually selectable. To tristate an FPGA I/O pin, set the direction to input.|
|Input ports only||In this mode the PIO ports can capture input only.|
|Output ports only||In this mode the PIO ports can drive output only.|
|Both input and output ports||In this mode, the input and output ports buses are separate, unidirectional buses of n bits wide.|
The Input Options tab allows the designer to specify edge-capture and IRQ generation settings. The Input Options tab is not available when Output ports only is selected on the Basic Settings tab.
When the Synchronously capture option is turned on, the PIO core contains the edge capture register, edgecapture. The user must further specify what type of edge(s) to detect:
The edge capture register allows the core to detect and (optionally) generate an interrupt when an edge of the specified type occurs on an input port.
When the Synchronously capture option is turned off, the edgecapture register does not exist.
When the Generate IRQ option is turned on, the PIO core is able to assert an IRQ output when a specified event occurs on input ports. The user must further specify the cause of an IRQ event:
When the Generate IRQ option is turned off, the interruptmask register does not exist.
This section describes the software programming model for the PIO core, including the register map and software constructs used to access the hardware. For Nios® II processor users, Altera provides the HAL system library header file that defines the PIO core registers. The PIO core does not match the generic device model categories supported by the HAL, so it cannot be accessed via the HAL API or the ANSI C standard library.
fThe Nios II Embedded Design Suite (EDS) provides several example designs that demonstrate usage of the PIO core. In particular, the count_binary.c example uses the PIO core to drive LEDs, and detect button presses using PIO edge-detect interrupts.
The PIO core is accompanied by one software file, altera_avalon_pio_regs.h. This file defines the core’s register map, providing symbolic constants to access the low-level hardware.
An Avalon-MM master peripheral, such as a CPU, controls and communicates with the PIO core via the four 32-bit registers, shown in Table 11–2. The table assumes that the PIO core’s I/O ports are configured to a width of n bits.
Table 11–2. Register Map for the PIO Core
|0||data||R||Data value currently on PIO inputs|
|W||New value to drive on PIO outputs|
|1||direction (1)||R/W||Individual direction control for each I/O port. A value of 0 sets the direction to input; 1 sets the direction to output.|
|2||interruptmask (1)||R/W||IRQ enable/disable for each input port. Setting a bit to 1 enables interrupts for the corresponding port.|
|3||edgecapture (1), (2)||R/W||Edge detection for each input port.|
Notes to Table 11–2:
Reading from data returns the value present at the input ports. If the PIO core hardware is configured in output-only mode, reading from data returns an undefined value.
Writing to data stores the value to a register that drives the output ports. If the PIO core hardware is configured in input-only mode, writing to data has no effect. If the PIO core hardware is in bidirectional mode, the registered value appears on an output port only when the corresponding bit in the direction register is set to 1 (output).
The direction register controls the data direction for each PIO port, assuming the port is bidirectional. When bit n in direction is set to 1, port n drives out the value in the corresponding bit of the data register.
The direction register only exists when the PIO core hardware is configured in bidirectional mode. The mode (input, output, or bidirectional) is specified at system generation time, and cannot be changed at runtime. In input-only or output-only mode, the direction register does not exist. In this case, reading direction returns an undefined value, writing direction has no effect.
After reset, all bits of direction are 0, so that all bidirectional I/O ports are configured as inputs. If those PIO ports are connected to device pins, the pins are held in a high-impedance state.
Setting a bit in the interruptmask register to 1 enables interrupts for the corresponding PIO input port. Interrupt behavior depends on the hardware configuration of the PIO core. See “Interrupt Behavior” on page 11–9.
The interruptmask register only exists when the hardware is configured to generate IRQs. If the core cannot generate IRQs, reading interruptmask returns an undefined value, and writing to interruptmask has no effect.
After reset, all bits of interruptmask are zero, so that interrupts are disabled for all PIO ports.
Bit n in the edgecapture register is set to 1 whenever an edge is detected on input port n. An Avalon-MM master peripheral can read the edgecapture register to determine if an edge has occurred on any of the PIO input ports. Writing any value to edgecapture clears all bits in the register.
The type of edge(s) to detect is fixed in hardware at system generation time. The edgecapture register only exists when the hardware is configured to capture edges. If the core is not configured to capture edges, reading from edgecapture returns an undefined value, and writing to edgecapture has no effect.
The PIO core outputs a single interrupt-request (IRQ) signal that can connect to any master peripheral in the system. The master can read either the data register or the edgecapture register to determine which input port caused the interrupt.
When the hardware is configured for level-sensitive interrupts, the IRQ is asserted whenever corresponding bits in the data and interruptmask registers are 1. When the hardware is configured for edge-sensitive interrupts, the IRQ is asserted whenever corresponding bits in the edgecapture and interruptmask registers are 1. The IRQ remains asserted until explicitly acknowledged by disabling the appropriate bit(s) in interruptmask, or by writing to edgecapture.
The PIO core is accompanied by the following software file. This file provide low-level access to the hardware. Application developers should not modify the file.
#ifndef __ALTERA_AVALON_PIO_REGS_H__ #define __ALTERA_AVALON_PIO_REGS_H__ #include <io.h> #define IOADDR_ALTERA_AVALON_PIO_DATA(base) __IO_CALC_ADDRESS_NATIVE(base, 0) #define IORD_ALTERA_AVALON_PIO_DATA(base) 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) #define 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_ALTERA_AVALON_PIO_EDGE_CAP(base) IORD(base, 3) #define IOWR_ALTERA_AVALON_PIO_EDGE_CAP(base, data) IOWR(base, 3, data) #endif /* __ALTERA_AVALON_PIO_REGS_H__ */
Quartus II Version 8.0 Handbook Volume 5: Embedded Peripherals Altera, May 2008.
Section 9 in current version, section 11 in earlier version of the handbook.
Maintained by John Loomis, last updated 3 Sept 2008