This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TCA8418: TCA8418 Interfacing

Part Number: TCA8418


Hi,
I asked this question long ago and somehow i resolved the problem but I lost the solution due to window problem and i am back to the same problem.
I am using the given code that i downloaded from a github. Linked given on the code.
It works fine for me but the last 6 keys, it shows double output as shown in serial monitor data.

/*
 * TCA8418 Driver
 * This code is adapted from the phishman's driver for arduino, https://github.com/phishman/TCA8418
 * The difference is that it is written to be easily ported to another microcontroller
 * Author: Henry Troutman
 */

/*
 * Keyboard PCB Hookup Guide:
 * 1 -> 3.3V
 * 2 -> GND
 * 3 -> SDA
 * 4 -> SCL
 * 5 -> INT_PIN
 * 6 -> RTC_INT (ds3231)
 */

// Arduino I2C Library
#include <Wire.h>

// keyboard Constants
#define KEYBOARD_ADDRESS 0x34
#define KEYBOARD_INT_PIN 1
#define KEYBOARD_STATE_REGISTER 0x04
#define KEYBOARD_FLAG_REGISTER 0x02
#define KEYBOARD_KEY_DOWN 0x80
#define KEYBOARD_KEY_MASK 0x7F




// configuration commands (configures the 3x9 matrix as inputs with pullups, interrupts ...
// For more information look at the code in the repo linked above
const uint8_t KEYBOARD_CONFIG_COMMANDS[] = {0x1D,0x07,0x1E,0xFF,0x1F,0x01,0x01,0xB9,0x02,0x09}; 



// Define our functions before use
void keyboard_configure(void);
void keyboard_clearFlag(void);
uint8_t keyboard_getState(void);

// keyInt allows our event to ultimately be handled in the loop
volatile bool keyInt = false;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  keyboard_configure();
  pinMode(KEYBOARD_INT_PIN,INPUT); // There is an external pullup on the pin

  // Set up a falling edge pin interrupt on pin 1  
  attachInterrupt(digitalPinToInterrupt(KEYBOARD_INT_PIN), keyboard_ISR, FALLING); 
}

void loop() {
  if(keyInt)
  {
    uint8_t key_code = keyboard_getState(); // Get first keycode from FIFO
    if(key_code & KEYBOARD_KEY_DOWN) 
    {
      // This is where we can write to a screen or handle control keys
      Serial.print(key_code&KEYBOARD_KEY_MASK); // print the keycode
      Serial.print(",");
    }
      keyInt = false;
      keyboard_clearFlag();
    delay(100); 
  }
}

void keyboard_configure(void){
  for(uint8_t i = 0;i < 9;i+=2){
    Wire.beginTransmission(KEYBOARD_ADDRESS);
    Wire.write(KEYBOARD_CONFIG_COMMANDS[i]);
    Wire.write(KEYBOARD_CONFIG_COMMANDS[i+1]);
    Wire.endTransmission(); 
  }
}
uint8_t keyboard_getState(void){
  uint8_t key;
  Wire.beginTransmission(KEYBOARD_ADDRESS);
  Wire.write(KEYBOARD_STATE_REGISTER);
  Wire.endTransmission(); 
  Wire.requestFrom(KEYBOARD_ADDRESS, 1);    // request 1 bytes from slave device 0x34
  while (Wire.available()) 
  { // slave may send less than requested
    key = Wire.read(); // receive a byte as character
  }
  return key;
}
void keyboard_clearFlag(void){
  Wire.beginTransmission(KEYBOARD_ADDRESS);
  Wire.write(KEYBOARD_FLAG_REGISTER);
  Wire.write(0x0F);
  Wire.endTransmission(); 
}
void keyboard_ISR(void){
  keyInt = true;
}

/*
I2C Command Summary

Setup board (3x9 keypad)
write to Register, value
            0x1D, 0x07
            0x1E, 0xFF
            0x1F, 0x01
            0x01, 0xB9
            0x02, 0x09

To get keys
read 1 byte from 0x04

To clear interrupt flag
write to register,value
            0x02, 0x0F
 
 */

I have two request if you can help me with it.

  1. Assign number in same sequence for SW1 to SW9 as for SW10 to SW18. For example, instead of 21 to SW1, it should be 1 for SW1. The sequence of SW10 to SW18 is perfect.
  2. Assign a single unique number from SW19 to SW27 instead of double number




Serial Monitor Data

21 to 29 for SW1 to SW9 press
11 to 19 for SW11 to SW18 press

So far it is acceptable to me until it give me a unique ID.

The problem starts when i press SW19 then it generate a pair output i.e. 1,2
SW20 2,3
SW21 3,4 and so on

I need to know where i am doing wrong for last 9 switches.
I am using 3X9 keypad matrix.

  • Hi Ali,

    I am trying to understand your question. So what you are saying is that when you press SW1 to SW10, you receive the numbers 21 to 30. When you press switch SW11 to SW20, you read numbers 11 to 20. Are the numbers you are referring to listed in the key event table in the datasheet below? 

    If that is the case, can you double check to make sure your wiring is correct? 

    For the last 9 switches SW21 to SW29, you receive a pair number. Does that mean you read two key events per one key press only? Or are you reading two key events for a press and release of a single switch? 

    For your requests...

    Assign number in same sequence for SW1 to SW9 as for SW10 to SW18. For example, instead of 21 to SW1, it should be 1 for SW1. The sequence of SW10 to SW18 is perfect.

    Please double check the connections of your switches to the IC. This seems like the connections might be backwards in a way, especially if you are reading 21 decimal for switch 1. 

    Regards,

    Tyler

  • Hi

    Thanks for your reply.

    I am trying to understand your question. So what you are saying is that when you press SW1 to SW10, you receive the numbers 21 to 30. When you press switch SW11 to SW20, you read numbers 11 to 20. Are the numbers you are referring to listed in the key event table in the datasheet below? 

    I am not sure about it but i explain the code.

    1. Check if interrupt occur
    2. Read 1 byte from I2C
    3. if(Byte received from I2C & 0x80 )
    4. print ( Byte received from I2C & 0x7F)
    5. Clear interrupt flags

    This is what i print on serial monitor and get results correspond to different switch press.

    The connections are OK, it has no issue.

    ignore net lable name because i am connecting keypad through wires in correct position i.e. ROW1 to ROW0 of IC and so on.

    The only concerns is last row. I have two types of keypad 3X9 and 3X10. Whenever i read data from last row then it gives me output in pair form irrespective to the button in each row.

    I resolved that issue before but lost the solution. I am making some mistake in register reading or something like that.

  • Hi 

    Do you have any further questions?
     I tested a new code to check what ROW and Column it gives me on pressing each switch. 
    Here is what i found, SW1 = R2 C0
    SW10 = R1 C0
    SW19 = R0 C0

    01:47:25.821 -> PRESS	R: 2	C: 0
    01:47:26.075 -> RELEASE	R: 2	C: 0
    01:47:31.278 -> PRESS	R: 2	C: 1
    01:47:31.483 -> RELEASE	R: 2	C: 1
    01:47:34.045 -> PRESS	R: 2	C: 2
    01:47:34.236 -> RELEASE	R: 2	C: 2
    01:47:36.686 -> PRESS	R: 2	C: 3
    01:47:36.892 -> RELEASE	R: 2	C: 3
    01:47:38.786 -> PRESS	R: 2	C: 4
    01:47:38.992 -> RELEASE	R: 2	C: 4
    01:47:40.884 -> PRESS	R: 2	C: 5
    01:47:41.153 -> RELEASE	R: 2	C: 5
    01:47:43.029 -> PRESS	R: 2	C: 6
    01:47:43.236 -> RELEASE	R: 2	C: 6
    01:47:45.607 -> PRESS	R: 2	C: 7
    01:47:45.845 -> RELEASE	R: 2	C: 7
    01:47:48.530 -> PRESS	R: 2	C: 8
    01:47:48.706 -> RELEASE	R: 2	C: 8
    01:47:50.551 -> PRESS	R: 1	C: 0
    01:47:50.709 -> RELEASE	R: 1	C: 0
    01:47:55.231 -> PRESS	R: 1	C: 1
    01:47:55.454 -> RELEASE	R: 1	C: 1
    01:48:03.847 -> PRESS	R: 1	C: 1
    01:48:04.022 -> RELEASE	R: 1	C: 1
    01:48:05.996 -> PRESS	R: 1	C: 2
    01:48:06.219 -> RELEASE	R: 1	C: 2
    01:48:08.767 -> PRESS	R: 1	C: 3
    01:48:09.022 -> RELEASE	R: 1	C: 3
    01:48:10.469 -> PRESS	R: 1	C: 4
    01:48:10.645 -> RELEASE	R: 1	C: 4
    01:48:12.300 -> PRESS	R: 1	C: 5
    01:48:12.476 -> RELEASE	R: 1	C: 5
    01:48:17.376 -> PRESS	R: 1	C: 6
    01:48:17.599 -> RELEASE	R: 1	C: 6
    01:48:19.797 -> PRESS	R: 1	C: 7
    01:48:20.002 -> RELEASE	R: 1	C: 7
    01:48:22.133 -> PRESS	R: 1	C: 8
    01:48:22.371 -> RELEASE	R: 1	C: 8
    01:48:26.241 -> PRESS	R: 0	C: 0
    01:48:26.241 -> PRESS	R: 0	C: 1
    01:48:26.479 -> RELEASE	R: 0	C: 0
    01:48:26.479 -> RELEASE	R: 0	C: 1
    01:48:35.222 -> PRESS	R: 0	C: 1
    01:48:35.222 -> PRESS	R: 0	C: 2
    01:48:35.411 -> RELEASE	R: 0	C: 1
    01:48:35.411 -> RELEASE	R: 0	C: 2
    01:48:42.304 -> PRESS	R: 0	C: 2
    01:48:42.304 -> PRESS	R: 0	C: 3
    01:48:42.558 -> RELEASE	R: 0	C: 2
    01:48:42.558 -> RELEASE	R: 0	C: 3
    01:48:47.590 -> PRESS	R: 0	C: 3
    01:48:47.590 -> PRESS	R: 0	C: 4
    01:48:47.827 -> RELEASE	R: 0	C: 3
    01:48:47.827 -> RELEASE	R: 0	C: 4
    01:48:49.704 -> PRESS	R: 0	C: 4
    01:48:49.704 -> PRESS	R: 0	C: 5
    01:48:49.927 -> RELEASE	R: 0	C: 4
    01:48:49.927 -> RELEASE	R: 0	C: 5
    01:48:51.930 -> PRESS	R: 0	C: 5
    01:48:51.930 -> PRESS	R: 0	C: 6
    01:48:52.198 -> RELEASE	R: 0	C: 5
    01:48:52.198 -> RELEASE	R: 0	C: 6
    01:48:54.334 -> PRESS	R: 0	C: 6
    01:48:54.334 -> PRESS	R: 0	C: 7
    01:48:54.571 -> RELEASE	R: 0	C: 6
    01:48:54.571 -> RELEASE	R: 0	C: 7
    01:48:56.211 -> PRESS	R: 0	C: 7
    01:48:56.211 -> PRESS	R: 0	C: 8
    01:48:56.481 -> RELEASE	R: 0	C: 7
    01:48:56.481 -> RELEASE	R: 0	C: 8
    01:49:05.302 -> PRESS	R: 0	C: 8
    01:49:05.540 -> RELEASE	R: 0	C: 8

    This is the output of serial monitor. I don't mind if numbering sequence is different that is probably due to wiring of the keypad.
    My only concern is that last row  give two times press and release on single press of each button.

    Do you have any idea why is that?
    Thanks

  • Hi Ali,

    Is it possible to print out all the registers? I specifically want to look at registers 0x29, 0x2A, 0x2B, but a full register read out would be super helpful since this issue was originally solved via software and was not hardware related.

    Print the register read-outs for 0x00 - 0x2E if possible please. 

    Regards,

    Tyler

  • Hi

    Plz, see the attached document for requested data. I also posted code for your reference. I played a lot with all registers that i used but didn't get any success Thanks

    #include <Wire.h>
    
    #define KEYBOARD_ADDRESS 0x34
    #define KEYBOARD_INT_PIN 1
    #define KEYBOARD_EVENT_REGISTER 0x04
    #define KEYBOARD_FLAG_REGISTER 0x02
    #define KEYBOARD_KEY_DOWN 0x80
    #define KEYBOARD_KEY_MASK 0x7F
    
    // configuration commands
    const uint8_t KEYBOARD_CONFIG_COMMANDS[] = {
      0x1D, 0x07,
      0x1E, 0xFF,
      0x1F, 0x01,
      0x01, 0x11,
      0x02, 0xFF
    };
    
    volatile bool keyInt = false;
    
    void setup() {
      Serial.begin(9600);
      Wire.begin();
      keyboard_configure();
      pinMode(KEYBOARD_INT_PIN, INPUT);
    
      attachInterrupt(digitalPinToInterrupt(KEYBOARD_INT_PIN), keyboard_ISR, FALLING);
    }
    
    void loop() {
      if (keyInt) {
        printRegisterReadouts();
        keyboard_clearFlag();
        keyInt = false;
      }
    }
    
    void printRegisterReadouts() {
      for (uint8_t reg = 0x01; reg <= 0x2E; reg++) {
        uint8_t value = readRegister(reg);
        Serial.print("Register 0x");
        Serial.print(reg, HEX);
        Serial.print(": ");
        Serial.println(value, HEX);
      }
      Serial.println();
    }
    
    void keyboard_configure() {
      for (uint8_t i = 0; i < sizeof(KEYBOARD_CONFIG_COMMANDS); i += 2) {
        Wire.beginTransmission(KEYBOARD_ADDRESS);
        Wire.write(KEYBOARD_CONFIG_COMMANDS[i]);
        Wire.write(KEYBOARD_CONFIG_COMMANDS[i + 1]);
        Wire.endTransmission();
      }
    }
    
    uint8_t readRegister(uint8_t reg) {
      Wire.beginTransmission(KEYBOARD_ADDRESS);
      Wire.write(reg);
      Wire.endTransmission();
      Wire.requestFrom(KEYBOARD_ADDRESS, 1);
      if (Wire.available()) {
        return Wire.read();
      }
      return 0;
    }
    
    void keyboard_clearFlag() {
      Wire.beginTransmission(KEYBOARD_ADDRESS);
      Wire.write(KEYBOARD_FLAG_REGISTER);
      Wire.write(0xFF);
      Wire.endTransmission();
    }
    
    void keyboard_ISR() {
      keyInt = true;
    }
    

    Serial Data.xlsx

  • Hi

    Let me know if you have any other update or required anything else. It would be great if we can resolve it asap.
    Thanks

  • Hi Ali,

    I am actually looking at this question right now. Let me get back to you soon.

    Regards,

    Tyler

  • Hi Ali,

    Register 0x03 shows a value of 1 and 2 for key press working vs. not working respectively. This tells me that upon a correct key press, only one event is stored in the FIFO for a singular press or release. On the bad button press, two events are stored for a singular press or release action. 

    I also noticed that in the serial monitor read out when R = 1 or 2, and C = 1/2/3/4/5/6/7/8, there is no issue. The issue only occurs when ROW = 0, double press/release events are present only when ROW = 0. Are we sure that the electrical connections are good for ROW 0? Would it be possible that the code is registering two falling edges and registers two key presses/releases because the signal is non-monotonic?  Otherwise, this seems like an indexing issue or something similar to it. 

    The function keyboard_configure() seems correct. Uint8_t cycles through i = 0/2/4/6/8, and writes to each register 0x1D, 0x1E, 0x1F, 0x01, 0x02 correctly. I don't see that this function is the problem. 

    I don't see anything wrong with the readRegister(uint8_t reg) function either. 

    This leads me to think that the issue has something to deal with the keyboard_clearFlag() function since I find no error with the printRegisterReadouts() in the loop. In your code in the keyboard_clearFlag() function, can you change the write of 0xFF to 0x1F just to ensure you are not messing with the first three bits that are always 0? Not sure if this will do anything, but just wanted to change this so it is writing to the correct bits in the register. I don't necessarily think this is the issue. 

    It looks like you begin transmission using the correct address 0x34. Then you write to 0x02 to clear interrupts by writing 0xFF (all 1's). Change this to 0x1F to see if anything different happens. A stop bit follows the transmission which is correct. In the loop function, is it possible to add a small delay after the "if" statement. Delay (10) should be just fine. It seems like a debounce issue, however you have registers 0x29, 0x2A, 0x2B all 0x00, so 50us debounce is enabled. It might be possible that the 50us is not enough time. 

    I checked over the register read outs on the excel document that you provided. Nothing is standing out to me as a major issue. 

    Please check to see if anything I stated here helps solve the issue. If not, I think the next step is to look at a scope capture of a working key press vs a non-working key press. I do not see any other software related issues in your code at the moment. 

    Regards,

    Tyler

  • Hi

    Thanks for your detailed explanation. I found the issue. Actually, it wasn't the software issue. It is hardware issue. I made two versions of keypad. The old one i did testing last year and prepared the final code then i asked supplier to provide me more keypad and they made clearly mistake in new stock. i just tested with one of the old keypad and it worked fine but when i try same pcb board with same code , the new keypad then it generate this issue.

    Thanks again for all your help.

  • Hi

    I found the issue but not sure how to correct it. Maybe if you can suggest something.
    There is backlight on the keypad.
    As soon, i connect it's two wires with the board then it start giving two key press on single push but if i disconnect it's cable then it start working fine. I was doing testing and found it is working fine then i connect el cable and it start behaving same.
    The issue do not come up with other 18 keys. Only last row cause problem
    Thanks

  • Hi Ali,

    I not so sure how to fix this issue without knowing the full details on how this is connected in the system. It sounds like the backlighting is an additional feature to the keypad, and probably introduces noise into the power supply from powering LED's to backlight the keypad numbers. 

    Is it possible to add decoupling capacitors to the supply of the TCA8418? 0.1uF 10V capacitors should work here. It is more beneficial if the capacitors are located as close to the supply pins as possible. 

    It might also be wise to add filter capacitance on the ROW and COL pins as well as caps close to the switching pins in order to slow down the rising/falling edges of the switch. There might be noise coupling on the switch that is causing the TCA8418 to recognize a double switch press. 

    Regards,

    Tyler

  • Hi

    I added the capacitor at supply but it didn't help much. I introduced a debouncing delay of 50ms and it started to giving me a single value. Now my question is, how i can configure register to introduce this delay in TCA8418 so i don't have to worry about it in the program each time.
    Is there any other suggestions related to hardware because i am gonna fabricate new boards soon.
    Thanks

  • Hi Ali,

    The TCA8418 is only capable of implementing a 50us debounce delay by itself. 

    This timing cannot be changed in the TCA8418. Only option is to add addition delay via software, or reduce ringing via external RC components, slow down the overall data rate. Any changes in order to reduce the slew rate of the edge transition will help. 

    Regards,

    Tyler

  • Ok Thanks
    I will add in the software in that case

  • Hi Ali,

    This sounds good.

    Please let me know if you have further questions.

    Regards,

    Tyler