Picking up stray voltage when handling 4+4 matrix keypad. What could be wrong?

I have a project to convert an old game console to a modern USB controller. It uses a Teensy 4.1 with USB host to interface with the xbox game controller and a standard 4+4 matrix keypad using keypad.h.

The game console has a wiring harness with GND, +5v, 4+4 matrix keypad lines, a POTX, POTY and POTC (5v) for a two-axis potentiometer joystick.

The Teensy outputs to a set of 4 CD74HC4066 switches using 16 output pins for a total of 16 switches. The switch inputs (E pins) are connected directly to Teensy output pins. Low is an open switch, high is a closed switch. The 4066 outputs (Y and Z) are matrixed into 8 lines and go to the console harness.

The Teensy also has an SPI connection through a bi-directional 3.3 to 5v level shifter module to an MCP42100 digital pot. This is connected to the console POTX, POTY and POTC lines. The level shifter is connected to the Teensy 3.3v and GND and the console 5v and GND.

This is working with one problem.

The 4+4 matrix keypad attached to the Teensy picks up stray voltage when I touch it. It is not mounted yet and just handling it sometimes causes a line to go high (confirmed with a logic probe). I can see the logic probe's high LED fade in as I move my finger across the pad. This causes the 4066 switch to close and registers and a button press on the console. If I don't touch the Matrix keypad there are no stray keypresses.

It stops happening when I plug the Teensy into the computer using USB. It does not happen when the Teensy is getting all power from USB (disconnected from console) and it doesn't happen when getting power from the console and connected to the computer with USB with the USB power line cut.

It seems like it must be a ground issue but I don't know enough about electronics to know how to fix it.

Does anyone have advice on what can cause this or how I can fix it?

It could be the code for reading the switch matrix. Are the input pins allowed to float or are using pull-up/pull-down resistors?
Anyway, post the code.

I will take a SWAG it sounds like a grounding problem. Your schematic is not complete and the power and grounds are missing among many other things.

6v6gt:
It could be the code for reading the switch matrix. Are the input pins allowed to float or are using pull-up/pull-down resistors?
Anyway, post the code.

I'm using the keypad.h library, I just define the pins and it handles the rest. I call keypad.getKey(); to see if anything is pressed. It works perfectly when hooked up with USB to the computer, it is only when running off the console power and ground that is has the problem.

const int ROW_NUM = 4; //four rows
const int COLUMN_NUM = 4; //three columns

char keys[ROW_NUM][COLUMN_NUM] = {
{'1', '2', '3', 'S'},
{'4', '5', '6', 'P'},
{'7', '8', '9', 'R'},
{'*', '0', '#', 'D'}
};

byte pin_rows[ROW_NUM] = {2, 3, 4, 5}; //connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {6, 7, 8, 9}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );

gilshultz:
I will take a SWAG it sounds like a grounding problem. Your schematic is not complete and the power and grounds are missing among many other things.

The power and ground are coming from the console harness and are the two lines in the top right. of my diagram.

Interesting. You seem to be decoding the 8 inputs from the keypad into 16 outputs then using four cd4066 switches to encode back to 8 inputs for the console.

Anyway, have you used decoupling capacitors (say 100nf) on the cd4066 chips ?
Do you need pull down resistors on the 8 key pad inputs (cd4066 outputs) on the console? I guess those switches have a very high impedance when open.

6v6gt:
Interesting. You seem to be decoding the 8 inputs from the keypad into 16 outputs then using four cd4066 switches to encode back to 8 inputs for the console.

Anyway, have you used decoupling capacitors (say 100nf) on the cd4066 chips ?
Do you need pull down resistors on the 8 key pad inputs (cd4066 outputs) on the console? I guess those switches have a very high impedance when open.

Yes, I'm decoding and reencoding the matrix keypads. I want to have the Teensy sit in the middle so I can use keypresses for different controller modes, etc.
No, I don't have decoupling capacitors on the 4066s. I can try that. I didn't put any pulldown resistors on the 4066 outputs. The original controller is a simple carbon dot switch without any pulldown, and this part seems to be working fine. I'm seeing the high voltage on the Teensy's 4+4 matrix, which translates into a high output pin to the 4066 input.

Decoupling is not optional for logic chips. Often datasheets don't mention decoupling because you
are supposed to know this :slight_smile:

Hi,
Just write some code JUST for the keypad and see if the problem occurs.
If you developed your code in stages you should have code that just tests your keypad already.

Do you have a DMM?
Can you please post a circuit diagram with power supply and gnd connections as well as pin numbers/names on your components?

Thanks.. Tom.. :slight_smile:

I've simplified my circuit to the bare bones and still have this issue.

The Teensy 4.1 is hooked up to the console 5v and GND. The keypad is attached to pins 2-9, and a logic probe is attached to the 3.3v and GND pins on the Teensy.

Normally the row pins 2-5 are high, column pins 6-9 float per the logic probe. Pressing a key causes the corresponding column pin to go high.

The problem occurs when the Teensy is hooked up to the console's 5v supply. Handling the keypad without pressing a button causes the column pins to sometimes go high. The logic probe's high LED gets brighter as I put more of my hand on the matrix keypad. I am not pushing on it or causing the switches to close.

This only happens when using the console power and ground. If I power it through another 5v supply it does not happen. If I power it with the console and attach a USB cable with ground, it does not happen. I measured the console power with a voltmeter at 4.95 volts.

I've tried both a 1uf and .1uf decoupling capacitor across the power supply lines. I tried a pulldown resistor on the column lines. Neither stopped the pins from going high when I handle the keypad.

How could my hand cause this voltage to cross the membrane switches without pressing them - only when using a certain power supply?

Thanks for any help.

The code I'm testing with:

#include <Keypad.h>
const int ROW_NUM = 4; //four rows
const int COLUMN_NUM = 4; //three columns

char keys[ROW_NUM][COLUMN_NUM] = {
{'1', '2', '3', 'S'},
{'4', '5', '6', 'P'},
{'7', '8', '9', 'R'},
{'*', '0', '#', 'D'}
};

byte pin_rows[ROW_NUM] = {2, 3, 4, 5}; //connect to the row pinouts of the keypad
byte pin_column[COLUMN_NUM] = {6, 7, 8, 9}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM );
char lastPressed = NO_KEY;

void setup() {
// put your setup code here, to run once:
Serial.println("Keypad Testing");
}

void loop() {
// put your main code here, to run repeatedly:
char key = keypad.getKey();

if (key != NO_KEY){
lastPressed = key;
Serial.println(key);
}
if(keypad.getState()==0) {
lastPressed = NO_KEY;
}
}

I see here at least 2 issues relating to non-AVR platforms for a keypad.h library:

Do you get any compiler warnings or messages relating to INPUT_PULLUP ? The method, sometimes used, of switching an input pin pullup resistor on, by writing a HIGH to it, is probably AVR specific.

For this project, an arduino IR learning remote control, I wrote my own matrix keyboard handler: https://forum.arduino.cc/index.php?topic=717762.0 . If you really get stuck, I can pick the code out for you to see if that helps.

Edit:

I’ve just looked at it again. There is something wrong here because pins should never float:

Normally the row pins 2-5 are high, column pins 6-9 float per the logic probe.

Which keypad library are you using. The one from the “issues” link above or another ?

The implementation of the keypad handler in that IR learning remote control project uses pin change interrupts because pressing a pin may also have to wake the device from sleep mode. It may not be that simple to adapt it for a Teensy 4.1

Hi,

Please read the post at the start of any forum , entitled “How to use this Forum”.
OR

Then look down to “code problems” about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Thanks. Tom… :slight_smile:

I was able to quickly put something together for reading a matrix keyboard based on an old project already mentioned. It hay help to narrow down the problem. It is quite compact when compared with the library. It simply prints the pressed key as your test sketch should do.

// read keyboard matrix
const uint8_t ROWS = 4 ;
const uint8_t COLS = 4 ;
const uint8_t keypadRowPins[ ROWS ] = { 7, 6, 5, 4 } ;  // change as required
const uint8_t keypadColPins[ COLS ] = { 9, 10, 11, 12 } ;  // change as required


// Check for dependencies in isKeyType() before making changes here
const int8_t keyMatrix [ ROWS ] [ COLS ] = {
  {'1', '2', '3', 'S'},
  {'4', '5', '6', 'P'},
  {'7', '8', '9', 'R'},
  {'*', '0', '#', 'D'}
} ;




int8_t keyScan( )  {
  // returns pressed key (if any) else -1
  // if multiple hits, returns the first.

  int8_t rv = -1 ; // assume failure

  int8_t rowFound = -1 ;
  int8_t colFound = -1 ;


  // set all rows LOW
  for ( uint8_t i = 0 ; i < ROWS; i++ ) {
    digitalWrite( keypadRowPins[ i ] , LOW ) ;
    pinMode( keypadRowPins[ i ] , OUTPUT ) ;
  }

  // scan all columns
  for ( uint8_t i = 0 ; i < COLS; i++ ) {
    pinMode( keypadColPins[ i ] , INPUT_PULLUP ) ;
    if ( digitalRead( keypadColPins[ i ] ) == LOW  ) {
      colFound = i ;
      break ;
    }
  }

  // set all cols LOW
  for ( uint8_t i = 0 ; i < COLS; i++ ) {
    digitalWrite( keypadColPins[ i ] , LOW ) ;
    pinMode( keypadColPins[ i ] , OUTPUT ) ;
  }

  // scan all rows
  for ( uint8_t i = 0 ; i < ROWS; i++ ) {
    pinMode( keypadRowPins[ i ] , INPUT_PULLUP ) ;
    if ( digitalRead( keypadRowPins[ i ] ) == LOW  ) {
      rowFound = i ;
      break ;
    }
  }

  if ( rowFound != -1 && colFound != -1  ) {
    // lastValidResultAtMs = millis() ;
    rv =  keyMatrix [ rowFound ] [ colFound ]  ;
  }

  // delay(50) ; // only for testing to minimise printout
  // DEBUG_PRINT( F("Key pressed = " )) ;
  // DEBUG_PRINTLN( rv ) ;

  return rv ;
}




void setup() {
  Serial.begin( 115200 ) ;
}

void loop() {
  static uint32_t lastScanAtMs = 0 ;
  if ( millis() - lastScanAtMs > 100 ) {   // set scan interval
    char ks = keyScan() ;
    if ( ks != -1 ) Serial.println( (char) ks ) ;
    lastScanAtMs = millis() ;
  }
}

Thank you for this, it looks very promising :grinning: I’ll have to rewire my full breadboard for a full test.

Initially your code was not working on my Teensy 4.1. All digitalReads reported the pins as LOW. I found that the Teensy requires a 10 microsecond delay between setting the pinMode to INPUT_PULLUP and reading a HIGH value from it. LINK

After making this change, the code works perfectly and I don’t see the phantom key presses from handling the keypad.

I wonder if the keypad.h library is doing something similar, and the indeterminate nature of reading the pin right after setting it to INPUT_PULLUP was nudged by my hand being on the keypad?

Replacing the keypad.h library with your code fixed the issue. My keypad matrix is working perfectly now. Thank you!

I’m glad that worked for you. Now that you have pointed out the issue related to the Teensy 4.1, I’ll restructure the code to do the INPUT_PULLUP settings as early as possible so they have a chance to be fully active before the corresponding digitalRead() statements are called. That will minimize the need for delay() statements in code. It will, however, add two for loops.
If I then notice that other users have similar problems, I’ll refer to this thread.

Restructure to increase the interval between switching on the pull up resistor and testing the pin:

const uint8_t ROWS = 4 ;
const uint8_t COLS = 4 ;
const uint8_t keypadRowPins[ ROWS ] = { 7, 6, 5, 4 } ;  // change as required
const uint8_t keypadColPins[ COLS ] = { 9, 10, 11, 12 } ;  // change as required


// Check for dependencies in isKeyType() before making changes here
const int8_t keyMatrix [ ROWS ] [ COLS ] = {
  {'1', '2', '3', 'S'},
  {'4', '5', '6', 'P'},
  {'7', '8', '9', 'R'},
  {'*', '0', '#', 'D'}
} ;




int8_t keyScan( )  {
  // returns pressed key (if any) else -1
  // if multiple hits, returns the first.
  // pinMode on fast MCUs may need stabilisation time before digitalRead()

  int8_t rv = -1 ; // assume failure

  int8_t rowFound = -1 ;
  int8_t colFound = -1 ;

  // preparation for scan: columns pulled HIGH, rows LOW
  for ( uint8_t i = 0 ; i < COLS; i++ ) pinMode( keypadColPins[ i ] , INPUT_PULLUP ) ;
  
  // set all rows LOW
  for ( uint8_t i = 0 ; i < ROWS; i++ ) {
    digitalWrite( keypadRowPins[ i ] , LOW ) ;
    pinMode( keypadRowPins[ i ] , OUTPUT ) ;
  }

  // scan all columns
  for ( uint8_t i = 0 ; i < COLS; i++ ) {
    if ( digitalRead( keypadColPins[ i ] ) == LOW  ) {
      colFound = i ;
      break ;
    }
  }

  // preparation for scan: rows pulled HIGH, columns LOW
  for ( uint8_t i = 0 ; i < ROWS; i++ ) pinMode( keypadRowPins[ i ] , INPUT_PULLUP ) ;

  // set all cols LOW
  for ( uint8_t i = 0 ; i < COLS; i++ ) {
    digitalWrite( keypadColPins[ i ] , LOW ) ;
    pinMode( keypadColPins[ i ] , OUTPUT ) ;
  }

  // scan all rows
  for ( uint8_t i = 0 ; i < ROWS; i++ ) {
    if ( digitalRead( keypadRowPins[ i ] ) == LOW  ) {
      rowFound = i ;
      break ;
    }
  }

  // check if we have a valid button press
  if ( rowFound != -1 && colFound != -1  ) {
    // lastValidResultAtMs = millis() ;
    rv =  keyMatrix [ rowFound ] [ colFound ]  ;
  }

  return rv ;
}




void setup() {
  Serial.begin( 115200 ) ;
}

void loop() {
  static uint32_t lastScanAtMs = 0 ;
  static char ksOld = -1 ;
  if ( millis() - lastScanAtMs > 50 ) {   // set scan interval
    char ks = keyScan() ;
    if ( ks != -1 && ksOld != ks ) Serial.println( ks ) ;
    ksOld = ks ;
    lastScanAtMs = millis() ;
  }
}

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.