Hexkeypad

The Hexkeypad can be plugged into either the JP1 or JP2 40-pin expansion headers. Once plugged in it is automatically connected to the lower 8 bits of that header and ignores the rest. The lower 8 bits are connected directly the 4 row pins and 4 column pins (so 8 pins in total) as shown further below.

DeviceHexkeypad
Input/Outputeither
Address BaseJP1=0xFF200060, JP2=0xFF200070
Address Map
AddressR/WDescription
baseR/WData Register for reading/writing from/to the pins
base+4R/WDirection Register configures each pin for input (0) or output (1)
base+8R/WInterrupt Mask Register enables interrupts for each pin (the corresponding pin should be configured as input)
base+12R/WEdge Capture Register, writing a 1 clears the corresponding bit. Writing 0xFFFFFFFF clears all bits.
InitializationSet direction register bits so that either rows are inputs and columns are output, or vice versa.
Interrupts
TriggeredNegative edge (when any interrupt-enabled input pin changes its value from 1 to 0)
IRQ LineJP1=11, JP2=12
EnableSet bits in Interrupt Mask Register that correspond to input pin you want to interrupt on
AcknowledgeWrite 0xFFFFFFFF to Edge Capture Register clears it
Hardware SetupConnect the 40-pin ribbon from the hexkeypad to either port JP1/2 on the DE1-SoC
Reference Hexkeypad Tutorial

Notes

Hexkeypad rows and columns

The hexkeypad is arranged as a 4x4 matrix of wires, and note that they are ONLY wires, no circuitry or logic other than pull-up exist. When you press a button the two wires touch, so to figure out when a key is pressed you need to configure, for example, the rows as outputs and the columns as inputs. You can then drive the rows low and see if any column pin turns low (since the hexkeypad is active-low as explained below). For example, if you press number 5 on the hexkeypad, that connects pin R1 to C1 so if you set R1 as a low output you would see it low on C1 if it was an input, and if you set C1 as a low output you would see low on R1 if it was an input. See the referenced Documentation above.

Active-low - The pins of the hexkeypad are set to be "pulled-up" to logical 1 (or high) by default, so if nothing is being pressed you should read 1's. You should hence drive the output pins low and observe which input pin is low.

Acknowledging interrupts - Interrupts are triggered when any bit in the Edge Capture Register is high. For the hexkeypad this usually means an interrupt gets generated when you first press a button. Make sure you clear the edge capture register before you enable interrupts and before you exit your interrupt handler.

Pinouts

The image below shows how the pins connect to the 4 row and 4 column pins of the hexkeypad.

Port BitHexpad Pin
0R0
1R1
2R2
3R3
4C0
5C1
6C2
7C3

Assembly Example: In JP1, Drive columns low and read rows into r3

.equ ADDR_JP1PORT, 0xFF200060

  movia r2,ADDR_JP1PORT
  movia r3,0xf0
  stwio r3,4(r2)  # Set directions - rows to input, columns to output 

  stwio r0,(r2)   # Drive all output pins low 

  ldwio r3,0(r2)  # Read port data 
  andi  r3,r3,0xf # Mask out all but last 4 bits 

Assembly Example: Using JP2, light up red LED 0, 1, 2, or 3 depending on row pressed

.equ ADDR_LEDR, 0xFF200000
.equ ADDR_JP2PORT, 0xFF200070
.equ ADDR_JP2PORT_DIR, 0xFF200074

.global _start
_start:

  movia r2,ADDR_LEDR
  mov   r5,zero   # Start display at 00000000 
  stwio r5,0(r2)  # Write to LED displays 

  movia r2,ADDR_JP2PORT_DIR
  movia r3,0x000000f0
  stwio r3,0(r2)  # Set rows to input, columns to output 

  movia r2,ADDR_JP2PORT
  stwio r0,(r2)   # Drive all output pins low 

LOOP:
  movia r2,ADDR_JP2PORT
  ldwio r3,0(r2)  # Read port data 
  movi  r4,0xf
  and   r3,r3,r4  # Mask out all but last 4 bits 

  beq   r4,r3,LOOP

  movia r2,ADDR_LEDR
  xori  r3,r3,0x0f # Invert bits to drive LEDs 
  stwio r3,0(r2)  # Write to LED displays 

                  # Debounce loop 
  movia r9,10000000
DELAY:
  subi r9,r9,1
  bne r9,r0, DELAY

  br _start

C Example: In JP1, Display the value of a pressed key


/*****
 * Gets a NON-DEBOUNCED key from the keypad. Note that this also shows the 
 * use of procedures and functions in C.
 *
 * This program detects a key pressed on the hexkeypad and displays it on the
 * red LEDs by lighting the corresponding LED
 *****/

#define ADDR_JP1PORT ((volatile long *) 0xFF200060)
#define HEXPAD_DIR ((volatile long *) 0xFF200064)
#define ADDR_LEDR ((volatile long *) 0xFF200000)
unsigned char colstims[]={0xe0,0xd0,0xb0,0x70}; //to run the hexpad


// start the hex keypad
// note that since this uses the GPIO interface you must set the
// directions of the individual bits. See the section on GPIO for
// more information.
void HexkeypadInit()
{
   *HEXPAD_DIR = 0xf0; // set directions . rows in, cols out
   *ADDR_JP1PORT = 0x0f; //set all rows to high
}

// return key found pressed, -1 if no key pressed
// note: if multiple keys pressed, returns the first key
// does not debounce key!
char HexkeypadIn()
{
  // Wait until a key is pressed
  int rowRead = (*ADDR_JP1PORT) & 0x0f;
  while (rowRead == 0x0f) {
    rowRead = (*ADDR_JP1PORT) & 0x0f;
  }
  
  // Key has been pressed!  Debounce!
  int d = 0;
  while (d < 100) {
    d++;
  }

  // Switch to read columns
  
  *HEXPAD_DIR = 0x0f; // rows out, cols in
  *ADDR_JP1PORT = 0xf0;  // set all cols to high
  
  // Process rows
  //rowRead = (*ADDR_JP1PORT) & 0x0f;
  rowRead = rowRead ^ 0x0f; // invert the number
  // Set it to first confirmed row
  if (rowRead & 0x01) {
    rowRead = 0;
  } else if (rowRead & 0x02) {
    rowRead = 1;
  } else if (rowRead & 0x04) {
    rowRead = 2;
  } else if (rowRead & 0x08) {
    rowRead = 3;
  } else {
    rowRead = -1;
  }
  

  // Read column
  int colRead = (*ADDR_JP1PORT) & 0xf0;
  // Process column
  colRead = colRead ^ 0xf0; // invert the number
  // Set it to first confirmed column
  if (colRead & 0x10) {
    colRead = 0;
  } else if (colRead & 0x20) {
    colRead = 1;
  } else if (colRead & 0x40) {
    colRead = 2;
  } else if (colRead & 0x80) {
    colRead = 3;
  } else {
    colRead = -1;
  }
  
  // Reset rows and columns
  *HEXPAD_DIR = 0xf0; // rows in, cols out
  *ADDR_JP1PORT = 0x0f;  // set all cols to high
  
  // Determine from rows and columns which key was pressed
  char numRead = -1;
  
  if ((rowRead != -1) && (colRead != -1)) {
    numRead = (char) (4*rowRead) + colRead;
  }
  return(numRead);

}  


int main()
{ 
   char inputkey;

   HexkeypadInit(); //this is a procedure to start the keypad

   while (1)
   {
      inputkey = HexkeypadIn(); //function, returns key pressed
      if (inputkey != -1) {
	    int i;
		int val = 1;
	    for (i = 0; i < inputkey; i++)
		{
		  val = val << 1;
		}
        *ADDR_LEDR = val;
      }
   }
}