Okt 17, 2017 by Robin Category: Unkategorisiert 0 comments


How to Connect a Keypad to iolinker

Raspberry Pi connected to the iolinker FPGA board with a matrix keypad attached to it

What Do We Want to Do?

We intend to connect a 4×4 matrix keypad to the iolinker FPGA board and react to button presses.

To read in the key matrix, we will cycle through all four columns, with one column output high (all others pulled down) at a time. After every column switch, we read in the four row pulldown inputs. When a button is pressed, the appropriate row input reads high.


Get a 4×4 matrix keypad or build one yourself and plug it into your FPGA board. Any GPIO pins (P…) are fine.

Wire up the FPGA board to your 3.3V master device as usual. In the picture the FPGA board is connected to a Raspberry Pi.

The Software

You can find the main program keypad_example.cpp in the git repository.

Let’s define the relevant parameters for our 4×4 keypad. The KEYPAD_ROW0 define is vital for configuring the lowest pin your keypad is connected to. All other pins are derived from that automatically. If the keypad is connected to P17 – P31, enter ’16‘ (= P17).

Since it is convenient to plug in the 1×8 connector from the keypad directly onto one of the 2×10 headers or onto the 2×13 header on the FPGA board, the PIN_INTERVAL define allows you to only use every second pin.

/** Keypad definitions **/

//#define KEYPAD_INVERT /*< Invert pin direction */
#define PIN_INTERVAL 2 /*< Use every second pin */
#define KEYPAD_COLS 4 /*< Column count */
#define KEYPAD_ROWS 4 /*< Row count */
#define KEYPAD_ROW0 16 /*< Lowest pin they keypad is connected to */

char keypad[KEYPAD_ROWS][KEYPAD_COLS] = {
        { '1', '2', '3', 'A' },
        { '4', '5', '6', 'B' },
        { '7', '8', '9', 'C' },
        { '*', '0', '#', 'D' } }; /*< Keypad buttons */

Now for the function that determines the actual key that is pressed:

char button_press() {
    /* Set all pins as pulldown input */
    iolinker.setPinType(IOLinker::IOLINKER_INPUT, KEYPAD_ROW0,
    iolinker.setPinType(IOLinker::IOLINKER_INPUT, KEYPAD_COL0,

    /* Cycle through columns */
    for (uint8_t i = 0; i < KEYPAD_COLS; i++) {
        /* One column is a high output, all other columns are
           configured as input */
                KEYPAD_COL0 + i*PIN_INTERVAL);
        iolinker.setOutput(true, KEYPAD_COL0 + i*PIN_INTERVAL);
        /* Read in rows */
        for (uint8_t k = 0; k < KEYPAD_ROWS; k++) {
            if (!iolinker.readInput(KEYPAD_ROW0 + k*PIN_INTERVAL)) {

            /* Row input is high, i.e. we found a pressed key */
            return keypad[i][k];
            return keypad[KEYPAD_ROWS - 1 - i][KEYPAD_COLS - 1 - k];

        /* Reset column to input state */
                KEYPAD_COL0 + i*PIN_INTERVAL);

    return '-';

First all pins are configured as inputs, and then one column is changed to a high output at a time. When the user presses a button, the row input is connected to the column pins — and only the column currently configured as an output can pull the row input high.

This would even allow to detect simultaneous button presses individually, but the above code only returns the first one it finds.

Note that it is vital that the inputs are pulldowns; as they are implicitly on the iolinker board. If they weren’t, floating input pins could cause random behaviour.

One column pin is an output at a time, and a pressed button connects the row input to it

The main program can continuously call the function and react to button presses, or, as in this example, just output them:

while (1) {
    char key;
    if ((key = button_press()) != '-') {
        printf("Button press: %c.\n", key);

Trying It Out…

To compile the example on a PC or Raspberry Pi, just type ‚make keypad_example‘ in a console window. Then run with ’sudo ./keypad_example‘.

Verify that the main() initialization routine connects to the appropriate port.

Sorry, the comment form is closed at this time.