Key Matrix
Wiring a CDU, FMC or GPS keypad as a row-and-column key matrix on an ESP32, with diodes against ghosting, so 60 keys need only 16 pins.
A CDU or FMC keypad has 40–70 keys. Wired one pin per key that is more pins than any ESP32 has. A key matrix puts the keys at the crossings of row and column wires: each key connects one row to one column. Scanning the rows one at a time tells which keys are closed, so a matrix of R rows and C columns reads R × C keys from R + C pins.
| Keypad | Matrix | Keys | Pins |
|---|---|---|---|
| Phone-style keypad | 4 × 3 | 12 | 7 |
| GPS / radio keypad | 4 × 6 | 24 | 10 |
| 737 CDU | 6 × 10 | 60 | 16 |
| Largest matrix | 10 × 10 | 100 | 20 |
The rows are driven : the ESP32 pulls one row LOW at a time, so row pins must be output-capable (not the input-only GPIO 34–39). The columns are read with the internal pull-up enabled; a column reads LOW while a key on the selected row is closed. A matrix has 2–10 rows and 2–10 columns.
| Line | Connect to | Colour |
|---|---|---|
| Row 0…n | One output-capable GPIO per row | Orange |
| Column 0…n | One GPIO per column with an internal pull-up (not the input-only GPIO 34–39, which have none) | Green |
| Each key | Between its row and its column, through a 1N4148 diode (cathode to row) | Yellow |
Without diodes, holding three keys at the corners of a rectangle closes a path through them, and the fourth corner reads as pressed even though nobody touched it. This ghost key is indistinguishable from a real press.
A 1N4148 diode in series with every key blocks the reverse path, so every key is read independently, however many are held. On a hand-wired keypad solder the diode straight onto the key's leg, cathode (the band) towards the row.
| Matrix | Several keys at once | Use when |
|---|---|---|
| With diodes | Every key reported independently | Hand-wired panels; keys that are held while another is pressed |
| Without diodes | Keys in an ambiguous rectangle are held at their last state | Ready-made membrane keypads, pressed one key at a time |
Select each row in turn by pulling it LOW, read every column, then release the row. Compare with the previous scan to report presses and releases.
// 3 × 3 key matrix scan — rows driven, columns read with pull-ups
const int ROW_PINS[] = { 13, 14, 27 };
const int COL_PINS[] = { 32, 33, 25 };
const int ROWS = 3;
const int COLS = 3;
bool keyState[ROWS][COLS];
void setup() {
Serial.begin(115200);
for (int r = 0; r < ROWS; r++) {
pinMode(ROW_PINS[r], OUTPUT);
digitalWrite(ROW_PINS[r], HIGH); // idle rows HIGH
}
for (int c = 0; c < COLS; c++) {
pinMode(COL_PINS[c], INPUT_PULLUP);
}
}
void loop() {
for (int r = 0; r < ROWS; r++) {
digitalWrite(ROW_PINS[r], LOW); // select one row
delayMicroseconds(5); // let the lines settle
for (int c = 0; c < COLS; c++) {
bool pressed = digitalRead(COL_PINS[c]) == LOW;
if (pressed != keyState[r][c]) {
keyState[r][c] = pressed;
Serial.printf("R%d C%d %s\n", r, c, pressed ? "pressed" : "released");
}
}
digitalWrite(ROW_PINS[r], HIGH); // deselect
}
delay(5); // ~200 scans a second; add debounce for real panels
}On a CockpitConnect controller you don't write this. Add a Key Matrix to the controller in the Flow Builder with its row and column pins and whether the keys have diodes; the first row pin names the matrix. Every key is then an ordinary Button on the matrix, shown as "R2 C3", with debounce, long-press gestures and its own Mappings. "Add all keys" places a Button node for every crossing at once. Without diodes the controller never reports a key it can't be sure of: keys in an ambiguous rectangle stay at their last state until the rectangle breaks.
| Application | Matrix | Notes |
|---|---|---|
| 737 CDU / Airbus MCDU | 6 × 10 or 7 × 10 | Diodes recommended; CLR is often held, so a long press clears the scratchpad |
| GPS keypad (GNS 430/530, G1000) | 4 × 6 | Soft keys and FMS buttons; encoders stay on their own pins |
| Radio / transponder keypad | 4 × 3 | Ready-made membrane keypad works, one key at a time |
| Overhead push-button rows | Up to 10 × 10 | Fewer wires through the panel; one harness per row |