Setup and use of Blackboard's GPIO devices


The term “General Purpose Input/Output” (GPIO) generally refers to digital signals that are either inputs driven by two-state devices like slide switches or pushbuttons, or outputs that drive an indicator device (like an LED). Blackboard’s General Purpose I/O (GPIO) devices include 12 single-pole double-throw (SPDT) slide switches, 6 momentary single-pole single-throw (SPST) pushbutton switches, 10 single-color LEDs, and 3 tricolor (RGB) LEDs. Most of these GPIO devices are connected to the FPGA, but two pushbuttons and one RGB LED are connected to the Processing System (PS). The ARM processor can access the PS-connected devices at any time, whether or not the FPGA has been programmed. But it can only access the FPGA-connected devices after the FPGA has been configured (note: the ZYNQ device works just fine as an ARM system without the FPGA being programmed – they are independent systems). Ultimately, all GPIO devices are accessed through register reads and writes, but the PS GPIO devices use different registers, and have different programming requirements than the FPGA GPIO.

The Blackboard’s onboard slide switches constantly output a ‘0’ or a ‘1’ depending on their position. The pushbuttons are normally open, and so normally output a ‘0’ when not pressed, and output a ‘1’ only while actively pressed. All switches are connected to ZYNQ pins through series resistors to prevent damage from inadvertent short circuits.

Figure 1. Top-level GPIO Diagram

All LED signals are active high. The individual/discrete LEDs are connected to FPGA pins via 330-ohm resistors, and so a logic high signal (3.3V) will illuminate them with about 3mA of current. RGB LEDs have higher voltage thresholds and different current requirements, so they cannot be connected directly to the FPGA like the discrete LEDs. RGB LEDs are driven by NPN bipolar transistors, and the transistor bases are connected to the FPGA. A logic high on any RGB LED signal will illuminate the LED with about 5mA of current.

Each RGB LED device includes three individual LEDs that are located very close together, giving the appearance of a single LED. Each LED is driven independently, and this allows different colors to be created. By simply turning LEDs on or off, seven different colors can be created. But by controlling the brightness levels of individual LEDs, a broad range of colors can be created. LED brightness levels are typically controlled using pulse-width modulated (PWM) signals. PWM signals are commonly used as simple “digital to analog” signals - when used to control LED brightness, the PWM signals turn individual LEDs on and off at a frequency higher than the human eye can detect, with different lengths of “on” time to create the appearance of different brightness levels (you can learn more about PWM circuits/signals in the linked documents). Since the RGB LEDs are connected to the FPGA, users can define custom PWM IP blocks to drive the LEDs. The Blackboard hardware definition file includes RGB LED PWM circuits as discussed below. You can read more about PWM circuits here: PWM signals

Processing system (PS) connected GPIOs

ZYNQ’s processing system contains about 20 IP cores which add additional features to the ARM processor. IP cores include controllers for USB, SPI, I2C, CAN, UART, SDIO and Ethernet busses, as well as a GPIO controller block. Between them, these cores have hundreds of I/O signals – far too many to route to external pins on the ZYNQ chip package. Not every system needs all these IP cores, and most systems will use only a few of them. The ZYNQ chip has only 54 “multiplexed I/O” (MIO) pins that the IP cores can use to connect to external devices. System designers must choose the IP cores and functions they need, and then carefully allocate the MIO pins to make sure all critical functions are supported. The Blackboard uses several of the cores, including SPI, I2C, UART, SDIO, USB, and GPIO; the GPIO IP core uses just five MIO pins to connect two pushbuttons and one RGB LED. Like all IP cores, the Zynq’s included GPIO block is accessed through a set of predefined/permanent registers. The rest of the blackboard’s GPIO peripherals are connected through the FPGA pins of the Zynq.

FPGA-connected GPIOs

The FPGA in ZYNQ has access to many more I/O pins than the processing system does. On the Blackboard, FPGA pins connect to several peripherals, including a seven-segment display, an HDMI connector, several sensors and expansion connectors, and 32 GPIO devices (12 slide switches, 4 pushbuttons, 10 LEDs, and 2 RGB LEDs). The ARM processor accesses all FPGA-connected devices through registers in user-programmed custom IP blocks. These custom IP blocks are not a permanent part of the processing system – rather, they are designed by the user and must programmed into the FPGA prior to use. Because these custom IP blocks are located in the FPGA, they can easily be modified to include new features or accommodate user alterations as desired. The Blackboard_standard_configuration defines custom IP blocks that can be used to connect to the FPGA GPIO devices.

Since MIO pins are very limited, and since many systems may need more than just 54 pins to connect ZYNQ’s hard-IP peripheral circuits to physical devices, ZYNQ includes a bypass method that allows PS peripherals to use FPGA pins directly. This is called the “Extended MIO” (EMIO) interface; the Blackboard takes advantage of that for the SPI bus (see the SPI reference for more information).

Figure 2. GPIO signal routing

Accessing FPGA GPIO devices

The FPGA-connected GPIO devices are shown in the figure below, together with the registers defined in the Blackboard_standard_configuration file. The buttons, switches, and LEDs are accessed through simple registers. The RGB LEDs use pulse-width-modulators so that a wide spectrum of colors can be created.

Figure 3. FPGA-connected GPIO

Buttons (0x41200000): Pushbutton data (read only). Bits will be a ’1’ when corresponding button is being actively pressed.

BUTTONS: Button press data (1 when actively pressed)

LEDs (0x41210000): LED data (write only). Writing a’1’ will illuminate the corresponding LED.

LEDS: LED data (1 to illuminate)

Switches (0x41220000): Switch data (read only). Bits read as 1 or 0 depending on switch state.

SWITCH: Switch data (1/0 depending on switch state)

RGB_EN (0x43C000XX (XX-00/10/20/30/40/50)): Enable individual RGB LEDs (write only). Bit0 turns on/off corresponding RGB LED.

EN: Enable LED (1 to enable). Six identical registers for six RGB LEDs.

RGB_PERIOD (0x43C000XX (XX-04/14/24/34/44/54)): RGB LED Period definition (write only). 32-bit divisor to establish PWM frequency.

PERIOD: Sets the duration of each PWM ‘period’. This configures how many time slots are in a pwm ‘window’. Each slot has the same amount of time allocated to it ((100MHz)^-1 = 10ns), thus the number of slots determines the width of the window. When the count reaches the window width value, it resets to zero.

RGB_WIDTH (0x43C000XX (XX-08/18/28/38/48/58)): RGB LED PWM pulse-width (write only). 32-bit value determines how long PWM signal is driven high.

WIDTH: Length of PWM pulse in system clocks (pulse_len = WIDTH*10ns). If the pulse length is greater than the window width the signal is always on. At count 0, the signal goes high, then at the value in this register the signal toggles low. If the value is zero, the signal will always be off.

The ratio of the pulse width and the window width values can be used to calculate the duty cycle of the PWM signal. Duty = pulse/window.

Using the period register, the cycle frequency can be changed: The period can be calculated as (1/100MHz * window width), simply invert the result to get the frequency. Smaller window widths increases the frequency, however, it also decreases the granularity of the duty cycle; With a window width of 1024, each step of pulse length adds about 0.1% to the signal’s duty cycle. With a window width of 256, each step adds about 0.39% (the smaller the window, the larger percent each step takes up).

For an Led, as in this module, the granularity and frequency do not have strict constraints, as long as the frequency is above 120Hz the flicker will be unnoticable to humans. The granularity in this case will define how perceivable steps in brightness are. As long as the jumps aren’t too large, smoothly ramping the brightness of a RGB channel can be accomplished. It should be noted, when using pwm to modulate an audio signal or motor control signal the frequency and window width need to be tuned precisely to the application.

Accessing Processing System (PS) GPIO devices

The ZYNQ processing system defines 118 GPIO signals; 54 are assigned to MIO pins, and 64 are assigned to the FPGA. All GPIO signals are bidirectional, meaning they can be driven as outputs, read as inputs, or dynamically switched between being inputs and outputs. Every GPIO signal has a “pin driver” circuit that uses several flip-flops – one to store output data, another to define data direction, another to store output enables, and so on. These flip-flops are gathered into 32-bit registers that are located in a “GPIO IP block” that can be accessed by the ARM processor. Available registers include control registers that can define GPIO signals as inputs or outputs; registers that can enable or disable output drive (three-state control); write data registers that can drive logic levels on GPIO output signals; read data registers whose bits are defined by GPIO input signals; and registers to configure interrupts.

Within the GPIO IP block, signals and their corresponding registers are divided into four banks. The first 32 MIO signals are in bank 0, and the next 22 MIO signals are in bank 1. Banks 2 and 3 are for the 64 EMIO/FPGA signals. Here, we’re interested in the MIO signals in banks 0 and 1.

Figure 4. GPIO Pin Driver Circuits and MIO Signal connections

Each of the 4 GPIO Banks has four associated control registers. The width of the registers associated with a bank is dependent on the number of signals the bank has; Banks 0, 2, and 3 have 32-bit wide registers and bank 1 has 22 bit wide control registers. The bitfields of each control register correspond to individual signals in a bank; The same bitfield in each of a bank’s 4 control registers will be for the same GPIO signal. i.e. MIO signal 12’s control bits are found in bit 12 of all of bank 0’s registers. Many of the control register’s configuration and use are described below.

Blackboard’s PS-connected pushbuttons are attached to MIO_50 and MIO_51, and the three RGB LED signals attached to MIO_16 (blue), MIO_17 (red), and MIO_18 (green). These pin/signal assignments result from the physical pin connections on the Blackboard, and they cannot be changed without redesigning the circuit board (any GPIO device connected to ZYNQ pin B13 would be assigned to MIO_50). GPIO input signals are always active and can always be read, so pushbutton inputs can be read by simply reading bits 18 and 19 in the Bank1 input register. To drive an RGB LED output, the output data, direction, and enable bits (16, 17 and 18 in Bank0 control registers) must all be written.

Figure 5. GPIO IP Block Registers

DATA_X (0xE000A00XX (XX = 40/44/48/4C))) Output data

Bits in this register drive the corresponding GPIO signal to the value written (0 or 1) if the direction is set to output and the output is enabled. Bank0 bits map to MIO signals 0-31; Bank1 bits map to MIO signals 32-53.

DATA_X_R0 (0xE000A00XX (XX = 60/64/68/6C))) Input data

Bits in this register always show the current value on the pin. Bank0 bits map to MIO signals 0-31; Bank1 bits map to MIO signals 32-53.

DIR_X (0xE000A0XXX (XXX = 204/244/284/2C4)) Pin Direction.

Bits in this register define the pin direction (1 for output). Bank0 bits map to MIO signals 0-31; Bank1 bits map to MIO signals 32-53.

OE_X (0xE000A0XXX (XXX = 208/248/288/2C8)) Pin Direction.

Bits in this register enable outputs (1 to enable). To drive an output, the corresponding bit in this register and the DIR_X register must both be a 1 (they are anded). Bank0 bits map to MIO signals 0-31; Bank1 bits map to MIO signals 32-53.

Blackboards PS-connected GPIO circuits

To setup GPIO pins, the physical pin characteristics must first be defined. All 54 MIO pins have a corresponding register that defines how the pin is configured). GPIO pins must be configured before they can be defined and used as inputs or outputs.

Figure 5. GPIO IP Block Registers

MIO_XX (0x00000XXX): MIO pin configuration registers

DR: Disable Input Buffer (1 to disable)
PU: Enable pull-up resistor on input (1 to enable)
IO_TYPE: Set I/O buffer type: 001 for LVCMOS18; 010 for LVCMOS25; 011 for LVCMOS33; 100 for HSTL
SP: Set buffer speed (0 for slow CMOS edge, 1 for fast)
L3_SEL: Level3 mux select (000 for GPIO)
L2_SEL: Level 2 mux select (00 for Level 3 mux; 01 for SRAM/NOR chip select; 10 for NAND chip select; 11 for SDIO
L1_SEL: 0 for L2 mux select

To setup the MIO pins for the Blackboard GPIO devices, the registers for MIO pins 16, 17, 18, 50 and 51 should be written with “0x600” to select LVCMOS33. The input buffers on the RGB LED output pins (16, 17 and 18) can optionally be disabled by writing “0x1600”. Note these five registers are programmed in the Blackboard_standard_configuration file with the code shown below, so there is no need to program them again.

Sample Code

The fist code segment illustrates setting up the MIO physical pins through software. Note that defining physical pin characteristics improperly can damage the ZYNQ device (or other devices). The registers that setup physical pins are protected system-level registers, and access to them must be unlocked before they can be changed. After setting up the physical pins, the LED MIO pins in Bank0 are setup as outputs and then enabled, and all the bits in Bank1 are set to inputs (so the pushbuttons on bts 51 and 51 are inputs).

// System Level Control Register Definitions
#define SLCR_LOCK	*((uint32_t *) 0xF8000004)
#define SLCR_UNLOCK	*((uint32_t *) 0xF8000008)
#define UNLOCK_KEY	0xDF0D
#define LOCK_KEY	0x767B

//  MIO pins register definitions
#define MIO_16		*((uint32_t *) 0xF8000740);
#define MIO_17		*((uint32_t *) 0xF8000744);
#define MIO_18		*((uint32_t *) 0xF8000748);
#define MIO_50		*((uint32_t *) 0xF80007C8);
#define MIO_51		*((uint32_t *) 0xF80007CC);

// Configure MIO pins for the Blackboard's PS-connected buttons and LEDs
void configure_PS_MIO (void)
	MIO_50 = 0x0600; // BTN4 is LVCMOS33
	MIO_51 = 0x0600; // BTN5 is LVCMOS33
	MIO_16 = 0x1600; // RGB_LED_B is LVCMOS33 with disabled input buffer
	MIO_17 = 0x1600; // RGB_LED_R is LVCMOS33 with disabled input buffer
	MIO_18 = 0x1600; // RGB_LED_G is LVCMOS33 with disabled input buffer

The code example below sets up GPIO control registers, defines a bit-mask constant that can be used to setup the RGB LEDs, and defines some basic functions to work with GPIOs. The last few lines show examples of using the functions.

//output data register
#define GPIO_DATA(n)		*(((uint32_t*) 0xE000A040)+n)

//input data register
#define GPIO_DATA_RO(n) 	*(((uint32_t*) 0xE000A060)+n)

//direction register
#define GPIO_DIRM(n) 		*(((uint32_t*) 0xE000A204) + 16*n)

//output enable register
#define GPIO_OEN(n) 		*(((uint32_t*) 0xE000A208) + 16*n)

//RGB LED channels are bits 16-18, in bank 0
#define RGB_MASK 0x70000	

//configures MIO 16,17,18 as outputs
void set_GPIO_RGB_output()

//configures MIO 16,17,18 as inputs
void set_GPIO_RGB_input()

//enables the output of bank0 16,17,18
void en_GPIO_RGB_output(){


//disables output of bank0 16-18
void dis_GPIO_RGB_output()

//writes the passed value into the 3 outputs for the RGB LED's
void write_GPIO_RGB(uint32_t val)
	val = (0x7&val)<<16;	//use only bottom 3 bits, and shift to place
	GPIO_DATA(0) = (GPIO_DATA(0)&~RGB_MASK) | val;	//change only RGB bits

//Configures RGB Connected GPIO as outputs on channels
//initializes value to zero and enables output
void init_GPIO_RGB()
	set_GPIO_RGB_output();	//configure as output
	write_GPIO_RGB(0);	//clear value of RGBs

The following functions use parameters to choose the GPIO register bank and a mask to select which bits within the register will be modified. This makes the code more modular and more generally applicable, so it can be reused later.

//Sets the channls in the mask, in bank n, as outputs
void set_GPIO_output(int n, uint32_t mask)
	GPIO_DIRM(n) |= mask; 

//sets the channels in the mask, in bank n, as inputs
void set_GPIO_input(int n, uint32_t mask)
	GPIO_DIRM(n) &= ~mask;

//gets the value of only the bits in the mask
int read_GPIO_input(int n, uint32_t mask)
	return (GPIO_DATA_RO(n) & mask);

The above general functions are then used below to configure the GPIO Module for a specific use: The PS-connected buttons on the blackboard. Fieldmasks and banks corresponding to the buttons are defined for easy modification outside of the functions.

//btn4 is 18 in bank 1, btn5 is 19 in bank 1
//define bit masks for easy access in banks
#define BT4_MASK 0x40000
#define BT5_MASK 0x80000
//define the bank the buttons are in
#define BT4_BANK 1
#define BT5_BANK 1

void configure_buttons(void)
	set_GPIO_input(BT4_BANK, BT4_MASK);
	set_GPIO_input(BT5_BANK, BT5_MASK);

//another way to write the above function,
//provided the GPIO-signals are in the same bank
void configure_buttons_alt(void)
	set_GPIO_input(BT4_BANK, BT5_MASK | BT5_MASK);

//returns the value of button 4 1:on, 0:off
int get_btn4_val(void)
	return ( read_GPIO_input(BT4_BANK, BT4_MASK) !=0 );

//returns the value of button 5 1:on, 0:off
int get_btn5_val(void)
	return ( read_GPIO_input(BT5_BANK, BT5_MASK) !=0 );